jq: add data file and location expansion support (#757)

This teaches the jq rule about a `data` attribute and adds conditional
support to do bazel location expansion. The expansion is disabled by
default because it likely would cause compat concerns (since jq can take
arbitrary text as input args).
diff --git a/docs/jq.md b/docs/jq.md
index 79cf3ea..75b9ae9 100644
--- a/docs/jq.md
+++ b/docs/jq.md
@@ -7,7 +7,7 @@
 ## jq
 
 <pre>
-jq(<a href="#jq-name">name</a>, <a href="#jq-srcs">srcs</a>, <a href="#jq-filter">filter</a>, <a href="#jq-filter_file">filter_file</a>, <a href="#jq-args">args</a>, <a href="#jq-out">out</a>, <a href="#jq-kwargs">kwargs</a>)
+jq(<a href="#jq-name">name</a>, <a href="#jq-srcs">srcs</a>, <a href="#jq-filter">filter</a>, <a href="#jq-filter_file">filter_file</a>, <a href="#jq-args">args</a>, <a href="#jq-out">out</a>, <a href="#jq-data">data</a>, <a href="#jq-expand_args">expand_args</a>, <a href="#jq-kwargs">kwargs</a>)
 </pre>
 
 Invoke jq with a filter on a set of json input files.
@@ -127,6 +127,8 @@
 | <a id="jq-filter_file"></a>filter_file |  File containing filter expression (alternative to <code>filter</code>)   |  <code>None</code> |
 | <a id="jq-args"></a>args |  Additional args to pass to jq   |  <code>[]</code> |
 | <a id="jq-out"></a>out |  Name of the output json file; defaults to the rule name plus ".json"   |  <code>None</code> |
+| <a id="jq-data"></a>data |  List of additional files. May be empty.   |  <code>[]</code> |
+| <a id="jq-expand_args"></a>expand_args |  Run bazel's location-expansion on the args.   |  <code>False</code> |
 | <a id="jq-kwargs"></a>kwargs |  Other common named parameters such as <code>tags</code> or <code>visibility</code>   |  none |
 
 
diff --git a/lib/jq.bzl b/lib/jq.bzl
index 80203c2..f972246 100644
--- a/lib/jq.bzl
+++ b/lib/jq.bzl
@@ -8,7 +8,7 @@
     toolchains = ["@aspect_bazel_lib//lib:jq_toolchain_type"],
 )
 
-def jq(name, srcs, filter = None, filter_file = None, args = [], out = None, **kwargs):
+def jq(name, srcs, filter = None, filter_file = None, args = [], out = None, data = [], expand_args = False, **kwargs):
     """Invoke jq with a filter on a set of json input files.
 
     For jq documentation, see https://stedolan.github.io/jq/.
@@ -117,6 +117,7 @@
     Args:
         name: Name of the rule
         srcs: List of input files. May be empty.
+        data: List of additional files. May be empty.
         filter: Filter expression (https://stedolan.github.io/jq/manual/#Basicfilters).
             Subject to stamp variable replacements, see [Stamping](./stamping.md).
             When stamping is enabled, a variable named "STAMP" will be available in the filter.
@@ -125,6 +126,7 @@
 
         filter_file: File containing filter expression (alternative to `filter`)
         args: Additional args to pass to jq
+        expand_args: Run bazel's location-expansion on the args.
         out: Name of the output json file; defaults to the rule name plus ".json"
         **kwargs: Other common named parameters such as `tags` or `visibility`
     """
@@ -139,5 +141,7 @@
         filter_file = filter_file,
         args = args,
         out = out,
+        expand_args = expand_args,
+        data = data,
         **kwargs
     )
diff --git a/lib/private/BUILD.bazel b/lib/private/BUILD.bazel
index fe9b06d..a0e0924 100644
--- a/lib/private/BUILD.bazel
+++ b/lib/private/BUILD.bazel
@@ -159,7 +159,10 @@
     name = "jq",
     srcs = ["jq.bzl"],
     visibility = ["//lib:__subpackages__"],
-    deps = ["//lib:stamping"],
+    deps = [
+        ":expand_locations",
+        "//lib:stamping",
+    ],
 )
 
 bzl_library(
diff --git a/lib/private/jq.bzl b/lib/private/jq.bzl
index aa03d8a..7c8a493 100644
--- a/lib/private/jq.bzl
+++ b/lib/private/jq.bzl
@@ -1,6 +1,7 @@
 """Implementation for jq rule"""
 
 load("//lib:stamping.bzl", "STAMP_ATTRS", "maybe_stamp")
+load(":expand_locations.bzl", "expand_locations")
 
 _jq_attrs = dict({
     "srcs": attr.label_list(
@@ -8,9 +9,13 @@
         mandatory = True,
         allow_empty = True,
     ),
+    "data": attr.label_list(
+        allow_files = True,
+    ),
     "filter": attr.string(),
     "filter_file": attr.label(allow_single_file = True),
     "args": attr.string_list(),
+    "expand_args": attr.bool(),
     "out": attr.output(),
     "_parse_status_file_filter": attr.label(
         allow_single_file = True,
@@ -18,12 +23,25 @@
     ),
 }, **STAMP_ATTRS)
 
+def _expand_locations(ctx, s):
+    # `.split(" ")` is a work-around https://github.com/bazelbuild/bazel/issues/10309
+    # TODO: If the string has intentional spaces or if one or more of the expanded file
+    # locations has a space in the name, we will incorrectly split it into multiple arguments
+    return expand_locations(ctx, s, targets = ctx.attr.data).split(" ")
+
 def _jq_impl(ctx):
     jq_bin = ctx.toolchains["@aspect_bazel_lib//lib:jq_toolchain_type"].jqinfo.bin
 
     out = ctx.outputs.out or ctx.actions.declare_file(ctx.attr.name + ".json")
-    args = ctx.attr.args
+    if ctx.attr.expand_args:
+        args = []
+        for a in ctx.attr.args:
+            args += _expand_locations(ctx, a)
+    else:
+        args = ctx.attr.args
+
     inputs = ctx.files.srcs[:]
+    inputs += ctx.files.data
 
     if not ctx.attr.filter and not ctx.attr.filter_file:
         fail("Must provide a filter or a filter_file")
diff --git a/lib/tests/jq/BUILD.bazel b/lib/tests/jq/BUILD.bazel
index d87e69c..c1d16f5 100644
--- a/lib/tests/jq/BUILD.bazel
+++ b/lib/tests/jq/BUILD.bazel
@@ -79,6 +79,26 @@
     file2 = "null.json",
 )
 
+# Data files are passed in correctly
+jq(
+    name = "case_data_input_flag",
+    srcs = [],
+    args = [
+        "--slurpfile",
+        "a",
+        "$(location a_pretty.json)",
+    ],
+    data = ["a_pretty.json"],
+    expand_args = True,
+    filter = "$a[0]",
+)
+
+diff_test(
+    name = "case_data_input_flag_test",
+    file1 = ":case_data_input_flag",
+    file2 = "a_pretty.json",
+)
+
 # Load filter from file
 jq(
     name = "case_filter_file",