Attribute Stories to Source Requirements
You are the lineage attribution agent. You are given one imported source file and the complete list of stories that already exist for this Target. Identify the distinct requirements the source states, and for each one name the stories that implement it.
This is a matching task against a closed set. Every story you may name is listed in <stories>. You are not decomposing work, proposing new stories, or judging whether the existing stories are correct.
Method
- Read the source and identify each distinct requirement it states. A requirement is a thing the
system must do, at whatever granularity the author wrote it. One sentence may state one requirement that several stories implement — for example "add a table and show it on screen" is one requirement implemented by a schema story, a route story, and a view story. Do not split a requirement to make the mapping tidier, and do not merge two requirements that a reader would act on separately.
- Give each requirement a short kebab-case name that describes it. The name is an identifier, not
a summary: mark-book-read, not the-reader-can-mark-a-book-as-read.
- For each requirement, list every story that implements any part of it. A story may implement
more than one requirement; a requirement may need more than one story.
- List any story that implements no requirement in the source as
<unattached>. This is expected
and correct for foundational work — application scaffolding, configuration, shared UI framing, test harnesses — that the author never asked for by name. Do not force such a story onto an unrelated requirement.
Rules
- Use only story ids that appear in
<stories>. Never invent one. - Every story must appear exactly once, either inside a
storiesattribute or as<unattached>. - Quote the requirement text verbatim from the source in the tag body. Do not paraphrase it.
- Emit nothing but the tags below. No preamble, no commentary, no explanation.
Output
<requirement name="add-remove-books" stories="add-book,remove-book,database">
The reader can add a book with a title and author, view the books in the order added, and remove a book.
</requirement>
<requirement name="reject-empty-fields" stories="validate-book">
An empty title or author is rejected with a clear error message.
</requirement>
<unattached story="architecture"/>
<unattached story="ui-general"/>
Attribution job
<source name="jq.test">
Tests are groups of three lines: program, input, expected output
Blank lines and lines starting with # are ignored
#
Simple value tests to check parser. Input is irrelevant
#
true null true
false null false
null 42 null
1 null 1
-1 null -1
FIXME: much more number testing needed
{} null {}
[] null []
{x:-1},{x:-.},{x:-.|abs} 1 {"x":-1} {"x":-1} {"x":1}
The input line starts with a 0xFEFF (byte order mark) codepoint
No, there is no reason to have a byte order mark in UTF8 text.
But apparently people do, so jq shouldn't break on it.
. "byte order mark" "byte order mark"
We test escapes by matching them against Unicode codepoints
FIXME: more tests needed for weird unicode stuff (e.g. utf16 pairs)
"Aa\r\n\t\b\f\u03bc" null "Aa\u000d\u000a\u0009\u0008\u000c\u03bc"
. "Aa\r\n\t\b\f\u03bc" "Aa\u000d\u000a\u0009\u0008\u000c\u03bc"
%%FAIL "u\vw" jq: error: Invalid escape at line 1, column 4 (while parsing '"\v"') at <top-level>, line 1, column 3: "u\vw" ^^
"inter\("pol" + "ation")" null "interpolation"
@text,@json,([1,.]|@csv,@tsv),@html,(@uri|.,@urid),@sh,(@base64|.,@base64d) "!()<>&'\"\t" "!()<>&'\"\t" "\"!()<>&'\\\"\\t\"" "1,\"!()<>&'\"\"\t\"" "1\t!()<>&'\"\\t" "!()<>&'"\t" "%21%28%29%3C%3E%26%27%22%09" "!()<>&'\"\t" "'!()<>&'\\''\"\t'" "ISgpPD4mJyIJ" "!()<>&'\"\t"
regression test for #436
@base64 "foóbar\n" "Zm/Ds2Jhcgo="
@base64d "Zm/Ds2Jhcgo=" "foóbar\n"
@uri "\u03bc" "%CE%BC"
@urid "%CE%BC" "\u03bc"
@html "<b>\(.)</b>" "<script>hax</script>" "<b><script>hax</script></b>"
[.[]|tojson|fromjson] ["foo", 1, ["a", 1, "b", 2, {"foo":"bar"}]] ["foo",1,["a",1,"b",2,{"foo":"bar"}]]
#
Dictionary construction syntax
#
{a: 1} null {"a":1}
{a,b,(.d):.a,e:.b} {"a":1, "b":2, "c":3, "d":"c"} {"a":1, "b":2, "c":1, "e":2}
{"a",b,"a$\(1+1)"} {"a":1, "b":2, "c":3, "a$2":4} {"a":1, "b":2, "a$2":4}
%%FAIL {(0):1} jq: error: Cannot use number (0) as object key at <top-level>, line 1, column 3: {(0):1} ^
%%FAIL {1+2:3} jq: error: May need parentheses around object key expression at <top-level>, line 1, column 2: {1+2:3} ^^^
%%FAIL {non_const:., (0):1} jq: error: Cannot use number (0) as object key at <top-level>, line 1, column 16: {non_const:., (0):1} ^
#
Field access, piping
#
.foo {"foo": 42, "bar": 43} 42
.foo | .bar {"foo": {"bar": 42}, "bar": "badvalue"} 42
.foo.bar {"foo": {"bar": 42}, "bar": "badvalue"} 42
.foo_bar {"foo_bar": 2} 2
.["foo"].bar {"foo": {"bar": 42}, "bar": "badvalue"} 42
."foo"."bar" {"foo": {"bar": 20}} 20
.e0, .E1, .E-1, .E+1 {"e0": 1, "E1": 2, "E": 3} 1 2 2 4
[.[]|.foo?] [1,[2],{"foo":3,"bar":4},{},{"foo":5}] [3,null,5]
[.[]|.foo?.bar?] [1,[2],[],{"foo":3},{"foo":{"bar":4}},{}] [4,null]
[..] [1,[[2]],{ "a":[1]}] [[1,[[2]],{"a":[1]}],1,[[2]],[2],2,{"a":[1]},[1],1]
[.[]|.[]?] [1,null,[],[1,[2,[[3]]]],[{}],[{"a":[1,[2]]}]] [1,[2,[[3]]],{},{"a":[1,[2]]}]
[.[]|.[1:3]?] [1,null,true,false,"abcdef",{},{"a":1,"b":2},[],[1,2,3,4,5],[1,2]] [null,"bc",[],[2,3],[2]]
chaining/suffix-list, with and without dot
map(try .a[] catch ., try .a.[] catch ., .a[]?, .a.[]?) [{"a": [1,2]}, {"a": 123}] [1,2,1,2,1,2,1,2,"Cannot iterate over number (123)","Cannot iterate over number (123)"]
oss-fuzz #66070: objects[] leaks if a non-last element throws an error
try ["OK", (.[] | error)] catch ["KO", .] {"a":["b"],"c":["d"]} ["KO",["b"]]
#
Negative array indices
#
try (.foo[-1] = 0) catch . null "Out of bounds negative array index"
try (.foo[-2] = 0) catch . null "Out of bounds negative array index"
.[-1] = 5 [0,1,2] [0,1,5]
.[-2] = 5 [0,1,2] [0,5,2]
try (.[999999999] = 0) catch . null "Array index too large"
#
Multiple outputs, iteration
#
.[] [1,2,3] 1 2 3
1,1 [] 1 1
1,. [] 1 []
[.] [2] [[2]]
[[2]] [3] [[2]]
[{}] [2] [{}]
[.[]] ["a"] ["a"]
[(.,1),((.,.[]),(2,3))] ["a","b"] [["a","b"],1,["a","b"],"a","b",2,3]
[([5,5][]),.,.[]] [1,2,3] [5,5,[1,2,3],1,2,3]
{x: (1,2)},{x:3} | .x null 1 2 3
[.[-4,-3,-2,-1,0,1,2,3]] [1,2,3] [null,1,2,3,1,2,3,null]
[range(0;10)] null [0,1,2,3,4,5,6,7,8,9]
[range(0,1;3,4)] null [0,1,2, 0,1,2,3, 1,2, 1,2,3]
[range(0;10;3)] null [0,3,6,9]
[range(0;10;-1)] null []
[range(0;-5;-1)] null [0,-1,-2,-3,-4]
[range(0,1;4,5;1,2)] null [0,1,2,3,0,2, 0,1,2,3,4,0,2,4, 1,2,3,1,3, 1,2,3,4,1,3]
[while(.<100; .*2)] 1 [1,2,4,8,16,32,64]
[(label $here | .[] | if .>1 then break $here else . end), "hi!"] [0,1,2] [0,1,"hi!"]
[(label $here | .[] | if .>1 then break $here else . end), "hi!"] [0,2,1] [0,"hi!"]
%%FAIL . as $foo | break $foo jq: error: $*label-foo is not defined at <top-level>, line 1, column 13: . as $foo | break $foo ^^^^^^^^^^
[.[]|[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]] [1,2,3,4,5] [1,2,6,24,120]
[label $out | foreach .[] as $item ([3, null]; if .[0] < 1 then break $out else [.[0] -1, $item] end; .[1])] [11,22,33,44,55,66,77,88,99] [11,22,33]
[foreach range(5) as $item (0; $item)] null [0,1,2,3,4]
[foreach .[] as [$i, $j] (0; . + $i - $j)] [[2,1], [5,3], [6,4]] [1,3,5]
[foreach .[] as {a:$a} (0; . + $a; -.)] [{"a":1}, {"b":2}, {"a":3, "b":4}] [-1, -1, -4]
[-foreach -.[] as $x (0; . + $x)] [1,2,3] [1,3,6]
[foreach .[] / .[] as $i (0; . + $i)] [1,2] [1,3,3.5,4.5]
[foreach .[] as $x (0; . + $x) as $x | $x] [1,2,3] [1,3,6]
[limit(3; .[])] [11,22,33,44,55,66,77,88,99] [11,22,33]
[limit(0; error)] "badness" []
[limit(1; 1, error)] "badness" [1]
try limit(-1; error) catch . null "limit doesn't support negative count"
[skip(3; .[])] [1,2,3,4,5,6,7,8,9] [4,5,6,7,8,9]
[skip(0,2,3,4; .[])] [1,2,3] [1,2,3,3]
[skip(3; .[])] [] []
try skip(-1; error) catch . null "skip doesn't support negative count"
nth(1; 0,1,error("foo")) null 1
[first(range(.)), last(range(.))] 10 [0,9]
[first(range(.)), last(range(.))] 0 []
[nth(0,5,9,10,15; range(.)), try nth(-1; range(.)) catch .] 10 [0,5,9,"nth doesn't support negative indices"]
Check that first(g) does not extract more than one value from g
first(1,error("foo")) null 1
#
Check that various builtins evaluate all arguments where appropriate,
doing cartesian products where appropriate.
#
Check that limit does work for each value produced by n!
[limit(5,7; range(9))] null [0,1,2,3,4,0,1,2,3,4,5,6]
Same check for nth
[nth(5,7; range(9;0;-1))] null [4,2]
Same check for range/3
[range(0,1,2;4,3,2;2,3)] null [0,2,0,3,0,2,0,0,0,1,3,1,1,1,1,1,2,2,2,2]
Same check for range/1
[range(3,5)] null [0,1,2,0,1,2,3,4]
Same check for index/1, rindex/1, indices/1
[(index(",","|"), rindex(",","|")), indices(",","|")] "a,b|c,d,e||f,g,h,|,|,i,j" [1,3,22,19,[1,5,7,12,14,16,18,20,22],[3,9,10,17,19]]
Same check for join/1
join(",","/") ["a","b","c","d"] "a,b,c,d" "a/b/c/d"
[.[]|join("a")] [[],[""],["",""],["","",""]] ["","","a","aa"]
Same check for flatten/1
flatten(3,2,1) [0, [1], [[2]], [[[3]]]] [0,1,2,3] [0,1,2,[3]] [0,1,[2],[[3]]]
#
Slices
#
[.[3:2], .[-5:4], .[:-2], .[-2:], .[3:3][1:], .[10:]] [0,1,2,3,4,5,6] [[], [2,3], [0,1,2,3,4], [5,6], [], []]
[.[3:2], .[-5:4], .[:-2], .[-2:], .[3:3][1:], .[10:]] "abcdefghi" ["","","abcdefg","hi","",""]
del(.[2:4],.[0],.[-2:]) [0,1,2,3,4,5,6,7] [1,4,5]
.[2:4] = ([], ["a","b"], ["a","b","c"]) [0,1,2,3,4,5,6,7] [0,1,4,5,6,7] [0,1,"a","b",4,5,6,7] [0,1,"a","b","c",4,5,6,7]
Slices at large offsets (issue #1108)
#
This is written this way because [range(<large number>)] is
significantly slower under valgrind than .[<large number>] = value.
#
We range down rather than up so that we have just one realloc.
reduce range(65540;65536;-1) as $i ([]; .[$i] = $i)|.[65536:] null [null,65537,65538,65539,65540]
#
Variables
#
1 as $x | 2 as $y | [$x,$y,$x] null [1,2,1]
[1,2,3][] as $x | [[4,5,6,7][$x]] null [5] [6] [7]
42 as $x | . | . | . + 432 | $x + 1 34324 43
1 + 2 as $x | -$x null -3
"x" as $x | "a"+"y" as $y | $x+","+$y null "x,ay"
1 as $x | [$x,$x,$x as $x | $x] null [1,1,1]
[1, {c:3, d:4}] as [$a, {c:$b, b:$c}] | $a, $b, $c null 1 3 null
. as {as: $kw, "str": $str, ("e"+"x"+"p"): $exp} | [$kw, $str, $exp] {"as": 1, "str": 2, "exp": 3} [1, 2, 3]
.[] as [$a, $b] | [$b, $a] [[1], [1, 2, 3]] [null, 1] [2, 1]
. as $i | . as [$i] | $i [0] 0
. as [$i] | . as $i | $i [0] [0]
%%FAIL . as [] | null jq: error: syntax error, unexpected ']', expecting BINDING or '[' or '{' at <top-level>, line 1, column 7: . as [] | null ^
%%FAIL . as {} | null jq: error: syntax error, unexpected '}' at <top-level>, line 1, column 7: . as {} | null ^
%%FAIL . as $foo | [$foo, $bar] jq: error: $bar is not defined at <top-level>, line 1, column 20: . as $foo | [$foo, $bar] ^^^^
%%FAIL . as {(true):$foo} | $foo jq: error: Cannot use boolean (true) as object key at <top-level>, line 1, column 8: . as {(true):$foo} | $foo ^^^^
[.,(.[] | {x:.},.),.,.[]]
#
Builtin functions
#
1+1 null 2
1+1 "wtasdf" 2.0
2-1 null 1
2-(-1) null 3
1e+0+0.001e3 "I wonder what this will be?" 20e-1
.+4 15 19.0
.+null {"a":42} {"a":42}
null+. null null
.a+.b {"a":42} 42
[1,2,3] + [.] null [1,2,3,null]
{"a":1} + {"b":2} + {"c":3} "asdfasdf" {"a":1, "b":2, "c":3}
"asdf" + "jkl;" + . + . + . "some string" "asdfjkl;some stringsome stringsome string"
"\u0000\u0020\u0000" + . "\u0000\u0020\u0000" "\u0000 \u0000\u0000 \u0000"
42 - . 11 31
[1,2,3,4,1] - [.,3] 1 [2,4]
[-1 as $x | 1,$x] null [1,-1]
[10 * 20, 20 / .] 4 [200, 5]
1 + 2 * 2 + 10 / 2 null 10
[16 / 4 / 2, 16 / 4 * 2, 16 - 4 - 2, 16 - 4 + 2] null [2, 8, 10, 14]
1e-19 + 1e-20 - 5e-21 null 1.05e-19
1 / 1e-17 null 1e+17
9E999999999, 9999999999E999999990, 1E-999999999, 0.000000001E-999999990 null 9E+999999999 9.999999999E+999999999 1E-999999999 1E-999999999
5E500000000 > 5E-5000000000, 10000E500000000 > 10000E-5000000000 null true true
#2825
(1e999999999, 10e999999999) > (1e-1147483646, 0.1e-1147483646) null true true true true
25 % 7 null 4
49732 % 472 null 172
[(infinite, -infinite) % (1, -1, infinite)] null [0,0,0,0,0,-1]
[nan % 1, 1 % nan | isnan] null [true,true]
1 + tonumber + ("10" | tonumber) 4 15
"123\u0000456" | try tonumber catch . null "string (\"123\\u0000456\") cannot be parsed as a number"
map(toboolean) ["false","true",false,true] [false,true,false,true]
.[] | try toboolean catch . [null,0,"tru","truee","fals","falsee",[],{}] "null (null) cannot be parsed as a boolean" "number (0) cannot be parsed as a boolean" "string (\"tru\") cannot be parsed as a boolean" "string (\"truee\") cannot be parsed as a boolean" "string (\"fals\") cannot be parsed as a boolean" "string (\"falsee\") cannot be parsed as a boolean" "array ([]) cannot be parsed as a boolean" "object ({}) cannot be parsed as a boolean"
"true\u0000x", "false\u0000" | try toboolean catch . null "string (\"true\\u0000x\") cannot be parsed as a boolean" "string (\"false\\u0000\") cannot be parsed as a boolean"
[{"a":42},.object,10,.num,false,true,null,"b",[1,4]] | .[] as $x | [$x == .[]] {"object": {"a":42}, "num":10.0} [true, true, false, false, false, false, false, false, false] [true, true, false, false, false, false, false, false, false] [false, false, true, true, false, false, false, false, false] [false, false, true, true, false, false, false, false, false] [false, false, false, false, true, false, false, false, false] [false, false, false, false, false, true, false, false, false] [false, false, false, false, false, false, true, false, false] [false, false, false, false, false, false, false, true, false] [false, false, false, false, false, false, false, false, true ]
[.[] | length] [[], {}, [1,2], {"a":42}, "asdf", "\u03bc"] [0, 0, 2, 1, 4, 1]
utf8bytelength "asdf\u03bc" 6
[.[] | try utf8bytelength catch .] [[], {}, [1,2], 55, true, false] ["array ([]) only strings have UTF-8 byte length","object ({}) only strings have UTF-8 byte length","array ([1,2]) only strings have UTF-8 byte length","number (55) only strings have UTF-8 byte length","boolean (true) only strings have UTF-8 byte length","boolean (false) only strings have UTF-8 byte length"]
map(keys) [{}, {"abcd":1,"abc":2,"abcde":3}, {"x":1, "z": 3, "y":2}] [[], ["abc","abcd","abcde"], ["x","y","z"]]
[1,2,empty,3,empty,4] null [1,2,3,4]
map(add) [[], [1,2,3], ["a","b","c"], [[3],[4,5],[6]], [{"a":1}, {"b":2}, {"a":3}]] [null, 6, "abc", [3,4,5,6], {"a":3, "b": 2}]
map_values(.+1) [0,1,2] [1,2,3]
[add(null), add(range(range(10))), add(empty), add(10,range(10))] null [null,120,null,55]
Real-world use case for add(empty)
.sum = add(.arr[]) {"arr":[]} {"arr":[],"sum":null}
add({(.[]):1}) | keys ["a","a","b","a","d","b","d","a","d"] ["a","b","d"]
#
User-defined functions
Oh god.
#
def f: . + 1; def g: def g: . + 100; f | g | f; (f | g), g 3.0 106.0 105.0
def f: (1000,2000); f 123412345 1000 2000
def f(a;b;c;d;e;f): [a+1,b,c,d,e,f]; f(.[0];.[1];.[0];.[0];.[0];.[0]) [1,2] [2,2,1,1,1,1]
def f: 1; def g: f, def f: 2; def g: 3; f, def f: g; f, g; def f: 4; [f, def f: g; def g: 5; f, g]+[f,g] null [4,1,2,3,3,5,4,1,2,3,3]
Test precedence of 'def' vs '|'
def a: 0; . | a null 0
Many arguments
def f(a;b;c;d;e;f;g;h;i;j): [j,i,h,g,f,e,d,c,b,a]; f(.[0];.[1];.[2];.[3];.[4];.[5];.[6];.[7];.[8];.[9]) [0,1,2,3,4,5,6,7,8,9] [9,8,7,6,5,4,3,2,1,0]
([1,2] + [4,5]) [1,2,3] [1,2,4,5]
true [1] true
null,1,null "hello" null 1 null
[1,2,3] [5,6] [1,2,3]
[.[]|floor] [-1.1,1.1,1.9] [-2, 1, 1]
[.[]|sqrt] [4,9] [2,3]
(add / length) as $m | map((. - $m) as $d | $d * $d) | add / length | sqrt [2,4,4,4,5,5,7,9] 2
Should write a test that calls the -lm function from C (or bc(1)) to
check that they match the corresponding jq functions. However,
there's so little template code standing between that it suffices to
test a handful of these. The results were checked by eye against
bc(1).
atan * 4 * 1000000|floor / 1000000 1 3.141592
[(3.141592 / 2) * (range(0;20) / 20)|cos * 1000000|floor / 1000000] null [1,0.996917,0.987688,0.972369,0.951056,0.923879,0.891006,0.85264,0.809017,0.760406,0.707106,0.649448,0.587785,0.522498,0.45399,0.382683,0.309017,0.233445,0.156434,0.078459]
[(3.141592 / 2) * (range(0;20) / 20)|sin * 1000000|floor / 1000000] null [0,0.078459,0.156434,0.233445,0.309016,0.382683,0.45399,0.522498,0.587785,0.649447,0.707106,0.760405,0.809016,0.85264,0.891006,0.923879,0.951056,0.972369,0.987688,0.996917]
def f(x): x | x; f([.], . + [42]) [1,2,3] [[[1,2,3]]] [[1,2,3],42] [[1,2,3,42]] [1,2,3,42,42]
test multiple function arities and redefinition
def f: .+1; def g: f; def f: .+100; def f(a):a+.+11; [(g|f(20)), f] 1 [33,101]
test closures and lexical scoping
def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x | f($x,$x+x); g($x) "more testing" [1,100,2100.0,100,2100.0]
test def f($a) syntax
def x(a;b): a as $a | b as $b | $a + $b; def y($a;$b): $a + $b; def check(a;b): [x(a;b)] == [y(a;b)]; check(.[];.[]*2) [1,2,3] true
test backtracking through function calls and returns
this test is evil
[[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f] 999999999 [[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]]
test recursion
def fac: if . == 1 then 1 else . * (. - 1 | fac) end; [.[] | fac] [1,2,3,4] [1,2,6,24]
test stack overflow and reallocation
this test is disabled for now, it takes a realllllly long time.
def f: if length > 1000 then . else .+[1]|f end; f | length
[]
1001
reduce .[] as $x (0; . + $x) [1,2,4] 7
reduce .[] as [$i, {j:$j}] (0; . + $i - $j) [[2,{"j":1}], [5,{"j":3}], [6,{"j":4}]] 5
reduce [[1,2,10], [3,4,10]][] as [$i,$j] (0; . + $i * $j) null 14
[-reduce -.[] as $x (0; . + $x)] [1,2,3] [6]
[reduce .[] / .[] as $i (0; . + $i)] [1,2] [4.5]
reduce .[] as $x (0; . + $x) as $x | $x [1,2,3] 6
This, while useless, should still compile.
reduce . as $n (.; .) null null
Destructuring
. as {$a, b: [$c, {$d}]} | [$a, $c, $d] {"a":1, "b":[2,{"d":3}]} [1,2,3]
. as {$a, $b:[$c, $d]}| [$a, $b, $c, $d] {"a":1, "b":[2,{"d":3}]} [1,[2,{"d":3}],2,{"d":3}]
Destructuring with alternation
.[] | . as {$a, b: [$c, {$d}]} ?// [$a, {$b}, $e] ?// $f | [$a, $b, $c, $d, $e, $f] [{"a":1, "b":[2,{"d":3}]}, [4, {"b":5, "c":6}, 7, 8, 9], "foo"] [1, null, 2, 3, null, null] [4, 5, null, null, 7, null] [null, null, null, null, null, "foo"]
Destructuring DUP/POP issues
.[] | . as {a:$a} ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6]
Runtime error: "jq: Cannot index array with string (\"c\")"
.[] as {a:$a} ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6]
Runtime error: "jq: Cannot index array with string (\"c\")"
[[3],[4],[5],6][] | . as {a:$a} ?// {a:$a} ?// {a:$a} | $a null
Runtime error: "jq: Cannot index array with string (\"c\")"
[[3],[4],[5],6] | .[] as {a:$a} ?// {a:$a} ?// {a:$a} | $a null
Runtime error: "jq: Cannot index array with string (\"c\")"
.[] | . as {a:$a} ?// {a:$a} ?// $a | $a [[3],[4],[5],6] [3] [4] [5] 6
.[] as {a:$a} ?// {a:$a} ?// $a | $a [[3],[4],[5],6] [3] [4] [5] 6
[[3],[4],[5],6][] | . as {a:$a} ?// {a:$a} ?// $a | $a null [3] [4] [5] 6
[[3],[4],[5],6] | .[] as {a:$a} ?// {a:$a} ?// $a | $a null [3] [4] [5] 6
.[] | . as {a:$a} ?// $a ?// {a:$a} | $a [[3],[4],[5],6] [3] [4] [5] 6
.[] as {a:$a} ?// $a ?// {a:$a} | $a [[3],[4],[5],6] [3] [4] [5] 6
[[3],[4],[5],6][] | . as {a:$a} ?// $a ?// {a:$a} | $a null [3] [4] [5] 6
[[3],[4],[5],6] | .[] as {a:$a} ?// $a ?// {a:$a} | $a null [3] [4] [5] 6
.[] | . as $a ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6] [3] [4] [5] 6
.[] as $a ?// {a:$a} ?// {a:$a} | $a [[3],[4],[5],6] [3] [4] [5] 6
[[3],[4],[5],6][] | . as $a ?// {a:$a} ?// {a:$a} | $a null [3] [4] [5] 6
[[3],[4],[5],6] | .[] as $a ?// {a:$a} ?// {a:$a} | $a null [3] [4] [5] 6
. as $dot|any($dot[];not) [1,2,3,4,true,false,1,2,3,4,5] true
. as $dot|any($dot[];not) [1,2,3,4,true] false
. as $dot|all($dot[];.) [1,2,3,4,true,false,1,2,3,4,5] false
. as $dot|all($dot[];.) [1,2,3,4,true] true
Check short-circuiting
any(true, error; .) "badness" true
all(false, error; .) "badness" false
any(not) [] false
all(not) [] true
any(not) [false] true
all(not) [false] true
[any,all] [] [false,true]
[any,all] [true] [true,true]
[any,all] [false] [false,false]
[any,all] [true,false] [true,false]
[any,all] [null,null,true] [true,false]
#
Paths
#
path(.foo[0,1]) null ["foo", 0] ["foo", 1]
path(.[] | select(.>3)) [1,5,3] [1]
path(.) 42 []
try path(.a | map(select(.b == 0))) catch . {"a":[{"b":0}]} "Invalid path expression with result [{\"b\":0}]"
try path(.a | map(select(.b == 0)) | .[0]) catch . {"a":[{"b":0}]} "Invalid path expression near attempt to access element 0 of [{\"b\":0}]"
try path(.a | map(select(.b == 0)) | .c) catch . {"a":[{"b":0}]} "Invalid path expression near attempt to access element \"c\" of [{\"b\":0}]"
try path(.a | map(select(.b == 0)) | .[]) catch . {"a":[{"b":0}]} "Invalid path expression near attempt to iterate through [{\"b\":0}]"
path(.a[path(.b)[0]]) {"a":{"b":0}} ["a","b"]
[paths] [1,[[],{"a":2}]] [[0],[1],[1,0],[1,1],[1,1,"a"]]
["foo",1] as $p | getpath($p), setpath($p; 20), delpaths([$p]) {"bar": 42, "foo": ["a", "b", "c", "d"]} "b" {"bar": 42, "foo": ["a", 20, "c", "d"]} {"bar": 42, "foo": ["a", "c", "d"]}
map(getpath([2])), map(setpath([2]; 42)), map(delpaths([[2]])) [[0], [0,1], [0,1,2]] [null, null, 2] [[0,null,42], [0,1,42], [0,1,42]] [[0], [0,1], [0,1]]
map(delpaths([[0,"foo"]])) [[{"foo":2, "x":1}], [{"bar":2}]] [[{"x":1}], [{"bar":2}]]
["foo",1] as $p | getpath($p), setpath($p; 20), delpaths([$p]) {"bar":false} null {"bar":false, "foo": [null, 20]} {"bar":false}
delpaths([[-200]]) [1,2,3] [1,2,3]
try delpaths(0) catch . {} "Paths must be specified as an array"
del(.), del(empty), del((.foo,.bar,.baz) | .[2,3,0]), del(.foo[0], .bar[0], .foo, .baz.bar[0].x) {"foo": [0,1,2,3,4], "bar": [0,1]} null {"foo": [0,1,2,3,4], "bar": [0,1]} {"foo": [1,4], "bar": [1]} {"bar": [1]}
del(.[1], .[-6], .[2], .[-3:9]) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 3, 5, 6, 9]
del(.[nan]) [1,2,3] [1,2,3]
del(.[nan,nan]) [1,2,3] [1,2,3]
negative index
setpath([-1]; 1) [0] [1]
pick(.a.b.c) null {"a":{"b":{"c":null}}}
pick(first) [1,2] [1]
pick(first|first) [[10,20],30] [[10]]
negative indices in path expressions (since last/1 is .[-1])
try pick(last) catch . [1,2] "Out of bounds negative array index"
#
Assignment
# .message = "goodbye" {"message": "hello"} {"message": "goodbye"}
.foo = .bar {"bar":42} {"foo":42, "bar":42}
.foo |= .+1 {"foo": 42} {"foo": 43}
.[] += 2, .[] *= 2, .[] -= 2, .[] /= 2, .[] %=2 [1,3,5] [3,5,7] [2,6,10] [-1,1,3] [0.5, 1.5, 2.5] [1,1,1]
[.[] % 7] [-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7] [0,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,0]
.foo += .foo {"foo":2} {"foo":4}
.[0].a |= {"old":., "new":(.+1)} [{"a":1,"b":2}] [{"a":{"old":1, "new":2},"b":2}]
def inc(x): x |= .+1; inc(.[].a) [{"a":1,"b":2},{"a":2,"b":4},{"a":7,"b":8}] [{"a":2,"b":2},{"a":3,"b":4},{"a":8,"b":8}]
#1358, getpath/1 should work in path expressions
.[] | try (getpath(["a",0,"b"]) |= 5) catch . [null,{"b":0},{"a":0},{"a":null},{"a":[0,1]},{"a":{"b":1}},{"a":[{}]},{"a":[{"c":3}]}] {"a":[{"b":5}]} {"b":0,"a":[{"b":5}]} "Cannot index number with number (0)" {"a":[{"b":5}]} "Cannot index number with string (\"b\")" "Cannot index object with number (0)" {"a":[{"b":5}]} {"a":[{"c":3,"b":5}]}
#2051, deletion using assigning empty against arrays
(.[] | select(. >= 2)) |= empty [1,5,3,0,7] [1,0]
.[] |= select(. % 2 == 0) [0,1,2,3,4,5] [0,2,4]
.foo[1,4,2,3] |= empty {"foo":[0,1,2,3,4,5]} {"foo":[0,5]}
.[2][3] = 1 [4] [4, null, [null, null, null, 1]]
.foo[2].bar = 1 {"foo":[11], "bar":42} {"foo":[11,null,{"bar":1}], "bar":42}
try ((map(select(.a == 1))[].b) = 10) catch . [{"a":0},{"a":1}] "Invalid path expression near attempt to iterate through [{\"a\":1}]"
try ((map(select(.a == 1))[].a) |= .+1) catch . [{"a":0},{"a":1}] "Invalid path expression near attempt to iterate through [{\"a\":1}]"
def x: .[1,2]; x=10 [0,1,2] [0,10,10]
try (def x: reverse; x=10) catch . [0,1,2] "Invalid path expression with result [2,1,0]"
.[] = 1 [1,null,Infinity,-Infinity,NaN,-NaN] [1,1,1,1,1,1]
#
Conditionals
#
[.[] | if .foo then "yep" else "nope" end] [{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}] ["yep","yep","yep","yep","nope","nope","yep","nope"]
[.[] | if .baz then "strange" elif .foo then "yep" else "nope" end] [{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}] ["yep","yep","yep","yep","nope","nope","yep","nope"]
[if 1,null,2 then 3 else 4 end] null [3,4,3]
[if empty then 3 else 4 end] null []
[if 1 then 3,4 else 5 end] null [3,4]
[if null then 3 else 5,6 end] null [5,6]
[if true then 3 end] 7 [3]
[if false then 3 end] 7 [7]
[if false then 3 else . end] 7 [7]
[if false then 3 elif false then 4 end] 7 [7]
[if false then 3 elif false then 4 else . end] 7 [7]
[-if true then 1 else 2 end] null [-1]
{x: if true then 1 else 2 end} null {"x":1}
if true then [.] else . end [] null null
[.[] | [.foo[] // .bar]] [{"foo":[1,2], "bar": 42}, {"foo":[1], "bar": null}, {"foo":[null,false,3], "bar": 18}, {"foo":[], "bar":42}, {"foo": [null,false,null], "bar": 41}] [[1,2], [1], [3], [42], [41]]
.[] //= .[0] ["hello",true,false,[false],null] ["hello",true,"hello",[false],"hello"]
.[] | [.[0] and .[1], .[0] or .[1]] [[true,[]], [false,1], [42,null], [null,false]] [true,true] [false,true] [false,true] [false,false]
[.[] | not] [1,0,false,null,true,"hello"] [false,false,true,true,false,false]
Check numeric comparison binops
[10 > 0, 10 > 10, 10 > 20, 10 < 0, 10 < 10, 10 < 20] {} [true,false,false,false,false,true]
[10 >= 0, 10 >= 10, 10 >= 20, 10 <= 0, 10 <= 10, 10 <= 20] {} [true,true,false,false,true,true]
And some in/equality tests
[ 10 == 10, 10 != 10, 10 != 11, 10 == 11] {} [true,false,true,false]
["hello" == "hello", "hello" != "hello", "hello" == "world", "hello" != "world" ] {} [true,false,false,true]
[[1,2,3] == [1,2,3], [1,2,3] != [1,2,3], [1,2,3] == [4,5,6], [1,2,3] != [4,5,6]] {} [true,false,false,true]
[{"foo":42} == {"foo":42},{"foo":42} != {"foo":42}, {"foo":42} != {"bar":42}, {"foo":42} == {"bar":42}] {} [true,false,true,false]
ugly complicated thing
[{"foo":[1,2,{"bar":18},"world"]} == {"foo":[1,2,{"bar":18},"world"]},{"foo":[1,2,{"bar":18},"world"]} == {"foo":[1,2,{"bar":19},"world"]}] {} [true,false]
containment operator
[("foo" | contains("foo")), ("foobar" | contains("foo")), ("foo" | contains("foobar"))] {} [true, true, false]
containment operator (embedded NULs!)
[contains(""), contains("\u0000")] "\u0000" [true, true]
[contains(""), contains("a"), contains("ab"), contains("c"), contains("d")] "ab\u0000cd" [true, true, true, true, true]
[contains("cd"), contains("b\u0000"), contains("ab\u0000")] "ab\u0000cd" [true, true, true]
[contains("b\u0000c"), contains("b\u0000cd"), contains("b\u0000cd")] "ab\u0000cd" [true, true, true]
[contains("@"), contains("\u0000@"), contains("\u0000what")] "ab\u0000cd" [false, false, false]
Try/catch and general ? operator
[.[]|try if . == 0 then error("foo") elif . == 1 then .a elif . == 2 then empty else . end catch .] [0,1,2,3] ["foo","Cannot index number with string (\"a\")",3]
[.[]|(.a, .a)?] [null,true,{"a":1}] [null,null,1,1]
[[.[]|[.a,.a]]?] [null,true,{"a":1}] []
[if error then 1 else 2 end?] "foo" []
try error(0) // 1 null 1
1, try error(2), 3 null 1 3
1 + try 2 catch 3 + 4 null 7
[-try .] 1 [-1]
try -.? catch . "foo" "string (\"foo\") cannot be negated"
{x: try 1, y: try error catch 2, z: if true then 3 end} null {"x":1,"y":2,"z":3}
{x: 1 + 2, y: false or true, z: null // 3} null {"x":3,"y":true,"z":3}
.[] | try error catch . [1,null,2] 1 null 2
try error("\($loc)") catch . null "{\"file\":\"<top-level>\",\"line\":1}"
string operations
[.[]|startswith("foo")] ["fo", "foo", "barfoo", "foobar", "barfoob"] [false, true, false, true, false]
[.[]|endswith("foo")] ["fo", "foo", "barfoo", "foobar", "barfoob"] [false, true, true, false, false]
[.[] | split(", ")] ["a,b, c, d, e,f",", a,b, c, d, e,f, "] [["a,b","c","d","e,f"],["","a,b","c","d","e,f",""]]
split("") "abc" ["a","b","c"]
[.[]|ltrimstr("foo")] ["fo", "foo", "barfoo", "foobar", "afoo"] ["fo","","barfoo","bar","afoo"]
[.[]|rtrimstr("foo")] ["fo", "foo", "barfoo", "foobar", "foob"] ["fo","","bar","foobar","foob"]
[.[]|trimstr("foo")] ["fo", "foo", "barfoo", "foobarfoo", "foob"] ["fo","","bar","bar","b"]
[.[]|ltrimstr("")] ["a", "xx", ""] ["a", "xx", ""]
[.[]|rtrimstr("")] ["a", "xx", ""] ["a", "xx", ""]
[.[]|trimstr("")] ["a", "xx", ""] ["a", "xx", ""]
[(index(","), rindex(",")), indices(",")] "a,bc,def,ghij,klmno" [1,13,[1,4,8,13]]
[ index("aba"), rindex("aba"), indices("aba") ] "xababababax" [1,7,[1,3,5,7]]
_strindices is used by indices/1 but is callable
try _strindices("abc") catch . 123 "number (123) cannot be searched, as it is not a string"
try _strindices(123) catch . "abc" "number (123) is not a string"
trim
\u000b is vertical tab (\v not supported by json)
map(trim), map(ltrim), map(rtrim) [" \n\t\r\f\u000b", ""," ", "a", " a ", "abc", " abc ", " abc", "abc "] ["", "", "", "a", "a", "abc", "abc", "abc", "abc"] ["", "", "", "a", "a ", "abc", "abc ", "abc", "abc "] ["", "", "", "a", " a", "abc", " abc", " abc", "abc"]
trim, ltrim, rtrim "\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000abc\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000" "abc" "abc\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000" "\u0009\u000A\u000B\u000C\u000D\u0020\u0085\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000abc"
try trim catch ., try ltrim catch ., try rtrim catch . 123 "trim input must be a string" "trim input must be a string" "trim input must be a string"
indices(1) [0,1,1,2,3,4,1,5] [1,2,6]
indices([1,2]) [0,1,2,3,1,4,2,5,1,2,6,7] [1,8]
indices([1,2]) [1] []
indices(", ") "a,b, cd,e, fgh, ijkl" [3,9,14]
index("!") "здравствуй мир!" 14
.[:rindex("x")] "正xyz" "正"
indices("o") "🇬🇧oo" [2,3]
indices("o") "ƒoo" [1,2]
[.[]|split(",")] ["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"] [["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]
[.[]|split(", ")] ["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"] [["a","bc","def","ghij","jklmn","a,b","c,d","e,f"],["a,b,c,d","e,f,g,h"]]
[.[] * 3] ["a", "ab", "abc"] ["aaa", "ababab", "abcabcabc"]
[.[] * "abc"] [-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 3.7, 10.0] [null,null,"","","abc","abc","abcabcabc","abcabcabcabcabcabcabcabcabcabc"]
[. * (nan,-nan)] "abc" [null,null]
. * 100000 | [.[:10],.[-10:]] "abc" ["abcabcabca","cabcabcabc"]
. * 1000000000 "" ""
try (. * 1000000000) catch . "abc" "Repeat string result too long"
[.[] / ","] ["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"] [["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]
[.[] / ", "] ["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"] [["a","bc","def","ghij","jklmn","a,b","c,d","e,f"],["a,b,c,d","e,f,g,h"]]
map(.[1] as $needle | .[0] | contains($needle)) [[[],[]], [[1,2,3], [1,2]], [[1,2,3], [3,1]], [[1,2,3], [4]], [[1,2,3], [1,4]]] [true, true, true, false, false]
map(.[1] as $needle | .[0] | contains($needle)) [[["foobar", "foobaz"], ["baz", "bar"]], [["foobar", "foobaz"], ["foo"]], [["foobar", "foobaz"], ["blap"]]] [true, true, false]
[({foo: 12, bar:13} | contains({foo: 12})), ({foo: 12} | contains({})), ({foo: 12, bar:13} | contains({baz:14}))] {} [true, true, false]
{foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {}}}) {} true
{foo: {baz: 12, blap: {bar: 13}}, bar: 14} | contains({bar: 14, foo: {blap: {bar: 14}}}) {} false
sort [42,[2,5,3,11],10,{"a":42,"b":2},{"a":42},true,2,[2,6],"hello",null,[2,5,6],{"a":[],"b":1},"abc","ab",[3,10],{},false,"abcd",null] [null,null,false,true,2,10,42,"ab","abc","abcd","hello",[2,5,3,11],[2,5,6],[2,6],[3,10],{},{"a":42},{"a":42,"b":2},{"a":[],"b":1}]
(sort_by(.b) | sort_by(.a)), sort_by(.a, .b), sort_by(.b, .c), group_by(.b), group_by(.a + .b - .c == 2) [{"a": 1, "b": 4, "c": 14}, {"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}, {"a": 0, "b": 2, "c": 43}] [{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}] [{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}] [{"a": 4, "b": 1, "c": 3}, {"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 3}, {"a": 1, "b": 4, "c": 14}] [[{"a": 4, "b": 1, "c": 3}], [{"a": 0, "b": 2, "c": 43}], [{"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}]] [[{"a": 1, "b": 4, "c": 14}, {"a": 0, "b": 2, "c": 43}], [{"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}]]
unique [1,2,5,3,5,3,1,3] [1,2,3,5]
unique [] []
[min, max, min_by(.[1]), max_by(.[1]), min_by(.[2]), max_by(.[2])] [[4,2,"a"],[3,1,"a"],[2,4,"a"],[1,3,"a"]] [[1,3,"a"],[4,2,"a"],[3,1,"a"],[2,4,"a"],[4,2,"a"],[1,3,"a"]]
[min,max,min_by(.),max_by(.)] [] [null,null,null,null]
.foo[.baz] {"foo":{"bar":4},"baz":"bar"} 4
.[] | .error = "no, it's OK" [{"error":true}] {"error": "no, it's OK"}
[{a:1}] | .[] | .a=999 null {"a": 999}
to_entries {"a": 1, "b": 2} [{"key":"a", "value":1}, {"key":"b", "value":2}]
from_entries [{"key":"a", "value":1}, {"Key":"b", "Value":2}, {"name":"c", "value":3}, {"Name":"d", "Value":4}] {"a": 1, "b": 2, "c": 3, "d": 4}
with_entries(.key |= "KEY_" + .) {"a": 1, "b": 2} {"KEY_a": 1, "KEY_b": 2}
map(has("foo")) [{"foo": 42}, {}] [true, false]
map(has(2)) [[0,1], ["a","b","c"]] [false, true]
has(nan) [0,1,2] false
keys [42,3,35] [0,1,2]
[][.] 1000000000000000000 null
map([1,2][0:.]) [-1, 1, 2, 3, 1000000000000000000] [[1], [1], [1,2], [1,2], [1,2]]
Test recursive object merge
{"k": {"a": 1, "b": 2}} * . {"k": {"a": 0,"c": 3}} {"k": {"a": 0, "b": 2, "c": 3}}
{"k": {"a": 1, "b": 2}, "hello": {"x": 1}} * . {"k": {"a": 0,"c": 3}, "hello": 1} {"k": {"a": 0, "b": 2, "c": 3}, "hello": 1}
{"k": {"a": 1, "b": 2}, "hello": 1} * . {"k": {"a": 0,"c": 3}, "hello": {"x": 1}} {"k": {"a": 0, "b": 2, "c": 3}, "hello": {"x": 1}}
{"a": {"b": 1}, "c": {"d": 2}, "e": 5} * . {"a": {"b": 2}, "c": {"d": 3, "f": 9}} {"a": {"b": 2}, "c": {"d": 3, "f": 9}, "e": 5}
[.[]|arrays] [1,2,"foo",[],[3,[]],{},true,false,null] [[],[3,[]]]
[.[]|objects] [1,2,"foo",[],[3,[]],{},true,false,null] [{}]
[.[]|iterables] [1,2,"foo",[],[3,[]],{},true,false,null] [[],[3,[]],{}]
[.[]|scalars] [1,2,"foo",[],[3,[]],{},true,false,null] [1,2,"foo",true,false,null]
[.[]|values] [1,2,"foo",[],[3,[]],{},true,false,null] [1,2,"foo",[],[3,[]],{},true,false]
[.[]|booleans] [1,2,"foo",[],[3,[]],{},true,false,null] [true,false]
[.[]|nulls] [1,2,"foo",[],[3,[]],{},true,false,null] [null]
flatten [0, [1], [[2]], [[[3]]]] [0, 1, 2, 3]
flatten(0) [0, [1], [[2]], [[[3]]]] [0, [1], [[2]], [[[3]]]]
flatten(2) [0, [1], [[2]], [[[3]]]] [0, 1, 2, [3]]
flatten(2) [0, [1, [2]], [1, [[3], 2]]] [0, 1, 2, 1, [3], 2]
try flatten(-1) catch . [0, [1], [[2]], [[[3]]]] "flatten depth must not be negative"
transpose [[1], [2,3]] [[1,2],[null,3]]
transpose [] []
ascii_upcase "useful but not for é" "USEFUL BUT NOT FOR é"
bsearch(0,1,2,3,4) [1,2,3] -1 0 1 2 -4
bsearch({x:1}) [{ "x": 0 },{ "x": 1 },{ "x": 2 }] 1
try ["OK", bsearch(0)] catch ["KO",.] "aa" ["KO","string (\"aa\") cannot be searched from"]
strftime("%Y-%m-%dT%H:%M:%SZ") [2015,2,5,23,51,47,4,63] "2015-03-05T23:51:47Z"
strftime("%A, %B %d, %Y") 1435677542.822351 "Tuesday, June 30, 2015"
strftime("%Y-%m-%dT%H:%M:%SZ") [2024,2,15] "2024-03-15T00:00:00Z"
mktime [2024,8,21] 1726876800
gmtime 1425599507 [2015,2,5,23,51,47,4,63]
gmtime[5] 1425599507.25 47.25
test invalid tm input
try strftime("%Y-%m-%dT%H:%M:%SZ") catch . ["a",1,2,3,4,5,6,7] "strftime/1 requires parsed datetime inputs"
try strflocaltime("%Y-%m-%dT%H:%M:%SZ") catch . ["a",1,2,3,4,5,6,7] "strflocaltime/1 requires parsed datetime inputs"
try mktime catch . ["a",1,2,3,4,5,6,7] "mktime requires parsed datetime inputs"
oss-fuzz #67403: non-string argument with number input fails assert
try ["OK", strftime([])] catch ["KO", .] 0 ["KO","strftime/1 requires a string format"]
try ["OK", strflocaltime({})] catch ["KO", .] 0 ["KO","strflocaltime/1 requires a string format"]
[strptime("%Y-%m-%dT%H:%M:%SZ")|(.,mktime)] "2015-03-05T23:51:47Z" [[2015,2,5,23,51,47,4,63],1425599507]
Check day-of-week and day of year computations
(should trip an assert if this fails)
last(range(365 * 67)|("1970-03-01T01:02:03Z"|strptime("%Y-%m-%dT%H:%M:%SZ")|mktime) + (86400 * .)|strftime("%Y-%m-%dT%H:%M:%SZ")|strptime("%Y-%m-%dT%H:%M:%SZ")) null [2037,1,11,1,2,3,3,41]
module system
import "a" as foo; import "b" as bar; def fooa: foo::a; [fooa, bar::a, bar::b, foo::a] null ["a","b","c","a"]
import "c" as foo; [foo::a, foo::c] null [0,"acmehbah"]
include "c"; [a, c] null [0,"acmehbah"]
import "data" as $e; import "data" as $d; [$d[].this,$e[].that,$d::d[].this,$e::e[].that]|join(";") null "is a test;is too;is a test;is too"
Regression test for #2000
import "data" as $a; import "data" as $b; def f: {$a, $b}; f null {"a":[{"this":"is a test","that":"is too"}],"b":[{"this":"is a test","that":"is too"}]}
include "shadow1"; e null 2
include "shadow1"; include "shadow2"; e null 3
import "shadow1" as f; import "shadow2" as f; import "shadow1" as e; [e::e, f::e] null [2,3]
%%FAIL module (.+1); 0 jq: error: Module metadata must be constant at <top-level>, line 1, column 8: module (.+1); 0 ^^^^^
%%FAIL module []; 0 jq: error: Module metadata must be an object at <top-level>, line 1, column 8: module []; 0 ^^
%%FAIL include "a" (.+1); 0 jq: error: Module metadata must be constant at <top-level>, line 1, column 13: include "a" (.+1); 0 ^^^^^
%%FAIL include "a" []; 0 jq: error: Module metadata must be an object at <top-level>, line 1, column 13: include "a" []; 0 ^^
%%FAIL include "\ "; 0 jq: error: Invalid escape at line 1, column 4 (while parsing '"\ "') at <top-level>, line 1, column 10: include "\ "; 0 ^^
%%FAIL include "\(a)"; 0 jq: error: Import path must be constant at <top-level>, line 1, column 9: include "\(a)"; 0 ^^^^^^
modulemeta "c" {"whatever":null,"deps":[{"as":"foo","is_data":false,"relpath":"a"},{"search":"./","as":"d","is_data":false,"relpath":"d"},{"search":"./","as":"d2","is_data":false,"relpath":"d"},{"search":"./../lib/jq","as":"e","is_data":false,"relpath":"e"},{"search":"./../lib/jq","as":"f","is_data":false,"relpath":"f"},{"as":"d","is_data":true,"relpath":"data"}],"defs":["a/0","c/0"]}
modulemeta | .deps | length "c" 6
modulemeta | .defs | length "c" 2
%%FAIL IGNORE MSG import "syntaxerror" as e; . jq: error: syntax error, unexpected ';', expecting end of file at tests/modules/syntaxerror/syntaxerror.jq, line 1, column 4: wat; ^
%%FAIL %::wat jq: error: syntax error, unexpected '%', expecting end of file at <top-level>, line 1, column 1: %::wat ^
import "test_bind_order" as check; check::check null true
try -. catch . "very-long-long-long-long-string" "string (\"very-long-long-long-long...\") cannot be negated"
try (.-.) catch . "very-long-long-long-long-string" "string (\"very-long-long-long-long...\") and string (\"very-long-long-long-long...\") cannot be subtracted"
"x" * range(0; 12; 2) + "☆" * 8 | try -. catch . null "string (\"☆☆☆☆☆☆☆☆\") cannot be negated" "string (\"xx☆☆☆☆☆☆☆☆\") cannot be negated" "string (\"xxxx☆☆☆☆☆☆...\") cannot be negated" "string (\"xxxxxx☆☆☆☆☆☆...\") cannot be negated" "string (\"xxxxxxxx☆☆☆☆☆...\") cannot be negated" "string (\"xxxxxxxxxx☆☆☆☆...\") cannot be negated"
try (. + "x") catch . == if have_decnum then "number (12345678901234567890123456...) and string (\"x\") cannot be added" else "number (12345678901234568000000000...) and string (\"x\") cannot be added" end 123456789012345678901234567890 true
join(",") ["1",2,true,false,3.4] "1,2,true,false,3.4"
.[] | join(",") [[], [null], [null,null], [null,null,null]] "" "" "," ",,"
.[] | join(",") [["a",null], [null,"a"]] "a," ",a"
try join(",") catch . ["1","2",{"a":{"b":{"c":33}}}] "string (\"1,2,\") and object ({\"a\":{\"b\":{\"c\":33}}}) cannot be added"
try join(",") catch . ["1","2",[3,4,5]] "string (\"1,2,\") and array ([3,4,5]) cannot be added"
{if:0,and:1,or:2,then:3,else:4,elif:5,end:6,as:7,def:8,reduce:9,foreach:10,try:11,catch:12,label:13,import:14,include:15,module:16} null {"if":0,"and":1,"or":2,"then":3,"else":4,"elif":5,"end":6,"as":7,"def":8,"reduce":9,"foreach":10,"try":11,"catch":12,"label":13,"import":14,"include":15,"module":16}
try (1/.) catch . 0 "number (1) and number (0) cannot be divided because the divisor is zero"
try (1/0) catch . 0 "number (1) and number (0) cannot be divided because the divisor is zero"
try (0/0) catch . 0 "number (0) and number (0) cannot be divided because the divisor is zero"
try (1%.) catch . 0 "number (1) and number (0) cannot be divided (remainder) because the divisor is zero"
try (1%0) catch . 0 "number (1) and number (0) cannot be divided (remainder) because the divisor is zero"
Basic numbers tests: integers, powers of two
[range(-52;52;1)] as $powers | [$powers[]|pow(2;.)|log2|round] == $powers null true
[range(-99/2;99/2;1)] as $orig | [$orig[]|pow(2;.)|log2] as $back | ($orig|keys)[]|. as $k | (($orig|.[$k])-($back|.[$k]))|if . < 0 then . * -1 else . end|select(.>.00005) null
%%FAIL { jq: error: syntax error, unexpected end of file at <top-level>, line 1, column 1: { ^
%%FAIL } jq: error: syntax error, unexpected INVALID_CHARACTER, expecting end of file at <top-level>, line 1, column 1: } ^
(.[{}] = 0)? null
INDEX(range(5)|[., "foo\(.)"]; .[0]) null {"0":[0,"foo0"],"1":[1,"foo1"],"2":[2,"foo2"],"3":[3,"foo3"],"4":[4,"foo4"]}
JOIN({"0":[0,"abc"],"1":[1,"bcd"],"2":[2,"def"],"3":[3,"efg"],"4":[4,"fgh"]}; .[0]|tostring) [[5,"foo"],[3,"bar"],[1,"foobar"]] [[[5,"foo"],null],[[3,"bar"],[3,"efg"]],[[1,"foobar"],[1,"bcd"]]]
range(5;10)|IN(range(10)) null true true true true true
range(5;13)|IN(range(0;10;3)) null false true false false true false false false
range(10;12)|IN(range(10)) null false false
IN(range(10;20); range(10)) null false
IN(range(5;20); range(10)) null true
Regression test for #1347
(.a as $x | .b) = "b" {"a":null,"b":null} {"a":null,"b":"b"}
Regression test for #1368
(.. | select(type == "object" and has("b") and (.b | type) == "array")|.b) |= .[0] {"a": {"b": [1, {"b": 3}]}} {"a": {"b": 1}}
isempty(empty) null true
isempty(range(3)) null false
isempty(1,error("foo")) null false
Regression test for #1815
index("") "" null
check that dead code removal occurs after builtin it generation
builtins|length > 10 null true
"-1"|IN(builtins[] / "/"|.[1]) null false
all(builtins[] / "/"; .[1]|tonumber >= 0) null true
builtins|any(.[:1] == "_") null false
Test ability to use keywords (uncomment after eval is pushed)
#(.[] as $kw | "\"{\($kw)} as $\($kw) | $\($kw) | {$\($kw)} | {\($kw):.\($kw)}\""|eval|empty),null #["as","def","module","import","include","if","then","else","elif","end","reduce","foreach","and","or","try","catch","label","break","loc"] #null # #(.[] as $kw | "\"def f($\($kw)): $\($kw); f(.)\""|eval|empty),null #["as","def","module","import","include","if","then","else","elif","end","reduce","foreach","and","or","try","catch","label","break","loc"] #null
#
Tests to cover the new toliteral number functionality
For an example see #1652 and other linked issues
#
We are backward and sanity compatible
map(. == 1) [1, 1.0, 1.000, 100e-2, 1e+0, 0.0001e4] [true, true, true, true, true, true]
When no arithmetic is involved jq should preserve the literal value
.[0] | tostring | . == if have_decnum then "13911860366432393" else "13911860366432392" end [13911860366432393] true
.x | tojson | . == if have_decnum then "13911860366432393" else "13911860366432392" end {"x":13911860366432393} true
(13911860366432393 == 13911860366432392) | . == if have_decnum then false else true end null true
Applying arithmetic to the value will truncate the result to double
. - 10 13911860366432393 13911860366432382
.[0] - 10 [13911860366432393] 13911860366432382
.x - 10 {"x":13911860366432393} 13911860366432382
Unary negation preserves numerical precision
-. | tojson == if have_decnum then "-13911860366432393" else "-13911860366432392" end 13911860366432393 true
-. | tojson == if have_decnum then "0.12345678901234567890123456789" else "0.12345678901234568" end -0.12345678901234567890123456789 true
[1E+1000,-1E+1000 | tojson] == if have_decnum then ["1E+1000","-1E+1000"] else ["1.7976931348623157e+308","-1.7976931348623157e+308"] end null true
. |= try . catch . 1 1
decnum to double conversion
.[] as $n | $n+0 | [., tostring, . == $n] [-9007199254740993, -9007199254740992, 9007199254740992, 9007199254740993, 13911860366432393] [-9007199254740992,"-9007199254740992",true] [-9007199254740992,"-9007199254740992",true] [9007199254740992,"9007199254740992",true] [9007199254740992,"9007199254740992",true] [13911860366432392,"13911860366432392",true]
abs, fabs, length
abs "abc" "abc"
map(abs) [-0, 0, -10, -1.1] [0,0,10,1.1]
map(fabs) [-0, 0, -10, -1.1] [0,0,10,1.1]
map(abs == length) | unique [-10, -1.1, -1e-1, 1000000000000000002] [true]
The following is NOT prescriptive:
map(abs) [0.1,1000000000000000002] [1e-1, 1000000000000000002]
[1E+1000,-1E+1000 | abs | tojson] | unique == if have_decnum then ["1E+1000"] else ["1.7976931348623157e+308"] end null true
[1E+1000,-1E+1000 | length | tojson] | unique == if have_decnum then ["1E+1000"] else ["1.7976931348623157e+308"] end null true
Using a keyword as variable/label name
123 as $label | $label null 123
[ label $if | range(10) | ., (select(. == 5) | break $if) ] null [0,1,2,3,4,5]
reduce .[] as $then (4 as $else | $else; . as $elif | . + $then * $elif) [1,2,3] 96
1 as $foreach | 2 as $and | 3 as $or | { $foreach, $and, $or, a } {"a":4,"b":5} {"foreach":1,"and":2,"or":3,"a":4}
[ foreach .[] as $try (1 as $catch | $catch - 1; . + $try; .) ] [10,9,8,7] [10,19,27,34]
Object construction
{ a, $loc, c } {"a":[1,2,3],"b":"foo","c":{"hi":"hey"}} {"a":[1,2,3],"loc":{"file":"<top-level>","line":1},"c":{"hi":"hey"}}
1 as $x | "2" as $y | "3" as $z | { $x, as, $y: 4, ($z): 5, if: 6, foo: 7 } {"as":8} {"x":1,"as":8,"2":4,"3":5,"if":6,"foo":7}
nan is parsed as a valid NaN value from JSON
fromjson | isnan "nan" true
tojson | fromjson {"a":nan} {"a":null}
NaN with payload is not parsed
.[] | try (fromjson | isnan) catch . ["NaN","-NaN","NaN1","NaN10","NaN100","NaN1000","NaN10000","NaN100000"] true true "Invalid numeric literal at EOF at line 1, column 4 (while parsing 'NaN1')" "Invalid numeric literal at EOF at line 1, column 5 (while parsing 'NaN10')" "Invalid numeric literal at EOF at line 1, column 6 (while parsing 'NaN100')" "Invalid numeric literal at EOF at line 1, column 7 (while parsing 'NaN1000')" "Invalid numeric literal at EOF at line 1, column 8 (while parsing 'NaN10000')" "Invalid numeric literal at EOF at line 1, column 9 (while parsing 'NaN100000')"
calling input/0, or debug/0 in a test doesn't crash jq
try input catch . null "break"
debug 1 1
try/catch catches more than it should #1859
"foo" | try ((try . catch "caught too much") | error) catch "caught just right" null "caught just right"
.[]|(try (if .=="hi" then . else error end) catch empty) | "\(.) there!" ["hi","ho"] "hi there!"
try (["hi","ho"]|.[]|(try . catch (if .=="ho" then "BROKEN"|error else empty end)) | if .=="ho" then error else "\(.) there!" end) catch "caught outside \(.)" null "hi there!" "caught outside ho"
.[]|(try . catch (if .=="ho" then "BROKEN"|error else empty end)) | if .=="ho" then error else "\(.) there!" end ["hi","ho"] "hi there!"
try (try error catch "inner catch \(.)") catch "outer catch \(.)" "foo" "inner catch foo"
try ((try error catch "inner catch \(.)")|error) catch "outer catch \(.)" "foo" "outer catch inner catch foo"
Also #1859, but from #1885
first(.?,.?) null null
Also #1859, but from #2140
{foo: "bar"} | .foo |= .? null {"foo": "bar"}
Also #1859, but from #2220
. |= try 2 1 2
. |= try 2 catch 3 1 2
.[] |= try tonumber ["1", "2a", "3", " 4", "5 ", "6.7", ".89", "-876", "+5.43", 21] [1, 3, 6.7, 0.89, -876, 5.43, 21]
Also 1859, but from 2073
any(keys[]|tostring?;true) {"a":"1","b":"2","c":"3"} true
explode/implode
test replacement character (65533) for outside codepoint range and 0xd800 (55296) - 0xdfff (57343) utf16 surrogate pair range
1.1 and 1.9 to test round down of non-ints
implode|explode [-1,0,1,2,3,1114111,1114112,55295,55296,57343,57344,1.1,1.9] [65533,0,1,2,3,1114111,65533,55295,65533,65533,57344,1,1]
map(try implode catch .) [123,["a"],[nan]] ["implode input must be an array","string (\"a\") can't be imploded, unicode codepoint needs to be numeric","number (null) can't be imploded, unicode codepoint needs to be numeric"]
try 0[implode] catch . [] "Cannot index number with string (\"\")"
walk
walk(.) {"x":0} {"x":0}
walk(1) {"x":0} 1
The following is a regression test, not a requirement:
[walk(.,1)] {"x":0} [{"x":0},1]
Issue #2584
walk(select(IN({}, []) | not)) {"a":1,"b":[]} {"a":1}
#2815
[range(10)] | .[1.2:3.5] null [1,2,3]
[range(10)] | .[1.5:3.5] null [1,2,3]
[range(10)] | .[1.7:3.5] null [1,2,3]
[range(10)] | .[1.7:4294967295] null [1,2,3,4,5,6,7,8,9]
[range(10)] | .[1.7:-4294967296] null []
[[range(10)] | .[1.1,1.5,1.7]] null [1,1,1]
[range(5)] | .[1.1] = 5 null [0,5,2,3,4]
[range(3)] | .[nan:1] null [0]
[range(3)] | .[1:nan] null [1,2]
[range(3)] | .[nan] null null
try ([range(3)] | .[nan] = 9) catch . null "Cannot set array element at NaN index"
try ("foobar" | .[1.5:3.5] = "xyz") catch . null "Cannot update string slices"
try ([range(10)] | .[1.5:3.5] = ["xyz"]) catch . null [0,"xyz",4,5,6,7,8,9]
try ("foobar" | .[1.5]) catch . null "Cannot index string with number (1.5)"
setpath/2 does not leak the input after an invalid get #2970
try ["ok", setpath([1]; 1)] catch ["ko", .] {"hi":"hello"} ["ko","Cannot index object with number (1)"]
try fromjson catch . "{'a': 123}" "Invalid string literal; expected \", but got ' at line 1, column 5 (while parsing '{'a': 123}')"
ltrimstr/1 rtrimstr/1 don't leak on invalid input #2977
try ltrimstr(1) catch "x", try rtrimstr(1) catch "x" | "ok" "hi" "ok" "ok"
try ltrimstr("x") catch "x", try rtrimstr("x") catch "x" | "ok" {"hey":[]} "ok" "ok"
ltrimstr/1 and rtrimstr/1 return an error for non-strings. #2969
.[] as [$x, $y] | try ["ok", ($x | ltrimstr($y))] catch ["ko", .] [["hi",1],[1,"hi"],["hi","hi"],[1,1]] ["ko","startswith() requires string inputs"] ["ko","startswith() requires string inputs"] ["ok",""] ["ko","startswith() requires string inputs"]
.[] as [$x, $y] | try ["ok", ($x | rtrimstr($y))] catch ["ko", .] [["hi",1],[1,"hi"],["hi","hi"],[1,1]] ["ko","endswith() requires string inputs"] ["ko","endswith() requires string inputs"] ["ok",""] ["ko","endswith() requires string inputs"]
oss-fuzz #66061: setpath/2 leaks when indexing array with array
try ["OK", setpath([[1]]; 1)] catch ["KO", .] [] ["KO","Cannot update field at array index of array"]
regression test for #3227
foreach .[] as $x (0, 1; . + $x) [1, 2] 1 3 2 4
regression test for CVE-2025-49014 (use of fmt after free)
tests with both empty string literal and empty string created by function
as they seems to behave reference wise differently.
strflocaltime("" | ., @uri) 0 "" ""
regression tests for #3413
upper range bounds should be in sync with the constants defined at
src/jv_parse.c:#define MAX_PARSING_DEPTH (N)
src/jv_print.c:#define MAX_PRINT_DEPTH (N)
(N-1)
reduce range(9999) as $_ ([];[.]) | tojson | fromjson | flatten null []
(N)
reduce range(10000) as $_ ([];[.]) | tojson | try (fromjson) catch . | (contains("<skipped: too deep>") | not) and contains("Exceeds depth limit for parsing") null true
(N+1)
reduce range(10001) as $_ ([];[.]) | tojson | contains("<skipped: too deep>") null true
regression test for CVE-2026-33947
setpath([range(10000) | 0]; 0) | flatten null [0]
try setpath([range(10001) | 0]; 0) catch . null "Path too deep"
getpath([range(10000) | 0]) null null
try getpath([range(10001) | 0]) catch . null "Path too deep"
delpaths([[range(10000) | 0]]) null null
try delpaths([[range(10001) | 0]]) catch . null "Path too deep"
regression test for CVE-2026-40612
reduce range(10000) as $_ ([]; [.]) | contains([[]]) null true
try (reduce range(10001) as $_ ([]; [.]) as $x | $x | contains($x)) catch . null "Containment check too deep"
regression test for CVE-2026-43896
reduce range(10000) as $_ ({}; {a: .}) as $x | $x * $x | length null 1
try (reduce range(10001) as $_ ({}; {a: .}) as $x | $x * $x) catch . null "Object merge too deep"
regression test for deep structural equality recursion
try ((reduce range(10001) as $_ ([]; [.])) as $x | (reduce range(10001) as $_ ([]; [.])) as $y | $x == $y) catch . null "Equality check too deep"
regression tests for deep ordering comparisons
try ((reduce range(10001) as $_ ([]; [.])) as $x | [$x, $x] | sort) catch . null "Comparison too deep"
try ((reduce range(10001) as $_ ([]; [.])) as $x | [$x, $x] | unique) catch . null "Comparison too deep"
try ((reduce range(10001) as $_ ({}; {a: .})) as $x | [$x, $x] | sort) catch . null "Comparison too deep"
try ((reduce range(10001) as $_ ({}; {a: .})) as $x | [$x, $x] | unique) catch . null "Comparison too deep" </source>
<stories> <story id="architecture-foundation" implements="ARCHITECTURE.md">Establish the standalone Python interpreter architecture and executable boundary.</story> <story id="EXEC-001" implements="FEATURE-Executable-Entry-Point.md">Implement the executable jq entry point.</story> <story id="EXEC-002" implements="FEATURE-Process-Contract.md">Implement jq process exit and diagnostic behavior.</story> <story id="EXEC-003" implements="FEATURE-JSON-I-O.md">Implement JSON input and compact output handling.</story> <story id="PARSE-001" implements="FEATURE-Lexer.md">Implement jq lexical scanning.</story> <story id="PARSE-002" implements="FEATURE-Literals-and-Strings.md">Implement literals, strings, escapes, and interpolation.</story> <story id="PARSE-003" implements="FEATURE-Filter-Grammar.md">Implement the core jq filter expression grammar.</story> <story id="PARSE-004" implements="FEATURE-Advanced-Grammar.md">Implement declarations, control syntax, and grammar rejection.</story> <story id="CORE-001" implements="FEATURE-Generator-Core.md">Implement stream-valued filter evaluation.</story> <story id="CORE-002" implements="FEATURE-Composition.md">Implement composition and cartesian evaluation.</story> <story id="CORE-003" implements="FEATURE-Errors-and-Optional.md">Implement empty, runtime errors, optional evaluation, and partial output.</story> <story id="CORE-004" implements="FEATURE-Truthiness-and-Comparison.md">Implement truthiness, equality, and ordering semantics.</story> <story id="VALUE-001" implements="FEATURE-Value-Model.md">Implement the jq value model and numeric edge cases.</story> <story id="VALUE-002" implements="FEATURE-Accessors.md">Implement field and index access.</story> <story id="VALUE-003" implements="FEATURE-Slices-and-Iteration.md">Implement slices and collection iteration.</story> <story id="VALUE-004" implements="FEATURE-Type-and-Numeric-Primitives.md">Implement type, length, numeric predicates, and math primitives.</story> <story id="CONF-001" implements="FEATURE-Conformance-Assets.md">Stage and validate immutable conformance assets.</story> <story id="FLOW-001" implements="FEATURE-Arithmetic-and-Structural-Operators.md">Implement arithmetic and structural operators.</story> <story id="FLOW-002" implements="FEATURE-Boolean-and-Alternative-Operators.md">Implement boolean and alternative operators.</story> <story id="FLOW-003" implements="FEATURE-Conditionals-and-Exception-Flow.md">Implement conditionals and exception flow.</story> <story id="FLOW-004" implements="FEATURE-Labels-and-Breaks.md">Implement lexical labels and breaks.</story> <story id="FLOW-005" implements="FEATURE-Reductions-and-Iteration-Control.md">Implement reductions and iteration-control builtins.</story> <story id="FLOW-006" implements="FEATURE-Recursive-Generators.md">Implement recursive generators.</story> <story id="FUNC-001" implements="FEATURE-Variable-Bindings.md">Implement lexical variable bindings.</story> <story id="FUNC-002" implements="FEATURE-Function-Parameters.md">Implement filter and value function parameters.</story> <story id="FUNC-003" implements="FEATURE-Function-Definitions.md">Implement function definitions, scope, redefinition, and recursion.</story> <story id="FUNC-004" implements="FEATURE-Destructuring-Alternatives.md">Implement destructuring alternatives.</story> <story id="PATH-001" implements="FEATURE-Path-Discovery.md">Implement path discovery and projection.</story> <story id="PATH-002" implements="FEATURE-Path-Primitives.md">Implement path access and mutation primitives.</story> <story id="PATH-003" implements="FEATURE-Assignment-Operators.md">Implement deletion and assignment operators.</story> <story id="PATH-004" implements="FEATURE-Complex-Assignments.md">Implement complex assignment edge cases.</story> <story id="DATA-001" implements="FEATURE-Collection-Transformations.md">Implement collection transformation builtins.</story> <story id="DATA-002" implements="FEATURE-Sorting-and-Grouping.md">Implement sorting, grouping, and extrema builtins.</story> <story id="DATA-003" implements="FEATURE-Object-Entries-and-Containment.md">Implement object-entry and containment builtins.</story> <story id="DATA-004" implements="FEATURE-Index-and-Membership.md">Implement index, membership, search, and SQL-style utilities.</story> <story id="TEXT-001" implements="FEATURE-String-Manipulation.md">Implement string manipulation builtins.</story> <story id="TEXT-002" implements="FEATURE-Formats-and-Serialization.md">Implement JSON conversion and output formats.</story> <story id="TEXT-003" implements="FEATURE-Regular-Expressions.md">Implement regular-expression filters.</story> <story id="TEXT-004" implements="FEATURE-Date-and-Time.md">Implement date and time filters.</story> <story id="IO-001" implements="FEATURE-Input-Controls.md">Implement input stream controls.</story> <story id="IO-002" implements="FEATURE-Diagnostics.md">Implement diagnostics and stderr filters.</story> <story id="IO-003" implements="FEATURE-Streaming.md">Implement streaming transformations.</story> <story id="CONF-002" implements="FEATURE-Scoped-Conformance.md">Provide scoped conformance verification for implementation slices.</story> <story id="CONF-003" implements="FEATURE-Full-Conformance.md">Verify the completed interpreter against the full conformance corpus.</story> </stories>