Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion crates/wit-component/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ use wasm_encoder::{
};
use wasm_metadata::Producers;
use wasmparser::{BinaryReader, Encoding, Parser, Payload};
use wit_parser::{CloneMaps, Package, PackageName, Resolve, World, WorldId, WorldItem, WorldKey};
use wit_parser::{
CloneMaps, Package, PackageMetadata, PackageName, Resolve, World, WorldId, WorldItem, WorldKey,
};

const CURRENT_VERSION: u8 = 0x04;
const CUSTOM_SECTION_NAME: &str = "wit-component-encoding";
Expand Down Expand Up @@ -292,6 +294,12 @@ pub fn encode(
data: Cow::Borrowed(&[CURRENT_VERSION, string_encoding]),
});

let package_docs = PackageMetadata::extract(resolve, world.package.unwrap());
builder.custom_section(&CustomSection {
name: PackageMetadata::SECTION_NAME.into(),
data: package_docs.encode()?.into(),
});

let ty = builder.type_component(None, &outer_ty);
builder.export(&world.name, ComponentExportKind::Type, ty, None);

Expand Down
19 changes: 18 additions & 1 deletion crates/wit-parser/src/decoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,8 @@ pub fn decode_world(wasm: &[u8]) -> Result<(Resolve, WorldId)> {
let mut exports = Vec::new();
let mut depth = 1;
let mut types = None;
#[cfg(feature = "serde")]
let mut package_metadata: Option<PackageMetadata> = None;

for payload in Parser::new(0).parse_all(wasm) {
let payload = payload?;
Expand All @@ -451,6 +453,16 @@ pub fn decode_world(wasm: &[u8]) -> Result<(Resolve, WorldId)> {
exports.push(export?);
}
}
// Best-effort: a bad section just drops docs, not the world.
// Guard takes the first top-level package-docs section; duplicates are ignored.
#[cfg(feature = "serde")]
Payload::CustomSection(s)
if depth == 1
&& s.name() == PackageMetadata::SECTION_NAME
&& package_metadata.is_none() =>
{
package_metadata = PackageMetadata::decode(s.data()).ok();
}
_ => {}
}
}
Expand Down Expand Up @@ -489,12 +501,17 @@ pub fn decode_world(wasm: &[u8]) -> Result<(Resolve, WorldId)> {
worlds: &mut worlds,
},
)?;
let (resolve, pkg) = decoder.finish(Package {
let (mut resolve, pkg) = decoder.finish(Package {
name,
interfaces,
worlds,
docs: Default::default(),
});
#[cfg(feature = "serde")]
if let Some(metadata) = package_metadata {
// Best-effort: a failure here just drops some docs.
let _ = metadata.inject(&mut resolve, pkg);
}
// The package decoded here should only have a single world so extract that
// here to return.
let world = *resolve.packages[pkg].worlds.iter().next().unwrap().1;
Expand Down
1 change: 1 addition & 0 deletions tests/cli/component-embed-only-custom.wit.stdout
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(component
(@custom "wit-component-encoding" "/04/00")
(@custom "package-docs" "/01{/22docs/22:/22RUN: component embed --only-custom -w foo % | print/22}")
(type (;0;)
(component
(type (;0;)
Expand Down
17 changes: 17 additions & 0 deletions tests/cli/component-embed-preserves-docs.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: component embed --dummy % | component wit

package foo:docs-test;

/// The interface.
interface my-interface {
/// The function.
my-func: func(
/// The function's argument.
my-arg: string,
) -> string;
}

/// A world with documentation.
world my-world {
export my-interface;
}
17 changes: 17 additions & 0 deletions tests/cli/component-embed-preserves-docs.wit.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package root:root;

world root {
export foo:docs-test/my-interface;
}
/// RUN: component embed --dummy % | component wit
package foo:docs-test {
/// The interface.
interface my-interface {
/// The function.
my-func: func(my-arg: string) -> string;
}
/// A world with documentation.
world my-world {
export my-interface;
}
}
1 change: 1 addition & 0 deletions tests/cli/component-wit-of-core-module.wit.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ world root {

export y: func();
}
/// RUN: component embed --dummy % | component wit
package a:b {
world foo {
import x: func();
Expand Down
10 changes: 10 additions & 0 deletions tests/cli/importize.wit.simple-component.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ package root:root;
world root-importized {
import importize:importize/t;
}
/// RUN[simple]: component wit --importize-world simple %
/// RUN[simple-rename]: component wit --importize-world simple-rename --importize-out-world-name test-rename %
/// RUN[simple-component]: component embed --dummy --world simple % | /
/// component wit --importize
/// RUN[with-deps]: component wit --importize-world with-deps %
/// RUN[simple-toplevel]: component wit --importize-world simple-toplevel %
/// RUN[toplevel-deps]: component wit --importize-world toplevel-deps %
/// FAIL[fail1]: component wit --importize-world fail1 %
/// RUN[trim-imports]: component wit --importize-world trim-imports %
/// RUN[tricky-import]: component wit --importize-world tricky-import %
package importize:importize {
interface t {
resource r;
Expand Down
1 change: 1 addition & 0 deletions tests/cli/multiple-packages-one-world.wit.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package test:foo2 {
}


/// RUN: component embed --dummy --wat % | component wit
package foo:root {
world hello {
import test:foo1/bar;
Expand Down
1 change: 1 addition & 0 deletions tests/cli/print-core-wasm-wit.wit.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package root:root;
world root {
import foo:foo/my-interface;
}
/// RUN: component embed --dummy % | component wit
package foo:foo {
interface my-interface {
foo: func();
Expand Down
5 changes: 5 additions & 0 deletions tests/cli/reparent-anonymous-interfaces-on-merge.wit.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ world root {
export b: interface {
}
}
/// RUN: component embed --dummy --world w1 % | /
/// component embed --world w2 % | /
/// component embed --world w3 % | /
/// component embed --world w4 % | /
/// component wit
package a:b {
world w1 {
}
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/wit-deep-record.wit.abi.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: decoding custom section component-type

Caused by:
0: effective type size exceeds the limit of 1000000 (at offset 0x27)
0: effective type size exceeds the limit of 1000000 (at offset 0x97)
2 changes: 1 addition & 1 deletion tests/cli/wit-deep-tuple.wit.abi.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: decoding custom section component-type

Caused by:
0: effective type size exceeds the limit of 1000000 (at offset 0x27)
0: effective type size exceeds the limit of 1000000 (at offset 0x97)
3 changes: 3 additions & 0 deletions tests/cli/world-merge-add-resource-func.wit.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ world root {
constructor();
}
}
/// RUN: component embed --dummy --world a % | /
/// component embed --world b % | /
/// component wit
package a:b {
world a {
resource a;
Expand Down
1 change: 1 addition & 0 deletions tests/cli/world-merging-add-imports.wit.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ world root {
use a:b/b.{t};
import c: func() -> t;
}
/// RUN: component embed --dummy --world into % | component embed --world %from % | component wit
package a:b {
interface b {
type t = u32;
Expand Down
1 change: 1 addition & 0 deletions tests/cli/world-merging-same-imports.wit.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ world root {
use a:b/b.{t};
import c: func();
}
/// RUN: component embed --dummy --world into % | component embed --world %from % | component wit
package a:b {
interface b {
type t = u32;
Expand Down
3 changes: 3 additions & 0 deletions tests/cli/world-merging.wit.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ world root {
export x: interface {
}
}
/// RUN: component embed --dummy --world foo % | component embed --world foo % | component wit
/// This test embeds this world twice and then ensures that merging the two
/// worlds together works (it's the same definition anyway).
package a:b {
interface x {
type t = u32;
Expand Down
Loading