Skip to content

Commit

Permalink
Merge pull request #312 from rustwasm/mod-mod-mod
Browse files Browse the repository at this point in the history
modules modules modules
  • Loading branch information
mgattozzi authored Sep 20, 2018
2 parents 5304a49 + f5eaad2 commit 1e9d8de
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 93 deletions.
143 changes: 76 additions & 67 deletions src/manifest.rs → src/manifest/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//! Reading and writing Cargo.toml and package.json manifests.
mod npm;

use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

use self::npm::{repository::Repository, CommonJSPackage, ESModulesPackage, NpmPackage};
use console::style;
use emoji;
use error::Error;
Expand Down Expand Up @@ -57,6 +60,27 @@ struct CargoPackage {
repository: Option<String>,
}

impl CargoPackage {
fn check_optional_fields(&self) {
let warn_fmt = |field| {
format!(
"Field '{}' is missing from Cargo.toml. It is not necessary, but recommended",
field
)
};

if self.description.is_none() {
PBAR.warn(&warn_fmt("description"));
}
if self.repository.is_none() {
PBAR.warn(&warn_fmt("repository"));
}
if self.license.is_none() {
PBAR.warn(&warn_fmt("license"));
}
}
}

#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum CargoDependency {
Expand All @@ -75,32 +99,6 @@ struct CargoLib {
crate_type: Option<Vec<String>>,
}

#[derive(Serialize)]
struct NpmPackage {
name: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
collaborators: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
version: String,
#[serde(skip_serializing_if = "Option::is_none")]
license: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
repository: Option<Repository>,
#[serde(skip_serializing_if = "Vec::is_empty")]
files: Vec<String>,
main: String,
#[serde(skip_serializing_if = "Option::is_none")]
types: Option<String>,
}

#[derive(Serialize)]
struct Repository {
#[serde(rename = "type")]
ty: String,
url: String,
}

