shadowplay 0.16.3

Utility for checking puppet syntax, a puppet manifest linter, a pretty printer, and a utility for exploring the Hiera.
Documentation
use crate::puppet_pp_printer::Printer;
use pretty::RcDoc;

fn definition_to_doc<'a, EXTRA>(
    keyword: &'static str,
    identifier: &'a crate::puppet_lang::identifier::LowerIdentifier<EXTRA>,
    args: &'a crate::puppet_lang::List<EXTRA, crate::puppet_lang::argument::Argument<EXTRA>>,
    inherits: &'a Option<crate::puppet_lang::identifier::LowerIdentifier<EXTRA>>,
    return_type: &'a Option<crate::puppet_lang::typing::TypeSpecification<EXTRA>>,
    body: &'a crate::puppet_lang::List<EXTRA, crate::puppet_lang::statement::Statement<EXTRA>>,
) -> RcDoc<'a, ()> {
    let inherits = match inherits {
        Some(v) => RcDoc::text("inherits")
            .append(RcDoc::softline())
            .append(v.to_doc())
            .append(RcDoc::softline()),
        None => RcDoc::nil(),
    };

    let return_type = match return_type {
        Some(v) => RcDoc::text(">>")
            .append(RcDoc::softline())
            .append(v.to_doc())
            .append(RcDoc::softline()),
        None => RcDoc::nil(),
    };

    RcDoc::text(keyword)
        .append(RcDoc::softline())
        .append(identifier.to_doc())
        .append(RcDoc::softline())
        .append(crate::puppet_pp_printer::argument::list_to_rounded_doc(
            args,
        ))
        .append(RcDoc::softline())
        .append(inherits)
        .append(return_type)
        .append(crate::puppet_pp_printer::statement::statement_block_to_doc(
            body, true,
        ))
}

impl<EXTRA> Printer for crate::puppet_lang::toplevel::ToplevelVariant<EXTRA> {
    fn to_doc(&self) -> RcDoc<()> {
        match self {
            crate::puppet_lang::toplevel::ToplevelVariant::Class(v) => definition_to_doc(
                "class",
                &v.identifier,
                &v.arguments,
                &v.inherits,
                &None,
                &v.body,
            ),
            crate::puppet_lang::toplevel::ToplevelVariant::Definition(v) => {
                definition_to_doc("define", &v.identifier, &v.arguments, &None, &None, &v.body)
            }
            crate::puppet_lang::toplevel::ToplevelVariant::Plan(v) => {
                definition_to_doc("plan", &v.identifier, &v.arguments, &None, &None, &v.body)
            }
            crate::puppet_lang::toplevel::ToplevelVariant::TypeDef(v) => RcDoc::text("type")
                .append(RcDoc::softline())
                .append(v.identifier.to_doc())
                .append(RcDoc::softline())
                .append(
                    RcDoc::text("=")
                        .append(RcDoc::space())
                        .append(v.value.to_doc())
                        .nest(2),
                )
                .group()
                .nest(2),
            crate::puppet_lang::toplevel::ToplevelVariant::FunctionDef(v) => definition_to_doc(
                "function",
                &v.identifier,
                &v.arguments,
                &None,
                &v.return_type,
                &v.body,
            ),
        }
    }
}

#[test]
fn test_idempotence_short() {
    let cases = vec![
        "class aaa::bbb () inherits zzz {\n  \n}",
        "class aaa::bbb () inherits zzz {\n  if $a {\n    1\n  } else {\n    2\n  }\n}",
        "function aaa::bbb (\n  $empty,\n  $a                           = 1,\n  String $b                    = 'a b c',\n) >> String {\n  \n}",
        "type Aaa::Bbb = String[1, 2]",
    ];

    for case in cases {
        let (_, v) =
            crate::puppet_parser::toplevel::parse(crate::puppet_parser::Span::new(case)).unwrap();

        let mut w = Vec::new();
        v.data.to_doc().render(50, &mut w).unwrap();
        let generated = String::from_utf8(w).unwrap();
        println!("{} ==>\n------\n{}\n------", case, generated);

        assert_eq!(&generated, case)
    }
}