jarq 0.2.1

An interactive jq-like JSON query tool with a TUI
Documentation
//! Array and object construction parsing

use nom::{
    branch::alt,
    character::complete::{char, multispace0},
    multi::many0,
    sequence::delimited,
    Parser,
};

use crate::filter::ast::{Filter, ObjectKey};
use super::parse_pipe_chain;
use super::primitives::{identifier, parse_string_literal};

pub fn parse_array_construction(input: &str) -> nom::IResult<&str, Filter> {
    let (input, _) = char('[').parse(input)?;
    let (input, _) = multispace0(input)?;

    // Handle empty array
    if let Ok((input, _)) = char::<_, nom::error::Error<&str>>(']').parse(input) {
        return Ok((input, Filter::Array(vec![])));
    }

    // Parse comma-separated filter expressions
    let (input, first) = parse_pipe_chain(input)?;
    let (input, rest) = many0(|i| {
        let (i, _) = multispace0(i)?;
        let (i, _) = char(',').parse(i)?;
        let (i, _) = multispace0(i)?;
        parse_pipe_chain(i)
    })
    .parse(input)?;

    let (input, _) = multispace0(input)?;
    let (input, _) = char(']').parse(input)?;

    let mut elements = vec![first];
    elements.extend(rest);
    Ok((input, Filter::Array(elements)))
}

pub fn parse_object_construction(input: &str) -> nom::IResult<&str, Filter> {
    let (input, _) = char('{').parse(input)?;
    let (input, _) = multispace0(input)?;

    // Handle empty object
    if let Ok((input, _)) = char::<_, nom::error::Error<&str>>('}').parse(input) {
        return Ok((input, Filter::Object(vec![])));
    }

    // Parse comma-separated key: value pairs
    let (input, first) = parse_object_pair(input)?;
    let (input, rest) = many0(|i| {
        let (i, _) = delimited(multispace0, char(','), multispace0).parse(i)?;
        parse_object_pair(i)
    })
    .parse(input)?;

    let (input, _) = multispace0(input)?;
    let (input, _) = char('}').parse(input)?;

    let mut pairs = vec![first];
    pairs.extend(rest);
    Ok((input, Filter::Object(pairs)))
}

fn parse_object_pair(input: &str) -> nom::IResult<&str, (ObjectKey, Filter)> {
    // Parse key: dynamic (filter), static identifier, or quoted string
    let (input, key) = alt((parse_dynamic_key, parse_static_key)).parse(input)?;

    let (input, _) = multispace0(input)?;
    let (input, _) = char(':').parse(input)?;
    let (input, _) = multispace0(input)?;
    let (input, value) = parse_pipe_chain(input)?;

    Ok((input, (key, value)))
}

fn parse_dynamic_key(input: &str) -> nom::IResult<&str, ObjectKey> {
    let (input, _) = char('(').parse(input)?;
    let (input, _) = multispace0(input)?;
    let (input, filter) = parse_pipe_chain(input)?;
    let (input, _) = multispace0(input)?;
    let (input, _) = char(')').parse(input)?;
    Ok((input, ObjectKey::Dynamic(Box::new(filter))))
}

fn parse_static_key(input: &str) -> nom::IResult<&str, ObjectKey> {
    let (input, key) = alt((parse_string_literal, identifier)).parse(input)?;
    Ok((input, ObjectKey::Static(key)))
}