{"id":13477795,"url":"https://github.com/01mf02/jaq","last_synced_at":"2025-05-14T11:06:19.337Z","repository":{"id":37330066,"uuid":"318753449","full_name":"01mf02/jaq","owner":"01mf02","description":"A jq clone focussed on correctness, speed, and simplicity","archived":false,"fork":false,"pushed_at":"2025-04-25T21:00:33.000Z","size":1609,"stargazers_count":3063,"open_issues_count":26,"forks_count":84,"subscribers_count":21,"default_branch":"main","last_synced_at":"2025-05-07T10:52:33.973Z","etag":null,"topics":["jq","json","query","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/01mf02.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-MIT","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-12-05T09:53:21.000Z","updated_at":"2025-05-07T02:36:40.000Z","dependencies_parsed_at":"2024-01-22T10:54:46.886Z","dependency_job_id":"0bddc39b-2c93-4f62-ae81-eefe7b73bc69","html_url":"https://github.com/01mf02/jaq","commit_stats":{"total_commits":1419,"total_committers":23,"mean_commits":61.69565217391305,"dds":"0.25229034531360117","last_synced_commit":"1a4b0c28df305c753104e6b99280cfcb5264a47d"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/01mf02%2Fjaq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/01mf02%2Fjaq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/01mf02%2Fjaq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/01mf02%2Fjaq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/01mf02","download_url":"https://codeload.github.com/01mf02/jaq/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254129479,"owners_count":22019628,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jq","json","query","rust"],"created_at":"2024-07-31T16:01:47.690Z","updated_at":"2025-05-14T11:06:19.325Z","avatar_url":"https://github.com/01mf02.png","language":"Rust","funding_links":[],"categories":["Rust","Command-line tools","\u003ca name=\"data-management-json\"\u003e\u003c/a\u003eData management - JSON/YAML/etc.","json","JSON / YAML / CSV","Dev-Utilities"],"sub_categories":[],"readme":"# jaq\n\n![Build status](https://github.com/01mf02/jaq/actions/workflows/check.yml/badge.svg)\n[![Crates.io](https://img.shields.io/crates/v/jaq-core.svg)](https://crates.io/crates/jaq-core)\n[![Documentation](https://docs.rs/jaq-core/badge.svg)](https://docs.rs/jaq-core)\n[![Rust 1.65+](https://img.shields.io/badge/rust-1.65+-orange.svg)](https://www.rust-lang.org)\n\njaq (pronounced /ʒaːk/, like *Jacques*[^jacques]) is a clone of the JSON data processing tool [jq].\njaq aims to support a large subset of jq's syntax and operations.\n\nYou can try jaq online on the [jaq playground](https://gedenkt.at/jaq/).\nInstructions for the playground can be found [here](jaq-play/).\n\njaq focuses on three goals:\n\n* **Correctness**:\n  jaq aims to provide a more correct and predictable implementation of jq,\n  while preserving compatibility with jq in most cases.\n* **Performance**:\n  I created jaq originally because I was bothered by\n  [the long start-up time of jq 1.6](https://github.com/jqlang/jq/issues/1411),\n  which amounts to about 50ms on my machine.\n  This can be particularly seen when processing a large number of small files.\n  Although the startup time has been vastly improved in jq 1.7,\n  jaq is still faster than jq on many other [benchmarks](#performance).\n* **Simplicity**:\n  jaq aims to have a simple and small implementation, in order to\n  reduce the potential for bugs and to\n  facilitate contributions.\n\nI drew inspiration from another Rust program, namely [jql].\nHowever, unlike jql, jaq aims to closely imitate jq's syntax and semantics.\nThis should allow users proficient in jq to easily use jaq.\n\n[jq]: https://jqlang.github.io/jq/\n[jql]: https://github.com/yamafaktory/jql\n\n[^jacques]: I wanted to create a tool that should be discreet and obliging, like a good waiter.\n  And when I think of a typical name for a (French) waiter, to my mind comes \"Jacques\".\n  Later, I found out about the old French word *jacquet*, meaning \"squirrel\",\n  which makes for a nice *ex post* inspiration for the name.\n\n\n\n# Installation\n\n\n## Binaries\n\nYou can download binaries for Linux, Mac, and Windows on the [releases page](https://github.com/01mf02/jaq/releases).\nOn a Linux system, you can download it using the following commands:\n\n    $ curl -fsSL https://github.com/01mf02/jaq/releases/latest/download/jaq-$(uname -m)-unknown-linux-musl -o jaq \u0026\u0026 chmod +x jaq\n\nYou may also install jaq using [homebrew](https://formulae.brew.sh/formula/jaq) on macOS or Linux:\n\n    $ brew install jaq\n    $ brew install --HEAD jaq # latest development version\n\n[![Packaging status](https://repology.org/badge/vertical-allrepos/jaq.svg)](https://repology.org/project/jaq/versions)\n\n\n## From Source\n\nTo compile jaq, you need a Rust toolchain.\nSee \u003chttps://rustup.rs/\u003e for instructions.\n(Note that Rust compilers shipped with Linux distributions\nmay be too outdated to compile jaq.)\n\nAny of the following commands install jaq:\n\n    $ cargo install --locked jaq\n    $ cargo install --locked --git https://github.com/01mf02/jaq # latest development version\n\nOn my system, both commands place the executable at `~/.cargo/bin/jaq`.\n\nIf you have cloned this repository, you can also build jaq by executing one of the commands in the cloned repository:\n\n    $ cargo build --release # places binary into target/release/jaq\n    $ cargo install --locked --path jaq # installs binary\n\njaq should work on any system supported by Rust.\nIf it does not, please file an issue.\n\n\n\n# Examples\n\nThe following examples should give an impression of what jaq can currently do.\nYou should obtain the same outputs by replacing jaq with jq.\nIf not, your filing an issue would be appreciated. :)\nThe syntax is documented in the [jq manual].\n\n[jq manual]: https://jqlang.github.io/jq/manual/v1.6/\n\nAccess a field:\n\n    $ echo '{\"a\": 1, \"b\": 2}' | jaq '.a'\n    1\n\nAdd values:\n\n    $ echo '{\"a\": 1, \"b\": 2}' | jaq 'add'\n    3\n\nConstruct an array from an object in two ways and show that they are equal:\n\n    $ echo '{\"a\": 1, \"b\": 2}' | jaq '[.a, .b] == [.[]]'\n    true\n\nApply a filter to all elements of an array and filter the results:\n\n    $ echo '[0, 1, 2, 3]' | jaq 'map(.*2) | [.[] | select(. \u003c 5)]'\n    [0, 2, 4]\n\nRead (slurp) input values into an array and get the average of its elements:\n\n    $ echo '1 2 3 4' | jaq -s 'add / length'\n    2.5\n\nRepeatedly apply a filter to itself and output the intermediate results:\n\n    $ echo '0' | jaq '[recurse(.+1; . \u003c 3)]'\n    [0, 1, 2]\n\nLazily fold over inputs and output intermediate results:\n\n    $ seq 1000 | jaq -n 'foreach inputs as $x (0; . + $x)'\n    1 3 6 10 15 [...]\n\n\n\n# Performance\n\nThe following evaluation consists of several benchmarks that\nallow comparing the performance of jaq, jq, and [gojq].\nThe `empty` benchmark runs `n` times the filter `empty` with null input,\nserving to measure the startup time.\nThe `bf-fib` benchmark runs a Brainfuck interpreter written in jq,\ninterpreting a Brainfuck script that produces `n` Fibonacci numbers.\nThe other benchmarks evaluate various filters with `n` as input;\nsee [`bench.sh`](bench.sh) for details.\n\nI generated the benchmark data with\n`bench.sh target/release/jaq jq-1.7.1 gojq-0.12.16 | tee bench.json`\non a Linux system with an AMD Ryzen 5 5500U.[^binaries]\nI then processed the results with a \"one-liner\" (stretching the term and the line a bit):\n\n    jq -rs '.[] | \"|`\\(.name)`|\\(.n)|\" + ([.time[] | min | (.*1000|round)? // \"N/A\"] | min as $total_min | map(if . == $total_min then \"**\\(.)**\" else \"\\(.)\" end) | join(\"|\"))' bench.json\n\n(Of course, you can also use jaq here instead of jq.)\nFinally, I concatenated the table header with the output and piped it through `pandoc -t gfm`.\n\n[^binaries]: The binaries for jq-1.7.1 and gojq-0.12.16 were retrieved from their GitHub release pages.\n\nTable: Evaluation results in milliseconds (\"N/A\" if error or more than 10 seconds).\n\n| Benchmark       |       n | jaq-2.0 | jq-1.7.1 | gojq-0.12.16 |\n|-----------------|--------:|--------:|---------:|-------------:|\n| `empty`         |     512 |     300 |      500 |      **230** |\n| `bf-fib`        |      13 | **440** |     1230 |          570 |\n| `defs`          |  100000 |  **60** |      N/A |         1020 |\n| `upto`          |    8192 |   **0** |      470 |          460 |\n| `reduce-update` |   16384 |  **10** |      550 |         1340 |\n| `reverse`       | 1048576 |  **40** |      690 |          280 |\n| `sort`          | 1048576 | **110** |      530 |          630 |\n| `group-by`      | 1048576 | **500** |     1920 |         1500 |\n| `min-max`       | 1048576 | **210** |      320 |          260 |\n| `add`           | 1048576 | **460** |      630 |         1300 |\n| `kv`            |  131072 | **110** |      150 |          230 |\n| `kv-update`     |  131072 | **130** |      540 |          470 |\n| `kv-entries`    |  131072 | **570** |     1150 |          730 |\n| `ex-implode`    | 1048576 | **520** |     1110 |          580 |\n| `reduce`        | 1048576 | **770** |      890 |          N/A |\n| `try-catch`     | 1048576 | **290** |      320 |          370 |\n| `repeat`        | 1048576 | **140** |      840 |          530 |\n| `from`          | 1048576 | **320** |     1010 |          590 |\n| `last`          | 1048576 |  **40** |      240 |          110 |\n| `pyramid`       |  524288 | **340** |      350 |          480 |\n| `tree-contains` |      23 |  **70** |      610 |          210 |\n| `tree-flatten`  |      17 |     780 |      360 |       **10** |\n| `tree-update`   |      17 | **700** |      970 |         1340 |\n| `tree-paths`    |      17 |     440 |  **280** |          870 |\n| `to-fromjson`   |   65536 |  **40** |      360 |          110 |\n| `ack`           |       7 | **520** |      710 |         1220 |\n| `range-prop`    |     128 |     360 |      320 |      **230** |\n| `cumsum`        | 1048576 | **280** |      380 |          450 |\n| `cumsum-xy`     | 1048576 | **430** |      470 |          710 |\n\nThe results show that\njaq-2.0 is fastest on 25 benchmarks, whereas\njq-1.7.1 is fastest on 1 benchmark and\ngojq-0.12.16 is fastest on 3 benchmarks.\ngojq is much faster on `tree-flatten` because it implements the filter `flatten` natively instead of by definition.\n\n[gojq]: https://github.com/itchyny/gojq\n\n\n# Security\n\njaq's core has been audited by\n[Radically Open Security](https://www.radicallyopensecurity.com/)\nas part of an [NLnet](https://nlnet.nl/) grant ---\nthanks to both organisations for their support!\nThe [security audit](https://github.com/01mf02/jaq/releases/download/v2.2.0/jaq.penetration.test.report.2025.1.0.pdf) found\none low severity issue and three issues that are likely not exploitable at all.\nAs a result of this security audit, all issues were addressed and\nseveral fuzzing targets for jaq were added at `jaq-core/fuzz`.\nBefore that, jaq's JSON parser [hifijson](https://github.com/01mf02/hifijson/)\nalready disposed of a fuzzing target.\nFinally, jaq disposes of a carefully crafted test suite of more than 500 tests\nthat is checked at every commit.\n\n\n# Features\n\nHere is an overview that summarises:\n\n* [x] features already implemented, and\n* [ ] features not yet implemented.\n\n[Contributions to extend jaq are highly welcome.](#contributing)\n\n\n## Basics\n\n- [x] Identity (`.`)\n- [x] Recursion (`..`)\n- [x] Basic data types (null, boolean, number, string, array, object)\n- [x] if-then-else (`if .a \u003c .b then .a else .b end`)\n- [x] Folding (`reduce .[] as $x (0; . + $x)`, `foreach .[] as $x (0; . + $x; . + .)`)\n- [x] Error handling (`try ... catch ...`)\n- [x] Breaking (`label $x | f | ., break $x`)\n- [x] String interpolation (`\"The successor of \\(.) is \\(.+1).\"`)\n- [x] Format strings (`@json`, `@text`, `@csv`, `@tsv`, `@html`, `@sh`, `@base64`, `@base64d`)\n\n\n## Paths\n\n- [x] Indexing of arrays/objects (`.[0]`, `.a`, `.[\"a\"]`)\n- [x] Iterating over arrays/objects (`.[]`)\n- [x] Optional indexing/iteration (`.a?`, `.[]?`)\n- [x] Array slices (`.[3:7]`, `.[0:-1]`)\n- [x] String slices\n\n\n## Operators\n\n- [x] Composition (`|`)\n- [x] Variable binding (`. as $x | $x`)\n- [x] Pattern  binding (`. as {a: [$x, {(\"b\", \"c\"): $y, $z}]} | $x, $y, $z`)\n- [x] Concatenation (`,`)\n- [x] Plain assignment (`=`)\n- [x] Update assignment (`|=`)\n- [x] Arithmetic update assignment (`+=`, `-=`, ...)\n- [x] Alternation (`//`)\n- [x] Logic (`or`, `and`)\n- [x] Equality and comparison (`.a == .b`, `.a \u003c .b`)\n- [x] Arithmetic (`+`, `-`, `*`, `/`, `%`)\n- [x] Negation (`-`)\n- [x] Error suppression (`?`)\n\n\n## Definitions\n\n- [x] Basic definitions (`def map(f): [.[] | f];`)\n- [x] Recursive definitions (`def r: r; r`)\n\n\n## Core filters\n\n- [x] Empty (`empty`)\n- [x] Errors (`error`)\n- [x] Input (`inputs`)\n- [x] Length (`length`, `utf8bytelength`)\n- [x] Rounding (`floor`, `round`, `ceil`)\n- [x] String \u003c-\u003e JSON (`fromjson`, `tojson`)\n- [x] String \u003c-\u003e integers (`explode`, `implode`)\n- [x] String normalisation (`ascii_downcase`, `ascii_upcase`)\n- [x] String prefix/postfix (`startswith`, `endswith`, `ltrimstr`, `rtrimstr`)\n- [x] String whitespace trimming (`trim`, `ltrim`, `rtrim`)\n- [x] String splitting (`split(\"foo\")`)\n- [x] Array filters (`reverse`, `sort`, `sort_by(-.)`, `group_by`, `min_by`, `max_by`)\n- [x] Stream consumers (`first`, `last`, `range`, `fold`)\n- [x] Stream generators (`range`, `recurse`)\n- [x] Time (`now`, `fromdateiso8601`, `todateiso8601`)\n- [x] More numeric filters (`sqrt`, `sin`, `log`, `pow`, ...) ([list of numeric filters](#numeric-filters))\n- [x] More time filters (`strptime`, `strftime`, `strflocaltime`, `mktime`, `gmtime`, and `localtime`)\n\n## Standard filters\n\nThese filters are defined via more basic filters.\nTheir definitions are at [`std.jq`](jaq-std/src/std.jq).\n\n- [x] Undefined (`null`)\n- [x] Booleans (`true`, `false`, `not`)\n- [x] Special numbers (`nan`, `infinite`, `isnan`, `isinfinite`, `isfinite`, `isnormal`)\n- [x] Type (`type`)\n- [x] Filtering (`select(. \u003e= 0)`)\n- [x] Selection (`values`, `nulls`, `booleans`, `numbers`, `strings`, `arrays`, `objects`, `iterables`, `scalars`)\n- [x] Conversion (`tostring`, `tonumber`)\n- [x] Iterable filters (`map(.+1)`, `map_values(.+1)`, `add`, `join(\"a\")`)\n- [x] Array filters (`transpose`, `first`, `last`, `nth(10)`, `flatten`, `min`, `max`)\n- [x] Object-array conversion (`to_entries`, `from_entries`, `with_entries`)\n- [x] Universal/existential (`all`, `any`)\n- [x] Recursion (`walk`)\n- [x] I/O (`input`)\n- [x] Regular expressions (`test`, `scan`, `match`, `capture`, `splits`, `sub`, `gsub`)\n- [x] Time (`fromdate`, `todate`)\n\n## Numeric filters\n\njaq imports many filters from [libm](https://crates.io/crates/libm)\nand follows their type signature.\n\n\u003cdetails\u003e\u003csummary\u003eFull list of numeric filters defined in jaq\u003c/summary\u003e\n\nZero-argument filters:\n\n- [x] `acos`\n- [x] `acosh`\n- [x] `asin`\n- [x] `asinh`\n- [x] `atan`\n- [x] `atanh`\n- [x] `cbrt`\n- [x] `cos`\n- [x] `cosh`\n- [x] `erf`\n- [x] `erfc`\n- [x] `exp`\n- [x] `exp10`\n- [x] `exp2`\n- [x] `expm1`\n- [x] `fabs`\n- [x] `frexp`, which returns pairs of (float, integer).\n- [x] `gamma`\n- [x] `ilogb`, which returns integers.\n- [x] `j0`\n- [x] `j1`\n- [x] `lgamma`\n- [x] `log`\n- [x] `log10`\n- [x] `log1p`\n- [x] `log2`\n- [x] `logb`\n- [x] `modf`, which returns pairs of (float, float).\n- [x] `nearbyint`\n- [x] `pow10`\n- [x] `rint`\n- [x] `significand`\n- [x] `sin`\n- [x] `sinh`\n- [x] `sqrt`\n- [x] `tan`\n- [x] `tanh`\n- [x] `tgamma`\n- [x] `trunc`\n- [x] `y0`\n- [x] `y1`\n\nTwo-argument filters that ignore `.`:\n\n- [x] `atan2`\n- [x] `copysign`\n- [x] `drem`\n- [x] `fdim`\n- [x] `fmax`\n- [x] `fmin`\n- [x] `fmod`\n- [x] `hypot`\n- [x] `jn`, which takes an integer as first argument.\n- [x] `ldexp`, which takes an integer as second argument.\n- [x] `nextafter`\n- [x] `nexttoward`\n- [x] `pow`\n- [x] `remainder`\n- [x] `scalb`\n- [x] `scalbln`, which takes as integer as second argument.\n- [x] `yn`, which takes an integer as first argument.\n\nThree-argument filters that ignore `.`:\n\n- [x] `fma`\n\n\u003c/details\u003e\n\n## Modules\n\n- [x] `include \"path\";`\n- [x] `import \"path\" as mod;`\n- [x] `import \"path\" as $data;`\n\n## Advanced features\n\njaq currently does *not* aim to support several features of jq, such as:\n\n- SQL-style operators\n- Streaming\n\n\n\n# Differences between jq and jaq\n\n\n## Numbers\n\njq uses 64-bit floating-point numbers (floats) for any number.\nBy contrast, jaq interprets\nnumbers such as 0   or -42 as machine-sized integers and\nnumbers such as 0.0 or 3e8 as 64-bit floats.\nMany operations in jaq, such as array indexing,\ncheck whether the passed numbers are indeed integer.\nThe motivation behind this is to avoid\nrounding errors that may silently lead to wrong results.\nFor example:\n\n    $ jq  -n '[0, 1, 2] | .[1.0000000000000001]'\n    1\n    $ jaq -n '[0, 1, 2] | .[1.0000000000000001]'\n    Error: cannot use 1.0 as integer\n    $ jaq -n '[0, 1, 2] | .[1]'\n    1\n\nThe rules of jaq are:\n\n* The sum, difference, product, and remainder of two integers is integer.\n* Any other operation between two numbers yields a float.\n\nExamples:\n\n    $ jaq -n '1 + 2'\n    3\n    $ jaq -n '10 / 2'\n    5.0\n    $ jaq -n '1.0 + 2'\n    3.0\n\nYou can convert an integer to a floating-point number e.g.\nby adding 0.0, by multiplying with 1.0, or by dividing with 1.\nYou can convert a floating-point number to an integer by\n`round`, `floor`, or `ceil`:\n\n    $ jaq -n '1.2 | [floor, round, ceil]'\n    [1, 1, 2]\n\n### NaN and infinity\n\nIn jq, division by 0 yields an error, whereas\nin jaq, `n / 0` yields `nan` if `n == 0`, `infinite` if `n \u003e 0`, and `-infinite` if `n \u003c 0`.\njaq's behaviour is closer to the IEEE standard for floating-point arithmetic (IEEE 754).\n\n\n## Assignments\n\nLike jq, jaq allows for assignments of the form `p |= f`.\nHowever, jaq interprets these assignments differently.\nFortunately, in most cases, the result is the same.\n\nIn jq, an assignment `p |= f` first constructs paths to all values that match `p`.\n*Only then*, it applies the filter `f` to these values.\n\nIn jaq, an assignment `p |= f` applies `f` *immediately* to any value matching `p`.\nUnlike in jq, assignment does not explicitly construct paths.\n\njaq's implementation of assignment likely yields higher performance,\nbecause it does not construct paths.\nFurthermore, this allows jaq to use multiple outputs of the right-hand side, whereas\njq uses only the first.\nFor example, `0 | (., .) |= (., .+1)` yields `0 1 1 2` in jaq,\nwhereas it yields only `0` in jq.\nHowever, `{a: 1} | .a |= (2, 3)` yields `{\"a\": 2}` in both jaq and jq,\nbecause an object can only associate a single value with any given key,\nso we cannot use multiple outputs in a meaningful way here.\n\nBecause jaq does not construct paths,\nit does not allow some filters on the left-hand side of assignments,\nfor example `first`, `last`, `limit`:\nFor example, `[1, 2, 3] | first(.[]) |= .-1`\nyields `[0, 2, 3]` in jq, but is invalid in jaq.\nSimilarly, `[1, 2, 3] | limit(2; .[]) |= .-1`\nyields `[0, 1, 3]` in jq, but is invalid in jaq.\n(Inconsequentially, jq also does not allow for `last`.)\n\n\n## Folding\n\njq and jaq provide filters\n`reduce xs as $x (init; update)`,\n`foreach xs as $x (init; update)`, and\n`foreach xs as $x (init; update; project)`, where\n`foreach xs as $x (init; update)` is equivalent to\n`foreach xs as $x (init; update; .)`.\n\nIn jaq, the output of these filters is defined very simply:\nAssuming that `xs` evaluates to `x0`, `x1`, ..., `xn`,\n`reduce xs as $x (init; update)` evaluates to\n\n~~~\ninit\n| x0 as $x | update\n| ...\n| xn as $x | update\n~~~\n\nand `foreach xs as $x (init; update; project)` evaluates to\n\n~~~ text\ninit |\n( x0 as $x | update | project,\n( ...\n( xn as $x | update | project,\n( empty )...)\n~~~\n\nThe interpretation of `reduce`/`foreach` in jaq has the following advantages over jq:\n\n* It deals very naturally with filters that yield multiple outputs.\n  In contrast, jq discriminates outputs of `f`,\n  because it recurses only on the last of them,\n  although it outputs all of them.\n  \u003cdetails\u003e\u003csummary\u003eExample\u003c/summary\u003e\n\n  `foreach (5, 10) as $x (1; .+$x, -.)` yields\n  `6, -1, 9, 1` in jq, whereas it yields\n  `6, 16, -6, -1, 9, 1` in jaq.\n  We can see that both jq and jaq yield the values `6` and `-1`\n  resulting from the first iteration (where `$x` is 5), namely\n  `1 | 5 as $x | (.+$x, -.)`.\n  However, jq performs the second iteration (where `$x` is 10)\n  *only on the last value* returned from the first iteration, namely `-1`,\n  yielding the values `9` and `1` resulting from\n  `-1 | 10 as $x | (.+$x, -.)`.\n  jaq yields these values too, but it also performs the second iteration\n  on all other values returned from the first iteration, namely `6`,\n  yielding the values `16` and `-6` that result from\n  ` 6 | 10 as $x | (.+$x, -.)`.\n\n  \u003c/details\u003e\n* It makes the implementation of `reduce` and `foreach`\n  special cases of the same code, reducing the potential for bugs.\n\n\n## Miscellaneous\n\n* Slurping: When files are slurped in (via the `-s` / `--slurp` option),\n  jq combines the inputs of all files into one single array, whereas\n  jaq yields an array for every file.\n  This is motivated by the `-i` / `--in-place` option,\n  which could not work with the behaviour implemented by jq.\n  The behaviour of jq can be approximated in jaq;\n  for example, to achieve the output of\n  `jq -s . a b`, you may use\n  `jaq -s . \u003c(cat a b)`.\n* Cartesian products:\n  In jq, `[(1,2) * (3,4)]` yields `[3, 6, 4, 8]`, whereas\n  `[{a: (1,2), b: (3,4)} | .a * .b]` yields `[3, 4, 6, 8]`.\n  jaq yields `[3, 4, 6, 8]` in both cases.\n* Indexing `null`:\n  In jq, when given `null` input, `.[\"a\"]` and `.[0]` yield `null`, but `.[]` yields an error.\n  jaq yields an error in all cases to prevent accidental indexing of `null` values.\n  To obtain the same behaviour in jq and jaq, you can use\n  `.[\"a\"]? // null` or `.[0]? // null` instead.\n* List updating:\n  In jq, `[0, 1] | .[3] = 3` yields `[0, 1, null, 3]`; that is,\n  jq fills up the list with `null`s if we update beyond its size.\n  In contrast, jaq fails with an out-of-bounds error in such a case.\n* Input reading:\n  When there is no more input value left,\n  in jq, `input` yields an error, whereas in jaq, it yields no output value.\n* Joining:\n  When given an array `[x0, x1, ..., xn]`,\n  in jq, `join(x)` converts all elements of the input array to strings and intersperses them with `x`, whereas\n  in jaq, `join(x)` simply calculates `x0 + x + x1 + x + ... + xn`.\n  When all elements of the input array and `x` are strings, jq and jaq yield the same output.\n\n\n\n# Contributing\n\nContributions to jaq are welcome.\nPlease make sure that after your change, `cargo test` runs successfully.\n\n\n\n# Acknowledgements\n\n[This project](https://nlnet.nl/project/jaq/) was funded through the\n\u003ca href=\"https://nlnet.nl/entrust\"\u003eNGI0 Entrust\u003c/a\u003e Fund, a fund established by\n\u003ca href=\"https://nlnet.nl\"\u003eNLnet\u003c/a\u003e with financial support from the\nEuropean Commission's \u003ca href=\"https://ngi.eu\"\u003eNext Generation Internet\u003c/a\u003e\nprogramme, under the aegis of \u003ca href=\"https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en\"\u003eDG Communications Networks, Content and Technology\u003c/a\u003e under grant agreement N\u003csup\u003eo\u003c/sup\u003e 101069594.\n\njaq has also profited from:\n\n* [serde_json] to read and [colored_json] to output JSON,\n* [chumsky] to parse and [ariadne] to pretty-print parse errors,\n* [mimalloc] to boost the performance of memory allocation, and\n* the Rust standard library, in particular its awesome [Iterator],\n  which builds the rock-solid base of jaq's filter execution\n\n[serde_json]: https://docs.rs/serde_json/\n[colored_json]: https://docs.rs/colored_json/\n[chumsky]: https://docs.rs/chumsky/\n[ariadne]: https://docs.rs/ariadne/\n[mimalloc]: https://docs.rs/mimalloc/\n[Iterator]: https://doc.rust-lang.org/std/iter/trait.Iterator.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F01mf02%2Fjaq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F01mf02%2Fjaq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F01mf02%2Fjaq/lists"}