jsrmx 0.2.0

A command-line tool to manipulate JSON files. It can split large single-object JSON files into many files; merge multiple JSON files into one large JSON file; bundle multiple JSON files into one NDJSON file, and unbundle one NDJSON file into many JSON files.
Documentation
mod directory;
mod file;
mod stdin;

pub use directory::InputDirectory;
use eyre::{Report, Result, eyre};
use file::InputFile;
use serde_json::Value;
use std::{ops::Deref, path::PathBuf, sync::Arc};
use stdin::InputStdin;

pub trait JsonSource: Send + Sync {
    fn get_entries(&self, sort: bool) -> Vec<(String, Value)>;
    fn read_entry(&self) -> Result<(String, Value)>;
}

pub trait JsonReader: Send + Sync {
    fn get_object(&self) -> Result<Value>;
    fn read_line(&self, buf: &mut String) -> Result<()>;
}

#[derive(Clone)]
pub struct JsonSourceInput(Arc<dyn JsonSource>);

impl std::str::FromStr for JsonSourceInput {
    type Err = Report;

    fn from_str(input: &str) -> Result<Self> {
        match input {
            "-" => Ok(JsonSourceInput(Arc::new(InputStdin::new()))),
            input => {
                let path = PathBuf::from(input);
                if path.is_dir() {
                    Ok(JsonSourceInput(Arc::new(InputDirectory::new(path))))
                } else {
                    Err(eyre!("Cannot read entries from file: {input}"))
                }
            }
        }
    }
}

impl Deref for JsonSourceInput {
    type Target = Arc<dyn JsonSource>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[derive(Clone)]
pub struct JsonReaderInput(Arc<dyn JsonReader>);

impl std::str::FromStr for JsonReaderInput {
    type Err = Report;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        match input {
            "-" => Ok(JsonReaderInput(Arc::new(InputStdin::new()))),
            input => {
                let path = PathBuf::from(input);
                if path.is_dir() {
                    Err(eyre!("Cannot read object from directory: {input}"))
                } else {
                    Ok(JsonReaderInput(Arc::new(InputFile::new(path)?)))
                }
            }
        }
    }
}

impl Deref for JsonReaderInput {
    type Target = Arc<dyn JsonReader>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}