From cc573c4719a62824fdd137c8f5f2e5001daab3cb Mon Sep 17 00:00:00 2001 From: Alex Ozdemir Date: Thu, 7 Jul 2016 15:26:17 -0400 Subject: [PATCH] `paths` now includes paths to `null`s There are a few reasonable ways recurse could behave. The standard libraries implemntation does the following: `recurse(f;cond)` yields ., then . | f if . | f satisfies cond, then . | f | f if . | f | f satisfies cond, etc... But it turns out that for paths, you want the following behavior: `recurse(f;cond)` yields ., then . | f is . satisfies cond, then . | f | f if . | f satisfies cond, etc. The difference is non-trivial (and there are actually a few degrees of freedom here), so I gave paths its own definition, rather than adding a new builtin. This means we don't have two builtin recurses floating around. --- src/builtin.jq | 3 ++- tests/jq.test | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/builtin.jq b/src/builtin.jq index 088f09e62f..5c430f8f35 100644 --- a/src/builtin.jq +++ b/src/builtin.jq @@ -29,7 +29,8 @@ def indices($i): if type == "array" and ($i|type) == "array" then .[$i] else .[$i] end; def index($i): indices($i) | .[0]; # TODO: optimize def rindex($i): indices($i) | .[-1:][0]; # TODO: optimize -def paths: path(recurse(if (type|. == "array" or . == "object") then .[] else empty end))|select(length > 0); +def paths: def recurse_pre(f; cond): def r: ., (select(cond) | f | r); r; + path(recurse_pre(.[]?;.!=null))|select(length > 0); def paths(node_filter): . as $dot|paths|select(. as $p|$dot|getpath($p)|node_filter); def any(generator; condition): [label $out | foreach generator as $i diff --git a/tests/jq.test b/tests/jq.test index 297f1e6e2e..420f8ea354 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -743,6 +743,16 @@ path(.a[path(.b)[0]]) [1,[[],{"a":2}]] [[0],[1],[1,0],[1,1],[1,1,"a"]] +# Make sure we get paths to nulls +[paths] +[1,null] +[[0],[1]] + +# Make sure we don't get paths to lone items +[paths] +5 +[] + [leaf_paths] [1,[[],{"a":2}]] [[0],[1,1,"a"]]