Skip to content

Commit 6ab7264

Browse files
committed
Print each jq output on its own line to match gh --jq behavior
1 parent 5fdfb01 commit 6ab7264

3 files changed

Lines changed: 41 additions & 26 deletions

File tree

src/jq.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use jaq_interpret::{Ctx, FilterT, ParseCtx, RcIter, Val};
22
use serde_json::Value;
33

4-
pub fn apply(expression: &str, input: &Value) -> Result<Value, Box<dyn std::error::Error>> {
4+
pub fn apply(expression: &str, input: &Value) -> Result<Vec<Value>, Box<dyn std::error::Error>> {
55
let mut defs = ParseCtx::new(Vec::new());
66
defs.insert_natives(jaq_core::core());
77
defs.insert_defs(jaq_std::std());
@@ -27,9 +27,5 @@ pub fn apply(expression: &str, input: &Value) -> Result<Value, Box<dyn std::erro
2727
.map(|v| v.map(Value::from).map_err(|e| format!("jq error: {:?}", e)))
2828
.collect::<Result<Vec<_>, _>>()?;
2929

30-
match out.len() {
31-
0 => Ok(Value::Null),
32-
1 => Ok(out.into_iter().next().unwrap()),
33-
_ => Ok(Value::Array(out)),
34-
}
30+
Ok(out)
3531
}

src/main.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,29 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
9696

9797
match result {
9898
Ok(value) => {
99-
let filtered = match cli.jq.as_deref() {
100-
Some(expr) => jq::apply(expr, &value)?,
101-
None => value,
102-
};
103-
output::print_json(&filtered, json_mode).map_err(|e| {
104-
let err = error::CliError::ApiError {
105-
message: format!("Output error: {}", e),
106-
};
107-
error::print_error(&err);
108-
std::process::exit(error::exit_code(&err));
109-
}).ok();
99+
match cli.jq.as_deref() {
100+
Some(expr) => {
101+
let results = jq::apply(expr, &value)?;
102+
for v in &results {
103+
output::print_json(v, json_mode).map_err(|e| {
104+
let err = error::CliError::ApiError {
105+
message: format!("Output error: {}", e),
106+
};
107+
error::print_error(&err);
108+
std::process::exit(error::exit_code(&err));
109+
}).ok();
110+
}
111+
}
112+
None => {
113+
output::print_json(&value, json_mode).map_err(|e| {
114+
let err = error::CliError::ApiError {
115+
message: format!("Output error: {}", e),
116+
};
117+
error::print_error(&err);
118+
std::process::exit(error::exit_code(&err));
119+
}).ok();
120+
}
121+
}
110122
}
111123
Err(e) => {
112124
error::print_error(&e);

tests/integration_tests.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -231,63 +231,70 @@ mod jq_tests {
231231
fn test_jq_identity() {
232232
let input = json!({"a": 1, "b": 2});
233233
let result = jq::apply(".", &input).unwrap();
234-
assert_eq!(result, input);
234+
assert_eq!(result, vec![input]);
235235
}
236236

237237
#[test]
238238
fn test_jq_field_access() {
239239
let input = json!({"name": "test", "value": 42});
240240
let result = jq::apply(".name", &input).unwrap();
241-
assert_eq!(result, json!("test"));
241+
assert_eq!(result, vec![json!("test")]);
242242
}
243243

244244
#[test]
245245
fn test_jq_nested_access() {
246246
let input = json!({"a": {"b": {"c": "deep"}}});
247247
let result = jq::apply(".a.b.c", &input).unwrap();
248-
assert_eq!(result, json!("deep"));
248+
assert_eq!(result, vec![json!("deep")]);
249249
}
250250

251251
#[test]
252252
fn test_jq_array_index() {
253253
let input = json!({"items": ["a", "b", "c"]});
254254
let result = jq::apply(".items[0]", &input).unwrap();
255-
assert_eq!(result, json!("a"));
255+
assert_eq!(result, vec![json!("a")]);
256256
}
257257

258258
#[test]
259259
fn test_jq_array_slice() {
260260
let input = json!({"items": [1, 2, 3, 4, 5]});
261261
let result = jq::apply(".items[0:3]", &input).unwrap();
262-
assert_eq!(result, json!([1, 2, 3]));
262+
assert_eq!(result, vec![json!([1, 2, 3])]);
263263
}
264264

265265
#[test]
266266
fn test_jq_select_fields() {
267267
let input = json!({"name": "test", "age": 30, "extra": true});
268268
let result = jq::apply("{name, age}", &input).unwrap();
269-
assert_eq!(result, json!({"name": "test", "age": 30}));
269+
assert_eq!(result, vec![json!({"name": "test", "age": 30})]);
270270
}
271271

272272
#[test]
273273
fn test_jq_pipe() {
274274
let input = json!({"items": [{"name": "a"}, {"name": "b"}]});
275275
let result = jq::apply(".items | length", &input).unwrap();
276-
assert_eq!(result, json!(2));
276+
assert_eq!(result, vec![json!(2)]);
277277
}
278278

279279
#[test]
280280
fn test_jq_map() {
281281
let input = json!({"items": [{"name": "a", "v": 1}, {"name": "b", "v": 2}]});
282282
let result = jq::apply("[.items[] | .name]", &input).unwrap();
283-
assert_eq!(result, json!(["a", "b"]));
283+
assert_eq!(result, vec![json!(["a", "b"])]);
284284
}
285285

286286
#[test]
287287
fn test_jq_null_on_missing() {
288288
let input = json!({"a": 1});
289289
let result = jq::apply(".nonexistent", &input).unwrap();
290-
assert_eq!(result, json!(null));
290+
assert_eq!(result, vec![json!(null)]);
291+
}
292+
293+
#[test]
294+
fn test_jq_multiple_outputs() {
295+
let input = json!({"items": [{"name": "a"}, {"name": "b"}, {"name": "c"}]});
296+
let result = jq::apply(".items[].name", &input).unwrap();
297+
assert_eq!(result, vec![json!("a"), json!("b"), json!("c")]);
291298
}
292299

293300
#[test]

0 commit comments

Comments
 (0)