hq-json-0.1.1: docs/LANG.md
# hq language reference
## Commands
Optics are used with different queries:
| Command | Meaning |
| --- | --- |
| `fold OPTIC` | Print every focused value, one per line. |
| `preview OPTIC` | Print at most the first focused value. |
| `set OPTIC VALUE` | Replace each focus with `VALUE`. |
| `over OPTIC TRANSFORMATION` | Rewrite each focused value in place. |
| `delete OPTIC` | Remove each focused value. |
`preview` accepts any optic and prints its first focus in document
order, stopping input there; it is `fold` capped at one value.
`set` takes a JSON literal and
is `over` with a constant transformation. `over` fails the whole query
when a focused value rejects the transformation (adding to a string,
for example). Deleting a missing field, or an empty focus, leaves the
input unchanged.
Input may hold any number of whitespace-separated JSON values
(JSON-lines style); every command except `preview` processes each
top-level value in turn. Trailing bytes that do not parse as JSON are
an error.
## Optic language
Optics select and traverse JSON values. Optics are composed with `.`;
each component focuses on a new set of values. Spaces around `.` are
optional, so `@a.each.@b` means `@a . each . @b`. Parentheses group
explicitly: `(@a . each) . @b`.
An optic may focus on nothing at all (a missing field, a value of the
wrong shape, an out-of-bounds `ix`); such focuses simply select no
values. Rewriting through `keys` renames object members.
| Optic | Meaning |
| --- | --- |
| `@field` | Focus the `"field"` member of an object. |
| `each` | Focus every element of an array, or every value of an object. |
| `keys` | Focus every object key, as a string. |
| `values` | Focus every value of an object. For arrays use `each` or `ix`. |
| `id` | Focus the whole value unchanged (the unit of `.`). |
| `_String` | Focus the value only if it is a string, and nothing otherwise. |
| `_Number` | Focus the value only if it is a number, and nothing otherwise. |
| `_Bool` | Focus the value only if it is a boolean, and nothing otherwise. |
| `_Null` | Focus the value only if it is null, and nothing otherwise. |
| `_Array` | Focus the value only if it is an array, and nothing otherwise. |
| `_Object` | Focus the value only if it is an object, and nothing otherwise. |
| `_Just` | Focus any non-null value. |
| `ix N` | Focus array element `N` (0-based). |
| `A . B` | Composition: focus `A`, then `B` within each target. |
### `filter OPTIC TRANSFORMATION`
Keep the input when `TRANSFORMATION` maps some value focused by `OPTIC`
to `true`, and focus on nothing otherwise. The transformation must
produce a boolean.
Single atoms stay bare:
```hq
filter @age == 30
```
Anything longer takes its own paren group per side:
```hq
filter (each . @age) (== 30)
```
A `.` after a bare optic starts an outer composition, so a dotted optic
inside `filter` needs its sides parenthesized:
```hq
each . filter (@tags . each) (== "x")
```
Examples:
- `@name` : Focus the `"name"` field.
- `@users . each . @name` : Focus the `"name"` field of every
element in `"users"`.
- `@users . each . @age` : Focus the `"age"` field of every element
in `"users"`.
- `each . _Number` : Focus every number inside an array.
- `@a . ix 1` : Focus the second element of the array in `"a"`.
## Transformations
Transformations describe how a focused value is rewritten. They apply
to one value at a time and compose right-to-left with `.`: in `A . B`,
`B` runs first and `A` runs over its result. So `+ 1 . * 2` doubles
first, then adds one.
Operators bind tightest at the atoms, then `.`, then `and`/`&&`, then
`xor`/`^^`, then `or`/`||` loosest. Parentheses override:
`(== "x") or (== "hi")`.
### Numbers (input and output are numbers)
| Transformation | Meaning |
| --- | --- |
| `+ N` | Add `N`. Example: `+ 1`. |
| `* N` | Multiply by `N`. Example: `* 2`. |
| `- N` | Subtract `N`. Example: `- 1`. |
### Comparisons (input is a number, output is a boolean)
| Transformation | Meaning |
| --- | --- |
| `< N` | Test whether the value is less than `N`. Example: `< 30`. |
| `<= N` | Test whether the value is at most `N`. Example: `<= 30`. |
| `> N` | Test whether the value is greater than `N`. Sugar for `not . <= N`. |
| `>= N` | Test whether the value is at least `N`. Sugar for `not . < N`. |
### Strings (input is a string)
| Transformation | Meaning |
| --- | --- |
| `++ "s"` | Append `s`. Example: `++ "!"`. |
| `trim` | Strip surrounding whitespace. |
| `replace "a" "b"` | Replace occurrences of `a` with `b`. |
| `stripPrefix "p"` | Remove the prefix when present. |
| `stripSuffix "s"` | Remove the suffix when present. |
| `isPrefixOf "p"` | Test whether the value starts with `p`. |
| `isSuffixOf "s"` | Test whether the value ends with `s`. |
| `isInfixOf "i"` | Test whether the value contains `i`. |
`stripPrefix` and `stripSuffix` leave the value unchanged when the
affix is absent. The `is*` tests yield a boolean.
### Arrays (input is an array)
| Transformation | Meaning |
| --- | --- |
| `concat [...]` | Append the given elements. Example: `concat [3, 4]`. |
| `reverse` | Reverse the elements. |
| `unique` | Drop duplicates, keeping first occurrences. |
| `sort` | Sort (canonical order): null, bools, nums, strings, arrays, objs. |
| `length` | Element count, as a number. |
| `isEmpty` | Test whether the array is empty, yielding a boolean. |
### Objects (input is an object)
| Transformation | Meaning |
| --- | --- |
| `merge {...}` | Shallow-merge the operand into the value (operand has pref). |
| `deepMerge {...}` | Recursively merge the operand into the value. |
### Any value
| Transformation | Meaning |
| --- | --- |
| `== VALUE` (or `= VALUE`) | Test equality with a JSON literal. |
| `const VALUE` | Replace with `VALUE`. |
Equality examples: `== 30`, `== "hi"`, `== true`. `set` is `over`
with `const`.
### Booleans (inputs are booleans, outputs are booleans)
| Transformation | Meaning |
| --- | --- |
| `not` | Negate the value. |
| `A or B` (or `A \|\| B`) | Disjunction; `B` runs only when `A` is `false`. |
| `A and B` (or `A && B`) | Conjunction; `B` runs only when `A` is `true`. |
| `A xor B` (or `A ^^ B`) | Exclusive disjunction. |
| `A . B` | Composition: apply `B` first, then `A` over its result. |
For example:
```sh
hq over '@users . each . @age' '+ 1'
```
increments every user's age, and
```sh
hq over '@users . each . @name' 'stripPrefix "dr. "'
```
strips the prefix from every user's name when present.
### Static checks
Queries are checked before running. Steps that cannot work are
rejected up front instead of failing mid-stream:
- `/ 0` is rejected: division by zero.
- A transformation applied where it cannot fit is rejected:
`over 'each._Number' '++ "x"'` fails because the optic focuses
numbers and the transformation needs a string. Optics without a
pinned shape (`@field`, `each`, `ix`) focus values of unknown
type and accept anything; only prisms (and `keys`) narrow the
focus, so only provable mismatches are reported.
- `filter` predicates must produce booleans, and accept their
sub-optic's focus type.
## Examples
```sh
echo '{"name":"ada","score":96}' | hq fold '@name'
# "ada"
echo '{"name":"ada"}' | hq fold '@name' -r
# ada (raw: strings print without quotes)
echo '{"a":[1,2,3]}' | hq fold '@a . each'
# 1, 2, 3 (one per line)
echo '[{"a":90},{"a":96}]' | hq fold 'each . filter (@a) (== 90)' -c
# [{"a":90}]
echo '{"a":1}' | hq over '@a' '+ 1' -c
# {"a":2}
echo '{"a":1,"b":2}' | hq set '@b' '3' -c
# {"a":1,"b":3}
echo '{"a":1,"b":2}' | hq delete '@b' -c
# {"a":1}
# nix
nix build . --json \
| hq -r fold 'each . @outputs . values' \
| cachix push my-cachix-cache
# Kubernetes
kubectl get pods -o json \
| hq -r fold '@items . each . @metadata . @name'
# ffmpeg
ffprobe -v quiet -print_format json -show_streams video.mp4 \
| hq -r fold 'each . @codec_name'
# Github
curl -s https://api.github.com/repos/damianfral/hq \
| hq -r fold '@topics.each'
```