fn read_cargo_toml(path: &Path) -> Result<CargoManifest, Error> {
let manifest_path = path.join("Cargo.toml");
if !manifest_path.is_file() {
Expand All @@ -120,43 +118,66 @@ fn read_cargo_toml(path: &Path) -> Result<CargoManifest, Error> {
}

impl CargoManifest {
fn into_npm(mut self, scope: &Option<String>, disable_dts: bool, target: &str) -> NpmPackage {
fn into_commonjs(mut self, scope: &Option<String>, disable_dts: bool) -> NpmPackage {
let filename = self.package.name.replace("-", "_");
let wasm_file = format!("{}_bg.wasm", filename);
let js_file = format!("{}.js", filename);
let mut files = vec![wasm_file];

let dts_file = if disable_dts == true {
None
let js_bg_file = format!("{}_bg.js", filename);
files.push(js_bg_file.to_string());

if let Some(s) = scope {
self.package.name = format!("@{}/{}", s, self.package.name);
}

let dts_file = if disable_dts == false {
let file = format!("{}.d.ts", filename);
files.push(file.to_string());
Some(file)
} else {
Some(format!("{}.d.ts", filename))
None
};

let js_bg_file = if target == "nodejs" {
Some(format!("{}_bg.js", filename))
&self.package.check_optional_fields();

NpmPackage::CommonJSPackage(CommonJSPackage {
name: self.package.name,
collaborators: self.package.authors,
description: self.package.description,
version: self.package.version,
license: self.package.license,
repository: self.package.repository.map(|repo_url| Repository {
ty: "git".to_string(),
url: repo_url,
}),
files: files,
main: js_file,
types: dts_file,
})
}

fn into_esmodules(mut self, scope: &Option<String>, disable_dts: bool) -> NpmPackage {
let filename = self.package.name.replace("-", "_");
let wasm_file = format!("{}_bg.wasm", filename);
let js_file = format!("{}.js", filename);
let mut files = vec![wasm_file, js_file.clone()];

let dts_file = if disable_dts == false {
let file = format!("{}.d.ts", filename);
files.push(file.to_string());
Some(file)
} else {
None
};

if let Some(s) = scope {
self.package.name = format!("@{}/{}", s, self.package.name);
}
let mut files = vec![wasm_file];

match dts_file {
Some(ref dts_file) => {
files.push(dts_file.to_string());
}
None => {}
}

match js_bg_file {
Some(ref js_bg_file) => {
files.push(js_bg_file.to_string());
}
None => {}
}
&self.package.check_optional_fields();

NpmPackage {
NpmPackage::ESModulesPackage(ESModulesPackage {
name: self.package.name,
collaborators: self.package.authors,
description: self.package.description,
Expand All @@ -167,9 +188,10 @@ impl CargoManifest {
url: repo_url,
}),
files: files,
main: js_file,
module: js_file,
types: dts_file,
}
side_effects: "false".to_string(),
})
}
}

Expand All @@ -184,28 +206,15 @@ pub fn write_package_json(
) -> Result<(), Error> {
let msg = format!("{}Writing a package.json...", emoji::MEMO);

let warn_fmt = |field| {
format!(
"Field '{}' is missing from Cargo.toml. It is not necessary, but recommended",
field
)
};

PBAR.step(step, &msg);
let pkg_file_path = out_dir.join("package.json");
let mut pkg_file = File::create(pkg_file_path)?;
let crate_data = read_cargo_toml(path)?;
let npm_data = crate_data.into_npm(scope, disable_dts, target);

if npm_data.description.is_none() {
PBAR.warn(&warn_fmt("description"));
}
if npm_data.repository.is_none() {
PBAR.warn(&warn_fmt("repository"));
}
if npm_data.license.is_none() {
PBAR.warn(&warn_fmt("license"));
}
let npm_data = if target == "nodejs" {
crate_data.into_commonjs(scope, disable_dts)
} else {
crate_data.into_esmodules(scope, disable_dts)
};

let npm_json = serde_json::to_string_pretty(&npm_data)?;
pkg_file.write_all(npm_json.as_bytes())?;
Expand Down
20 changes: 20 additions & 0 deletions src/manifest/npm/commonjs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use manifest::npm::repository::Repository;

#[derive(Serialize)]
pub struct CommonJSPackage {
pub name: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub collaborators: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub version: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub license: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub repository: Option<Repository>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub files: Vec<String>,
pub main: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub types: Option<String>,
}
22 changes: 22 additions & 0 deletions src/manifest/npm/esmodules.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use manifest::npm::repository::Repository;

#[derive(Serialize)]
pub struct ESModulesPackage {
pub name: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub collaborators: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub version: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub license: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub repository: Option<Repository>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub files: Vec<String>,
pub module: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub types: Option<String>,
#[serde(rename = "sideEffects")]
pub side_effects: String,
}
13 changes: 13 additions & 0 deletions src/manifest/npm/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
mod commonjs;
mod esmodules;
pub mod repository;

pub use self::commonjs::CommonJSPackage;
pub use self::esmodules::ESModulesPackage;

#[derive(Serialize)]
#[serde(untagged)]
pub enum NpmPackage {
CommonJSPackage(CommonJSPackage),
ESModulesPackage(ESModulesPackage),
}
6 changes: 6 additions & 0 deletions src/manifest/npm/repository.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[derive(Serialize)]
pub struct Repository {
#[serde(rename = "type")]
pub ty: String,
pub url: String,
}
44 changes: 19 additions & 25 deletions tests/all/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ fn it_creates_a_package_json_default_path() {
pkg.repository.url,
"https://github.com/ashleygwilliams/wasm-pack.git"
);
assert_eq!(pkg.main, "wasm_pack.js");
let types = pkg.types.unwrap_or_default();
assert_eq!(types, "wasm_pack.d.ts");
assert_eq!(pkg.module, "wasm_pack.js");
assert_eq!(pkg.types, "wasm_pack.d.ts");
assert_eq!(pkg.side_effects, "false");

let actual_files: HashSet<String> = pkg.files.into_iter().collect();
let expected_files: HashSet<String> = ["wasm_pack_bg.wasm", "wasm_pack.d.ts"]
let expected_files: HashSet<String> = ["wasm_pack_bg.wasm", "wasm_pack.d.ts", "wasm_pack.js"]
.iter()
.map(|&s| String::from(s))
.collect();
Expand All @@ -92,10 +92,14 @@ fn it_creates_a_package_json_provided_path() {
assert!(utils::manifest::read_package_json(&fixture.path, &out_dir).is_ok());
let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).unwrap();
assert_eq!(pkg.name, "js-hello-world");
assert_eq!(pkg.main, "js_hello_world.js");
assert_eq!(pkg.module, "js_hello_world.js");

let actual_files: HashSet<String> = pkg.files.into_iter().collect();
let expected_files: HashSet<String> = ["js_hello_world_bg.wasm", "js_hello_world.d.ts"]
let expected_files: HashSet<String> = [
"js_hello_world_bg.wasm",
"js_hello_world.d.ts",
"js_hello_world.js",
]
.iter()
.map(|&s| String::from(s))
.collect();
Expand Down Expand Up @@ -123,10 +127,14 @@ fn it_creates_a_package_json_provided_path_with_scope() {
assert!(utils::manifest::read_package_json(&fixture.path, &out_dir).is_ok());
let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).unwrap();
assert_eq!(pkg.name, "@test/scopes-hello-world");
assert_eq!(pkg.main, "scopes_hello_world.js");
assert_eq!(pkg.module, "scopes_hello_world.js");

let actual_files: HashSet<String> = pkg.files.into_iter().collect();
let expected_files: HashSet<String> = ["scopes_hello_world_bg.wasm", "scopes_hello_world.d.ts"]
let expected_files: HashSet<String> = [
"scopes_hello_world_bg.wasm",
"scopes_hello_world.d.ts",
"scopes_hello_world.js",
]
.iter()
.map(|&s| String::from(s))
.collect();
Expand Down Expand Up @@ -154,8 +162,7 @@ fn it_creates_a_pkg_json_with_correct_files_on_node() {
"https://github.com/ashleygwilliams/wasm-pack.git"
);
assert_eq!(pkg.main, "wasm_pack.js");
let types = pkg.types.unwrap_or_default();
assert_eq!(types, "wasm_pack.d.ts");
assert_eq!(pkg.types, "wasm_pack.d.ts");

let actual_files: HashSet<String> = pkg.files.into_iter().collect();
let expected_files: HashSet<String> =
Expand All @@ -177,19 +184,6 @@ fn it_creates_a_pkg_json_in_out_dir() {
let package_json_path = &fixture.path.join(&out_dir).join("package.json");
assert!(fs::metadata(package_json_path).is_ok());
assert!(utils::manifest::read_package_json(&fixture.path, &out_dir).is_ok());

let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).unwrap();
assert_eq!(pkg.name, "js-hello-world");
assert_eq!(pkg.main, "js_hello_world.js");

let actual_files: HashSet<String> = pkg.files.into_iter().collect();

let expected_files: HashSet<String> = ["js_hello_world_bg.wasm", "js_hello_world.d.ts"]
.iter()
.map(|&s| String::from(s))
.collect();

assert_eq!(actual_files, expected_files);
}

#[test]
Expand All @@ -209,10 +203,10 @@ fn it_creates_a_package_json_with_correct_keys_when_types_are_skipped() {
pkg.repository.url,
"https://github.com/ashleygwilliams/wasm-pack.git"
);
assert_eq!(pkg.main, "wasm_pack.js");
assert_eq!(pkg.module, "wasm_pack.js");

let actual_files: HashSet<String> = pkg.files.into_iter().collect();
let expected_files: HashSet<String> = ["wasm_pack_bg.wasm"]
let expected_files: HashSet<String> = ["wasm_pack_bg.wasm", "wasm_pack.js"]
.iter()
.map(|&s| String::from(s))
.collect();
Expand Down
12 changes: 11 additions & 1 deletion tests/all/utils/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,18 @@ pub struct NpmPackage {
pub license: String,
pub repository: Repository,
pub files: Vec<String>,
#[serde(default = "default_none")]
pub main: String,
pub types: Option<String>,
#[serde(default = "default_none")]
pub module: String,
#[serde(default = "default_none")]
pub types: String,
#[serde(default = "default_none", rename = "sideEffects")]
pub side_effects: String,
}

fn default_none() -> String {
"".to_string()
}

#[derive(Deserialize)]
Expand Down

0 comments on commit 1e9d8de

Please sign in to comment.