Skip to content

Commit d4bdb5b

Browse files
authored
Improve the output of wasm-tools component wit (#1657)
* Improve the `--out-dir` flag of `component wit` * Lift files in `deps` outside of their folders to be `deps/*.wit` instead of `deps/*/main.wit` since this structure is now supported. * Handle multi-package input documents by placing each package in the main folder. * Name the main wit file after the package name. * Add some tests for these cases. * Print all WIT packages by default This commit changes the output of `wasm-tools component wit` to by default output all WIT packages using the multi-package syntax implemented in #1577. This means that a complete view of the WIT will be seen when running this command instead of just the top-level world. * Fix build of fuzzer * Sanitize output to be more platform agnostic
1 parent b6b5ad5 commit d4bdb5b

16 files changed

+148
-48
lines changed

crates/wit-component/src/printing.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,13 @@ impl WitPrinter {
5151
}
5252

5353
/// Print a set of one or more WIT packages into a string.
54-
pub fn print(&mut self, resolve: &Resolve, pkg_ids: &[PackageId]) -> Result<String> {
55-
let has_multiple_packages = pkg_ids.len() > 1;
54+
pub fn print(
55+
&mut self,
56+
resolve: &Resolve,
57+
pkg_ids: &[PackageId],
58+
force_print_package_in_curlies: bool,
59+
) -> Result<String> {
60+
let print_package_in_curlies = force_print_package_in_curlies || pkg_ids.len() > 1;
5661
for (i, pkg_id) in pkg_ids.into_iter().enumerate() {
5762
if i > 0 {
5863
self.output.push_str("\n\n");
@@ -68,9 +73,8 @@ impl WitPrinter {
6873
self.output.push_str(&format!("@{version}"));
6974
}
7075

71-
if has_multiple_packages {
72-
self.output.push_str("{");
73-
self.output.indent += 1
76+
if print_package_in_curlies {
77+
self.output.push_str(" {\n");
7478
} else {
7579
self.print_semicolon();
7680
self.output.push_str("\n\n");
@@ -96,9 +100,8 @@ impl WitPrinter {
96100
writeln!(&mut self.output, "}}")?;
97101
}
98102

99-
if has_multiple_packages {
100-
self.output.push_str("}");
101-
self.output.indent -= 1
103+
if print_package_in_curlies {
104+
self.output.push_str("}\n");
102105
}
103106
}
104107

crates/wit-component/tests/components.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ fn run_test(path: &Path) -> Result<()> {
171171
}
172172
};
173173
let wit = WitPrinter::default()
174-
.print(&resolve, &[pkg])
174+
.print(&resolve, &[pkg], false)
175175
.context("failed to print WIT")?;
176176
assert_output(&wit, &component_wit_path)?;
177177

crates/wit-component/tests/interfaces.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ fn run_test(path: &Path, is_dir: bool) -> Result<()> {
9696
}
9797

9898
fn assert_print(resolve: &Resolve, pkg_ids: &[PackageId], path: &Path, is_dir: bool) -> Result<()> {
99-
let output = WitPrinter::default().print(resolve, &pkg_ids)?;
99+
let output = WitPrinter::default().print(resolve, &pkg_ids, false)?;
100100
for pkg_id in pkg_ids {
101101
let pkg = &resolve.packages[*pkg_id];
102102
let expected = if is_dir {

crates/wit-component/tests/merge.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ fn merging() -> Result<()> {
4646
.join("merge")
4747
.join(&pkg.name.name)
4848
.with_extension("wit");
49-
let output = WitPrinter::default().print(&into, &[id])?;
49+
let output = WitPrinter::default().print(&into, &[id], false)?;
5050
assert_output(&expected, &output)?;
5151
}
5252
}

fuzz/src/roundtrip_wit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fn roundtrip_through_printing(file: &str, resolve: &Resolve, wasm: &[u8]) {
8686
for (id, pkg) in resolve.packages.iter() {
8787
let mut map = SourceMap::new();
8888
let pkg_name = &pkg.name;
89-
let doc = WitPrinter::default().print(resolve, &[id]).unwrap();
89+
let doc = WitPrinter::default().print(resolve, &[id], false).unwrap();
9090
write_file(&format!("{file}-{pkg_name}.wit"), &doc);
9191
map.push(format!("{pkg_name}.wit").as_ref(), doc);
9292
let unresolved = map.parse().unwrap();

src/bin/wasm-tools/component.rs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -523,9 +523,7 @@ impl WitOpts {
523523
// This interprets all of the output options and performs such a task.
524524
if self.json {
525525
self.emit_json(&decoded)?;
526-
return Ok(());
527-
}
528-
if self.wasm || self.wat {
526+
} else if self.wasm || self.wat {
529527
self.emit_wasm(&decoded)?;
530528
} else {
531529
self.emit_wit(&decoded)?;
@@ -618,7 +616,6 @@ impl WitOpts {
618616
assert!(!self.wasm && !self.wat);
619617

620618
let resolve = decoded.resolve();
621-
let main = decoded.packages();
622619

623620
let mut printer = WitPrinter::default();
624621
printer.emit_docs(!self.no_docs);
@@ -641,28 +638,31 @@ impl WitOpts {
641638
*cnt += 1;
642639
}
643640

641+
let main = decoded.packages();
644642
for (id, pkg) in resolve.packages.iter() {
645-
let output = printer.print(resolve, &[id])?;
646-
let out_dir = if main.contains(&id) {
643+
let is_main = main.contains(&id);
644+
let output = printer.print(resolve, &[id], is_main)?;
645+
let out_dir = if is_main {
647646
dir.clone()
648647
} else {
649-
let dir = dir.join("deps");
650-
let packages_with_same_name = &names[&pkg.name.name];
651-
if packages_with_same_name.len() == 1 {
652-
dir.join(&pkg.name.name)
648+
dir.join("deps")
649+
};
650+
let packages_with_same_name = &names[&pkg.name.name];
651+
let stem = if packages_with_same_name.len() == 1 {
652+
pkg.name.name.clone()
653+
} else {
654+
let packages_with_same_namespace =
655+
packages_with_same_name[&pkg.name.namespace];
656+
if packages_with_same_namespace == 1 {
657+
format!("{}:{}", pkg.name.namespace, pkg.name.name)
653658
} else {
654-
let packages_with_same_namespace =
655-
packages_with_same_name[&pkg.name.namespace];
656-
if packages_with_same_namespace == 1 {
657-
dir.join(format!("{}:{}", pkg.name.namespace, pkg.name.name))
658-
} else {
659-
dir.join(pkg.name.to_string())
660-
}
659+
pkg.name.to_string()
661660
}
662661
};
663662
std::fs::create_dir_all(&out_dir)
664663
.with_context(|| format!("failed to create directory: {out_dir:?}"))?;
665-
let path = out_dir.join("main.wit");
664+
let filename = format!("{stem}.wit");
665+
let path = out_dir.join(&filename);
666666
std::fs::write(&path, &output)
667667
.with_context(|| format!("failed to write file: {path:?}"))?;
668668
println!("Writing: {}", path.display());
@@ -672,8 +672,7 @@ impl WitOpts {
672672
self.output.output(
673673
&self.general,
674674
Output::Wit {
675-
resolve: &resolve,
676-
ids: &main,
675+
wit: &decoded,
677676
printer,
678677
},
679678
)?;

src/lib.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,7 @@ pub struct OutputArg {
143143
pub enum Output<'a> {
144144
#[cfg(feature = "component")]
145145
Wit {
146-
resolve: &'a wit_parser::Resolve,
147-
ids: &'a [wit_parser::PackageId],
146+
wit: &'a wit_component::DecodedWasm,
148147
printer: wit_component::WitPrinter,
149148
},
150149
Wasm(&'a [u8]),
@@ -233,12 +232,14 @@ impl OutputArg {
233232
}
234233
Output::Json(s) => self.output_str(s),
235234
#[cfg(feature = "component")]
236-
Output::Wit {
237-
resolve,
238-
ids,
239-
mut printer,
240-
} => {
241-
let output = printer.print(resolve, ids)?;
235+
Output::Wit { wit, mut printer } => {
236+
let resolve = wit.resolve();
237+
let ids = resolve
238+
.packages
239+
.iter()
240+
.map(|(id, _)| id)
241+
.collect::<Vec<_>>();
242+
let output = printer.print(resolve, &ids, false)?;
242243
self.output_str(&output)
243244
}
244245
}

tests/cli.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use std::env;
3232
use std::io::Write;
3333
use std::path::{Path, PathBuf};
3434
use std::process::{Command, Output, Stdio};
35+
use tempfile::TempDir;
3536

3637
fn main() {
3738
let mut tests = Vec::new();
@@ -76,13 +77,16 @@ fn run_test(test: &Path, bless: bool) -> Result<()> {
7677

7778
let mut cmd = wasm_tools_exe();
7879
let mut stdin = None;
80+
let tempdir = TempDir::new()?;
7981
for arg in line.split_whitespace() {
8082
if arg == "|" {
8183
let output = execute(&mut cmd, stdin.as_deref(), false)?;
8284
stdin = Some(output.stdout);
8385
cmd = wasm_tools_exe();
8486
} else if arg == "%" {
8587
cmd.arg(test);
88+
} else if arg == "%tmpdir" {
89+
cmd.arg(tempdir.path());
8690
} else {
8791
cmd.arg(arg);
8892
}
@@ -94,12 +98,14 @@ fn run_test(test: &Path, bless: bool) -> Result<()> {
9498
bless,
9599
&output.stdout,
96100
&test.with_extension(&format!("{extension}.stdout")),
101+
&tempdir,
97102
)
98103
.context("failed to check stdout expectation (auto-update with BLESS=1)")?;
99104
assert_output(
100105
bless,
101106
&output.stderr,
102107
&test.with_extension(&format!("{extension}.stderr")),
108+
&tempdir,
103109
)
104110
.context("failed to check stderr expectation (auto-update with BLESS=1)")?;
105111
Ok(())
@@ -145,7 +151,14 @@ fn execute(cmd: &mut Command, stdin: Option<&[u8]>, should_fail: bool) -> Result
145151
Ok(output)
146152
}
147153

148-
fn assert_output(bless: bool, output: &[u8], path: &Path) -> Result<()> {
154+
fn assert_output(bless: bool, output: &[u8], path: &Path, tempdir: &TempDir) -> Result<()> {
155+
let tempdir = tempdir.path().to_str().unwrap();
156+
// sanitize the output to be consistent across platforms and handle per-test
157+
// differences such as `%tmpdir`.
158+
let output = String::from_utf8_lossy(output)
159+
.replace(tempdir, "%tmpdir")
160+
.replace("\\", "/");
161+
149162
if bless {
150163
if output.is_empty() {
151164
drop(std::fs::remove_file(path));
@@ -162,7 +175,6 @@ fn assert_output(bless: bool, output: &[u8], path: &Path) -> Result<()> {
162175
Ok(())
163176
}
164177
} else {
165-
let output = std::str::from_utf8(output)?;
166178
let contents = std::fs::read_to_string(path)
167179
.with_context(|| format!("failed to read {path:?}"))?
168180
.replace("\r\n", "\n");
Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
1-
package root:root;
1+
package root:root {
2+
world root {
3+
import bar:bar/my-interface;
4+
}
5+
}
6+
7+
8+
package bar:bar {
9+
interface my-interface {
10+
foo: func();
11+
}
212

3-
world root {
4-
import bar:bar/my-interface;
13+
world my-world {
14+
import my-interface;
15+
}
516
}
Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
1-
package root:root;
1+
package root:root {
2+
world root {
3+
import foo:foo/my-interface;
4+
}
5+
}
6+
7+
8+
package foo:foo {
9+
interface my-interface {
10+
foo: func();
11+
}
212

3-
world root {
4-
import foo:foo/my-interface;
13+
world my-world {
14+
import my-interface;
15+
}
516
}

0 commit comments

Comments
 (0)