1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
extern crate codegen;
extern crate inflector;
extern crate regex;

use codegen::Module;
use codegen::Scope;
use codegen::Type;
use inflector::Inflector;
use lazy_static::lazy_static;
use regex::Regex;
use std::fmt;
use std::fs::File;
use std::fs::{self};
use std::io;
use std::io::prelude::*;

mod resources;
use crate::resources::download_fa;

pub mod fa;
use crate::fa::req_icons;
use crate::fa::IconType;

static FA_RELEASE: &str = "5.13.0";

pub fn get_fa_resources(target_dir: &str) {
    download_fa(FA_RELEASE, target_dir).unwrap();
}

impl fmt::Display for IconType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

#[derive(Clone)]
struct IconSource {
    path: std::path::PathBuf,
    icon_type: IconType,
}

lazy_static! {
    static ref REGX: Regex = Regex::new(r"(.*)/fa([^/]+)\.js$").unwrap();
}

fn add_module(name: String, icon_type: IconType, fa_module: &mut Module) {
    let type_class = match icon_type {
        IconType::SOLID => "fas",
        IconType::REGULAR => "far",
        IconType::BRANDS => "fab",
    };

    let kebab_case_name: String = if name != "500px" {
        name.to_kebab_case()
    } else {
        String::from("500-px")
    };

    let module_name: String = if name == "500px" {
        String::from("a_500_px")
    } else if name == "box" {
        String::from("a_box")
    } else {
        name.to_snake_case()
    };

    if fa_module.get_module(&module_name).is_some() {
        return;
    }
    let module = fa_module.new_module(&module_name).vis("pub");

    module.import("seed", "*");
    module.import("seed::prelude", "*");
    module
        .new_fn("icon")
        .vis("pub")
        .generic("T")
        .ret("Node<T>")
        .arg("classes", Type::new("Vec<&str>"))
        .line(format!(
            r#"i![C!["{}", "fa-{}", classes]]"#,
            type_class, kebab_case_name
        ));
}

pub fn write_all(out_dir: &str) -> Result<(), fa::ReqErr> {
    prepare_structure(out_dir)?;
    let mut fa_scope = Scope::new();
    let module = fa_scope.new_module("fa").vis("pub");

    req_icons(FA_RELEASE).map(|icons| {
        icons.into_iter().for_each(|icon| {
            let type_module_name = icon.icon_type.to_string().to_lowercase();
            let type_module = module.get_module_mut(&type_module_name);
            let type_module_ref: &mut codegen::Module = if type_module.is_none() {
                module.new_module(&type_module_name).vis("pub")
            } else {
                type_module.unwrap()
            };

            add_module(icon.name, icon.icon_type, type_module_ref);
        });
        ()
    })?;

    let filename = format!("{}/fa/icons.rs", out_dir);
    let mut file = File::create(filename)?;
    file.write_all(fa_scope.to_string().as_bytes())?;

    Ok(())
}

fn prepare_structure(out_dir: &str) -> Result<(), io::Error> {
    fs::create_dir_all(&format!("{}/fa", out_dir))?;
    Ok(())
}