simi-cli 0.1.8

A command line tool to help build, test, serve a Simi app
Documentation
use std::fs;

use crate::config::{SimiConfig, SimiStage};
use crate::error::*;
use crate::external_cmds as cmds;

/// Create files required to run a simi-app at given output_path
pub fn create_simi_app(config: &SimiConfig) -> Result<(), Error> {
    create_style_css_from_scss(config)?;
    create_simi_app_index_html(config)?;
    copy_modified_statics_to_output(config)?;
    Ok(())
}

fn create_simi_app_index_html(config: &SimiConfig) -> Result<(), Error> {
    // index.html
    if let Some(index_path) = config.get_index_html_path(SimiStage::UserSource) {
        cmds::copy(
            &index_path.to_string_lossy(),
            &config.output_path().to_string_lossy(),
        )?;
    } else {
        println!("Generate default index.html");
        fs::write(
            config
                .get_index_html_path(SimiStage::SimiFinalApp)
                .expect("Path for SimiFinalApp must be exists"),
            default_index_html(config),
        )?;
    }
    Ok(())
}

fn create_style_css_from_scss(config: &SimiConfig) -> Result<(), Error> {
    use rsass::{compile_scss_file, OutputStyle};

    if let Some(scss) = config.get_scss_path() {
        println!(
            "Generate css from scss: {}",
            scss.file_name()
                .expect("There must be a filename")
                .to_string_lossy()
        );
        let css = match compile_scss_file(scss, OutputStyle::Compressed) {
            Ok(rs) => rs,
            Err(e) => {
                return Err(format_err!("error compiling scss: {}", e));
            }
        };
        fs::write(config.get_css_path(), css)?;
    }
    Ok(())
}

fn copy_modified_statics_to_output(config: &SimiConfig) -> Result<(), Error> {
    let static_source = config.get_static_path();
    if !static_source.exists() {
        return Ok(());
    }
    let output_path = config.output_path();

    let scss = config.get_scss_path();
    let index = config.get_index_html_path(SimiStage::UserSource);

    for entry in ::walkdir::WalkDir::new(&static_source) {
        match entry {
            Err(e) => println!("Ignore error {}", e),
            Ok(entry) => {
                let path = entry.path();
                if let Some(scss) = scss {
                    if scss == path {
                        continue;
                    }
                }
                if let Some(ref index) = index {
                    if index == path {
                        continue;
                    }
                }
                let rel_path = path
                    .strip_prefix(&static_source)
                    .expect("Strip prefix for static content must be ok");

                let output_path = output_path.join(rel_path);
                if path.is_dir() {
                    fs::create_dir_all(&output_path)?;
                } else {
                    cmds::copy(&path.to_string_lossy(), &output_path.to_string_lossy())?;
                }
            }
        }
    }
    Ok(())
}

fn default_index_html(config: &SimiConfig) -> String {
    let link_css = config.get_css_file_name().map_or("".to_string(), |css| {
        format!("<link rel='stylesheet' href='./{}'>", css)
    });
    let (js_path, wasm_path_to_fetch) = if let Some(path) = config.wasm_serve_path() {
        (
            format!("{}/{}.js", path, config.simi_app_name()),
            format!("{}/{}", path, config.get_wasm_file_name(true)),
        )
    } else {
        (
            format!("./{}.js", config.simi_app_name()),
            config.get_wasm_file_name(true),
        )
    };
    format!(
        "\
<html>
    <head>
        <meta content=\"text/html;charset=utf-8\" http-equiv=\"Content-Type\"/>
        {}
    </head>
    <body>
    <p>Your page is loading...! Please wait for a moment!</p>
    <p>If your page does not load correctly after a few moment, there must be some errors in your app. Did you add <b>#[simi_app]</b> to your struct?</p>
    <script type='module'>
        import {{ AppHandle, default as init }} from '{}'
        async function run() {{
            await init('{}');
            window.simi_app = new AppHandle();
        }}
        run();
    </script>
    </body>
</html>",
        link_css,
        js_path,
        wasm_path_to_fetch,
    )
}