Skip to content

Commit 40024e2

Browse files
authored
Merge pull request #360 from 01mf02/prepare-3.0-alpha
Prepare 3.0-alpha
2 parents 4b4ec36 + 061b2eb commit 40024e2

File tree

11 files changed

+291
-187
lines changed

11 files changed

+291
-187
lines changed

Cargo.lock

Lines changed: 96 additions & 92 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@
55
[![Documentation](https://docs.rs/jaq-core/badge.svg)](https://docs.rs/jaq-core)
66
[![Rust 1.69+](https://img.shields.io/badge/rust-1.69+-orange.svg)](https://www.rust-lang.org)
77

8-
jaq (pronounced /ʒaːk/, like *Jacques*[^jacques]) is a clone of the JSON data processing tool [jq].
9-
It is two things at a time:
8+
jaq (pronounced /ʒaːk/, like *Jacques*[^jacques]) is a clone of
9+
the JSON data processing tool [`jq`](https://jqlang.github.io/jq/).
10+
It has a few features not present in `jq`, such as
11+
support for the data formats YAML, CBOR, TOML, and XML.
12+
jaq has an own [manual](https://gedenkt.at/jaq/manual/).
13+
You can try jaq on the [playground](https://gedenkt.at/jaq/).
14+
15+
jaq is two things at a time:
1016

1117
- A command-line program, `jaq`, that can be used as drop-in replacement for `jq`.
1218
- A library, [`jaq-core`](https://docs.rs/jaq-core/),
@@ -15,10 +21,6 @@ It is two things at a time:
1521
can be safely used in multi-threaded environments and
1622
supports [arbitrary data types beyond JSON](https://docs.rs/jaq-core/latest/jaq_core/val/trait.ValT.html).
1723

18-
jaq has an own [manual].
19-
You can try jaq online on the jaq [playground].
20-
Instructions for the playground can be found [here](jaq-play/).
21-
2224
jaq focuses on three goals:
2325

2426
* **Correctness**:
@@ -36,10 +38,6 @@ jaq focuses on three goals:
3638
reduce the potential for bugs and to
3739
facilitate contributions.
3840

39-
[jq]: https://jqlang.github.io/jq/
40-
[manual]: https://gedenkt.at/jaq/manual/
41-
[playground]: https://gedenkt.at/jaq/
42-
4341
[^jacques]: I wanted to create a tool that should be discreet and obliging, like a good waiter.
4442
And when I think of a typical name for a (French) waiter, to my mind comes "Jacques".
4543
Later, I found out about the old French word *jacquet*, meaning "squirrel",
@@ -200,7 +198,13 @@ Add your own testimonials via <https://github.com/01mf02/jaq/issues/355>.
200198
# Acknowledgements
201199

202200
[This project](https://nlnet.nl/project/jaq/) was funded through the
203-
<a href="https://nlnet.nl/entrust">NGI0 Entrust</a> Fund, a fund established by
204-
<a href="https://nlnet.nl">NLnet</a> with financial support from the
205-
European Commission's <a href="https://ngi.eu">Next Generation Internet</a>
206-
programme, under the aegis of <a href="https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en">DG Communications Networks, Content and Technology</a> under grant agreement N<sup>o</sup> 101069594.
201+
[NGI0 Entrust](https://nlnet.nl/entrust) and
202+
[NGI0 Commons](https://nlnet.nl/commonsfund) funds established by
203+
[NLnet](https://nlnet.nl) with financial support from the
204+
European Commission's [Next Generation Internet](https://ngi.eu)
205+
programme, under the aegis of [DG Communications Networks, Content and Technology](https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en) under
206+
grant agreements
207+
[101069594](https://cordis.europa.eu/project/id/101069594) and
208+
[101135429](https://cordis.europa.eu/project/id/101135429).
209+
Additional funding is made available by the
210+
[Swiss State Secretariat for Education, Research and Innovation](https://www.sbfi.admin.ch/sbfi/en/home.html) (SERI).

docs/advanced.dj

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,23 @@ I think that he did a great job creating jq.)
1919

2020
jaq and `jq` pursue different approaches to execute assignments:
2121

22-
- *Path-based*: In `jq`, an assignment `p |= f` first constructs paths to all values that match `p`.
23-
*Only then*, it applies the filter `f` to these values.
24-
- *Pathless*: In jaq, an assignment `p |= f` applies `f` *immediately* to any value matching `p`.
25-
Unlike in `jq`, assignment does not explicitly construct paths.
26-
27-
Fortunately, in most cases, the result is the same.
22+
- *Path-based*: In `jq`, an assignment `p |= f`
23+
constructs paths to all values that match `p` and
24+
applies the filter `f` to these values.
25+
- *Pathless*: In jaq, an assignment `p |= f` is transformed to
26+
a different filter that does not construct any paths.
27+
28+
For example, consider the update
29+
`[1, 2, 3] | .[] |= .+1 --> [2, 3, 4]`:
30+
When `jq` executes this, it calculates
31+
`[1, 2, 3] | path(.[]) --> [0] [1] [2]` and applies
32+
`.+1` on each value at these paths.
33+
On the other hand, jaq transforms the update to
34+
`[1, 2, 3] | [.[] | .+1] --> [2, 3, 4]` ---
35+
the assignment does not involve any path construction.
36+
37+
Fortunately, like in the example above, in most cases,
38+
the result of the both approaches is the same.
2839
The following sections explain the two approaches in more detail,
2940
and how to write updates that behave the same in both `jq` and jaq.
3041

@@ -423,7 +434,7 @@ bind it to the variable `$name`, and
423434
make it accessible in the current module.
424435

425436
For example, if `foo.json` in the current working directory contains `1 2 3`, then
426-
`jaq -L . -n 'import "foo.json" as $myfoo; $myfoo'` yields `1 2 3`.
437+
`jaq -L . -n 'import "foo.json" as $myfoo; $myfoo'` yields `[1, 2, 3]`.
427438

428439
### Search paths
429440

@@ -476,6 +487,19 @@ This searches for `binary.json` at the following paths:
476487
2. `./bar/binary.json` (relative to the current working directory)
477488
3. `./binary.json` (relative to the parent directory of `decode.jq`)
478489

490+
::: Compatibility
491+
If a file to load has been given without extension,
492+
such as `decode` and `binary` above, then
493+
jaq adds an extension (`.jq` for modules or `.json` for data).
494+
`jq` adds an extension _unconditionally_; that is,
495+
even if an extension has been given as part of the file name,
496+
`jq` adds an extension.
497+
498+
jaq's behaviour is motivated by allowing instructions like
499+
`import "binary.cbor" as $binary` in the future.
500+
Here, unconditionally adding the `.json` extension would be counterproductive.
501+
:::
502+
479503

480504
## Comments
481505

docs/cli.dj

Lines changed: 121 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,25 @@ performs the following steps:
1212
- For each input value in the file:
1313

1414
- Run _FILTER_ on the input value and print its output values
15+
- If an uncaught error is encountered at any point, jaq stops.
1516

1617
For example, `jaq '.name?' persons.json`
1718
parses the filter `.name?`, then
1819
reads all values in `persons.json` one-by-one.
1920
It then executes the filter `.name?` on each of the values and
2021
prints the outputs of the filter as JSON.
2122

22-
There are a few rules:
23-
24-
- If no _FILTER_ is given, jaq uses `.` (the [identity filter](#identity)) as filter.
25-
- If no _FILE_ is given, jaq reads from standard input.
26-
- jaq determines the format to parse a _FILE_ as follows:
2723

28-
- If [`--from`](#--from) _FORMAT_ is used, jaq uses that format.
29-
- Otherwise, if _FILE_ has a file extension known by jaq, such as
30-
`.json`, `.yaml`, `.cbor`, `.toml`, `.xml`,
31-
jaq uses the corresponding format.
32-
- Otherwise, jaq assumes JSON.
33-
- If an uncaught error is encountered at any point, jaq stops.
34-
35-
When passing filters directly as _FILTER_ argument on the command-line,
36-
care has to be taken to properly escape the filter.
37-
How to do this depends from platform to platform, but on Unixoid systems,
38-
surrounding the filter with single quotes (`'`) and
39-
replacing occurrences of `'` in filters by `'\''` suffices.
40-
For example, to run the filter `"'"` that
41-
produces a string containing a single quote, you can use
42-
`jaq -n '"'\''"'`.
43-
44-
Running filters that start with the [negation operator](#negation),
45-
such as `jaq '-1'`, fails because `-` is interpreted as
46-
start of a command-line switch rather than negation.
47-
You can remedy this by using
48-
`jaq -- '-1'` instead, or by surrounding the filter in parentheses, i.e.
49-
`jaq '(-1)'`.
24+
## Input
5025

26+
If no _FILE_ is given, jaq reads from standard input.
27+
jaq determines the format to parse a _FILE_ as follows:
5128

52-
## Input options
29+
- If [`--from`](#--from) _FORMAT_ is used, jaq uses that format.
30+
- Otherwise, if _FILE_ has a file extension known by jaq, such as
31+
`.json`, `.yaml`, `.cbor`, `.toml`, `.xml`,
32+
jaq uses the corresponding format.
33+
- Otherwise, jaq assumes JSON.
5334

5435
{#--from}
5536
### `--from` _FORMAT_
@@ -90,30 +71,28 @@ This can be useful to fold over all inputs with [`reduce` / `foreach`](#reduce-f
9071
Read lines of the input as sequence of strings.
9172
For example,
9273
`echo -e "Hello\nWorld" | jaq -R` yields two outputs; `"Hello"` and `"World"`.
93-
When combined with `-s` (`--slurp`), this yields the whole input as a single string.
74+
75+
When combined with [`--slurp`](#--slurp),
76+
this yields the whole input as a single string.
9477
For example,
9578
`echo -e "Hello\nWorld" | jaq -Rs` yields `"Hello\nWorld\n"`.
79+
See [`--rawfile`](#--rawfile).
9680

9781
This is equivalent to `--from raw`.
9882

99-
::: Advanced
100-
When using `-Rs` to load a file (as opposed to standard input),
101-
jaq loads this file in constant time (if it can be memory-mapped).
102-
This is because unlike jq, jaq does not validate that strings are valid UTF-8.
103-
That permits loading arbitrary binary files;
104-
these can be processed as byte strings via [`tobytes`](#tobytes).
105-
:::
106-
10783
{#--slurp}
10884
### `-s`, `--slurp`
10985

11086
Read (slurp) all input values into one array.
11187
For example,
11288
`jaq -s <<< "1 2 3"` yields a single output, namely the array `[1, 2, 3]`, whereas
11389
`jaq <<< "1 2 3"` yields three outputs, namely `1`, `2`, and `3`.
114-
When combining `--slurp` with [`--raw-input`](#--raw-input), jaq reads
115-
the full input as a single string; for example,
90+
91+
When combined with [`--raw-input`](#--raw-input),
92+
jaq reads the full input as a single string.
93+
For example,
11694
`jaq -Rs <<< "1 2 3"` yields the single output `"1 2 3\n"`.
95+
See [`--rawfile`](#--rawfile).
11796

11897
::: Compatibility
11998
When multiple files are slurped in,
@@ -128,7 +107,7 @@ for example, to achieve the output of
128107
:::
129108

130109

131-
## Output options
110+
## Output
132111

133112
{#--to}
134113
### `--to` _FORMAT_
@@ -235,7 +214,25 @@ For example,
235214
Use _N_ spaces for indentation (default: 2).
236215

237216

238-
## Compilation options
217+
## Compilation
218+
219+
If no _FILTER_ is given, jaq uses `.` (the [identity filter](#identity)) as filter.
220+
221+
When passing filters directly as _FILTER_ argument on the command-line,
222+
care has to be taken to properly escape the filter.
223+
How to do this depends from platform to platform, but on Unixoid systems,
224+
surrounding the filter with single quotes (`'`) and
225+
replacing occurrences of `'` in filters by `'\''` suffices.
226+
For example, to run the filter `"'"` that
227+
produces a string containing a single quote, you can use
228+
`jaq -n '"'\''"'`.
229+
230+
Running filters that start with the [negation operator](#negation),
231+
such as `jaq '-1'`, fails because `-` is interpreted as
232+
start of a command-line switch rather than negation.
233+
You can remedy this by using
234+
`jaq -- '-1'` instead, or by surrounding the filter in parentheses, i.e.
235+
`jaq '(-1)'`.
239236

240237
{#--from-file}
241238
### `-f`, `--from-file`
@@ -270,7 +267,7 @@ If `--library-path` is not given, the following global search paths are used:
270267
See the [modules](#modules) section for more details.
271268

272269

273-
## Variable options
270+
## Variables
274271

275272
{#--arg}
276273
### `--arg` _A_ _V_
@@ -305,6 +302,19 @@ For example, if `values.json` contains `1 2 3`, then
305302

306303
Set variable `$A` to string containing the contents of file _F_.
307304

305+
jaq tries to load the file via memory mapping,
306+
taking constant time and allowing to load files that do not fit into memory.
307+
If this fails, jaq loads the file regularly, taking linear time.
308+
This is also what happens when using
309+
`-Rs` ([--raw-input](#--raw-input) and [--slurp](#--slurp))
310+
to load a file (as opposed to standard input).
311+
312+
::: Compatibility
313+
Unlike `jq`, jaq does not verify that the file is valid UTF-8.
314+
That permits loading arbitrary binary files;
315+
these can be processed as byte strings via [`tobytes`](#tobytes).
316+
:::
317+
308318
### `--args`
309319

310320
Collect remaining positional arguments into `$ARGS.positional`.
@@ -322,3 +332,72 @@ the latter because it would not have been interpreted as input file.
322332
However, `-c` is collected into the array because it comes after `--`,
323333
which leads every argument after it to be interpreted as input file.
324334

335+
336+
## Miscellanea
337+
338+
{#--exit-status}
339+
### `-e`, `--exit-status`
340+
341+
Use the last output value as exit status code.
342+
343+
This enables the use of the exit codes 1 and 4, which are not used otherwise.
344+
345+
jaq uses the following exit codes:
346+
347+
- 0: No errors.
348+
- 1: The last output value is `false` or `null`.
349+
- 2: I/O or CLI error, e.g. file not found or unknown CLI option.
350+
- 3: Filter parse/compilation error.
351+
- 4: The filter did not yield any output.
352+
- 5: Any other error, e.g. call to the filter [`error`](#error).
353+
354+
The filters [`halt`](#halt) and [`halt_error`](#halt_error)
355+
can be used to exit jaq with arbitrary exit codes.
356+
357+
For example:
358+
359+
```
360+
$ jaq -n empty; echo $?
361+
0
362+
$ jaq -n false >/dev/null; echo $?
363+
0
364+
$ jaq -en false >/dev/null; echo $?
365+
1
366+
$ jaq . does_not_exit.json 2>/dev/null; echo $?
367+
2
368+
$ jaq --foo 2>/dev/null; echo $?
369+
2
370+
$ jaq '+' 2>/dev/null; echo $?
371+
3
372+
$ jaq -en empty; echo $?
373+
4
374+
$ jaq -n error 2>/dev/null; echo $?
375+
5
376+
$ jaq -n 'halt(9)'; echo $?
377+
9
378+
```
379+
380+
381+
{#--help}
382+
### `-h`, `--help`
383+
384+
Print summary of CLI options.
385+
386+
{#--version}
387+
### `-V`, `--version`
388+
389+
Print jaq version.
390+
391+
392+
{#unsupported-cli}
393+
## Unsupported
394+
395+
The following command-line options are supported by `jq`, but not by jaq:
396+
397+
- `--ascii-output`, `-a`
398+
- `--raw-output0`
399+
- `--unbuffered`
400+
- `--stream`
401+
- `--stream-errors`
402+
- `--seq`
403+
- `--jsonargs`

docs/corelang.dj

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,10 @@ contain equivalent bytes are considered equal, e.g.
198198
`"Hello" | . == tobytes --> true`.
199199

200200
::: Compatibility
201-
202201
Byte strings do not exist in `jq`; however, they exist in `fq`.
203-
204202
:::
205203

206204
::: Advanced
207-
208205
To find out whether a value is a byte string, we can use:
209206

210207
```
@@ -213,11 +210,8 @@ def isbytes: isstring and try (.[0] | true) catch false;
213210
```
214211

215212
This works because we can index byte strings, but not text strings.
216-
217213
:::
218214

219-
220-
221215
### Arrays
222216

223217
An array is a finite sequence of values.
@@ -278,7 +272,6 @@ Note that here, it is necessary to surround `1, 2` with parentheses,
278272
in order to clarify that `,` does not start a new key-value pair.
279273

280274
::: Compatibility
281-
282275
In jq, keys must be strings, whereas
283276
in jaq, keys can be arbitrary values.
284277
Because object keys can be arbitrary values in jaq, you can write e.g.:
@@ -288,8 +281,10 @@ Because object keys can be arbitrary values in jaq, you can write e.g.:
288281
{ 0 : 1, "2": 3, [4] : 5, {} : 6}
289282
```
290283

291-
This yields an error in `jq`.
284+
Note that in a jq filter, non-string keys must be surrounded with parentheses,
285+
whereas in XJON, parentheses must not be used.
292286

287+
This yields an error in `jq`.
293288
:::
294289

295290

0 commit comments

Comments
 (0)