Skip to content

Commit

Permalink
Merge pull request #1305 from alexcrichton/npm-dependencies
Browse files Browse the repository at this point in the history
Implement transitive support for NPM dependencies
  • Loading branch information
alexcrichton authored Mar 25, 2019
2 parents 433a8d8 + faf49c7 commit b4b3926
Show file tree
Hide file tree
Showing 18 changed files with 432 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ members = [
"examples/fetch",
"examples/guide-supported-types-examples",
"examples/hello_world",
"examples/import_js",
"examples/import_js/crate",
"examples/julia_set",
"examples/paint",
"examples/performance",
Expand Down
File renamed without changes.
21 changes: 16 additions & 5 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,17 @@ jobs:
- template: ci/azure-install-sccache.yml
- script: cargo test --target wasm32-unknown-unknown --features nightly --test wasm

- job: test_cli_support
displayName: "Run wasm-bindgen-cli-support crate tests"
- job: test_cli
displayName: "Run wasm-bindgen-cli crate tests"
steps:
- template: ci/azure-install-rust.yml
- template: ci/azure-install-sccache.yml
- script: rustup target add wasm32-unknown-unknown
displayName: "install wasm target"
- script: cargo test -p wasm-bindgen-cli-support
displayName: "wasm-bindgen-cli-support tests"
- script: cargo test -p wasm-bindgen-cli
displayName: "wasm-bindgen-cli tests"

- job: test_web_sys
displayName: "Run web-sys crate tests"
Expand Down Expand Up @@ -139,16 +144,22 @@ jobs:
steps:
- template: ci/azure-install-rust.yml
- template: ci/azure-install-sccache.yml
- script: npm install
- script: mv _package.json package.json && npm install && rm package.json
displayName: "run npm install"
- script: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
- script: cargo build -p wasm-bindgen-cli
- script: ln -snf `pwd`/target/debug/wasm-bindgen $HOME/.cargo/bin/wasm-bindgen
displayName: "install wasm-pack"
- script: |
set -ex
cargo build -p wasm-bindgen-cli
ln -snf `pwd`/target/debug/wasm-bindgen $HOME/.cargo/bin/wasm-bindgen
displayName: "install wasm-bindgen for `wasm-pack` to use"
- script: |
for dir in `ls examples | grep -v README | grep -v asm.js | grep -v raytrace | grep -v without-a-bundler`; do
(cd examples/$dir &&
ln -fs ../../node_modules . &&
npm run build -- --output-path $BUILD_ARTIFACTSTAGINGDIRECTORY/exbuild/$dir) || exit 1;
done
displayName: "build examples"
- task: PublishPipelineArtifact@0
inputs:
artifactName: examples1
Expand Down
20 changes: 19 additions & 1 deletion crates/backend/src/encode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use proc_macro2::{Ident, Span};
use std::cell::RefCell;
use std::cell::{RefCell, Cell};
use std::collections::HashMap;
use std::env;
use std::fs;
Expand Down Expand Up @@ -28,6 +28,7 @@ struct Interner {
files: RefCell<HashMap<String, LocalFile>>,
root: PathBuf,
crate_name: String,
has_package_json: Cell<bool>,
}

struct LocalFile {
Expand All @@ -43,6 +44,7 @@ impl Interner {
files: RefCell::new(HashMap::new()),
root: env::var_os("CARGO_MANIFEST_DIR").unwrap().into(),
crate_name: env::var("CARGO_PKG_NAME").unwrap(),
has_package_json: Cell::new(false),
}
}

Expand All @@ -67,6 +69,7 @@ impl Interner {
if let Some(file) = files.get(id) {
return Ok(self.intern_str(&file.new_identifier))
}
self.check_for_package_json();
let path = if id.starts_with("/") {
self.root.join(&id[1..])
} else if id.starts_with("./") || id.starts_with("../") {
Expand All @@ -92,6 +95,16 @@ impl Interner {
fn unique_crate_identifier(&self) -> String {
format!("{}-{}", self.crate_name, ShortHash(0))
}

fn check_for_package_json(&self) {
if self.has_package_json.get() {
return
}
let path = self.root.join("package.json");
if path.exists() {
self.has_package_json.set(true);
}
}
}

fn shared_program<'a>(
Expand Down Expand Up @@ -144,6 +157,11 @@ fn shared_program<'a>(
.map(|js| intern.intern_str(js))
.collect(),
unique_crate_identifier: intern.intern_str(&intern.unique_crate_identifier()),
package_json: if intern.has_package_json.get() {
Some(intern.intern_str(intern.root.join("package.json").to_str().unwrap()))
} else {
None
},
})
}

Expand Down
1 change: 1 addition & 0 deletions crates/cli-support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ base64 = "0.9"
failure = "0.1.2"
log = "0.4"
rustc-demangle = "0.1.13"
serde_json = "1.0"
tempfile = "3.0"
walrus = "0.5.0"
wasm-bindgen-anyref-xform = { path = '../anyref-xform', version = '=0.2.40' }
Expand Down
72 changes: 72 additions & 0 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{Bindgen, EncodeInto, OutputMode};
use failure::{bail, Error, ResultExt};
use std::collections::{HashMap, HashSet, BTreeMap};
use std::env;
use std::fs;
use walrus::{MemoryId, Module};
use wasm_bindgen_wasm_interpreter::Interpreter;

