src/cli/command/json.rs

//! `ripgrab json` — emit matches as line-delimited JSON.
//!
//! Useful for piping into `jq`, `vector`, or feeding structured data into a
//! downstream log pipeline.

use std::io;

use anyhow::Result;

use crate::cli::args::JsonArgs;
use crate::filter::{FilterSet, MatchOutcome};
use crate::render::mode::json::JsonRenderer;
use crate::source::file::FileSource;
use crate::source::Source;

pub async fn run(args: JsonArgs) -> Result<()> {
    let filter = FilterSet::compile(&[], &[], None)?;
    let compiled = args
        .where_clause
        .as_deref()
        .map(crate::filter::dsl::parse_and_compile)
        .transpose()?;
    let stdout = io::stdout();
    let mut renderer = JsonRenderer::new(stdout.lock(), args.pretty);

    for path in &args.paths {
        let mut src = FileSource::open(path).await?;
        while let Some(item) = src.next_line().await? {
            if let Some(c) = &compiled {
                let mut ctx = crate::filter::dsl::EvalContext::new();
                ctx.set("origin", &item.origin);
                ctx.set("body", &item.line);
                if !crate::filter::dsl::evaluate(c, &ctx) {
                    continue;
                }
            }
            let fields = match filter.apply(&item.line) {
                MatchOutcome::Plain => Vec::new(),
                MatchOutcome::Fields(f) => f,
            };
            renderer.render_raw(
                &item.origin,
                &item.line,
                &fields,
                item.seq,
            )?;
        }
    }
    Ok(())
}