mq-run 0.9.1

Command-line interface for mq Markdown processing tool
Documentation
//! TOML output rendering for the `--output-format toml` CLI option.
//!
//! Converts [`mq_lang::RuntimeValue`]s into TOML by first merging them into a
//! [`serde_json::Value`] (see [`crate::json`]) and serializing that with the `toml` crate.
//!
//! TOML documents must be a table at the top level, so the merged value must be
//! a dict (JSON object); anything else is a descriptive error rather than a panic.

use miette::miette;
#[cfg(test)]
use mq_lang::Shared;

/// Converts a list of [`mq_lang::RuntimeValue`]s into a TOML string.
pub(crate) fn runtime_values_to_toml(runtime_values: &[mq_lang::RuntimeValue]) -> miette::Result<String> {
    let value = super::json::runtime_values_to_json_value(runtime_values);

    if !value.is_object() {
        return Err(miette!(
            "TOML output requires the top-level value to be a dict (TOML documents are tables), got: {}",
            value
        ));
    }

    toml::to_string_pretty(&value).map_err(|e| miette!("Failed to serialize to TOML: {}", e))
}

#[cfg(test)]
mod tests {
    use super::*;
    use mq_lang::RuntimeValue;

    #[test]
    fn test_dict_value() {
        let mut map = mq_lang::DictMap::default();
        map.insert(
            mq_lang::Ident::new("name"),
            RuntimeValue::String(Shared::new("Alice".to_string())),
        );
        let values = vec![RuntimeValue::Dict(Shared::new(map))];
        let result = runtime_values_to_toml(&values).unwrap();
        assert!(result.contains("name = \"Alice\""));
    }

    #[test]
    fn test_nested_dict() {
        let mut inner = mq_lang::DictMap::default();
        inner.insert(
            mq_lang::Ident::new("city"),
            RuntimeValue::String(Shared::new("NYC".to_string())),
        );
        let mut outer = mq_lang::DictMap::default();
        outer.insert(mq_lang::Ident::new("address"), RuntimeValue::Dict(Shared::new(inner)));
        let values = vec![RuntimeValue::Dict(Shared::new(outer))];
        let result = runtime_values_to_toml(&values).unwrap();
        assert!(result.contains("[address]"));
        assert!(result.contains("city = \"NYC\""));
    }

    #[test]
    fn test_non_dict_top_level_errors() {
        let values = vec![RuntimeValue::String(Shared::new("hello".to_string()))];
        let result = runtime_values_to_toml(&values);
        assert!(result.is_err());
    }

    #[test]
    fn test_array_top_level_errors() {
        let values = vec![RuntimeValue::Array(Shared::new(vec![RuntimeValue::String(
            Shared::new("a".to_string()),
        )]))];
        let result = runtime_values_to_toml(&values);
        assert!(result.is_err());
    }
}