php_codegen 0.4.0

Generate PHP code from Rust using a fluent API 🐘 🦀
Documentation
use std::fmt::Display;

use crate::class::Class;
use crate::constant::Constant;
use crate::function::Function;
use crate::interface::Interface;
use crate::literal::Value;
use crate::r#enum::Enum;
use crate::r#trait::Trait;
use crate::Generator;
use crate::Indentation;

#[derive(Debug)]
pub struct File {
    pub namespace: Option<String>,
    pub declares: Vec<(String, Value)>,
    pub uses: Vec<String>,
    pub constant_uses: Vec<String>,
    pub function_uses: Vec<String>,
    pub functions: Vec<Function>,
    pub constants: Vec<Constant>,
    pub classes: Vec<Class>,
    pub traits: Vec<Trait>,
    pub enums: Vec<Enum>,
    pub interfaces: Vec<Interface>,
}

impl File {
    pub fn new() -> Self {
        Self {
            namespace: None,
            declares: vec![],
            uses: vec![],
            constant_uses: vec![],
            function_uses: vec![],
            constants: vec![],
            functions: vec![],
            classes: vec![],
            traits: vec![],
            enums: vec![],
            interfaces: vec![],
        }
    }

    pub fn declare<T: ToString, Tv: Into<Value>>(mut self, name: T, value: Tv) -> Self {
        self.declares.push((name.to_string(), value.into()));

        self
    }

    pub fn namespaced<T: ToString>(mut self, namespace: T) -> Self {
        self.namespace = Some(namespace.to_string());

        self
    }

    pub fn uses<T: ToString>(mut self, symbol: T) -> Self {
        self.uses.push(symbol.to_string());

        self
    }

    pub fn uses_constant<T: ToString>(mut self, constant: T) -> Self {
        self.constant_uses.push(constant.to_string());

        self
    }

    pub fn uses_function<T: ToString>(mut self, function: T) -> Self {
        self.function_uses.push(function.to_string());

        self
    }

    pub fn constant<T: Into<Constant>>(mut self, constant: T) -> Self {
        self.constants.push(constant.into());

        self
    }

    pub fn function(mut self, function: Function) -> Self {
        self.functions.push(function);

        self
    }

    pub fn class(mut self, class: Class) -> Self {
        self.classes.push(class);

        self
    }

    pub fn r#trait(mut self, r#trait: Trait) -> Self {
        self.traits.push(r#trait);

        self
    }

    pub fn r#enum(mut self, r#enum: Enum) -> Self {
        self.enums.push(r#enum);

        self
    }

    pub fn interface(mut self, interface: Interface) -> Self {
        self.interfaces.push(interface);

        self
    }
}

impl Generator for File {
    fn generate(&self, indentation: Indentation, level: usize) -> String {
        let mut code = String::new();

        code.push_str("<?php\n\n");

        for (name, value) in &self.declares {
            code.push_str(&format!(
                "declare({}={});\n\n",
                name,
                value.generate(indentation, level)
            ));
        }

        if let Some(namespace) = &self.namespace {
            code.push_str(&format!("namespace {};\n\n", namespace));
        }

        let mut used = false;
        if !self.uses.is_empty() {
            used = true;
            for r#use in &self.uses {
                code.push_str(&format!("use {};\n", r#use));
            }

            code.push('\n');
        }

        if !self.function_uses.is_empty() {
            used = true;
            for function in &self.function_uses {
                code.push_str(&format!("use function {};\n", function));
            }

            code.push('\n');
        }

        if !self.constant_uses.is_empty() {
            used = true;
            for constant in &self.constant_uses {
                code.push_str(&format!("use const {};\n", constant));
            }

            code.push('\n');
        }

        if used {
            code.push('\n');
        }

        code.push_str(self.constants.generate(indentation, level).as_str());
        code.push_str(self.functions.generate(indentation, level).as_str());
        code.push_str(self.classes.generate(indentation, level).as_str());
        code.push_str(self.traits.generate(indentation, level).as_str());
        code.push_str(self.enums.generate(indentation, level).as_str());
        code.push_str(self.interfaces.generate(indentation, level).as_str());

        code = code.trim_end().to_string();
        code.push('\n');

        code
    }
}

impl Display for File {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.generate(Indentation::default(), 0))
    }
}

impl Default for File {
    fn default() -> Self {
        Self::new()
    }
}