Expand Down Expand Up @@ -64,6 +65,13 @@ pub struct Context<'a> {
/// the same `Program`.
pub snippet_offsets: HashMap<&'a str, usize>,

/// All package.json dependencies we've learned about so far
pub package_json_read: HashSet<&'a str>,

/// A map of the name of npm dependencies we've loaded so far to the path
/// they're defined in as well as their version specification.
pub npm_dependencies: HashMap<String, (&'a str, String)>,

pub anyref: wasm_bindgen_anyref_xform::Context,
}

Expand Down Expand Up @@ -2509,6 +2517,10 @@ impl<'a, 'b> SubContext<'a, 'b> {
self.cx.typescript.push_str("\n\n");
}

if let Some(path) = self.program.package_json {
self.add_package_json(path)?;
}

Ok(())
}

Expand Down Expand Up @@ -2980,6 +2992,66 @@ impl<'a, 'b> SubContext<'a, 'b> {
let import = self.determine_import(import, item)?;
Ok(self.cx.import_identifier(import))
}

fn add_package_json(&mut self, path: &'b str) -> Result<(), Error> {
if !self.cx.package_json_read.insert(path) {
return Ok(());
}
if !self.cx.config.mode.nodejs() && !self.cx.config.mode.bundler() {
bail!("NPM dependencies have been specified in `{}` but \
this is only compatible with the `bundler` and `nodejs` targets");
}
let contents = fs::read_to_string(path).context(format!("failed to read `{}`", path))?;
let json: serde_json::Value = serde_json::from_str(&contents)?;
let object = match json.as_object() {
Some(s) => s,
None => bail!(
"expected `package.json` to have an JSON object in `{}`",
path
),
};
let mut iter = object.iter();
let (key, value) = match iter.next() {
Some(pair) => pair,
None => return Ok(()),
};
if key != "dependencies" || iter.next().is_some() {
bail!(
"NPM manifest found at `{}` can currently only have one key, \
`dependencies`, and no other fields",
path
);
}
let value = match value.as_object() {
Some(s) => s,
None => bail!("expected `dependencies` to be a JSON object in `{}`", path),
};

for (name, value) in value.iter() {
let value = match value.as_str() {
Some(s) => s,
None => bail!(
"keys in `dependencies` are expected to be strings in `{}`",
path
),
};
if let Some((prev, _prev_version)) = self.cx.npm_dependencies.get(name) {
bail!(
"dependency on NPM package `{}` specified in two `package.json` files, \
which at the time is not allowed:\n * {}\n * {}",
name,
path,
prev
)
}

self.cx
.npm_dependencies
.insert(name.to_string(), (path, value.to_string()));
}

Ok(())
}
}

#[derive(Hash, Eq, PartialEq)]
Expand Down
21 changes: 20 additions & 1 deletion crates/cli-support/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![doc(html_root_url = "https://docs.rs/wasm-bindgen-cli-support/0.2")]

use failure::{bail, Error, ResultExt};
use std::collections::BTreeSet;
use std::collections::{BTreeSet, BTreeMap};
use std::env;
use std::fs;
use std::mem;
Expand Down Expand Up @@ -329,6 +329,8 @@ impl Bindgen {
start: None,
anyref: Default::default(),
snippet_offsets: Default::default(),
npm_dependencies: Default::default(),
package_json_read: Default::default(),
};
cx.anyref.enabled = self.anyref;
cx.anyref.prepare(cx.module)?;
Expand Down Expand Up @@ -366,6 +368,16 @@ impl Bindgen {
.with_context(|_| format!("failed to write `{}`", path.display()))?;
}

if cx.npm_dependencies.len() > 0 {
let map = cx
.npm_dependencies
.iter()
.map(|(k, v)| (k, &v.1))
.collect::<BTreeMap<_, _>>();
let json = serde_json::to_string_pretty(&map)?;
fs::write(out_dir.join("package.json"), json)?;
}

cx.finalize(stem)?
};

Expand Down Expand Up @@ -701,4 +713,11 @@ impl OutputMode {
_ => false,
}
}

fn bundler(&self) -> bool {
match self {
OutputMode::Bundler { .. } => true,
_ => false,
}
}
}
4 changes: 4 additions & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,9 @@ walrus = "0.5"
wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.40" }
wasm-bindgen-shared = { path = "../shared", version = "=0.2.40" }

[dev-dependencies]
assert_cmd = "0.11"
predicates = "1.0.0"

[features]
vendored-openssl = ['openssl/vendored']
2 changes: 1 addition & 1 deletion crates/cli/src/bin/wasm-bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fn main() {
};
eprintln!("error: {}", err);
for cause in err.iter_causes() {
eprintln!("\tcaused by: {}", cause);
eprintln!(" caused by: {}", cause);
}
process::exit(1);
}
Expand Down
Loading

0 comments on commit b4b3926

Please sign in to comment.