jsona 0.6.0

A JSONA parser, analyzer and formatter library
Documentation
use super::{Annotations, DomNode, Key, Node};
use crate::formatter::{Scope, ScopeKind};
use std::fmt::{Display, Formatter, Result};

impl Display for Node {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let scope = Scope::default();
        write_value(scope.clone(), self);
        if scope.is_last_char(',') {
            scope.remove_last_char();
        }
        scope.output().fmt(f)
    }
}

fn write_value(scope: Scope, value: &Node) {
    if !value.is_valid() {
        return;
    }
    match value {
        Node::Null(_) | Node::Bool(_) | Node::Number(_) | Node::String(_) => {
            if let Some(text) = value.scalar_text() {
                write_scalar(scope, text, value.annotations());
            }
        }
        Node::Array(v) => {
            if scope.kind == ScopeKind::Array {
                scope.write_ident();
                scope.write("[");
            } else {
                scope.write("[");
            }
            if v.inner.items.read().len() == 0
                && v.annotations()
                    .map(|v| v.value().read().len() == 0)
                    .unwrap_or(true)
            {
                scope.write("],");
            } else {
                let scope = scope.enter(ScopeKind::Array);
                write_annotations(scope.clone(), v.annotations());
                scope.newline();
                let value = v.value().read();
                for item in value.iter() {
                    write_value(scope.clone(), item);
                    scope.newline();
                }
                let scope = scope.exit();
                scope.write_ident();
                scope.write("],");
            }
        }
        Node::Object(v) => {
            if scope.kind == ScopeKind::Array {
                scope.write_ident();
                scope.write("{");
            } else {
                scope.write("{");
            }
            if v.inner.properties.read().len() == 0
                && v.annotations()
                    .map(|v| v.value().read().len() == 0)
                    .unwrap_or(true)
            {
                scope.write("],");
            } else {
                let scope = scope.enter(ScopeKind::Object);
                write_annotations(scope.clone(), v.annotations());
                scope.newline();
                let value = v.value().read();
                for (k, v) in value.iter() {
                    scope.write_ident();
                    scope.write(format!("{}: ", k));
                    write_value(scope.clone(), v);
                    scope.newline();
                }
                let scope = scope.exit();
                scope.write_ident();
                scope.write("},");
            }
        }
    }
}

fn write_scalar<T: Display>(scope: Scope, value: T, annotations: Option<&Annotations>) {
    if scope.kind == ScopeKind::Array {
        scope.write_ident();
        scope.write(format!("{},", value));
    } else if scope.kind == ScopeKind::Object {
        scope.write(format!("{},", value));
    } else {
        scope.write(value.to_string());
    }
    write_annotations(scope, annotations);
}

fn write_annotations(scope: Scope, annotations: Option<&Annotations>) {
    match annotations {
        Some(annotations) => {
            let annotations = annotations.value().read();
            for (key, value) in annotations.iter() {
                if !value.is_valid() {
                    continue;
                }
                match value {
                    Node::Null(_) => {
                        scope.write(format!(" {}", key));
                    }
                    Node::Bool(_) | Node::Number(_) | Node::String(_) => {
                        if let Some(text) = value.scalar_text() {
                            write_scalar_annotation(scope.clone(), key, text);
                        }
                    }
                    Node::Array(_) | Node::Object(_) => {
                        scope.write("\n");
                        scope.write_ident();
                        scope.write(format!("{}(", key));
                        scope.enter(ScopeKind::Annotation);
                        write_value(scope.clone(), value);
                        scope.exit();
                        if scope.is_last_char(',') {
                            scope.remove_last_char();
                        }
                        scope.write(")");
                    }
                }
            }
        }
        None => {}
    }
    scope.newline();
}

fn write_scalar_annotation<T: Display>(scope: Scope, key: &Key, value: T) {
    scope.write(format!(" {}({})", key, value));
}