1use crate::log;
2use core::fmt::{Display, Formatter};
3use hifijson::token::Lex;
4use hifijson::{SliceLexer, str};
5use jaq_core::{Ctx, RcIter, load};
6use jaq_json::Val;
7use load::{Arena, File, Loader};
8use serde::Deserialize;
9use serde::Serialize;
10pub use serde_json as utilities_serde_json;
11pub use serde_json::json as utilities_serde_json_json;
12use std::default::Default;
13use std::fmt;
14use thiserror::Error;
15
16#[macro_export]
18macro_rules! utilities_json_json {
19 ($($json:tt)+) => {
20 $crate::utilities::json::utilities_serde_json::to_string(&$crate::utilities::json::utilities_serde_json_json!($($json)+)).unwrap()
22 };
23}
24
25#[derive(Error, Debug)]
54#[error("Jaq JSON error")] enum JaqError {
56 Parse(String),
57}
58
59pub fn jq_formatted(query: &str, input: &str) -> anyhow::Result<String> {
60 let cli = Cli {
61 ..Default::default()
62 };
63
64 jq_implementation(query, input, cli)
65}
66
67pub fn jqq(query: &str, input: &str) -> anyhow::Result<String> {
68 let cli = Cli {
70 compact_output: true,
71 raw_output: true,
72 log: false,
73 ..Default::default()
74 };
75
76 jq_implementation(query, input, cli)
77}
78
79trait ErrorSized: std::marker::Sized + std::error::Error {}
80pub fn jq(query: &str, input: &str) -> anyhow::Result<String> {
81 let cli = Cli {
82 compact_output: true,
83 raw_output: true,
84 ..Default::default()
85 };
86
87 jq_implementation(query, input, cli)
88}
89
90pub fn jq_implementation(
91 query: &str,
92 input: &str,
93 options: Cli,
94) -> anyhow::Result<String> {
95 let program = File {
96 code: query,
97 path: (),
98 };
99
100 let loader = Loader::new(jaq_std::defs().chain(jaq_json::defs()));
101 let arena = Arena::default();
102
103 let modules_wrapped = loader.load(&arena, program);
104
105 if let Err(e) = modules_wrapped {
106 return Err(anyhow::anyhow!(format!("Error: {e:?}")));
107 }
108 let modules = modules_wrapped.unwrap();
109
110 let filter_wrapped = jaq_core::Compiler::default()
111 .with_funs(jaq_std::funs().chain(jaq_json::funs()))
112 .compile(modules);
113
114 if let Err(e) = filter_wrapped {
115 return Err(anyhow::anyhow!(format!("Error: {e:?}")));
116 }
117 let filter = filter_wrapped.unwrap();
118
119 let inputs = RcIter::new(core::iter::empty());
120
121 let slice = input.as_bytes();
122 let mut lexer = SliceLexer::new(slice);
123 let err = |e| JaqError::Parse(format!("{e} parsing JSON"));
124 let parsed = lexer.exactly_one(Val::parse).map_err(err)?;
125
126 let mut out = filter.run((Ctx::new([], &inputs), parsed));
127
128 let cli = options;
129
130 if cli.color_output {
131 yansi::enable();
132 } else {
133 yansi::disable();
134 }
135
136 let mut result = String::new();
137
138 if let Some(val_result) = out.next() {
139 match val_result {
140 Ok(val) => {
141 let f = |f: &mut Formatter| {
142 let opts = PpOpts {
143 compact: cli.compact_output,
144 indent: if cli.tab {
145 String::from("\t")
146 } else {
147 " ".repeat(cli.indent)
148 },
149 sort_keys: cli.sort_keys,
150 };
151 fmt_val(f, &opts, 0, &val)
152 };
153 if let Val::Str(s) = &val {
154 if cli.raw_output || cli.join_output {
155 result = format!("{result}{s}");
156 } else {
157 result = format!("{}{}", result, FormatterFn(f));
158 }
159 } else {
160 result = format!("{}{}", result, FormatterFn(f));
161 }
162 return Ok(result);
163 }
164 Err(e) => {
165 if cli.log {
166 log!(
167 format!("Error querying {input} with {query}: {e:?}")
168 .as_str()
169 );
170 }
171 return Err(anyhow::anyhow!(format!(
172 "Error querying {input} with {query}: {e:?}"
173 )));
174 }
175 }
176 }
177
178 Err(anyhow::anyhow!("Could not parse JSON"))
179}
180
181#[derive(Serialize, Deserialize)]
182pub struct Cli {
183 pub compact_output: bool,
185 pub raw_output: bool,
186 pub join_output: bool,
187 pub in_place: bool,
188 pub sort_keys: bool,
189 pub color_output: bool,
190 pub tab: bool,
191 pub indent: usize,
192 pub log: bool,
193}
194
195impl Default for Cli {
196 fn default() -> Self {
197 Self {
198 compact_output: false,
199 raw_output: false,
200 join_output: false,
201 in_place: false,
202 sort_keys: false,
203 color_output: false,
204 tab: false,
205 indent: 2,
206 log: true,
207 }
208 }
209}
210
211struct FormatterFn<F>(F);
213
214impl<F: Fn(&mut Formatter) -> fmt::Result> Display for FormatterFn<F> {
215 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
216 self.0(f)
217 }
218}
219
220struct PpOpts {
221 compact: bool,
222 indent: String,
223 sort_keys: bool,
224}
225
226impl PpOpts {
227 fn indent(&self, f: &mut Formatter, level: usize) -> fmt::Result {
228 if !self.compact {
229 write!(f, "{}", self.indent.repeat(level))?;
230 }
231 Ok(())
232 }
233
234 fn newline(&self, f: &mut Formatter) -> fmt::Result {
235 if !self.compact {
236 writeln!(f)?;
237 }
238 Ok(())
239 }
240}
241
242fn fmt_seq<T, I, F>(
243 fmt: &mut Formatter,
244 opts: &PpOpts,
245 level: usize,
246 xs: I,
247 f: F,
248) -> fmt::Result
249where
250 I: IntoIterator<Item = T>,
251 F: Fn(&mut Formatter, T) -> fmt::Result,
252{
253 opts.newline(fmt)?;
254 let mut iter = xs.into_iter().peekable();
255 while let Some(x) = iter.next() {
256 opts.indent(fmt, level + 1)?;
257 f(fmt, x)?;
258 if iter.peek().is_some() {
259 write!(fmt, ",")?;
260 }
261 opts.newline(fmt)?;
262 }
263 opts.indent(fmt, level)
264}
265
266fn fmt_val(
267 f: &mut Formatter,
268 opts: &PpOpts,
269 level: usize,
270 v: &Val,
271) -> fmt::Result {
272 use yansi::Paint;
273
274 match v {
275 Val::Null
276 | Val::Bool(_)
277 | Val::Int(_)
278 | Val::Float(_)
279 | Val::Num(_) => v.fmt(f),
280 Val::Str(_) => write!(f, "{}", v.green()),
281 Val::Arr(a) => {
282 '['.bold().fmt(f)?;
283 if !a.is_empty() {
284 fmt_seq(f, opts, level, &**a, |f, x| {
285 fmt_val(f, opts, level + 1, x)
286 })?;
287 }
288 ']'.bold().fmt(f)
289 }
290 Val::Obj(o) => {
291 '{'.bold().fmt(f)?;
292 let kv =
293 |f: &mut Formatter, (k, val): (&std::rc::Rc<String>, &Val)| {
294 write!(f, "{:?}:", k.bold())?;
295 if !opts.compact {
296 write!(f, " ")?;
297 }
298 fmt_val(f, opts, level + 1, val)
299 };
300 if !o.is_empty() {
301 if opts.sort_keys {
302 let mut o: Vec<_> = o.iter().collect();
303 o.sort_by_key(|(k, _v)| *k);
304 fmt_seq(f, opts, level, o, kv)
305 } else {
306 fmt_seq(f, opts, level, &**o, kv)
307 }?;
308 }
309 '}'.bold().fmt(f)
310 }
311 }
312}