diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 8f7a4059f9..875f387940 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -85,8 +85,8 @@ use std::mem; use wasm_encoder::*; use wasmparser::{Validator, WasmFeatures}; use wit_parser::{ - Function, FunctionKind, InterfaceId, LiveTypes, Param, Resolve, Stability, Type, TypeDefKind, - TypeId, TypeOwner, WorldItem, WorldKey, + Function, FunctionKind, InterfaceId, LiveTypes, PackageMetadata, Param, Resolve, Stability, + Type, TypeDefKind, TypeId, TypeOwner, WorldItem, WorldKey, abi::{AbiVariant, WasmSignature, WasmType}, }; @@ -3355,6 +3355,16 @@ impl ComponentEncoder { state .component .raw_custom_section(&crate::base_producers().raw_custom_section()); + for (pkg_id, _) in self.metadata.resolve.packages.iter() { + let package_docs = PackageMetadata::extract(&self.metadata.resolve, pkg_id); + if package_docs.is_empty() { + continue; + } + state.component.custom_section(&CustomSection { + name: PackageMetadata::SECTION_NAME.into(), + data: package_docs.encode()?.into(), + }); + } let bytes = state.component.finish(); if self.validate { diff --git a/crates/wit-component/src/metadata.rs b/crates/wit-component/src/metadata.rs index d6f52df07a..10bd64cfc7 100644 --- a/crates/wit-component/src/metadata.rs +++ b/crates/wit-component/src/metadata.rs @@ -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"; @@ -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); diff --git a/crates/wit-component/tests/components/adapt-preview1/component.wat b/crates/wit-component/tests/components/adapt-preview1/component.wat index 6630f7f9ea..dd5eecd886 100644 --- a/crates/wit-component/tests/components/adapt-preview1/component.wat +++ b/crates/wit-component/tests/components/adapt-preview1/component.wat @@ -116,4 +116,5 @@ (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22,\22interfaces\22:{\22my-wasi\22:{\22docs\22:\22This is the interface imported by the `adapt-*.wat` file which is used\5cnto implement the `wasi_snapshot_preview1` interface.\22}}}") ) diff --git a/crates/wit-component/tests/components/deduplicate-imports/component.wat b/crates/wit-component/tests/components/deduplicate-imports/component.wat index 64669bd949..07f38253a2 100644 --- a/crates/wit-component/tests/components/deduplicate-imports/component.wat +++ b/crates/wit-component/tests/components/deduplicate-imports/component.wat @@ -129,4 +129,5 @@ (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22,\22interfaces\22:{\22my-wasi\22:{\22docs\22:\22This is the interface imported by the `adapt-*.wat` file which is used\5cnto implement the `wasi_snapshot_preview1` interface.\22}}}") ) diff --git a/crates/wit-component/tests/components/imports/component.wat b/crates/wit-component/tests/components/imports/component.wat index 479fc7c9ae..cf5adebdea 100644 --- a/crates/wit-component/tests/components/imports/component.wat +++ b/crates/wit-component/tests/components/imports/component.wat @@ -146,4 +146,7 @@ (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) + (@custom "package-docs" "\01{\22package\22:\22root:root\22,\22worlds\22:{\22root\22:{\22interfaces\22:{\22foo\22:{\22types\22:{\22unused-record\22:{\22docs\22:\22doesn't show up in the wit output despite being exported here since it's\5cnnot actually used by anything\22}}}}}}}") + (@custom "package-docs" "\01{\22package\22:\22root:root\22,\22worlds\22:{\22root\22:{\22interfaces\22:{\22foo\22:{\22types\22:{\22unused-record\22:{\22docs\22:\22doesn't show up in the wit output despite being exported here since it's\5cnnot actually used by anything\22}}}}}}}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22,\22worlds\22:{\22module\22:{\22interfaces\22:{\22foo\22:{\22types\22:{\22unused-record\22:{\22docs\22:\22doesn't show up in the wit output despite being exported here since it's\5cnnot actually used by anything\22}}}}}}}") ) diff --git a/crates/wit-component/tests/interfaces/console.wat b/crates/wit-component/tests/interfaces/console.wat index de72334a7c..a6a9d63205 100644 --- a/crates/wit-component/tests/interfaces/console.wat +++ b/crates/wit-component/tests/interfaces/console.wat @@ -11,7 +11,7 @@ ) ) (export (;1;) "console" (type 0)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:console\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/diamond-disambiguate.wat b/crates/wit-component/tests/interfaces/diamond-disambiguate.wat index 2e08d1a4ef..9b4f27ef51 100644 --- a/crates/wit-component/tests/interfaces/diamond-disambiguate.wat +++ b/crates/wit-component/tests/interfaces/diamond-disambiguate.wat @@ -63,7 +63,7 @@ ) ) (export (;5;) "w1" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/diamond.wat b/crates/wit-component/tests/interfaces/diamond.wat index d2266eb69b..f7035c3f8b 100644 --- a/crates/wit-component/tests/interfaces/diamond.wat +++ b/crates/wit-component/tests/interfaces/diamond.wat @@ -100,7 +100,7 @@ ) ) (export (;7;) "w3" (type 6)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/doc-comments.wat b/crates/wit-component/tests/interfaces/doc-comments.wat index c2bd4d067f..ca179ec0de 100644 --- a/crates/wit-component/tests/interfaces/doc-comments.wat +++ b/crates/wit-component/tests/interfaces/doc-comments.wat @@ -66,7 +66,7 @@ ) ) (export (;5;) "coverage-world" (type 4)) - (@custom "package-docs" "\01{\22docs\22:\22package docs;\22,\22worlds\22:{\22coverage-world\22:{\22docs\22:\22world docs\22,\22types\22:{\22t\22:{\22docs\22:\22world typedef docs\22}},\22funcs\22:{\22imp\22:{\22docs\22:\22world func import docs\22}},\22interface_exports\22:{\22i\22:{\22docs\22:\22world inline interface docs\22,\22funcs\22:{\22f\22:{\22docs\22:\22inline interface func docs\22}},\22types\22:{\22t\22:{\22docs\22:\22inline interface typedef docs\22}}}},\22func_exports\22:{\22exp\22:{\22docs\22:\22world func export docs\22}}}},\22interfaces\22:{\22coverage-iface\22:{\22docs\22:\22interface docs\22,\22funcs\22:{\22[constructor]res\22:{\22docs\22:\22constructor docs\22},\22[method]res.m\22:{\22docs\22:\22method docs\22},\22[static]res.s\22:{\22docs\22:\22static func docs\22},\22f\22:{\22docs\22:\22interface func docs\22}},\22types\22:{\22t\22:{\22docs\22:\22basic typedef docs\22},\22r\22:{\22docs\22:\22record typedef docs\22,\22items\22:{\22f1\22:\22record field docs\22}},\22fl\22:{\22items\22:{\22f1\22:\22flag docs\22}},\22v\22:{\22items\22:{\22c1\22:\22variant case docs\22}},\22e\22:{\22items\22:{\22c1\22:\22enum case docs\22}}}},\22other-comment-forms\22:{\22docs\22:\22other comment forms\5cn multi-line block\22,\22funcs\22:{\22multiple-lines-split\22:{\22docs\22:\22one doc line\5cnnon-doc in the middle\5cnanother doc line\22},\22mixed-forms\22:{\22docs\22:\22mixed forms; line doc\5cnplus block doc\5cn multi-line\22}}}}}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22,\22docs\22:\22package docs;\22,\22worlds\22:{\22coverage-world\22:{\22docs\22:\22world docs\22,\22types\22:{\22t\22:{\22docs\22:\22world typedef docs\22}},\22funcs\22:{\22imp\22:{\22docs\22:\22world func import docs\22}},\22interface_exports\22:{\22i\22:{\22docs\22:\22world inline interface docs\22,\22funcs\22:{\22f\22:{\22docs\22:\22inline interface func docs\22}},\22types\22:{\22t\22:{\22docs\22:\22inline interface typedef docs\22}}}},\22func_exports\22:{\22exp\22:{\22docs\22:\22world func export docs\22}}}},\22interfaces\22:{\22coverage-iface\22:{\22docs\22:\22interface docs\22,\22funcs\22:{\22[constructor]res\22:{\22docs\22:\22constructor docs\22},\22[method]res.m\22:{\22docs\22:\22method docs\22},\22[static]res.s\22:{\22docs\22:\22static func docs\22},\22f\22:{\22docs\22:\22interface func docs\22}},\22types\22:{\22t\22:{\22docs\22:\22basic typedef docs\22},\22r\22:{\22docs\22:\22record typedef docs\22,\22items\22:{\22f1\22:\22record field docs\22}},\22fl\22:{\22items\22:{\22f1\22:\22flag docs\22}},\22v\22:{\22items\22:{\22c1\22:\22variant case docs\22}},\22e\22:{\22items\22:{\22c1\22:\22enum case docs\22}}}},\22other-comment-forms\22:{\22docs\22:\22other comment forms\5cn multi-line block\22,\22funcs\22:{\22multiple-lines-split\22:{\22docs\22:\22one doc line\5cnnon-doc in the middle\5cnanother doc line\22},\22mixed-forms\22:{\22docs\22:\22mixed forms; line doc\5cnplus block doc\5cn multi-line\22}}}}}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/empty.wat b/crates/wit-component/tests/interfaces/empty.wat index 5ad120e0f1..b003fce7c2 100644 --- a/crates/wit-component/tests/interfaces/empty.wat +++ b/crates/wit-component/tests/interfaces/empty.wat @@ -43,7 +43,7 @@ ) ) (export (;5;) "actually-empty-world" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:empty\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/export-other-packages-interface.wat b/crates/wit-component/tests/interfaces/export-other-packages-interface.wat index cd38295805..a3da175e01 100644 --- a/crates/wit-component/tests/interfaces/export-other-packages-interface.wat +++ b/crates/wit-component/tests/interfaces/export-other-packages-interface.wat @@ -16,7 +16,7 @@ ) ) (export (;1;) "foo" (type 0)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/exports.wat b/crates/wit-component/tests/interfaces/exports.wat index 31f1c80163..39bbe6b2b7 100644 --- a/crates/wit-component/tests/interfaces/exports.wat +++ b/crates/wit-component/tests/interfaces/exports.wat @@ -32,7 +32,7 @@ ) ) (export (;3;) "export-foo" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/flags.wat b/crates/wit-component/tests/interfaces/flags.wat index 42707ffb95..cfa8c09fa3 100644 --- a/crates/wit-component/tests/interfaces/flags.wat +++ b/crates/wit-component/tests/interfaces/flags.wat @@ -72,7 +72,7 @@ ) ) (export (;3;) "flags-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:flags\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/floats.wat b/crates/wit-component/tests/interfaces/floats.wat index 6fa1673412..e8072a44c4 100644 --- a/crates/wit-component/tests/interfaces/floats.wat +++ b/crates/wit-component/tests/interfaces/floats.wat @@ -40,7 +40,7 @@ ) ) (export (;3;) "floats-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:floats\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/foreign-use-chain.wat b/crates/wit-component/tests/interfaces/foreign-use-chain.wat index 5639f64daf..d74b0c07bd 100644 --- a/crates/wit-component/tests/interfaces/foreign-use-chain.wat +++ b/crates/wit-component/tests/interfaces/foreign-use-chain.wat @@ -24,7 +24,7 @@ ) ) (export (;1;) "foo" (type 0)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/implements.wat b/crates/wit-component/tests/interfaces/implements.wat index 8d5f242e38..edba9f5ed2 100644 --- a/crates/wit-component/tests/interfaces/implements.wat +++ b/crates/wit-component/tests/interfaces/implements.wat @@ -123,7 +123,7 @@ ) ) (export (;9;) "mixed" (type 8)) - (@custom "package-docs" "\01{\22worlds\22:{\22multi-import\22:{\22docs\22:\22A world that imports the same interface multiple times under different\5cnplain names using the `implements` syntax.\22},\22multi-export\22:{\22docs\22:\22A world that exports the same interface multiple times.\22},\22mixed\22:{\22docs\22:\22A world with both implements imports and a normal interface import,\5cntesting that elaboration adds the dependency correctly.\22}}}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22,\22worlds\22:{\22multi-import\22:{\22docs\22:\22A world that imports the same interface multiple times under different\5cnplain names using the `implements` syntax.\22},\22multi-export\22:{\22docs\22:\22A world that exports the same interface multiple times.\22},\22mixed\22:{\22docs\22:\22A world with both implements imports and a normal interface import,\5cntesting that elaboration adds the dependency correctly.\22}}}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/import-and-export.wat b/crates/wit-component/tests/interfaces/import-and-export.wat index 53ea896abb..aa4755a561 100644 --- a/crates/wit-component/tests/interfaces/import-and-export.wat +++ b/crates/wit-component/tests/interfaces/import-and-export.wat @@ -47,7 +47,7 @@ ) ) (export (;5;) "import-and-export" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/integers.wat b/crates/wit-component/tests/interfaces/integers.wat index e63c3e146a..ff580b037c 100644 --- a/crates/wit-component/tests/interfaces/integers.wat +++ b/crates/wit-component/tests/interfaces/integers.wat @@ -100,7 +100,7 @@ ) ) (export (;3;) "integers-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/lists.wat b/crates/wit-component/tests/interfaces/lists.wat index f1c9397a53..a3642b6926 100644 --- a/crates/wit-component/tests/interfaces/lists.wat +++ b/crates/wit-component/tests/interfaces/lists.wat @@ -204,7 +204,7 @@ ) ) (export (;3;) "lists-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/maps.wat b/crates/wit-component/tests/interfaces/maps.wat index 91e2f862aa..2af5773b94 100644 --- a/crates/wit-component/tests/interfaces/maps.wat +++ b/crates/wit-component/tests/interfaces/maps.wat @@ -179,7 +179,7 @@ ) ) (export (;3;) "maps-test-world" (type 2)) - (@custom "package-docs" "\01{\22interfaces\22:{\22maps-interface\22:{\22funcs\22:{\22map-param\22:{\22docs\22:\22Functions\22}},\22types\22:{\22bool-map\22:{\22docs\22:\22Test all primitive key types\22},\22string-to-bool\22:{\22docs\22:\22Test all value types\22},\22map-of-maps\22:{\22docs\22:\22Nested structures\22}}}}}") + (@custom "package-docs" "\01{\22package\22:\22foo:maps-test\22,\22interfaces\22:{\22maps-interface\22:{\22funcs\22:{\22map-param\22:{\22docs\22:\22Functions\22}},\22types\22:{\22bool-map\22:{\22docs\22:\22Test all primitive key types\22},\22string-to-bool\22:{\22docs\22:\22Test all value types\22},\22map-of-maps\22:{\22docs\22:\22Nested structures\22}}}}}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/multi-doc.wat b/crates/wit-component/tests/interfaces/multi-doc.wat index d29bb9cff7..998a49de17 100644 --- a/crates/wit-component/tests/interfaces/multi-doc.wat +++ b/crates/wit-component/tests/interfaces/multi-doc.wat @@ -71,7 +71,7 @@ ) ) (export (;7;) "a2" (type 6)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/multiple-use.wat b/crates/wit-component/tests/interfaces/multiple-use.wat index 434eea259c..23256eae9f 100644 --- a/crates/wit-component/tests/interfaces/multiple-use.wat +++ b/crates/wit-component/tests/interfaces/multiple-use.wat @@ -60,7 +60,7 @@ ) ) (export (;5;) "baz" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:multiuse\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain.wat b/crates/wit-component/tests/interfaces/pkg-use-chain.wat index a7b5483e4b..c69eebefec 100644 --- a/crates/wit-component/tests/interfaces/pkg-use-chain.wat +++ b/crates/wit-component/tests/interfaces/pkg-use-chain.wat @@ -63,7 +63,7 @@ ) ) (export (;5;) "foo" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:chain\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain2.wat b/crates/wit-component/tests/interfaces/pkg-use-chain2.wat index 1ed4b570d7..b592e46c64 100644 --- a/crates/wit-component/tests/interfaces/pkg-use-chain2.wat +++ b/crates/wit-component/tests/interfaces/pkg-use-chain2.wat @@ -63,7 +63,7 @@ ) ) (export (;5;) "foo" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat b/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat index ac21521ad7..9009c23708 100644 --- a/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat +++ b/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat @@ -40,7 +40,7 @@ ) ) (export (;3;) "bar" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat b/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat index c0773a7315..822c371821 100644 --- a/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat +++ b/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat @@ -17,7 +17,7 @@ ) ) (export (;1;) "foo" (type 0)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/print-keyword.wat b/crates/wit-component/tests/interfaces/print-keyword.wat index 456d4f5cd1..6bf4a32fd2 100644 --- a/crates/wit-component/tests/interfaces/print-keyword.wat +++ b/crates/wit-component/tests/interfaces/print-keyword.wat @@ -14,7 +14,7 @@ ) ) (export (;1;) "interface" (type 0)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/records.wat b/crates/wit-component/tests/interfaces/records.wat index 4697c297b7..ec75b6c298 100644 --- a/crates/wit-component/tests/interfaces/records.wat +++ b/crates/wit-component/tests/interfaces/records.wat @@ -134,7 +134,7 @@ ) ) (export (;3;) "records-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:records\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/reference-out-of-order.wat b/crates/wit-component/tests/interfaces/reference-out-of-order.wat index 03e52aaebb..dcb1c4d203 100644 --- a/crates/wit-component/tests/interfaces/reference-out-of-order.wat +++ b/crates/wit-component/tests/interfaces/reference-out-of-order.wat @@ -56,7 +56,7 @@ ) ) (export (;3;) "foo-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/resources.wat b/crates/wit-component/tests/interfaces/resources.wat index 7715d8b704..75d4fdbf04 100644 --- a/crates/wit-component/tests/interfaces/resources.wat +++ b/crates/wit-component/tests/interfaces/resources.wat @@ -185,7 +185,7 @@ ) ) (export (;11;) "implicit-own-handles3" (type 10)) - (@custom "package-docs" "\01{\22worlds\22:{\22implicit-own-handles3\22:{\22types\22:{\22a\22:{\22docs\22:\22there should only be one `list` type despite there looking like two\5cnlist types here\22}}}},\22interfaces\22:{\22implicit-own-handles2\22:{\22types\22:{\22a\22:{\22docs\22:\22the `own` return and list param should be the same `own`\22},\22b\22:{\22docs\22:\22same as above, even when the `list` implicitly-defined `own` comes\5cnbefore an explicitly defined `own`\22},\22c\22:{\22docs\22:\22same as the above, the `own` argument should have the same type as the\5cnreturn value\22}}}}}") + (@custom "package-docs" "\01{\22package\22:\22foo:bar\22,\22worlds\22:{\22implicit-own-handles3\22:{\22types\22:{\22a\22:{\22docs\22:\22there should only be one `list` type despite there looking like two\5cnlist types here\22}}}},\22interfaces\22:{\22implicit-own-handles2\22:{\22types\22:{\22a\22:{\22docs\22:\22the `own` return and list param should be the same `own`\22},\22b\22:{\22docs\22:\22same as above, even when the `list` implicitly-defined `own` comes\5cnbefore an explicitly defined `own`\22},\22c\22:{\22docs\22:\22same as the above, the `own` argument should have the same type as the\5cnreturn value\22}}}}}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/simple-deps.wat b/crates/wit-component/tests/interfaces/simple-deps.wat index 09f74538fb..10642a2360 100644 --- a/crates/wit-component/tests/interfaces/simple-deps.wat +++ b/crates/wit-component/tests/interfaces/simple-deps.wat @@ -19,7 +19,7 @@ ) ) (export (;1;) "foo" (type 0)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/simple-multi.wat b/crates/wit-component/tests/interfaces/simple-multi.wat index 3a0ac123eb..dafc86cb8b 100644 --- a/crates/wit-component/tests/interfaces/simple-multi.wat +++ b/crates/wit-component/tests/interfaces/simple-multi.wat @@ -17,7 +17,7 @@ ) ) (export (;3;) "foo" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/simple-use.wat b/crates/wit-component/tests/interfaces/simple-use.wat index f6d5e0fed6..2260590aa0 100644 --- a/crates/wit-component/tests/interfaces/simple-use.wat +++ b/crates/wit-component/tests/interfaces/simple-use.wat @@ -33,7 +33,7 @@ ) ) (export (;3;) "console" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/simple-world.wat b/crates/wit-component/tests/interfaces/simple-world.wat index d94e158217..48a2891dd5 100644 --- a/crates/wit-component/tests/interfaces/simple-world.wat +++ b/crates/wit-component/tests/interfaces/simple-world.wat @@ -28,7 +28,7 @@ ) ) (export (;3;) "the-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/type-alias.wat b/crates/wit-component/tests/interfaces/type-alias.wat index eec3bbfa70..faa8b1634f 100644 --- a/crates/wit-component/tests/interfaces/type-alias.wat +++ b/crates/wit-component/tests/interfaces/type-alias.wat @@ -44,7 +44,7 @@ ) ) (export (;3;) "my-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/type-alias2.wat b/crates/wit-component/tests/interfaces/type-alias2.wat index 6517e2cbf7..6ce7630896 100644 --- a/crates/wit-component/tests/interfaces/type-alias2.wat +++ b/crates/wit-component/tests/interfaces/type-alias2.wat @@ -34,7 +34,7 @@ ) ) (export (;3;) "my-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat b/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat index 18a98b5711..7b30c6b574 100644 --- a/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat +++ b/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat @@ -29,7 +29,7 @@ ) ) (export (;1;) "a" (type 0)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/use-chain.wat b/crates/wit-component/tests/interfaces/use-chain.wat index 840c1015c3..9fd68507c8 100644 --- a/crates/wit-component/tests/interfaces/use-chain.wat +++ b/crates/wit-component/tests/interfaces/use-chain.wat @@ -65,7 +65,7 @@ ) ) (export (;5;) "baz" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/use-for-type.wat b/crates/wit-component/tests/interfaces/use-for-type.wat index 419a1aaf67..5fce9034a1 100644 --- a/crates/wit-component/tests/interfaces/use-for-type.wat +++ b/crates/wit-component/tests/interfaces/use-for-type.wat @@ -42,7 +42,7 @@ ) ) (export (;5;) "baz" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/variants.wat b/crates/wit-component/tests/interfaces/variants.wat index 6b449c9eaf..7fec9606ec 100644 --- a/crates/wit-component/tests/interfaces/variants.wat +++ b/crates/wit-component/tests/interfaces/variants.wat @@ -190,7 +190,7 @@ ) ) (export (;3;) "variants-world" (type 2)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:variants\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/wasi-http.wat b/crates/wit-component/tests/interfaces/wasi-http.wat index 546e545f62..b798ead9f5 100644 --- a/crates/wit-component/tests/interfaces/wasi-http.wat +++ b/crates/wit-component/tests/interfaces/wasi-http.wat @@ -874,7 +874,7 @@ ) ) (export (;7;) "proxy" (type 6)) - (@custom "package-docs" "\01{\22worlds\22:{\22proxy\22:{\22docs\22:\22The `wasi:http/proxy` world captures a widely-implementable intersection of\5cnhosts that includes HTTP forward and reverse proxies. Components targeting\5cnthis world may concurrently stream in and out any number of incoming and\5cnoutgoing HTTP requests.\22}},\22interfaces\22:{\22types\22:{\22docs\22:\22This interface defines all of the types and methods for implementing\5cnHTTP Requests and Responses, both incoming and outgoing, as well as\5cntheir headers, trailers, and bodies.\22,\22funcs\22:{\22http-error-code\22:{\22docs\22:\22Attempts to extract a http-related `error` from the wasi:io `error`\5cnprovided.\5cn\5cnStream operations which return\5cn`wasi:io/stream/stream-error::last-operation-failed` have a payload of\5cntype `wasi:io/error/error` with more information about the operation\5cnthat failed. This payload can be passed through to this function to see\5cnif there's http-related information about the error to return.\5cn\5cnNote that this function is fallible because not all io-errors are\5cnhttp-related errors.\22},\22[constructor]fields\22:{\22docs\22:\22Construct an empty HTTP Fields.\5cn\5cnThe resulting `fields` is mutable.\22},\22[static]fields.from-list\22:{\22docs\22:\22Construct an HTTP Fields.\5cn\5cnThe resulting `fields` is mutable.\5cn\5cnThe list represents each key-value pair in the Fields. Keys\5cnwhich have multiple values are represented by multiple entries in this\5cnlist with the same key.\5cn\5cnThe tuple is a pair of the field key, represented as a string, and\5cnValue, represented as a list of bytes. In a valid Fields, all keys\5cnand values are valid UTF-8 strings. However, values are not always\5cnwell-formed, so they are represented as a raw list of bytes.\5cn\5cnAn error result will be returned if any header or value was\5cnsyntactically invalid, or if a header was forbidden.\22},\22[method]fields.get\22:{\22docs\22:\22Get all of the values corresponding to a key. If the key is not present\5cnin this `fields`, an empty list is returned. However, if the key is\5cnpresent but empty, this is represented by a list with one or more\5cnempty field-values present.\22},\22[method]fields.has\22:{\22docs\22:\22Returns `true` when the key is present in this `fields`. If the key is\5cnsyntactically invalid, `false` is returned.\22},\22[method]fields.set\22:{\22docs\22:\22Set all of the values for a key. Clears any existing values for that\5cnkey, if they have been set.\5cn\5cnFails with `header-error.immutable` if the `fields` are immutable.\22},\22[method]fields.delete\22:{\22docs\22:\22Delete all values for a key. Does nothing if no values for the key\5cnexist.\5cn\5cnFails with `header-error.immutable` if the `fields` are immutable.\22},\22[method]fields.append\22:{\22docs\22:\22Append a value for a key. Does not change or delete any existing\5cnvalues for that key.\5cn\5cnFails with `header-error.immutable` if the `fields` are immutable.\22},\22[method]fields.entries\22:{\22docs\22:\22Retrieve the full set of keys and values in the Fields. Like the\5cnconstructor, the list represents each key-value pair.\5cn\5cnThe outer list represents each key-value pair in the Fields. Keys\5cnwhich have multiple values are represented by multiple entries in this\5cnlist with the same key.\22},\22[method]fields.clone\22:{\22docs\22:\22Make a deep copy of the Fields. Equivalent in behavior to calling the\5cn`fields` constructor on the return value of `entries`. The resulting\5cn`fields` is mutable.\22},\22[method]incoming-request.method\22:{\22docs\22:\22Returns the method of the incoming request.\22},\22[method]incoming-request.path-with-query\22:{\22docs\22:\22Returns the path with query parameters from the request, as a string.\22},\22[method]incoming-request.scheme\22:{\22docs\22:\22Returns the protocol scheme from the request.\22},\22[method]incoming-request.authority\22:{\22docs\22:\22Returns the authority from the request, if it was present.\22},\22[method]incoming-request.headers\22:{\22docs\22:\22Get the `headers` associated with the request.\5cn\5cnThe returned `headers` resource is immutable: `set`, `append`, and\5cn`delete` operations will fail with `header-error.immutable`.\5cn\5cnThe `headers` returned are a child resource: it must be dropped before\5cnthe parent `incoming-request` is dropped. Dropping this\5cn`incoming-request` before all children are dropped will trap.\22},\22[method]incoming-request.consume\22:{\22docs\22:\22Gives the `incoming-body` associated with this request. Will only\5cnreturn success at most once, and subsequent calls will return error.\22},\22[constructor]outgoing-request\22:{\22docs\22:\22Construct a new `outgoing-request` with a default `method` of `GET`, and\5cn`none` values for `path-with-query`, `scheme`, and `authority`.\5cn\5cn* `headers` is the HTTP Headers for the Request.\5cn\5cnIt is possible to construct, or manipulate with the accessor functions\5cnbelow, an `outgoing-request` with an invalid combination of `scheme`\5cnand `authority`, or `headers` which are not permitted to be sent.\5cnIt is the obligation of the `outgoing-handler.handle` implementation\5cnto reject invalid constructions of `outgoing-request`.\22},\22[method]outgoing-request.body\22:{\22docs\22:\22Returns the resource corresponding to the outgoing Body for this\5cnRequest.\5cn\5cnReturns success on the first call: the `outgoing-body` resource for\5cnthis `outgoing-request` can be retrieved at most once. Subsequent\5cncalls will return error.\22},\22[method]outgoing-request.method\22:{\22docs\22:\22Get the Method for the Request.\22},\22[method]outgoing-request.set-method\22:{\22docs\22:\22Set the Method for the Request. Fails if the string present in a\5cn`method.other` argument is not a syntactically valid method.\22},\22[method]outgoing-request.path-with-query\22:{\22docs\22:\22Get the combination of the HTTP Path and Query for the Request.\5cnWhen `none`, this represents an empty Path and empty Query.\22},\22[method]outgoing-request.set-path-with-query\22:{\22docs\22:\22Set the combination of the HTTP Path and Query for the Request.\5cnWhen `none`, this represents an empty Path and empty Query. Fails is the\5cnstring given is not a syntactically valid path and query uri component.\22},\22[method]outgoing-request.scheme\22:{\22docs\22:\22Get the HTTP Related Scheme for the Request. When `none`, the\5cnimplementation may choose an appropriate default scheme.\22},\22[method]outgoing-request.set-scheme\22:{\22docs\22:\22Set the HTTP Related Scheme for the Request. When `none`, the\5cnimplementation may choose an appropriate default scheme. Fails if the\5cnstring given is not a syntactically valid uri scheme.\22},\22[method]outgoing-request.authority\22:{\22docs\22:\22Get the HTTP Authority for the Request. A value of `none` may be used\5cnwith Related Schemes which do not require an Authority. The HTTP and\5cnHTTPS schemes always require an authority.\22},\22[method]outgoing-request.set-authority\22:{\22docs\22:\22Set the HTTP Authority for the Request. A value of `none` may be used\5cnwith Related Schemes which do not require an Authority. The HTTP and\5cnHTTPS schemes always require an authority. Fails if the string given is\5cnnot a syntactically valid uri authority.\22},\22[method]outgoing-request.headers\22:{\22docs\22:\22Get the headers associated with the Request.\5cn\5cnThe returned `headers` resource is immutable: `set`, `append`, and\5cn`delete` operations will fail with `header-error.immutable`.\5cn\5cnThis headers resource is a child: it must be dropped before the parent\5cn`outgoing-request` is dropped, or its ownership is transferred to\5cnanother component by e.g. `outgoing-handler.handle`.\22},\22[constructor]request-options\22:{\22docs\22:\22Construct a default `request-options` value.\22},\22[method]request-options.connect-timeout\22:{\22docs\22:\22The timeout for the initial connect to the HTTP Server.\22},\22[method]request-options.set-connect-timeout\22:{\22docs\22:\22Set the timeout for the initial connect to the HTTP Server. An error\5cnreturn value indicates that this timeout is not supported.\22},\22[method]request-options.first-byte-timeout\22:{\22docs\22:\22The timeout for receiving the first byte of the Response body.\22},\22[method]request-options.set-first-byte-timeout\22:{\22docs\22:\22Set the timeout for receiving the first byte of the Response body. An\5cnerror return value indicates that this timeout is not supported.\22},\22[method]request-options.between-bytes-timeout\22:{\22docs\22:\22The timeout for receiving subsequent chunks of bytes in the Response\5cnbody stream.\22},\22[method]request-options.set-between-bytes-timeout\22:{\22docs\22:\22Set the timeout for receiving subsequent chunks of bytes in the Response\5cnbody stream. An error return value indicates that this timeout is not\5cnsupported.\22},\22[static]response-outparam.set\22:{\22docs\22:\22Set the value of the `response-outparam` to either send a response,\5cnor indicate an error.\5cn\5cnThis method consumes the `response-outparam` to ensure that it is\5cncalled at most once. If it is never called, the implementation\5cnwill respond with an error.\5cn\5cnThe user may provide an `error` to `response` to allow the\5cnimplementation determine how to respond with an HTTP error response.\22},\22[method]incoming-response.status\22:{\22docs\22:\22Returns the status code from the incoming response.\22},\22[method]incoming-response.headers\22:{\22docs\22:\22Returns the headers from the incoming response.\5cn\5cnThe returned `headers` resource is immutable: `set`, `append`, and\5cn`delete` operations will fail with `header-error.immutable`.\5cn\5cnThis headers resource is a child: it must be dropped before the parent\5cn`incoming-response` is dropped.\22},\22[method]incoming-response.consume\22:{\22docs\22:\22Returns the incoming body. May be called at most once. Returns error\5cnif called additional times.\22},\22[method]incoming-body.stream\22:{\22docs\22:\22Returns the contents of the body, as a stream of bytes.\5cn\5cnReturns success on first call: the stream representing the contents\5cncan be retrieved at most once. Subsequent calls will return error.\5cn\5cnThe returned `input-stream` resource is a child: it must be dropped\5cnbefore the parent `incoming-body` is dropped, or consumed by\5cn`incoming-body.finish`.\5cn\5cnThis invariant ensures that the implementation can determine whether\5cnthe user is consuming the contents of the body, waiting on the\5cn`future-trailers` to be ready, or neither. This allows for network\5cnbackpressure is to be applied when the user is consuming the body,\5cnand for that backpressure to not inhibit delivery of the trailers if\5cnthe user does not read the entire body.\22},\22[static]incoming-body.finish\22:{\22docs\22:\22Takes ownership of `incoming-body`, and returns a `future-trailers`.\5cnThis function will trap if the `input-stream` child is still alive.\22},\22[method]future-trailers.subscribe\22:{\22docs\22:\22Returns a pollable which becomes ready when either the trailers have\5cnbeen received, or an error has occurred. When this pollable is ready,\5cnthe `get` method will return `some`.\22},\22[method]future-trailers.get\22:{\22docs\22:\22Returns the contents of the trailers, or an error which occurred,\5cnonce the future is ready.\5cn\5cnThe outer `option` represents future readiness. Users can wait on this\5cn`option` to become `some` using the `subscribe` method.\5cn\5cnThe outer `result` is used to retrieve the trailers or error at most\5cnonce. It will be success on the first call in which the outer option\5cnis `some`, and error on subsequent calls.\5cn\5cnThe inner `result` represents that either the HTTP Request or Response\5cnbody, as well as any trailers, were received successfully, or that an\5cnerror occurred receiving them. The optional `trailers` indicates whether\5cnor not trailers were present in the body.\5cn\5cnWhen some `trailers` are returned by this method, the `trailers`\5cnresource is immutable, and a child. Use of the `set`, `append`, or\5cn`delete` methods will return an error, and the resource must be\5cndropped before the parent `future-trailers` is dropped.\22},\22[constructor]outgoing-response\22:{\22docs\22:\22Construct an `outgoing-response`, with a default `status-code` of `200`.\5cnIf a different `status-code` is needed, it must be set via the\5cn`set-status-code` method.\5cn\5cn* `headers` is the HTTP Headers for the Response.\22},\22[method]outgoing-response.status-code\22:{\22docs\22:\22Get the HTTP Status Code for the Response.\22},\22[method]outgoing-response.set-status-code\22:{\22docs\22:\22Set the HTTP Status Code for the Response. Fails if the status-code\5cngiven is not a valid http status code.\22},\22[method]outgoing-response.headers\22:{\22docs\22:\22Get the headers associated with the Request.\5cn\5cnThe returned `headers` resource is immutable: `set`, `append`, and\5cn`delete` operations will fail with `header-error.immutable`.\5cn\5cnThis headers resource is a child: it must be dropped before the parent\5cn`outgoing-request` is dropped, or its ownership is transferred to\5cnanother component by e.g. `outgoing-handler.handle`.\22},\22[method]outgoing-response.body\22:{\22docs\22:\22Returns the resource corresponding to the outgoing Body for this Response.\5cn\5cnReturns success on the first call: the `outgoing-body` resource for\5cnthis `outgoing-response` can be retrieved at most once. Subsequent\5cncalls will return error.\22},\22[method]outgoing-body.write\22:{\22docs\22:\22Returns a stream for writing the body contents.\5cn\5cnThe returned `output-stream` is a child resource: it must be dropped\5cnbefore the parent `outgoing-body` resource is dropped (or finished),\5cnotherwise the `outgoing-body` drop or `finish` will trap.\5cn\5cnReturns success on the first call: the `output-stream` resource for\5cnthis `outgoing-body` may be retrieved at most once. Subsequent calls\5cnwill return error.\22},\22[static]outgoing-body.finish\22:{\22docs\22:\22Finalize an outgoing body, optionally providing trailers. This must be\5cncalled to signal that the response is complete. If the `outgoing-body`\5cnis dropped without calling `outgoing-body.finalize`, the implementation\5cnshould treat the body as corrupted.\5cn\5cnFails if the body's `outgoing-request` or `outgoing-response` was\5cnconstructed with a Content-Length header, and the contents written\5cnto the body (via `write`) does not match the value given in the\5cnContent-Length.\22},\22[method]future-incoming-response.subscribe\22:{\22docs\22:\22Returns a pollable which becomes ready when either the Response has\5cnbeen received, or an error has occurred. When this pollable is ready,\5cnthe `get` method will return `some`.\22},\22[method]future-incoming-response.get\22:{\22docs\22:\22Returns the incoming HTTP Response, or an error, once one is ready.\5cn\5cnThe outer `option` represents future readiness. Users can wait on this\5cn`option` to become `some` using the `subscribe` method.\5cn\5cnThe outer `result` is used to retrieve the response or error at most\5cnonce. It will be success on the first call in which the outer option\5cnis `some`, and error on subsequent calls.\5cn\5cnThe inner `result` represents that either the incoming HTTP Response\5cnstatus and headers have received successfully, or that an error\5cnoccurred. Errors may also occur while consuming the response body,\5cnbut those will be reported by the `incoming-body` and its\5cn`output-stream` child.\22}},\22types\22:{\22method\22:{\22docs\22:\22This type corresponds to HTTP standard Methods.\22},\22scheme\22:{\22docs\22:\22This type corresponds to HTTP standard Related Schemes.\22},\22DNS-error-payload\22:{\22docs\22:\22Defines the case payload type for `DNS-error` above:\22},\22TLS-alert-received-payload\22:{\22docs\22:\22Defines the case payload type for `TLS-alert-received` above:\22},\22field-size-payload\22:{\22docs\22:\22Defines the case payload type for `HTTP-response-{header,trailer}-size` above:\22},\22error-code\22:{\22docs\22:\22These cases are inspired by the IANA HTTP Proxy Error Types:\5cn https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types\22,\22items\22:{\22internal-error\22:\22This is a catch-all error for anything that doesn't fit cleanly into a\5cnmore specific case. It also includes an optional string for an\5cnunstructured description of the error. Users should not depend on the\5cnstring for diagnosing errors, as it's not required to be consistent\5cnbetween implementations.\22}},\22header-error\22:{\22docs\22:\22This type enumerates the different kinds of errors that may occur when\5cnsetting or appending to a `fields` resource.\22,\22items\22:{\22invalid-syntax\22:\22This error indicates that a `field-key` or `field-value` was\5cnsyntactically invalid when used with an operation that sets headers in a\5cn`fields`.\22,\22forbidden\22:\22This error indicates that a forbidden `field-key` was used when trying\5cnto set a header in a `fields`.\22,\22immutable\22:\22This error indicates that the operation on the `fields` was not\5cnpermitted because the fields are immutable.\22}},\22field-key\22:{\22docs\22:\22Field keys are always strings.\22},\22field-value\22:{\22docs\22:\22Field values should always be ASCII strings. However, in\5cnreality, HTTP implementations often have to interpret malformed values,\5cnso they are provided as a list of bytes.\22},\22fields\22:{\22docs\22:\22This following block defines the `fields` resource which corresponds to\5cnHTTP standard Fields. Fields are a common representation used for both\5cnHeaders and Trailers.\5cn\5cnA `fields` may be mutable or immutable. A `fields` created using the\5cnconstructor, `from-list`, or `clone` will be mutable, but a `fields`\5cnresource given by other means (including, but not limited to,\5cn`incoming-request.headers`, `outgoing-request.headers`) might be be\5cnimmutable. In an immutable fields, the `set`, `append`, and `delete`\5cnoperations will fail with `header-error.immutable`.\22},\22headers\22:{\22docs\22:\22Headers is an alias for Fields.\22},\22trailers\22:{\22docs\22:\22Trailers is an alias for Fields.\22},\22incoming-request\22:{\22docs\22:\22Represents an incoming HTTP Request.\22},\22outgoing-request\22:{\22docs\22:\22Represents an outgoing HTTP Request.\22},\22request-options\22:{\22docs\22:\22Parameters for making an HTTP Request. Each of these parameters is\5cncurrently an optional timeout applicable to the transport layer of the\5cnHTTP protocol.\5cn\5cnThese timeouts are separate from any the user may use to bound a\5cnblocking call to `wasi:io/poll.poll`.\22},\22response-outparam\22:{\22docs\22:\22Represents the ability to send an HTTP Response.\5cn\5cnThis resource is used by the `wasi:http/incoming-handler` interface to\5cnallow a Response to be sent corresponding to the Request provided as the\5cnother argument to `incoming-handler.handle`.\22},\22status-code\22:{\22docs\22:\22This type corresponds to the HTTP standard Status Code.\22},\22incoming-response\22:{\22docs\22:\22Represents an incoming HTTP Response.\22},\22incoming-body\22:{\22docs\22:\22Represents an incoming HTTP Request or Response's Body.\5cn\5cnA body has both its contents - a stream of bytes - and a (possibly\5cnempty) set of trailers, indicating that the full contents of the\5cnbody have been received. This resource represents the contents as\5cnan `input-stream` and the delivery of trailers as a `future-trailers`,\5cnand ensures that the user of this interface may only be consuming either\5cnthe body contents or waiting on trailers at any given time.\22},\22future-trailers\22:{\22docs\22:\22Represents a future which may eventually return trailers, or an error.\5cn\5cnIn the case that the incoming HTTP Request or Response did not have any\5cntrailers, this future will resolve to the empty set of trailers once the\5cncomplete Request or Response body has been received.\22},\22outgoing-response\22:{\22docs\22:\22Represents an outgoing HTTP Response.\22},\22outgoing-body\22:{\22docs\22:\22Represents an outgoing HTTP Request or Response's Body.\5cn\5cnA body has both its contents - a stream of bytes - and a (possibly\5cnempty) set of trailers, inducating the full contents of the body\5cnhave been sent. This resource represents the contents as an\5cn`output-stream` child resource, and the completion of the body (with\5cnoptional trailers) with a static function that consumes the\5cn`outgoing-body` resource, and ensures that the user of this interface\5cnmay not write to the body contents after the body has been finished.\5cn\5cnIf the user code drops this resource, as opposed to calling the static\5cnmethod `finish`, the implementation should treat the body as incomplete,\5cnand that an error has occurred. The implementation should propagate this\5cnerror to the HTTP protocol by whatever means it has available,\5cnincluding: corrupting the body on the wire, aborting the associated\5cnRequest, or sending a late status code for the Response.\22},\22future-incoming-response\22:{\22docs\22:\22Represents a future which may eventually return an incoming HTTP\5cnResponse, or an error.\5cn\5cnThis resource is returned by the `wasi:http/outgoing-handler` interface to\5cnprovide the HTTP Response corresponding to the sent Request.\22}}},\22incoming-handler\22:{\22docs\22:\22This interface defines a handler of incoming HTTP Requests. It should\5cnbe exported by components which can respond to HTTP Requests.\22,\22funcs\22:{\22handle\22:{\22docs\22:\22This function is invoked with an incoming HTTP Request, and a resource\5cn`response-outparam` which provides the capability to reply with an HTTP\5cnResponse. The response is sent by calling the `response-outparam.set`\5cnmethod, which allows execution to continue after the response has been\5cnsent. This enables both streaming to the response body, and performing other\5cnwork.\5cn\5cnThe implementor of this function must write a response to the\5cn`response-outparam` before returning, or else the caller will respond\5cnwith an error on its behalf.\22}}},\22outgoing-handler\22:{\22docs\22:\22This interface defines a handler of outgoing HTTP Requests. It should be\5cnimported by components which wish to make HTTP Requests.\22,\22funcs\22:{\22handle\22:{\22docs\22:\22This function is invoked with an outgoing HTTP Request, and it returns\5cna resource `future-incoming-response` which represents an HTTP Response\5cnwhich may arrive in the future.\5cn\5cnThe `options` argument accepts optional parameters for the HTTP\5cnprotocol's transport layer.\5cn\5cnThis function may return an error if the `outgoing-request` is invalid\5cnor not allowed to be made. Otherwise, protocol errors are reported\5cnthrough the `future-incoming-response`.\22}}}}}") + (@custom "package-docs" "\01{\22package\22:\22wasi:http@0.2.0-rc-2023-12-05\22,\22worlds\22:{\22proxy\22:{\22docs\22:\22The `wasi:http/proxy` world captures a widely-implementable intersection of\5cnhosts that includes HTTP forward and reverse proxies. Components targeting\5cnthis world may concurrently stream in and out any number of incoming and\5cnoutgoing HTTP requests.\22}},\22interfaces\22:{\22types\22:{\22docs\22:\22This interface defines all of the types and methods for implementing\5cnHTTP Requests and Responses, both incoming and outgoing, as well as\5cntheir headers, trailers, and bodies.\22,\22funcs\22:{\22http-error-code\22:{\22docs\22:\22Attempts to extract a http-related `error` from the wasi:io `error`\5cnprovided.\5cn\5cnStream operations which return\5cn`wasi:io/stream/stream-error::last-operation-failed` have a payload of\5cntype `wasi:io/error/error` with more information about the operation\5cnthat failed. This payload can be passed through to this function to see\5cnif there's http-related information about the error to return.\5cn\5cnNote that this function is fallible because not all io-errors are\5cnhttp-related errors.\22},\22[constructor]fields\22:{\22docs\22:\22Construct an empty HTTP Fields.\5cn\5cnThe resulting `fields` is mutable.\22},\22[static]fields.from-list\22:{\22docs\22:\22Construct an HTTP Fields.\5cn\5cnThe resulting `fields` is mutable.\5cn\5cnThe list represents each key-value pair in the Fields. Keys\5cnwhich have multiple values are represented by multiple entries in this\5cnlist with the same key.\5cn\5cnThe tuple is a pair of the field key, represented as a string, and\5cnValue, represented as a list of bytes. In a valid Fields, all keys\5cnand values are valid UTF-8 strings. However, values are not always\5cnwell-formed, so they are represented as a raw list of bytes.\5cn\5cnAn error result will be returned if any header or value was\5cnsyntactically invalid, or if a header was forbidden.\22},\22[method]fields.get\22:{\22docs\22:\22Get all of the values corresponding to a key. If the key is not present\5cnin this `fields`, an empty list is returned. However, if the key is\5cnpresent but empty, this is represented by a list with one or more\5cnempty field-values present.\22},\22[method]fields.has\22:{\22docs\22:\22Returns `true` when the key is present in this `fields`. If the key is\5cnsyntactically invalid, `false` is returned.\22},\22[method]fields.set\22:{\22docs\22:\22Set all of the values for a key. Clears any existing values for that\5cnkey, if they have been set.\5cn\5cnFails with `header-error.immutable` if the `fields` are immutable.\22},\22[method]fields.delete\22:{\22docs\22:\22Delete all values for a key. Does nothing if no values for the key\5cnexist.\5cn\5cnFails with `header-error.immutable` if the `fields` are immutable.\22},\22[method]fields.append\22:{\22docs\22:\22Append a value for a key. Does not change or delete any existing\5cnvalues for that key.\5cn\5cnFails with `header-error.immutable` if the `fields` are immutable.\22},\22[method]fields.entries\22:{\22docs\22:\22Retrieve the full set of keys and values in the Fields. Like the\5cnconstructor, the list represents each key-value pair.\5cn\5cnThe outer list represents each key-value pair in the Fields. Keys\5cnwhich have multiple values are represented by multiple entries in this\5cnlist with the same key.\22},\22[method]fields.clone\22:{\22docs\22:\22Make a deep copy of the Fields. Equivalent in behavior to calling the\5cn`fields` constructor on the return value of `entries`. The resulting\5cn`fields` is mutable.\22},\22[method]incoming-request.method\22:{\22docs\22:\22Returns the method of the incoming request.\22},\22[method]incoming-request.path-with-query\22:{\22docs\22:\22Returns the path with query parameters from the request, as a string.\22},\22[method]incoming-request.scheme\22:{\22docs\22:\22Returns the protocol scheme from the request.\22},\22[method]incoming-request.authority\22:{\22docs\22:\22Returns the authority from the request, if it was present.\22},\22[method]incoming-request.headers\22:{\22docs\22:\22Get the `headers` associated with the request.\5cn\5cnThe returned `headers` resource is immutable: `set`, `append`, and\5cn`delete` operations will fail with `header-error.immutable`.\5cn\5cnThe `headers` returned are a child resource: it must be dropped before\5cnthe parent `incoming-request` is dropped. Dropping this\5cn`incoming-request` before all children are dropped will trap.\22},\22[method]incoming-request.consume\22:{\22docs\22:\22Gives the `incoming-body` associated with this request. Will only\5cnreturn success at most once, and subsequent calls will return error.\22},\22[constructor]outgoing-request\22:{\22docs\22:\22Construct a new `outgoing-request` with a default `method` of `GET`, and\5cn`none` values for `path-with-query`, `scheme`, and `authority`.\5cn\5cn* `headers` is the HTTP Headers for the Request.\5cn\5cnIt is possible to construct, or manipulate with the accessor functions\5cnbelow, an `outgoing-request` with an invalid combination of `scheme`\5cnand `authority`, or `headers` which are not permitted to be sent.\5cnIt is the obligation of the `outgoing-handler.handle` implementation\5cnto reject invalid constructions of `outgoing-request`.\22},\22[method]outgoing-request.body\22:{\22docs\22:\22Returns the resource corresponding to the outgoing Body for this\5cnRequest.\5cn\5cnReturns success on the first call: the `outgoing-body` resource for\5cnthis `outgoing-request` can be retrieved at most once. Subsequent\5cncalls will return error.\22},\22[method]outgoing-request.method\22:{\22docs\22:\22Get the Method for the Request.\22},\22[method]outgoing-request.set-method\22:{\22docs\22:\22Set the Method for the Request. Fails if the string present in a\5cn`method.other` argument is not a syntactically valid method.\22},\22[method]outgoing-request.path-with-query\22:{\22docs\22:\22Get the combination of the HTTP Path and Query for the Request.\5cnWhen `none`, this represents an empty Path and empty Query.\22},\22[method]outgoing-request.set-path-with-query\22:{\22docs\22:\22Set the combination of the HTTP Path and Query for the Request.\5cnWhen `none`, this represents an empty Path and empty Query. Fails is the\5cnstring given is not a syntactically valid path and query uri component.\22},\22[method]outgoing-request.scheme\22:{\22docs\22:\22Get the HTTP Related Scheme for the Request. When `none`, the\5cnimplementation may choose an appropriate default scheme.\22},\22[method]outgoing-request.set-scheme\22:{\22docs\22:\22Set the HTTP Related Scheme for the Request. When `none`, the\5cnimplementation may choose an appropriate default scheme. Fails if the\5cnstring given is not a syntactically valid uri scheme.\22},\22[method]outgoing-request.authority\22:{\22docs\22:\22Get the HTTP Authority for the Request. A value of `none` may be used\5cnwith Related Schemes which do not require an Authority. The HTTP and\5cnHTTPS schemes always require an authority.\22},\22[method]outgoing-request.set-authority\22:{\22docs\22:\22Set the HTTP Authority for the Request. A value of `none` may be used\5cnwith Related Schemes which do not require an Authority. The HTTP and\5cnHTTPS schemes always require an authority. Fails if the string given is\5cnnot a syntactically valid uri authority.\22},\22[method]outgoing-request.headers\22:{\22docs\22:\22Get the headers associated with the Request.\5cn\5cnThe returned `headers` resource is immutable: `set`, `append`, and\5cn`delete` operations will fail with `header-error.immutable`.\5cn\5cnThis headers resource is a child: it must be dropped before the parent\5cn`outgoing-request` is dropped, or its ownership is transferred to\5cnanother component by e.g. `outgoing-handler.handle`.\22},\22[constructor]request-options\22:{\22docs\22:\22Construct a default `request-options` value.\22},\22[method]request-options.connect-timeout\22:{\22docs\22:\22The timeout for the initial connect to the HTTP Server.\22},\22[method]request-options.set-connect-timeout\22:{\22docs\22:\22Set the timeout for the initial connect to the HTTP Server. An error\5cnreturn value indicates that this timeout is not supported.\22},\22[method]request-options.first-byte-timeout\22:{\22docs\22:\22The timeout for receiving the first byte of the Response body.\22},\22[method]request-options.set-first-byte-timeout\22:{\22docs\22:\22Set the timeout for receiving the first byte of the Response body. An\5cnerror return value indicates that this timeout is not supported.\22},\22[method]request-options.between-bytes-timeout\22:{\22docs\22:\22The timeout for receiving subsequent chunks of bytes in the Response\5cnbody stream.\22},\22[method]request-options.set-between-bytes-timeout\22:{\22docs\22:\22Set the timeout for receiving subsequent chunks of bytes in the Response\5cnbody stream. An error return value indicates that this timeout is not\5cnsupported.\22},\22[static]response-outparam.set\22:{\22docs\22:\22Set the value of the `response-outparam` to either send a response,\5cnor indicate an error.\5cn\5cnThis method consumes the `response-outparam` to ensure that it is\5cncalled at most once. If it is never called, the implementation\5cnwill respond with an error.\5cn\5cnThe user may provide an `error` to `response` to allow the\5cnimplementation determine how to respond with an HTTP error response.\22},\22[method]incoming-response.status\22:{\22docs\22:\22Returns the status code from the incoming response.\22},\22[method]incoming-response.headers\22:{\22docs\22:\22Returns the headers from the incoming response.\5cn\5cnThe returned `headers` resource is immutable: `set`, `append`, and\5cn`delete` operations will fail with `header-error.immutable`.\5cn\5cnThis headers resource is a child: it must be dropped before the parent\5cn`incoming-response` is dropped.\22},\22[method]incoming-response.consume\22:{\22docs\22:\22Returns the incoming body. May be called at most once. Returns error\5cnif called additional times.\22},\22[method]incoming-body.stream\22:{\22docs\22:\22Returns the contents of the body, as a stream of bytes.\5cn\5cnReturns success on first call: the stream representing the contents\5cncan be retrieved at most once. Subsequent calls will return error.\5cn\5cnThe returned `input-stream` resource is a child: it must be dropped\5cnbefore the parent `incoming-body` is dropped, or consumed by\5cn`incoming-body.finish`.\5cn\5cnThis invariant ensures that the implementation can determine whether\5cnthe user is consuming the contents of the body, waiting on the\5cn`future-trailers` to be ready, or neither. This allows for network\5cnbackpressure is to be applied when the user is consuming the body,\5cnand for that backpressure to not inhibit delivery of the trailers if\5cnthe user does not read the entire body.\22},\22[static]incoming-body.finish\22:{\22docs\22:\22Takes ownership of `incoming-body`, and returns a `future-trailers`.\5cnThis function will trap if the `input-stream` child is still alive.\22},\22[method]future-trailers.subscribe\22:{\22docs\22:\22Returns a pollable which becomes ready when either the trailers have\5cnbeen received, or an error has occurred. When this pollable is ready,\5cnthe `get` method will return `some`.\22},\22[method]future-trailers.get\22:{\22docs\22:\22Returns the contents of the trailers, or an error which occurred,\5cnonce the future is ready.\5cn\5cnThe outer `option` represents future readiness. Users can wait on this\5cn`option` to become `some` using the `subscribe` method.\5cn\5cnThe outer `result` is used to retrieve the trailers or error at most\5cnonce. It will be success on the first call in which the outer option\5cnis `some`, and error on subsequent calls.\5cn\5cnThe inner `result` represents that either the HTTP Request or Response\5cnbody, as well as any trailers, were received successfully, or that an\5cnerror occurred receiving them. The optional `trailers` indicates whether\5cnor not trailers were present in the body.\5cn\5cnWhen some `trailers` are returned by this method, the `trailers`\5cnresource is immutable, and a child. Use of the `set`, `append`, or\5cn`delete` methods will return an error, and the resource must be\5cndropped before the parent `future-trailers` is dropped.\22},\22[constructor]outgoing-response\22:{\22docs\22:\22Construct an `outgoing-response`, with a default `status-code` of `200`.\5cnIf a different `status-code` is needed, it must be set via the\5cn`set-status-code` method.\5cn\5cn* `headers` is the HTTP Headers for the Response.\22},\22[method]outgoing-response.status-code\22:{\22docs\22:\22Get the HTTP Status Code for the Response.\22},\22[method]outgoing-response.set-status-code\22:{\22docs\22:\22Set the HTTP Status Code for the Response. Fails if the status-code\5cngiven is not a valid http status code.\22},\22[method]outgoing-response.headers\22:{\22docs\22:\22Get the headers associated with the Request.\5cn\5cnThe returned `headers` resource is immutable: `set`, `append`, and\5cn`delete` operations will fail with `header-error.immutable`.\5cn\5cnThis headers resource is a child: it must be dropped before the parent\5cn`outgoing-request` is dropped, or its ownership is transferred to\5cnanother component by e.g. `outgoing-handler.handle`.\22},\22[method]outgoing-response.body\22:{\22docs\22:\22Returns the resource corresponding to the outgoing Body for this Response.\5cn\5cnReturns success on the first call: the `outgoing-body` resource for\5cnthis `outgoing-response` can be retrieved at most once. Subsequent\5cncalls will return error.\22},\22[method]outgoing-body.write\22:{\22docs\22:\22Returns a stream for writing the body contents.\5cn\5cnThe returned `output-stream` is a child resource: it must be dropped\5cnbefore the parent `outgoing-body` resource is dropped (or finished),\5cnotherwise the `outgoing-body` drop or `finish` will trap.\5cn\5cnReturns success on the first call: the `output-stream` resource for\5cnthis `outgoing-body` may be retrieved at most once. Subsequent calls\5cnwill return error.\22},\22[static]outgoing-body.finish\22:{\22docs\22:\22Finalize an outgoing body, optionally providing trailers. This must be\5cncalled to signal that the response is complete. If the `outgoing-body`\5cnis dropped without calling `outgoing-body.finalize`, the implementation\5cnshould treat the body as corrupted.\5cn\5cnFails if the body's `outgoing-request` or `outgoing-response` was\5cnconstructed with a Content-Length header, and the contents written\5cnto the body (via `write`) does not match the value given in the\5cnContent-Length.\22},\22[method]future-incoming-response.subscribe\22:{\22docs\22:\22Returns a pollable which becomes ready when either the Response has\5cnbeen received, or an error has occurred. When this pollable is ready,\5cnthe `get` method will return `some`.\22},\22[method]future-incoming-response.get\22:{\22docs\22:\22Returns the incoming HTTP Response, or an error, once one is ready.\5cn\5cnThe outer `option` represents future readiness. Users can wait on this\5cn`option` to become `some` using the `subscribe` method.\5cn\5cnThe outer `result` is used to retrieve the response or error at most\5cnonce. It will be success on the first call in which the outer option\5cnis `some`, and error on subsequent calls.\5cn\5cnThe inner `result` represents that either the incoming HTTP Response\5cnstatus and headers have received successfully, or that an error\5cnoccurred. Errors may also occur while consuming the response body,\5cnbut those will be reported by the `incoming-body` and its\5cn`output-stream` child.\22}},\22types\22:{\22method\22:{\22docs\22:\22This type corresponds to HTTP standard Methods.\22},\22scheme\22:{\22docs\22:\22This type corresponds to HTTP standard Related Schemes.\22},\22DNS-error-payload\22:{\22docs\22:\22Defines the case payload type for `DNS-error` above:\22},\22TLS-alert-received-payload\22:{\22docs\22:\22Defines the case payload type for `TLS-alert-received` above:\22},\22field-size-payload\22:{\22docs\22:\22Defines the case payload type for `HTTP-response-{header,trailer}-size` above:\22},\22error-code\22:{\22docs\22:\22These cases are inspired by the IANA HTTP Proxy Error Types:\5cn https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types\22,\22items\22:{\22internal-error\22:\22This is a catch-all error for anything that doesn't fit cleanly into a\5cnmore specific case. It also includes an optional string for an\5cnunstructured description of the error. Users should not depend on the\5cnstring for diagnosing errors, as it's not required to be consistent\5cnbetween implementations.\22}},\22header-error\22:{\22docs\22:\22This type enumerates the different kinds of errors that may occur when\5cnsetting or appending to a `fields` resource.\22,\22items\22:{\22invalid-syntax\22:\22This error indicates that a `field-key` or `field-value` was\5cnsyntactically invalid when used with an operation that sets headers in a\5cn`fields`.\22,\22forbidden\22:\22This error indicates that a forbidden `field-key` was used when trying\5cnto set a header in a `fields`.\22,\22immutable\22:\22This error indicates that the operation on the `fields` was not\5cnpermitted because the fields are immutable.\22}},\22field-key\22:{\22docs\22:\22Field keys are always strings.\22},\22field-value\22:{\22docs\22:\22Field values should always be ASCII strings. However, in\5cnreality, HTTP implementations often have to interpret malformed values,\5cnso they are provided as a list of bytes.\22},\22fields\22:{\22docs\22:\22This following block defines the `fields` resource which corresponds to\5cnHTTP standard Fields. Fields are a common representation used for both\5cnHeaders and Trailers.\5cn\5cnA `fields` may be mutable or immutable. A `fields` created using the\5cnconstructor, `from-list`, or `clone` will be mutable, but a `fields`\5cnresource given by other means (including, but not limited to,\5cn`incoming-request.headers`, `outgoing-request.headers`) might be be\5cnimmutable. In an immutable fields, the `set`, `append`, and `delete`\5cnoperations will fail with `header-error.immutable`.\22},\22headers\22:{\22docs\22:\22Headers is an alias for Fields.\22},\22trailers\22:{\22docs\22:\22Trailers is an alias for Fields.\22},\22incoming-request\22:{\22docs\22:\22Represents an incoming HTTP Request.\22},\22outgoing-request\22:{\22docs\22:\22Represents an outgoing HTTP Request.\22},\22request-options\22:{\22docs\22:\22Parameters for making an HTTP Request. Each of these parameters is\5cncurrently an optional timeout applicable to the transport layer of the\5cnHTTP protocol.\5cn\5cnThese timeouts are separate from any the user may use to bound a\5cnblocking call to `wasi:io/poll.poll`.\22},\22response-outparam\22:{\22docs\22:\22Represents the ability to send an HTTP Response.\5cn\5cnThis resource is used by the `wasi:http/incoming-handler` interface to\5cnallow a Response to be sent corresponding to the Request provided as the\5cnother argument to `incoming-handler.handle`.\22},\22status-code\22:{\22docs\22:\22This type corresponds to the HTTP standard Status Code.\22},\22incoming-response\22:{\22docs\22:\22Represents an incoming HTTP Response.\22},\22incoming-body\22:{\22docs\22:\22Represents an incoming HTTP Request or Response's Body.\5cn\5cnA body has both its contents - a stream of bytes - and a (possibly\5cnempty) set of trailers, indicating that the full contents of the\5cnbody have been received. This resource represents the contents as\5cnan `input-stream` and the delivery of trailers as a `future-trailers`,\5cnand ensures that the user of this interface may only be consuming either\5cnthe body contents or waiting on trailers at any given time.\22},\22future-trailers\22:{\22docs\22:\22Represents a future which may eventually return trailers, or an error.\5cn\5cnIn the case that the incoming HTTP Request or Response did not have any\5cntrailers, this future will resolve to the empty set of trailers once the\5cncomplete Request or Response body has been received.\22},\22outgoing-response\22:{\22docs\22:\22Represents an outgoing HTTP Response.\22},\22outgoing-body\22:{\22docs\22:\22Represents an outgoing HTTP Request or Response's Body.\5cn\5cnA body has both its contents - a stream of bytes - and a (possibly\5cnempty) set of trailers, inducating the full contents of the body\5cnhave been sent. This resource represents the contents as an\5cn`output-stream` child resource, and the completion of the body (with\5cnoptional trailers) with a static function that consumes the\5cn`outgoing-body` resource, and ensures that the user of this interface\5cnmay not write to the body contents after the body has been finished.\5cn\5cnIf the user code drops this resource, as opposed to calling the static\5cnmethod `finish`, the implementation should treat the body as incomplete,\5cnand that an error has occurred. The implementation should propagate this\5cnerror to the HTTP protocol by whatever means it has available,\5cnincluding: corrupting the body on the wire, aborting the associated\5cnRequest, or sending a late status code for the Response.\22},\22future-incoming-response\22:{\22docs\22:\22Represents a future which may eventually return an incoming HTTP\5cnResponse, or an error.\5cn\5cnThis resource is returned by the `wasi:http/outgoing-handler` interface to\5cnprovide the HTTP Response corresponding to the sent Request.\22}}},\22incoming-handler\22:{\22docs\22:\22This interface defines a handler of incoming HTTP Requests. It should\5cnbe exported by components which can respond to HTTP Requests.\22,\22funcs\22:{\22handle\22:{\22docs\22:\22This function is invoked with an incoming HTTP Request, and a resource\5cn`response-outparam` which provides the capability to reply with an HTTP\5cnResponse. The response is sent by calling the `response-outparam.set`\5cnmethod, which allows execution to continue after the response has been\5cnsent. This enables both streaming to the response body, and performing other\5cnwork.\5cn\5cnThe implementor of this function must write a response to the\5cn`response-outparam` before returning, or else the caller will respond\5cnwith an error on its behalf.\22}}},\22outgoing-handler\22:{\22docs\22:\22This interface defines a handler of outgoing HTTP Requests. It should be\5cnimported by components which wish to make HTTP Requests.\22,\22funcs\22:{\22handle\22:{\22docs\22:\22This function is invoked with an outgoing HTTP Request, and it returns\5cna resource `future-incoming-response` which represents an HTTP Response\5cnwhich may arrive in the future.\5cn\5cnThe `options` argument accepts optional parameters for the HTTP\5cnprotocol's transport layer.\5cn\5cnThis function may return an error if the `outgoing-request` is invalid\5cnor not allowed to be made. Otherwise, protocol errors are reported\5cnthrough the `future-incoming-response`.\22}}}}}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/world-inline-interface.wat b/crates/wit-component/tests/interfaces/world-inline-interface.wat index 0c3d620169..281c5712a4 100644 --- a/crates/wit-component/tests/interfaces/world-inline-interface.wat +++ b/crates/wit-component/tests/interfaces/world-inline-interface.wat @@ -17,7 +17,7 @@ ) ) (export (;1;) "has-inline" (type 0)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/world-pkg-conflict.wat b/crates/wit-component/tests/interfaces/world-pkg-conflict.wat index 61b1a970ff..57e042a08b 100644 --- a/crates/wit-component/tests/interfaces/world-pkg-conflict.wat +++ b/crates/wit-component/tests/interfaces/world-pkg-conflict.wat @@ -40,7 +40,7 @@ ) ) (export (;5;) "c" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/world-top-level.wat b/crates/wit-component/tests/interfaces/world-top-level.wat index c496a5d0ee..ec2c1f3920 100644 --- a/crates/wit-component/tests/interfaces/world-top-level.wat +++ b/crates/wit-component/tests/interfaces/world-top-level.wat @@ -48,7 +48,7 @@ ) ) (export (;5;) "just-export" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-component/tests/interfaces/worlds-with-types.wat b/crates/wit-component/tests/interfaces/worlds-with-types.wat index b1d096e33b..677ea5aa08 100644 --- a/crates/wit-component/tests/interfaces/worlds-with-types.wat +++ b/crates/wit-component/tests/interfaces/worlds-with-types.wat @@ -49,7 +49,7 @@ ) ) (export (;5;) "with-imports" (type 4)) - (@custom "package-docs" "\01{}") + (@custom "package-docs" "\01{\22package\22:\22foo:foo\22}") (@producers (processed-by "wit-component" "$CARGO_PKG_VERSION") ) diff --git a/crates/wit-parser/src/decoding.rs b/crates/wit-parser/src/decoding.rs index feda2174ff..b210fbb5ba 100644 --- a/crates/wit-parser/src/decoding.rs +++ b/crates/wit-parser/src/decoding.rs @@ -26,8 +26,10 @@ struct ComponentInfo { types: types::Types, /// List of all imports and exports from this component. externs: Vec<(String, Extern)>, - /// Decoded package metadata - package_metadata: Option, + /// Decoded package metadata. A single component can carry one section per + /// package (each tagged with its [`PackageName`]) when produced by + /// `ComponentEncoder::encode`. + package_metadata: Vec, } struct DecodingExport { @@ -54,7 +56,7 @@ impl ComponentInfo { let mut externs = Vec::new(); let mut depth = 1; let mut types = None; - let mut _package_metadata = None; + let mut _package_metadata: Vec = Vec::new(); let mut cur = Parser::new(0); let mut eof = false; let mut stack = Vec::new(); @@ -116,12 +118,13 @@ impl ComponentInfo { )); } } + // Best-effort: a bad section just drops docs for one package. + // Multiple sections are allowed (one per package). #[cfg(feature = "serde")] Payload::CustomSection(s) if s.name() == PackageMetadata::SECTION_NAME => { - if _package_metadata.is_some() { - bail!("multiple {:?} sections", PackageMetadata::SECTION_NAME); + if let Ok(meta) = PackageMetadata::decode(s.data()) { + _package_metadata.push(meta); } - _package_metadata = Some(PackageMetadata::decode(s.data())?); } Payload::ModuleSection { parser, .. } | Payload::ComponentSection { parser, .. } => { @@ -210,8 +213,9 @@ impl ComponentInfo { let pkg = pkg.ok_or_else(|| anyhow!("no exported component type found"))?; let (mut resolve, package) = decoder.finish(pkg); - if let Some(package_metadata) = &self.package_metadata { - package_metadata.inject(&mut resolve, package)?; + for metadata in &self.package_metadata { + // Best-effort: a failure here just drops some docs. + let _ = metadata.inject(&mut resolve, package); } Ok((resolve, package)) } @@ -290,8 +294,9 @@ impl ComponentInfo { }; let (mut resolve, package) = decoder.finish(pkg); - if let Some(package_metadata) = &self.package_metadata { - package_metadata.inject(&mut resolve, package)?; + for metadata in &self.package_metadata { + // Best-effort: a failure here just drops some docs. + let _ = metadata.inject(&mut resolve, package); } Ok((resolve, package)) } @@ -344,8 +349,9 @@ impl ComponentInfo { } let (mut resolve, pkg) = decoder.finish(package); - if let Some(package_metadata) = &self.package_metadata { - package_metadata.inject(&mut resolve, pkg)?; + for metadata in &self.package_metadata { + // Best-effort: a failure here just drops some docs. + let _ = metadata.inject(&mut resolve, pkg); } Ok((resolve, world)) } @@ -429,6 +435,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 = None; for payload in Parser::new(0).parse_all(wasm) { let payload = payload?; @@ -451,6 +459,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(); + } _ => {} } } @@ -489,12 +507,18 @@ pub fn decode_world(wasm: &[u8]) -> Result<(Resolve, WorldId)> { worlds: &mut worlds, }, )?; - let (resolve, pkg) = decoder.finish(Package { + #[cfg_attr(not(feature = "serde"), allow(unused_mut))] + 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; diff --git a/crates/wit-parser/src/metadata.rs b/crates/wit-parser/src/metadata.rs index 46b6fec1a1..b4280d60e4 100644 --- a/crates/wit-parser/src/metadata.rs +++ b/crates/wit-parser/src/metadata.rs @@ -53,6 +53,16 @@ const TRY_TO_EMIT_V0_BY_DEFAULT: bool = false; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(deny_unknown_fields))] pub struct PackageMetadata { + /// The fully-qualified name of the package this metadata describes (the + /// [`crate::PackageName`] `Display` form, e.g. `wasi:logging@0.1.0`). When + /// set, [`inject`] looks the target up by this name instead of using the + /// caller-supplied [`PackageId`]; this lets a single component carry + /// metadata for multiple packages. + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] + package: Option, #[cfg_attr( feature = "serde", serde(default, skip_serializing_if = "Option::is_none") @@ -91,6 +101,7 @@ impl PackageMetadata { .collect(); Self { + package: Some(package.name.to_string()), docs: package.docs.contents.as_deref().map(Into::into), worlds, interfaces, @@ -99,22 +110,38 @@ impl PackageMetadata { /// Inject package docs for the given package. /// - /// This will override any existing docs in the [`Resolve`]. + /// If this metadata carries a package name, the target is looked up in + /// the resolve by that name (matched against [`crate::PackageName`] + /// `Display`) and the supplied `package` is used only as a fallback. This + /// will override any existing docs in the [`Resolve`]. pub fn inject(&self, resolve: &mut Resolve, package: PackageId) -> Result<()> { + let target = self + .package + .as_ref() + .and_then(|name| { + resolve + .package_names + .iter() + .find(|(pkg_name, _)| pkg_name.to_string() == *name) + .map(|(_, id)| *id) + }) + .unwrap_or(package); + // Items missing from the target package are skipped: a componentized + // resolve may drop the original world (it gets merged into the + // synthetic component world), but the interfaces still survive and + // their docs should still be applied. for (name, docs) in &self.worlds { - let Some(&id) = resolve.packages[package].worlds.get(name) else { - bail!("missing world {name:?}"); - }; - docs.inject(resolve, id)?; + if let Some(&id) = resolve.packages[target].worlds.get(name) { + let _ = docs.inject(resolve, id); + } } for (name, docs) in &self.interfaces { - let Some(&id) = resolve.packages[package].interfaces.get(name) else { - bail!("missing interface {name:?}"); - }; - docs.inject(resolve, id)?; + if let Some(&id) = resolve.packages[target].interfaces.get(name) { + let _ = docs.inject(resolve, id); + } } if let Some(docs) = &self.docs { - resolve.packages[package].docs.contents = Some(docs.to_string()); + resolve.packages[target].docs.contents = Some(docs.to_string()); } Ok(()) } @@ -155,6 +182,10 @@ impl PackageMetadata { Ok(serde_json::from_slice(&data[1..])?) } + pub fn is_empty(&self) -> bool { + self.docs.is_none() && self.worlds.is_empty() && self.interfaces.is_empty() + } + #[cfg(feature = "serde")] fn is_compatible_with_v0(&self) -> bool { self.worlds.iter().all(|(_, w)| w.is_compatible_with_v0()) diff --git a/tests/cli/component-embed-only-custom.wit.stdout b/tests/cli/component-embed-only-custom.wit.stdout index 74e8d4d90a..3615442584 100644 --- a/tests/cli/component-embed-only-custom.wit.stdout +++ b/tests/cli/component-embed-only-custom.wit.stdout @@ -1,5 +1,6 @@ (component (@custom "wit-component-encoding" "/04/00") + (@custom "package-docs" "/01{/22package/22:/22a:b/22,/22docs/22:/22RUN: component embed --only-custom -w foo % | print/22}") (type (;0;) (component (type (;0;) diff --git a/tests/cli/component-embed-preserves-docs.wit b/tests/cli/component-embed-preserves-docs.wit new file mode 100644 index 0000000000..4218f548ff --- /dev/null +++ b/tests/cli/component-embed-preserves-docs.wit @@ -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; +} diff --git a/tests/cli/component-embed-preserves-docs.wit.stdout b/tests/cli/component-embed-preserves-docs.wit.stdout new file mode 100644 index 0000000000..2a9865e7da --- /dev/null +++ b/tests/cli/component-embed-preserves-docs.wit.stdout @@ -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; + } +} diff --git a/tests/cli/component-wit-of-core-module.wit.stdout b/tests/cli/component-wit-of-core-module.wit.stdout index 6321454f2d..417b2a8760 100644 --- a/tests/cli/component-wit-of-core-module.wit.stdout +++ b/tests/cli/component-wit-of-core-module.wit.stdout @@ -5,6 +5,7 @@ world root { export y: func(); } +/// RUN: component embed --dummy % | component wit package a:b { world foo { import x: func(); diff --git a/tests/cli/dummy-async-future-export-with-named-type.wit.stdout b/tests/cli/dummy-async-future-export-with-named-type.wit.stdout index 41035914a4..955d7e7c37 100644 --- a/tests/cli/dummy-async-future-export-with-named-type.wit.stdout +++ b/tests/cli/dummy-async-future-export-with-named-type.wit.stdout @@ -1,3 +1,6 @@ +/// RUN: component embed % --dummy-names legacy --async-callback | / +/// component new | / +/// component wit package root:component; world root { diff --git a/tests/cli/dummy-async-indirect-task-return-with-named-type.wit.stdout b/tests/cli/dummy-async-indirect-task-return-with-named-type.wit.stdout index 5ceb3af412..824d5f1f23 100644 --- a/tests/cli/dummy-async-indirect-task-return-with-named-type.wit.stdout +++ b/tests/cli/dummy-async-indirect-task-return-with-named-type.wit.stdout @@ -1,3 +1,6 @@ +/// RUN: component embed % --dummy-names legacy --async-callback | / +/// component new | / +/// component wit package root:component; world root { diff --git a/tests/cli/dummy-async-valid-component1.wit.stdout b/tests/cli/dummy-async-valid-component1.wit.stdout index 68e186ea16..8774649a36 100644 --- a/tests/cli/dummy-async-valid-component1.wit.stdout +++ b/tests/cli/dummy-async-valid-component1.wit.stdout @@ -1,3 +1,6 @@ +/// RUN: component embed % --dummy-names legacy --async-callback | / +/// component new | / +/// component wit package root:component; world root { diff --git a/tests/cli/importize.wit.simple-component.stdout b/tests/cli/importize.wit.simple-component.stdout index f9a7f62d68..07fe789907 100644 --- a/tests/cli/importize.wit.simple-component.stdout +++ b/tests/cli/importize.wit.simple-component.stdout @@ -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; diff --git a/tests/cli/multiple-packages-one-world.wit.stdout b/tests/cli/multiple-packages-one-world.wit.stdout index 96952d2b86..6cadb2137d 100644 --- a/tests/cli/multiple-packages-one-world.wit.stdout +++ b/tests/cli/multiple-packages-one-world.wit.stdout @@ -19,6 +19,7 @@ package test:foo2 { } +/// RUN: component embed --dummy --wat % | component wit package foo:root { world hello { import test:foo1/bar; diff --git a/tests/cli/print-core-wasm-wit.wit.stdout b/tests/cli/print-core-wasm-wit.wit.stdout index 3cb25875b0..4316ffeced 100644 --- a/tests/cli/print-core-wasm-wit.wit.stdout +++ b/tests/cli/print-core-wasm-wit.wit.stdout @@ -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(); diff --git a/tests/cli/reparent-anonymous-interfaces-on-merge.wit.stdout b/tests/cli/reparent-anonymous-interfaces-on-merge.wit.stdout index 2b8ca640f6..71061ea653 100644 --- a/tests/cli/reparent-anonymous-interfaces-on-merge.wit.stdout +++ b/tests/cli/reparent-anonymous-interfaces-on-merge.wit.stdout @@ -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 { } diff --git a/tests/cli/semver-check-add-export.wit.stderr b/tests/cli/semver-check-add-export.wit.stderr index 75401ed650..bdb0df04ef 100644 --- a/tests/cli/semver-check-add-export.wit.stderr +++ b/tests/cli/semver-check-add-export.wit.stderr @@ -2,4 +2,4 @@ error: new world is not semver-compatible with the previous world Caused by: 0: type mismatch for import `new` - missing export named `a` (at offset 0x1d3) + missing export named `a` (at offset 0x232) diff --git a/tests/cli/semver-check-remove-import.wit.stderr b/tests/cli/semver-check-remove-import.wit.stderr index 1fc9bb0ac7..11b7a5ec31 100644 --- a/tests/cli/semver-check-remove-import.wit.stderr +++ b/tests/cli/semver-check-remove-import.wit.stderr @@ -2,4 +2,4 @@ error: new world is not semver-compatible with the previous world Caused by: 0: type mismatch for import `new` - missing import named `a` (at offset 0x20e) + missing import named `a` (at offset 0x26d) diff --git a/tests/cli/wit-deep-record.wit.abi.stderr b/tests/cli/wit-deep-record.wit.abi.stderr index 22fec7a96b..36c3f32394 100644 --- a/tests/cli/wit-deep-record.wit.abi.stderr +++ b/tests/cli/wit-deep-record.wit.abi.stderr @@ -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 0xa7) diff --git a/tests/cli/wit-deep-tuple.wit.abi.stderr b/tests/cli/wit-deep-tuple.wit.abi.stderr index 22fec7a96b..36c3f32394 100644 --- a/tests/cli/wit-deep-tuple.wit.abi.stderr +++ b/tests/cli/wit-deep-tuple.wit.abi.stderr @@ -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 0xa7) diff --git a/tests/cli/world-merge-add-resource-func.wit.stdout b/tests/cli/world-merge-add-resource-func.wit.stdout index 43a3bb6d90..ab85de6423 100644 --- a/tests/cli/world-merge-add-resource-func.wit.stdout +++ b/tests/cli/world-merge-add-resource-func.wit.stdout @@ -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; diff --git a/tests/cli/world-merging-add-imports.wit.stdout b/tests/cli/world-merging-add-imports.wit.stdout index 80d325e6c7..a7bd13fca9 100644 --- a/tests/cli/world-merging-add-imports.wit.stdout +++ b/tests/cli/world-merging-add-imports.wit.stdout @@ -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; diff --git a/tests/cli/world-merging-same-imports.wit.stdout b/tests/cli/world-merging-same-imports.wit.stdout index e5c366b4dc..06242da4ec 100644 --- a/tests/cli/world-merging-same-imports.wit.stdout +++ b/tests/cli/world-merging-same-imports.wit.stdout @@ -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; diff --git a/tests/cli/world-merging.wit.stdout b/tests/cli/world-merging.wit.stdout index d18e6f53cd..b59da0a717 100644 --- a/tests/cli/world-merging.wit.stdout +++ b/tests/cli/world-merging.wit.stdout @@ -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;