factorio-exporter 0.1.2

A library to export prototype definitions from Factorio (http://www.factorio.com)
Documentation
use std::fmt::{self, Write};

use indoc::writedoc;

#[derive(Default)]
pub struct ScriptBuilder {
    script: String,
    indentation: usize,
}

impl ScriptBuilder {
    pub fn new() -> ScriptBuilder {
        let mut builder = ScriptBuilder::default();

        writedoc! {&mut builder, "
            local prototypes={{}}
            export = require('export')
            function prototypes.export()
        "}
        .unwrap();

        builder.indentation += 4;
        builder
    }

    pub fn export_primitive(&mut self, primitive_type: &str, object: &str, property: &str) {
        writeln!(
            self,
            r#"export.Export{primitive_type}("{property}", {object}.{property})"#,
        )
        .unwrap();
    }

    pub fn export_string(&mut self, object: &str, property: &str) {
        self.export_primitive("String", object, property);
    }

    pub fn export_number(&mut self, object: &str, property: &str) {
        self.export_primitive("Number", object, property);
    }

    pub fn export_bool(&mut self, object: &str, property: &str) {
        self.export_primitive("Bool", object, property);
    }

    pub fn begin_block(&mut self, block_type: &str, object: &str, attribute: &str) -> String {
        let element = "prototype";
        writeln!(
            self,
            r#"export.Export{block_type}("{attribute}", {object}, function({element})"#,
        )
        .unwrap();
        self.indentation += 4;
        element.into()
    }

    pub fn end_block(&mut self) {
        self.indentation -= 4;
        writeln!(self, "end)").unwrap();
    }

    pub fn begin_table(&mut self, table: &str, attribute: &str) -> String {
        self.begin_block("Table", table, attribute)
    }

    pub fn end_table(&mut self) {
        self.end_block();
    }

    pub fn begin_array(&mut self, array: &str, attribute: &str) -> String {
        self.begin_block("Array", &format!("{array}.{attribute}"), attribute)
    }

    pub fn end_array(&mut self) {
        self.end_block();
    }

    pub fn build(mut self) -> String {
        self.indentation -= 4;

        writeln!(self, r#"end"#).unwrap();
        writeln!(self, r#"return prototypes"#).unwrap();

        self.script
    }
}
impl Write for ScriptBuilder {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let indentation = if self.script.is_empty() || self.script.ends_with('\n') {
            self.indentation
        } else {
            0
        };
        self.script.push_str(&format!("{:indentation$}{s}", ""));
        Ok(())
    }
}