Simplified standard library
Close #426. Signed-off-by: Nicolas Williams <nico@cryptonector.com>
This commit is contained in:
1 parent
7ee3b724d1
commit
dde43f796e
3 files changed
+91
-66
No files matched your search
@@ -693,19 +693,25 @@ static block bind_bytecoded_builtins(block b) {
|
|||||||
static const char* const jq_builtins[] = {
|
static const char* const jq_builtins[] = {
|
||||||
"def map(f): [.[] | f];",
|
"def map(f): [.[] | f];",
|
||||||
"def select(f): if f then . else empty end;",
|
"def select(f): if f then . else empty end;",
|
||||||
"def sort_by(f): _sort_by_impl(map([f]));",
|
"def sort(f): _sort_by_impl(map([f]));",
|
||||||
"def group_by(f): _group_by_impl(map([f]));",
|
"def sort_by(f): sort(f);",
|
||||||
"def unique: group_by(.) | map(.[0]);",
|
"def group(f): _group_by_impl(map([f]));",
|
||||||
"def unique_by(f): group_by(f) | map(.[0]);",
|
"def group_by(f): group(f);",
|
||||||
"def max_by(f): _max_by_impl(map([f]));",
|
"def unique: group(.) | map(.[0]);",
|
||||||
"def min_by(f): _min_by_impl(map([f]));",
|
"def unique(f): group(f) | map(.[0]);",
|
||||||
|
"def unique_by(f): unique(f);",
|
||||||
|
"def max(f): _max_by_impl(map([f]));",
|
||||||
|
"def min(f): _min_by_impl(map([f]));",
|
||||||
|
"def max_by(f): max(f);",
|
||||||
|
"def min_by(f): min(f);",
|
||||||
#include "libm.h"
|
#include "libm.h"
|
||||||
"def add: reduce .[] as $x (null; . + $x);",
|
"def add: reduce .[] as $x (null; . + $x);",
|
||||||
"def del(f): delpaths([path(f)]);",
|
"def del(f): delpaths([path(f)]);",
|
||||||
"def _assign(paths; value): value as $v | reduce path(paths) as $p (.; setpath($p; $v));",
|
"def _assign(paths; value): value as $v | reduce path(paths) as $p (.; setpath($p; $v));",
|
||||||
"def _modify(paths; update): reduce path(paths) as $p (.; setpath($p; getpath($p) | update));",
|
"def _modify(paths; update): reduce path(paths) as $p (.; setpath($p; getpath($p) | update));",
|
||||||
"def recurse(f): ., (f | select(. != null) | recurse(f));",
|
"def recurse(f): ., (f | select(. != null) | recurse(f));",
|
||||||
"def recurse_down: recurse(.[]?);",
|
"def recurse: recurse(.[]?);",
|
||||||
|
"def recurse_down: recurse;",
|
||||||
"def to_entries: [keys[] as $k | {key: $k, value: .[$k]}];",
|
"def to_entries: [keys[] as $k | {key: $k, value: .[$k]}];",
|
||||||
"def from_entries: map({(.key): .value}) | add | .//={};",
|
"def from_entries: map({(.key): .value}) | add | .//={};",
|
||||||
"def with_entries(f): to_entries | map(f) | from_entries;",
|
"def with_entries(f): to_entries | map(f) | from_entries;",
|
||||||
@@ -714,7 +720,7 @@ static const char* const jq_builtins[] = {
|
|||||||
"def index(i): if type == \"array\" and (i|type) == \"array\" then .[i] elif type == \"array\" then .[[i]] else .[i] end | .[0];",
|
"def index(i): if type == \"array\" and (i|type) == \"array\" then .[i] elif type == \"array\" then .[[i]] else .[i] end | .[0];",
|
||||||
"def rindex(i): if type == \"array\" and (i|type) == \"array\" then .[i] elif type == \"array\" then .[[i]] else .[i] end | .[-1:][0];",
|
"def rindex(i): if type == \"array\" and (i|type) == \"array\" then .[i] elif type == \"array\" then .[[i]] else .[i] end | .[-1:][0];",
|
||||||
"def paths: path(recurse(if (type|. == \"array\" or . == \"object\") then .[] else empty end))|select(length > 0);",
|
"def paths: path(recurse(if (type|. == \"array\" or . == \"object\") then .[] else empty end))|select(length > 0);",
|
||||||
"def leaf_paths: . as $dot|paths|select(. as $p|$dot|getpath($p)|type|. != \"array\" and . != \"object\");",
|
"def paths(node_filter): . as $dot|paths|select(. as $p|$dot|getpath($p)|node_filter);",
|
||||||
"def any: reduce .[] as $i (false; . or $i);",
|
"def any: reduce .[] as $i (false; . or $i);",
|
||||||
"def all: reduce .[] as $i (true; . and $i);",
|
"def all: reduce .[] as $i (true; . and $i);",
|
||||||
"def arrays: select(type == \"array\");",
|
"def arrays: select(type == \"array\");",
|
||||||
@@ -726,9 +732,11 @@ static const char* const jq_builtins[] = {
|
|||||||
"def nulls: select(type == \"null\");",
|
"def nulls: select(type == \"null\");",
|
||||||
"def values: arrays, objects, booleans, numbers, strings;",
|
"def values: arrays, objects, booleans, numbers, strings;",
|
||||||
"def scalars: select(. == null or . == true or . == false or type == \"number\" or type == \"string\");",
|
"def scalars: select(. == null or . == true or . == false or type == \"number\" or type == \"string\");",
|
||||||
|
"def leaf_paths: paths(scalars);",
|
||||||
"def join(x): reduce .[] as $i (\"\"; . + (if . == \"\" then $i else x + $i end));",
|
"def join(x): reduce .[] as $i (\"\"; . + (if . == \"\" then $i else x + $i end));",
|
||||||
"def flatten: reduce .[] as $i ([]; if $i | type == \"array\" then . + ($i | flatten) else . + [$i] end);",
|
"def flatten: reduce .[] as $i ([]; if $i | type == \"array\" then . + ($i | flatten) else . + [$i] end);",
|
||||||
"def flatten(x): reduce .[] as $i ([]; if $i | type == \"array\" and x > 0 then . + ($i | flatten(x-1)) else . + [$i] end);",
|
"def flatten(x): reduce .[] as $i ([]; if $i | type == \"array\" and x > 0 then . + ($i | flatten(x-1)) else . + [$i] end);",
|
||||||
|
"def range(x): range(0;x);",
|
||||||
};
|
};
|
||||||
#undef LIBM_DD
|
#undef LIBM_DD
|
||||||
|
|
||||||
|
|||||||
@@ -708,29 +708,25 @@ sections:
|
|||||||
input: '[1,2,3]'
|
input: '[1,2,3]'
|
||||||
output: ['[2,3,4]']
|
output: ['[2,3,4]']
|
||||||
|
|
||||||
- title: "`paths`"
|
- title: "`paths`, `paths(node_filter)`, `leaf_paths`"
|
||||||
body: |
|
body: |
|
||||||
|
|
||||||
Outputs the paths to all the elements in its input (except it
|
`paths` outputs the paths to all the elements in its input
|
||||||
does not output the empty list, representing . itself).
|
(except it does not output the empty list, representing .
|
||||||
|
itself).
|
||||||
|
|
||||||
`paths` is equivalent to
|
`paths(f)` outputs the paths to any values for which `f` is true.
|
||||||
|
That is, `paths(numbers)` outputs the paths to all numeric
|
||||||
|
values.
|
||||||
|
|
||||||
def paths: path(recurse(if (type|. == "array" or . == "object") then .[] else empty end))|select(length > 0);
|
`leaf_paths` is an alias of `paths(scalars)`; `leaf_paths` is
|
||||||
|
*deprecated* and will be removed in the next major release.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- program: '[paths]'
|
- program: '[paths]'
|
||||||
input: '[1,[[],{"a":2}]]'
|
input: '[1,[[],{"a":2}]]'
|
||||||
output: ['[[0],[1],[1,0],[1,1],[1,1,"a"]]']
|
output: ['[[0],[1],[1,0],[1,1],[1,1,"a"]]']
|
||||||
|
- program: '[paths(scalars)]'
|
||||||
- title: "`leaf_paths`"
|
|
||||||
body: |
|
|
||||||
|
|
||||||
Outputs the paths to all the leaves (non-array, non-object
|
|
||||||
elements) in its input.
|
|
||||||
|
|
||||||
examples:
|
|
||||||
- program: '[leaf_paths]'
|
|
||||||
input: '[1,[[],{"a":2}]]'
|
input: '[1,[[],{"a":2}]]'
|
||||||
output: ['[[0],[1,1,"a"]]']
|
output: ['[[0],[1,1,"a"]]']
|
||||||
|
|
||||||
@@ -818,7 +814,7 @@ sections:
|
|||||||
input: '[{"foo": "bar"}, [{"foo": "baz"}]]'
|
input: '[{"foo": "bar"}, [{"foo": "baz"}]]'
|
||||||
output: ['[{"foo": "bar"}, {"foo": "baz"}]']
|
output: ['[{"foo": "bar"}, {"foo": "baz"}]']
|
||||||
|
|
||||||
- title: "`range`"
|
- title: "`range(upto), `range(from;upto)`"
|
||||||
body: |
|
body: |
|
||||||
|
|
||||||
The `range` function produces a range of numbers. `range(4;10)`
|
The `range` function produces a range of numbers. `range(4;10)`
|
||||||
@@ -826,6 +822,8 @@ sections:
|
|||||||
are produced as separate outputs. Use `[range(4;10)]` to get a range as
|
are produced as separate outputs. Use `[range(4;10)]` to get a range as
|
||||||
an array.
|
an array.
|
||||||
|
|
||||||
|
Its first argument can be omitted; it defaults to zero.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- program: 'range(2;4)'
|
- program: 'range(2;4)'
|
||||||
input: 'null'
|
input: 'null'
|
||||||
@@ -833,6 +831,9 @@ sections:
|
|||||||
- program: '[range(2;4)]'
|
- program: '[range(2;4)]'
|
||||||
input: 'null'
|
input: 'null'
|
||||||
output: ['[2,3]']
|
output: ['[2,3]']
|
||||||
|
- program: '[range(4)]'
|
||||||
|
input: 'null'
|
||||||
|
output: ['[0,1,2,3]']
|
||||||
|
|
||||||
- title: "`floor`"
|
- title: "`floor`"
|
||||||
body: |
|
body: |
|
||||||
@@ -890,7 +891,7 @@ sections:
|
|||||||
input: '[0, false, [], {}, null, "hello"]'
|
input: '[0, false, [], {}, null, "hello"]'
|
||||||
output: ['["number", "boolean", "array", "object", "null", "string"]']
|
output: ['["number", "boolean", "array", "object", "null", "string"]']
|
||||||
|
|
||||||
- title: "`sort, sort_by`"
|
- title: "`sort, sort(path_expression), sort_by(path_expression)`"
|
||||||
body: |
|
body: |
|
||||||
|
|
||||||
The `sort` functions sorts its input, which must be an
|
The `sort` functions sorts its input, which must be an
|
||||||
@@ -909,23 +910,27 @@ sections:
|
|||||||
sorted order), and if their keys are equal then the values
|
sorted order), and if their keys are equal then the values
|
||||||
are compared key by key.
|
are compared key by key.
|
||||||
|
|
||||||
`sort_by` may be used to sort by a particular field of an
|
`sort` may be used to sort by a particular field of an
|
||||||
object, or by applying any jq filter. `sort_by(foo)`
|
object, or by applying any jq filter.
|
||||||
compares two elements by comparing the result of `foo` on
|
|
||||||
each element.
|
`sort(foo)` compares two elements by comparing the result of
|
||||||
|
`foo` on each element.
|
||||||
|
|
||||||
|
`sort_by(foo)` is an alias of `sort(foo)`; `sort_by()` is
|
||||||
|
*deprecated* and will be removed in the next major release.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- program: 'sort'
|
- program: 'sort'
|
||||||
input: '[8,3,null,6]'
|
input: '[8,3,null,6]'
|
||||||
output: ['[null,3,6,8]']
|
output: ['[null,3,6,8]']
|
||||||
- program: 'sort_by(.foo)'
|
- program: 'sort(.foo)'
|
||||||
input: '[{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}]'
|
input: '[{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}]'
|
||||||
output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":100}, {"foo":4, "bar":10}]']
|
output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":100}, {"foo":4, "bar":10}]']
|
||||||
|
|
||||||
- title: "`group_by`"
|
- title: "`group(path_expression)`, `group_by(path_expression)`"
|
||||||
body: |
|
body: |
|
||||||
|
|
||||||
`group_by(.foo)` takes as input an array, groups the
|
`group(.foo)` takes as input an array, groups the
|
||||||
elements having the same `.foo` field into separate arrays,
|
elements having the same `.foo` field into separate arrays,
|
||||||
and produces all of these arrays as elements of a larger
|
and produces all of these arrays as elements of a larger
|
||||||
array, sorted by the value of the `.foo` field.
|
array, sorted by the value of the `.foo` field.
|
||||||
@@ -934,57 +939,61 @@ sections:
|
|||||||
place of `.foo`. The sorting order is the same as described
|
place of `.foo`. The sorting order is the same as described
|
||||||
in the `sort` function above.
|
in the `sort` function above.
|
||||||
|
|
||||||
|
`group_by(foo)` is an alias of `group(foo)`; `group_by()` is
|
||||||
|
*deprecated* and will be removed in the next major release.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- program: 'group_by(.foo)'
|
- program: 'group(.foo)'
|
||||||
input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]'
|
input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]'
|
||||||
output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]']
|
output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]']
|
||||||
|
|
||||||
- title: "`min`, `max`, `min_by`, `max_by`"
|
- title: "`min`, `max`, `min(path_exp)`, `max(path_exp)`, `min_by(path_exp)`, `max_by(path_exp)`"
|
||||||
body: |
|
body: |
|
||||||
|
|
||||||
Find the minimum or maximum element of the input array. The
|
Find the minimum or maximum element of the input array.
|
||||||
`_by` versions allow you to specify a particular field or
|
This filter accepts an optional argument that
|
||||||
property to examine, e.g. `min_by(.foo)` finds the object
|
allows you to specify a particular field or
|
||||||
|
property to examine, e.g. `min(.foo)` finds the object
|
||||||
with the smallest `foo` field.
|
with the smallest `foo` field.
|
||||||
|
|
||||||
|
For legacy reasons, `min_by(.foo)` and `max_by(.foo)` exist as
|
||||||
|
aliases for `min(.foo)` and `max(.foo)`. These aliases are
|
||||||
|
considered *deprecated* and will be removed in the next major
|
||||||
|
release.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- program: 'min'
|
- program: 'min'
|
||||||
input: '[5,4,2,7]'
|
input: '[5,4,2,7]'
|
||||||
output: ['2']
|
output: ['2']
|
||||||
- program: 'max_by(.foo)'
|
- program: 'max(.foo)'
|
||||||
input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]'
|
input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]'
|
||||||
output: ['{"foo":2, "bar":3}']
|
output: ['{"foo":2, "bar":3}']
|
||||||
|
|
||||||
- title: "`unique`"
|
- title: "`unique`, `unique(path_exp)`, `unique_by(path_exp)`"
|
||||||
body: |
|
body: |
|
||||||
|
|
||||||
The `unique` function takes as input an array and produces
|
The `unique` function takes as input an array and produces
|
||||||
an array of the same elements, in sorted order, with
|
an array of the same elements, in sorted order, with
|
||||||
duplicates removed.
|
duplicates removed. If an optional argument is passed, it
|
||||||
|
will keep only one element for each value obtained by applying
|
||||||
|
the argument. Think of it as making an array by taking one
|
||||||
|
element out of every group produced by `group`.
|
||||||
|
|
||||||
|
For legacy reasons, `unique_by(.foo)` exists as an alias for
|
||||||
|
`unique(.foo)`. This alias is considered *deprecated* and will
|
||||||
|
be removed in the next major release.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- program: 'unique'
|
- program: 'unique'
|
||||||
input: '[1,2,5,3,5,3,1,3]'
|
input: '[1,2,5,3,5,3,1,3]'
|
||||||
output: ['[1,2,3,5]']
|
output: ['[1,2,3,5]']
|
||||||
|
- program: 'unique(.foo)'
|
||||||
- title: "`unique_by`"
|
|
||||||
body: |
|
|
||||||
|
|
||||||
The `unique_by(.foo)` function takes as input an array and produces
|
|
||||||
an array of the same elements, in sorted order, with
|
|
||||||
elqements with a duplicate `.foo` field removed. Think of it as making
|
|
||||||
an array by taking one element out of every group produced by
|
|
||||||
`group_by`.
|
|
||||||
|
|
||||||
examples:
|
|
||||||
- program: 'unique_by(.foo)'
|
|
||||||
input: '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]'
|
input: '[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]'
|
||||||
output: ['[{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]']
|
output: ['[{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]']
|
||||||
- program: 'unique_by(length)'
|
- program: 'unique(length)'
|
||||||
input: '["chunky", "bacon", "kitten", "cicada", "asparagus"]'
|
input: '["chunky", "bacon", "kitten", "cicada", "asparagus"]'
|
||||||
output: ['["chunky", "bacon", "asparagus"]']
|
output: ['["chunky", "bacon", "asparagus"]']
|
||||||
|
|
||||||
|
|
||||||
- title: "`reverse`"
|
- title: "`reverse`"
|
||||||
body: |
|
body: |
|
||||||
|
|
||||||
@@ -1144,10 +1153,10 @@ sections:
|
|||||||
output: ['"a, b,c,d, e"']
|
output: ['"a, b,c,d, e"']
|
||||||
|
|
||||||
|
|
||||||
- title: "`recurse`"
|
- title: "`recurse(f)`, `recurse`, `recurse_down`"
|
||||||
body: |
|
body: |
|
||||||
|
|
||||||
The `recurse` function allows you to search through a
|
The `recurse(f)` function allows you to search through a
|
||||||
recursive structure, and extract interesting data from all
|
recursive structure, and extract interesting data from all
|
||||||
levels. Suppose your input represents a filesystem:
|
levels. Suppose your input represents a filesystem:
|
||||||
|
|
||||||
@@ -1166,6 +1175,13 @@ sections:
|
|||||||
|
|
||||||
recurse(.children[]) | .name
|
recurse(.children[]) | .name
|
||||||
|
|
||||||
|
When called without an argument, `recurse` is equivalent to
|
||||||
|
`recurse(.[]?)`.
|
||||||
|
|
||||||
|
For legacy reasons, `recurse_down` exists as an alias to
|
||||||
|
calling `recurse` without arguments. This alias is considered
|
||||||
|
*deprecated* and will be removed in the next major release.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- program: 'recurse(.foo[])'
|
- program: 'recurse(.foo[])'
|
||||||
input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}'
|
input: '{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}'
|
||||||
@@ -1174,20 +1190,21 @@ sections:
|
|||||||
- '{"foo":[]}'
|
- '{"foo":[]}'
|
||||||
- '{"foo":[{"foo":[]}]}'
|
- '{"foo":[{"foo":[]}]}'
|
||||||
- '{"foo":[]}'
|
- '{"foo":[]}'
|
||||||
|
- program: 'recurse'
|
||||||
- title: "`recurse_down`"
|
input: '{"a":0,"b":[1]}'
|
||||||
body: |
|
output:
|
||||||
|
- '0'
|
||||||
A quieter version of `recurse(.[])`, equivalent to:
|
- '[1]'
|
||||||
|
- '1'
|
||||||
def recurse_down: recurse(.[]?);
|
|
||||||
|
|
||||||
- title: "`..`"
|
- title: "`..`"
|
||||||
body: |
|
body: |
|
||||||
|
|
||||||
Short-hand for `recurse_down`. This is intended to resemble
|
Short-hand for `recurse` without arguments. This is intended
|
||||||
the XPath `//` operator. Note that `..a` does not work; use
|
to resemble the XPath `//` operator. Note that `..a` does not
|
||||||
`..|a` instead.
|
work; use `..|a` instead. In the example below we use
|
||||||
|
`..|.a?` to find all the values of object keys "a" in any
|
||||||
|
object found "below" `.`.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- program: '..|.a?'
|
- program: '..|.a?'
|
||||||
|
|||||||
@@ -477,7 +477,7 @@ Term:
|
|||||||
$$ = gen_noop();
|
$$ = gen_noop();
|
||||||
} |
|
} |
|
||||||
REC {
|
REC {
|
||||||
$$ = gen_call("recurse_down", gen_noop());
|
$$ = gen_call("recurse", gen_noop());
|
||||||
} |
|
} |
|
||||||
Term FIELD '?' {
|
Term FIELD '?' {
|
||||||
$$ = gen_index_opt($1, gen_const($2));
|
$$ = gen_index_opt($1, gen_const($2));
|
||||||
|
|||||||
Reference in new issue
Block a user