jens 0.6.0

Readable templates for code generation
Documentation
extern crate jens;

use jens::{Block, File};

enum Json {
    JsString,
    JsNumber,
    JsArray(Box<Json>),
    JsObject(String),
}

impl Json {
    fn get_ts_type(&self) -> String {
        use Json::*;
        match self {
            JsString => "string".into(),
            JsNumber => "number".into(),
            JsArray(subtype) => format!("{}[]", subtype.get_ts_type()),
            JsObject(module_name) => format!("{}.T", module_name),
        }
    }

    fn get_serialize_func(&self) -> String {
        use Json::*;
        match self {
            JsString => format!("noop"),
            JsNumber => format!("noop"),
            JsArray(subtype) => format!("serialize_array({})", subtype.get_serialize_func()),
            JsObject(module_name) => format!("{}.serialize", module_name),
        }
    }

    fn get_deserialize_func(&self) -> String {
        use Json::*;
        match self {
            JsString => format!("deserialize_string"),
            JsNumber => format!("deserialize_number"),
            JsArray(subtype) => format!("deserialize_array({})", subtype.get_deserialize_func()),
            JsObject(module_name) => format!("{}.deserialize", module_name),
        }
    }
}

struct TsField {
    field_name: String,
    field_type: Json,
}

struct TsType {
    type_name: String,
    fields: Vec<TsField>,
}

fn main() {
    // A sample Json object schema
    let types = vec![
        TsType {
            type_name: "Book".into(),
            fields: vec![TsField {
                field_name: "title".into(),
                field_type: Json::JsString,
            }],
        },
        TsType {
            type_name: "LibraryMeta".into(),
            fields: vec![
                TsField {
                    field_name: "founded_year".into(),
                    field_type: Json::JsNumber,
                },
                TsField {
                    field_name: "name".into(),
                    field_type: Json::JsString,
                },
            ],
        },
        TsType {
            type_name: "Library".into(),
            fields: vec![
                TsField {
                    field_name: "count".into(),
                    field_type: Json::JsNumber,
                },
                TsField {
                    field_name: "meta".into(),
                    field_type: Json::JsObject("LibraryMeta".into()),
                },
                TsField {
                    field_name: "books".into(),
                    field_type: Json::JsArray(Box::new(Json::JsObject("Book".into()))),
                },
            ],
        },
    ];

    let f = File::parse(include_str!("./template.jens")).unwrap();

    let output = f.template("main").set(
        "types",
        Block::join_map(types, |t, _| {
            f.template("type")
                .set("type_name", t.type_name.clone())
                .set("type_def_fields", type_def_fields(&f, &t))
                .set("serialize_fields", serialize_fields(&f, &t))
                .set("deserialize_fields", deserialize_fields(&f, &t))
        }),
    );

    println!("{}", output);
}

fn type_def_fields(f: &File, t: &TsType) -> Block {
    Block::join_map(&t.fields, |field, _| {
        f.template("type_def")
            .set("field_name", field.field_name.clone())
            .set("field_type", field.field_type.get_ts_type())
    })
}

fn serialize_fields(f: &File, t: &TsType) -> Block {
    Block::join_map(&t.fields, |field, _| {
        f.template("serialize_field")
            .set("field_name", field.field_name.clone())
            .set("serialize_func", field.field_type.get_serialize_func())
    })
}

fn deserialize_fields(f: &File, t: &TsType) -> Block {
    Block::join_map(&t.fields, |field, _| {
        f.template("deserialize_field")
            .set("field_name", field.field_name.clone())
            .set("deserialize_func", field.field_type.get_deserialize_func())
    })
}