factorio-exporter 0.5.0

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_string_value(&mut self) {
        writeln!(self, r#"export.ExportStringValue(context)"#).unwrap();
    }

    pub fn export_number_value(&mut self) {
        writeln!(self, r#"export.ExportNumberValue(context)"#).unwrap();
    }

    pub fn export_bool_value(&mut self) {
        writeln!(self, r#"export.ExportBoolValue(context)"#).unwrap();
    }

    pub fn export_string_attr(&mut self, attr: &str) {
        writeln!(
            self,
            r#"export.ExportStringAttr("{attr}", export.SaveRead(context, "{attr}"))"#,
        )
        .unwrap();
    }

    pub fn export_number_attr(&mut self, attr: &str) {
        writeln!(self, r#"export.ExportNumberAttr("{attr}", context.{attr})"#,).unwrap();
    }

    pub fn export_bool_attr(&mut self, attr: &str) {
        writeln!(self, r#"export.ExportBoolAttr("{attr}", context.{attr})"#,).unwrap();
    }

    pub fn begin_context(&mut self, context: &str) {
        writeln!(self, r#"export.SetContext({context}, function(context)"#,).unwrap();
        self.indentation += 4;
    }

    pub fn begin_object(&mut self, attr: &str) {
        writeln!(
            self,
            r#"export.ExportObject("{attr}", export.SaveRead(context, "{attr}"), function(context)"#,
        )
        .unwrap();
        self.indentation += 4;
    }

    pub fn begin_mapping(&mut self) {
        writeln!(self, r#"export.ExportMapping(context, function(context)"#,).unwrap();
        self.indentation += 4;
    }

    pub fn begin_array(&mut self) {
        writeln!(self, r#"export.ExportArray(context, function(context)"#,).unwrap();
        self.indentation += 4;
    }

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

    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(())
    }
}