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 std::collections::HashMap;

use crate::puppet_parser::range::Range;
use serde::{Deserialize, Serialize};

use super::lint::{EarlyLintPass, LintError, LintPass};

#[derive(Clone, Serialize, Deserialize)]
pub struct OptionalArgumentsGoesFirst;

impl LintPass for OptionalArgumentsGoesFirst {
    fn name(&self) -> &str {
        "OptionalArgumentsGoesFirst"
    }
    fn description(&self) -> &str {
        "Warns if optional argument specified before required"
    }
}

impl OptionalArgumentsGoesFirst {
    fn check_order(&self, args: &[crate::puppet_lang::argument::Argument<Range>]) -> Vec<LintError> {
        let mut errors = Vec::new();
        let mut found_optional = false;
        for arg in args {
            if arg.default.is_some() {
                found_optional = true;
            } else if found_optional {
                errors.push(LintError::new(
                    Box::new(self.clone()),
                    "Required argument goes after optional",
                    &arg.extra,
                ))
            }
        }

        errors
    }
}

impl EarlyLintPass for OptionalArgumentsGoesFirst {
    fn check_class(&self, elt: &crate::puppet_lang::toplevel::Class<Range>) -> Vec<LintError> {
        self.check_order(&elt.arguments.value)
    }

    fn check_definition(&self, elt: &crate::puppet_lang::toplevel::Definition<Range>) -> Vec<LintError> {
        self.check_order(&elt.arguments.value)
    }

    fn check_plan(&self, elt: &crate::puppet_lang::toplevel::Plan<Range>) -> Vec<LintError> {
        self.check_order(&elt.arguments.value)
    }
}

#[derive(Clone, Serialize, Deserialize)]
pub struct UniqueArgumentsNames;

impl LintPass for UniqueArgumentsNames {
    fn name(&self) -> &str {
        "UniqueArgumentsNames"
    }
    fn description(&self) -> &str {
        "Checks for class/definition/plan arguments uniqueness"
    }
}

impl UniqueArgumentsNames {
    fn check(&self, args: &[crate::puppet_lang::argument::Argument<Range>]) -> Vec<LintError> {
        let mut errors = Vec::new();
        let mut names: HashMap<String, &crate::puppet_lang::argument::Argument<Range>> = HashMap::new();
        for arg in args {
            match names.get(&arg.name) {
                Some(prev) => errors.push(LintError::new(
                    Box::new(self.clone()),
                    &format!(
                        "Argument '{}' was already defined earlier at line {}",
                        arg.name,
                        prev.extra.start().line()
                    ),
                    &arg.extra,
                )),
                None => {
                    let _ = names.insert(arg.name.clone(), arg);
                }
            }
        }

        errors
    }
}

impl EarlyLintPass for UniqueArgumentsNames {
    fn check_class(&self, elt: &crate::puppet_lang::toplevel::Class<Range>) -> Vec<LintError> {
        self.check(&elt.arguments.value)
    }

    fn check_definition(&self, elt: &crate::puppet_lang::toplevel::Definition<Range>) -> Vec<LintError> {
        self.check(&elt.arguments.value)
    }

    fn check_plan(&self, elt: &crate::puppet_lang::toplevel::Plan<Range>) -> Vec<LintError> {
        self.check(&elt.arguments.value)
    }
}