jaq_all/lib.rs
1//! Compile & run jq filters and read & write data.
2//!
3//! This crate provides an opinionated, high-level API to
4//! integrate jaq into applications.
5//! It combines the functionality of several crates, which it re-exports:
6//!
7//! - `jaq-core`: basic compilation/execution of jq filters
8//! - `jaq-std`: standard library
9//! - `jaq-json`: type of values
10//! - `jaq-fmts`: multi-format support
11//!
12//! In contrast to these crates, which aim for
13//! minimal functionality and maximal flexibility, this crate aims for
14//! maximal functionality and minimal flexibility.
15//! This makes this crate easier to use,
16//! at the price of not covering all use cases.
17//! You could say that this crate is the "instant food" of jaq crates:
18//! it is easy to use, but difficult to customise.
19//!
20//! This crate is expected to change more frequently.
21//! However, because of its small amount of exposed functions,
22//! it may be easier to stay up-to-date with it than with its dependencies.
23//!
24//! # Usage
25//!
26//! Embedding jaq into your own application involves three steps:
27//!
28//! 1. Compile a filter.
29//! This takes a jq filter as string and parses & compiles it to
30//! a filter ready to be executed by jaq.
31//! You can do this with
32//! [`data::compile`], or with
33//! [`compile_with`] if you need more flexibility.
34//! If this fails, e.g. due to parse errors,
35//! you can use [`load::FileReportsDisp`] to pretty-print errors.
36//! 2. Read input data.
37//! Every jq filter needs to be supplied with input.
38//! This may be
39//! read from an input stream ([`std::io::Read`]) or
40//! parsed from a [`&str`]/bytes.
41//! You can do this with the functions in the [`fmts::read`] module, such as
42//! [`fmts::read::json::read_many`] or
43//! [`fmts::read::json::parse_many`].
44//! 3. Run the filter.
45//! You can do this with [`data::run`].
46//! 4. Write output data (optional).
47//! During or after filter execution, you may want to print output values.
48//! You can do this with the functions in the [`fmts::write`] module, such as
49//! [`fmts::write::write`].
50//!
51//! The `main` example in this crate shows you how to do all of this.
52//! You can run it with `cargo run --example main`.
53#![warn(missing_docs)]
54
55extern crate alloc;
56extern crate std;
57
58pub mod data;
59pub mod load;
60
61pub use jaq_core;
62pub use jaq_fmts as fmts;
63pub use jaq_json as json;
64pub use jaq_std;
65
66use jaq_core::load::{import, parse::Def, Arena, File, Loader};
67use jaq_core::{compile::Compiler, native::Fun, DataT, Filter};
68use load::{compile_errors, load_errors, FileReports};
69
70/// Compile a filter without access to external files.
71///
72/// A simplified version of this function is [`data::compile`].
73pub fn compile_with<D: DataT>(
74 code: &str,
75 defs: impl Iterator<Item = Def>,
76 funs: impl Iterator<Item = Fun<D>>,
77 vars: &[String],
78) -> Result<Filter<D>, Vec<FileReports>> {
79 let vars: Vec<_> = vars.iter().map(|v| format!("${v}")).collect();
80 let arena = Arena::default();
81 let loader = Loader::new(defs);
82 let modules = loader
83 .load(&arena, File { path: (), code })
84 .map_err(load_errors)?;
85
86 import(&modules, |_path| Err("file loading not supported".into())).map_err(load_errors)?;
87
88 Compiler::default()
89 .with_funs(funs)
90 .with_global_vars(vars.iter().map(|v| &**v))
91 .compile(modules)
92 .map_err(compile_errors)
93}
94
95/// Definitions from `jaq_core`, `jaq_std` and `jaq_json`.
96pub fn defs() -> impl Iterator<Item = Def> {
97 jaq_core::defs()
98 .chain(jaq_std::defs())
99 .chain(jaq_json::defs())
100}