~zethra/license

afdfdb7ec4ed97ed0810d624ad596658324ffe82 — Ben Aaron Goldberg a month ago e55d1f8
Added package.json support
M Cargo.lock => Cargo.lock +7 -0
@@ 238,6 238,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"

[[package]]
name = "json"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"

[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 254,6 260,7 @@ name = "license"
version = "1.0.0"
dependencies = [
 "chrono",
 "json",
 "license_codegen",
 "structopt",
 "tera",

M license/Cargo.toml => license/Cargo.toml +1 -0
@@ 13,6 13,7 @@ edition = "2018"
structopt = "0.3"
chrono = "0.4"
toml = "0.5"
json = "0.12"

[dependencies.license_codegen]
path = "../license_codegen"

M license/src/data_sources/mod.rs => license/src/data_sources/mod.rs +43 -8
@@ 8,6 8,7 @@ mod cargo;
mod date;
mod folder;
mod git;
mod package_json;

use tera::Context;



@@ 16,14 17,16 @@ pub fn get_info(context: &mut Context, show_errs: bool) {
    // Use info from Cargo.toml
    match cargo::cargo_data(show_errs) {
        Ok(cargo_data) => {
            if cargo_data.project_name.is_none() {
                eprintln!("Cargo.toml missing name");
            }
            if cargo_data.author.is_none() {
                eprintln!("Cargo.toml missing author");
            }
            if cargo_data.description.is_none() {
                eprintln!("Cargo.toml missing description");
            if show_errs {
                if cargo_data.project_name.is_none() {
                    eprintln!("Cargo.toml missing name");
                }
                if cargo_data.author.is_none() {
                    eprintln!("Cargo.toml missing author");
                }
                if cargo_data.description.is_none() {
                    eprintln!("Cargo.toml missing description");
                }
            }

            if cargo_data.project_name.is_some() && context.get("project_name").is_none() {


@@ 43,6 46,38 @@ pub fn get_info(context: &mut Context, show_errs: bool) {
        }
    }

    // Use info from package.json
    match package_json::json_data(show_errs) {
        Ok(json_data) => {
            if show_errs {
                if json_data.project_name.is_none() {
                    eprintln!("package.json missing name");
                }
                if json_data.author.is_none() {
                    eprintln!("package.json missing author");
                }
                if json_data.description.is_none() {
                    eprintln!("package.json missing description");
                }
            }

            if json_data.project_name.is_some() && context.get("project_name").is_none() {
                context.insert("project_name", json_data.project_name.as_ref().unwrap());
            }
            if json_data.author.is_some() && context.get("author").is_none() {
                context.insert("author", json_data.author.as_ref().unwrap());
            }
            if json_data.description.is_some() && context.get("description").is_none() {
                context.insert("description", json_data.description.as_ref().unwrap());
            }
        }
        Err(e) => {
            if show_errs {
                eprintln!("{}", e);
            }
        }
    }

    // Use git name and email as author
    if context.get("author").is_none() {
        let name = git::name();

A license/src/data_sources/package_json.rs => license/src/data_sources/package_json.rs +100 -0
@@ 0,0 1,100 @@
use json::JsonValue;
use std::{env, fs};

#[derive(Debug, Default, Clone)]
pub struct JsonData {
    pub author: Option<String>,
    pub project_name: Option<String>,
    pub description: Option<String>,
}

impl JsonData {
    fn rank(&self) -> u8 {
        let mut rank = 0;
        if self.author.is_some() {
            rank += 1;
        }
        if self.project_name.is_some() {
            rank += 1;
        }
        if self.description.is_some() {
            rank += 1;
        }
        rank
    }
}

pub fn json_data(show_errs: bool) -> Result<JsonData, String> {
    let mut dir =
        env::current_dir().map_err(|e| format!("Error getting current directory: {}", e))?;
    let mut cargo_tomls = vec![];
    loop {
        let path = dir.join("package.json");
        if path.exists() {
            cargo_tomls.push(path);
        }
        if !dir.pop() {
            break;
        }
    }
    if cargo_tomls.is_empty() {
        return Err("package.json not found".to_owned());
    }
    let parsed: Vec<_> = cargo_tomls
        .into_iter()
        .filter_map(|path| match fs::read_to_string(&path) {
            Ok(content) => match json::parse(&content) {
                Ok(value) => Some(value),
                Err(e) => {
                    if show_errs {
                        eprintln!("Error parsing package.json as {}: {}", path.display(), e);
                    }
                    None
                }
            },
            Err(e) => {
                if show_errs {
                    eprintln!("Error reading package.json at {}: {}", path.display(), e);
                }
                None
            }
        })
        .map(get_values)
        .filter(|v| v.rank() > 0)
        .collect();
    if parsed.is_empty() {
        return Err("package.json data not found".to_owned());
    }
    let mut min_rank = 3;
    loop {
        for file_data in &parsed {
            if file_data.rank() >= min_rank {
                return Ok(file_data.clone());
            }
        }
        min_rank -= 1;
    }
}

/// Get data out of json::JsonValue
fn get_values(value: JsonValue) -> JsonData {
    let mut data = JsonData::default();
    if let JsonValue::Object(object) = value {
        if let Some(package_name) = object.get("name") {
            if let Some(s) = package_name.as_str() {
                data.project_name = Some(s.to_owned());
            }
        }
        if let Some(description) = object.get("description") {
            if let Some(s) = description.as_str() {
                data.description = Some(s.to_owned());
            }
        }
        if let Some(author) = object.get("author") {
            if let Some(s) = author.as_str() {
                data.author = Some(s.to_owned());
            }
        }
    }
    data
}