Repository: bytecodealliance/wasm-tools
Pull request #1599 (2024-06-09 20:41:37)

wasm-tools, wit-parser: add --all-features to enable all features gated with @unstable
This PR adds the `--all-features` option to `wasm-tools component`, primarily so `wasm-tools component wit -j` can emit a JSON representation of the original WIT with all `@unstable` gated features intact.

It additionally adds support for `--features .` as an alias for `--all-features`.

Originally proposed here: https://bytecodealliance.zulipchat.com/#narrow/stream/327223-wit-bindgen/topic/wit-parser.20crate.3A.20JSON.20format.20changes/near/443516048


Patch:
diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs
index e227f7fc..72e0857b 100644
--- a/crates/wit-parser/src/lib.rs
+++ b/crates/wit-parser/src/lib.rs
@@ -827,7 +827,7 @@ impl Function {
 /// annotations were added to WIT.
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "serde", derive(serde_derive::Deserialize, Serialize))]
-#[cfg_attr(feature = "serde", serde(rename_all = "lowercase", tag = "type"))]
+#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
 pub enum Stability {
     /// `@since(version = 1.2.3)`
     ///
diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs
index 8a34a8e6..a41290a6 100644
--- a/crates/wit-parser/src/resolve.rs
+++ b/crates/wit-parser/src/resolve.rs
@@ -74,6 +74,10 @@ pub struct Resolve {
     /// set.
     #[cfg_attr(feature = "serde", serde(skip))]
     pub features: IndexSet<String>,
+
+    /// Activate all features for this [`Resolve`].
+    #[cfg_attr(feature = "serde", serde(skip))]
+    pub all_features: bool,
 }
 
 /// A WIT package within a `Resolve`.
@@ -1142,7 +1146,7 @@ impl Resolve {
     fn include_stability(&self, stability: &Stability) -> bool {
         match stability {
             Stability::Stable { .. } | Stability::Unknown => true,
-            Stability::Unstable { feature } => self.features.contains(feature),
+            Stability::Unstable { feature } => self.features.contains(feature) || self.all_features,
         }
     }
 }
diff --git a/src/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs
index b238adf4..5d759df4 100644
--- a/src/bin/wasm-tools/component.rs
+++ b/src/bin/wasm-tools/component.rs
@@ -182,11 +182,19 @@ struct WitResolve {
     /// items are otherwise hidden by default.
     #[clap(long)]
     features: Vec<String>,
+
+    /// Enable all features when parsing the `wit` option.
+    ///
+    /// This flag enables all `@unstable` features in WIT documents where the
+    /// items are otherwise hidden by default.
+    #[clap(long)]
+    all_features: bool,
 }
 
 impl WitResolve {
-    fn resolve_with_features(features: &[String]) -> Resolve {
+    fn resolve_with_features(features: &[String], all_features: bool) -> Resolve {
         let mut resolve = Resolve::default();
+        resolve.all_features = all_features;
         for feature in features {
             for f in feature.split_whitespace() {
                 for f in f.split(',').filter(|s| !s.is_empty()) {
@@ -198,7 +206,7 @@ impl WitResolve {
     }
 
     fn load(&self) -> Result<(Resolve, Vec<PackageId>)> {
-        let mut resolve = Self::resolve_with_features(&self.features);
+        let mut resolve = Self::resolve_with_features(&self.features, self.all_features);
         let (pkg_ids, _) = resolve.push_path(&self.wit)?;
         Ok((resolve, pkg_ids))
     }
@@ -494,6 +502,13 @@ pub struct WitOpts {
     /// items are otherwise hidden by default.
     #[clap(long)]
     features: Vec<String>,
+
+    /// Enable all features when parsing the `wit` option.
+    ///
+    /// This flag enables all `@unstable` features in WIT documents where the
+    /// items are otherwise hidden by default.
+    #[clap(long)]
+    all_features: bool,
 }
 
 impl WitOpts {
@@ -524,7 +539,8 @@ impl WitOpts {
         // `parse_wit_from_path`.
         if let Some(input) = &self.input {
             if input.is_dir() {
-                let mut resolve = WitResolve::resolve_with_features(&self.features);
+                let mut resolve =
+                    WitResolve::resolve_with_features(&self.features, self.all_features);
                 let (pkg_ids, _) = resolve.push_dir(&input)?;
                 return Ok(DecodedWasm::WitPackages(resolve, pkg_ids));
             }
@@ -572,7 +588,8 @@ impl WitOpts {
                     Ok(s) => s,
                     Err(_) => bail!("input was not valid utf-8"),
                 };
-                let mut resolve = WitResolve::resolve_with_features(&self.features);
+                let mut resolve =
+                    WitResolve::resolve_with_features(&self.features, self.all_features);
                 let pkgs = UnresolvedPackageGroup::parse(path, input)?;
                 let ids = resolve.append(pkgs)?;
                 Ok(DecodedWasm::WitPackages(resolve, ids))


Test patch:
diff --git a/crates/wit-parser/tests/ui/feature-gates.wit.json b/crates/wit-parser/tests/ui/feature-gates.wit.json
index e211f045..9cdb44c5 100644
--- a/crates/wit-parser/tests/ui/feature-gates.wit.json
+++ b/crates/wit-parser/tests/ui/feature-gates.wit.json
@@ -7,8 +7,9 @@
           "interface": {
             "id": 4,
             "stability": {
-              "type": "unstable",
-              "feature": "active"
+              "unstable": {
+                "feature": "active"
+              }
             }
           }
         }
@@ -18,16 +19,18 @@
           "interface": {
             "id": 4,
             "stability": {
-              "type": "unstable",
-              "feature": "active"
+              "unstable": {
+                "feature": "active"
+              }
             }
           }
         }
       },
       "package": 0,
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       }
     },
     {
@@ -37,8 +40,9 @@
           "interface": {
             "id": 4,
             "stability": {
-              "type": "unstable",
-              "feature": "active"
+              "unstable": {
+                "feature": "active"
+              }
             }
           }
         }
@@ -48,8 +52,9 @@
           "interface": {
             "id": 4,
             "stability": {
-              "type": "unstable",
-              "feature": "active"
+              "unstable": {
+                "feature": "active"
+              }
             }
           }
         }
@@ -68,14 +73,16 @@
           "params": [],
           "results": [],
           "stability": {
-            "type": "unstable",
-            "feature": "active"
+            "unstable": {
+              "feature": "active"
+            }
           }
         }
       },
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       },
       "package": 0
     },
@@ -87,8 +94,9 @@
       },
       "functions": {},
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       },
       "package": 0
     },
@@ -99,8 +107,9 @@
       },
       "functions": {},
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       },
       "package": 0
     },
@@ -111,8 +120,9 @@
       },
       "functions": {},
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       },
       "package": 0
     },
@@ -121,8 +131,9 @@
       "types": {},
       "functions": {},
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       },
       "package": 0
     },
@@ -144,8 +155,9 @@
             }
           ],
           "stability": {
-            "type": "unstable",
-            "feature": "active"
+            "unstable": {
+              "feature": "active"
+            }
           }
         },
         "[static]ungated.x": {
@@ -156,8 +168,9 @@
           "params": [],
           "results": [],
           "stability": {
-            "type": "unstable",
-            "feature": "active"
+            "unstable": {
+              "feature": "active"
+            }
           }
         },
         "[method]ungated.y": {
@@ -173,8 +186,9 @@
           ],
           "results": [],
           "stability": {
-            "type": "unstable",
-            "feature": "active"
+            "unstable": {
+              "feature": "active"
+            }
           }
         }
       },
@@ -191,8 +205,9 @@
         "interface": 1
       },
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       }
     },
     {
@@ -204,8 +219,9 @@
         "interface": 1
       },
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       }
     },
     {
@@ -217,8 +233,9 @@
         "interface": 2
       },
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       }
     },
     {
@@ -230,8 +247,9 @@
         "interface": 3
       },
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       }
     },
     {
@@ -241,8 +259,9 @@
         "interface": 5
       },
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       }
     },
     {
@@ -254,8 +273,9 @@
       },
       "owner": null,
       "stability": {
-        "type": "unstable",
-        "feature": "active"
+        "unstable": {
+          "feature": "active"
+        }
       }
     },
     {
diff --git a/crates/wit-parser/tests/ui/since-and-unstable.wit.json b/crates/wit-parser/tests/ui/since-and-unstable.wit.json
index c5efc938..31c4fa0c 100644
--- a/crates/wit-parser/tests/ui/since-and-unstable.wit.json
+++ b/crates/wit-parser/tests/ui/since-and-unstable.wit.json
@@ -6,8 +6,9 @@
       "exports": {},
       "package": 0,
       "stability": {
-        "type": "stable",
-        "since": "1.0.1"
+        "stable": {
+          "since": "1.0.1"
+        }
       }
     },
     {
@@ -16,8 +17,9 @@
       "exports": {},
       "package": 0,
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -27,8 +29,9 @@
           "interface": {
             "id": 5,
             "stability": {
-              "type": "stable",
-              "since": "1.0.0"
+              "stable": {
+                "since": "1.0.0"
+              }
             }
           }
         },
@@ -36,8 +39,9 @@
           "interface": {
             "id": 4,
             "stability": {
-              "type": "stable",
-              "since": "1.0.0"
+              "stable": {
+                "since": "1.0.0"
+              }
             }
           }
         },
@@ -69,8 +73,9 @@
             "params": [],
             "results": [],
             "stability": {
-              "type": "stable",
-              "since": "1.0.0"
+              "stable": {
+                "since": "1.0.0"
+              }
             }
           }
         },
@@ -87,8 +92,9 @@
               }
             ],
             "stability": {
-              "type": "stable",
-              "since": "1.0.0"
+              "stable": {
+                "since": "1.0.0"
+              }
             }
           }
         }
@@ -101,8 +107,9 @@
             "params": [],
             "results": [],
             "stability": {
-              "type": "stable",
-              "since": "1.0.0"
+              "stable": {
+                "since": "1.0.0"
+              }
             }
           }
         },
@@ -110,8 +117,9 @@
           "interface": {
             "id": 6,
             "stability": {
-              "type": "stable",
-              "since": "1.0.0"
+              "stable": {
+                "since": "1.0.0"
+              }
             }
           }
         },
@@ -119,8 +127,9 @@
           "interface": {
             "id": 4,
             "stability": {
-              "type": "stable",
-              "since": "1.0.0"
+              "stable": {
+                "since": "1.0.0"
+              }
             }
           }
         }
@@ -134,8 +143,9 @@
       "types": {},
       "functions": {},
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       },
       "package": 0
     },
@@ -144,9 +154,10 @@
       "types": {},
       "functions": {},
       "stability": {
-        "type": "stable",
-        "since": "1.0.0",
-        "feature": "foo"
+        "stable": {
+          "since": "1.0.0",
+          "feature": "foo"
+        }
       },
       "package": 0
     },
@@ -155,9 +166,10 @@
       "types": {},
       "functions": {},
       "stability": {
-        "type": "stable",
-        "since": "1.0.0",
-        "feature": "foo-bar"
+        "stable": {
+          "since": "1.0.0",
+          "feature": "foo-bar"
+        }
       },
       "package": 0
     },
@@ -180,8 +192,9 @@
           "params": [],
           "results": [],
           "stability": {
-            "type": "stable",
-            "since": "1.0.0"
+            "stable": {
+              "since": "1.0.0"
+            }
           }
         },
         "[constructor]r3": {
@@ -196,8 +209,9 @@
             }
           ],
           "stability": {
-            "type": "stable",
-            "since": "1.0.0"
+            "stable": {
+              "since": "1.0.0"
+            }
           }
         },
         "[static]r3.x1": {
@@ -208,8 +222,9 @@
           "params": [],
           "results": [],
           "stability": {
-            "type": "stable",
-            "since": "1.0.0"
+            "stable": {
+              "since": "1.0.0"
+            }
           }
         },
         "[method]r3.x2": {
@@ -225,8 +240,9 @@
           ],
           "results": [],
           "stability": {
-            "type": "stable",
-            "since": "1.0.0"
+            "stable": {
+              "since": "1.0.0"
+            }
           }
         }
       },
@@ -243,8 +259,9 @@
       "types": {},
       "functions": {},
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       },
       "package": 0
     },
@@ -253,8 +270,9 @@
       "types": {},
       "functions": {},
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       },
       "package": 0
     }
@@ -267,8 +285,9 @@
         "interface": 3
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -278,8 +297,9 @@
         "interface": 3
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -291,8 +311,9 @@
         "interface": 3
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -311,8 +332,9 @@
         "interface": 3
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -330,8 +352,9 @@
         "interface": 3
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -349,8 +372,9 @@
         "interface": 3
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -369,8 +393,9 @@
         "interface": 3
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -380,8 +405,9 @@
         "interface": 3
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -393,8 +419,9 @@
       },
       "owner": null,
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -413,8 +440,9 @@
         "world": 2
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -432,8 +460,9 @@
         "world": 2
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -452,8 +481,9 @@
         "world": 2
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -471,8 +501,9 @@
         "world": 2
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -484,8 +515,9 @@
         "world": 2
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -495,8 +527,9 @@
         "world": 2
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
@@ -506,8 +539,9 @@
         "world": 2
       },
       "stability": {
-        "type": "stable",
-        "since": "1.0.0"
+        "stable": {
+          "since": "1.0.0"
+        }
       }
     },
     {
diff --git a/tests/cli/wit-with-all-features.wit b/tests/cli/wit-with-all-features.wit
new file mode 100644
index 00000000..cdae70c7
--- /dev/null
+++ b/tests/cli/wit-with-all-features.wit
@@ -0,0 +1,18 @@
+// RUN: component wit --all-features %
+
+package a:b;
+
+@unstable(feature = foo)
+interface foo {
+  @unstable(feature = foo)
+  type t = u32;
+}
+
+@unstable(feature = bar)
+interface bar {
+  @unstable(feature = baz)
+  use foo.{t};
+
+  @unstable(feature = qux)
+  record x { y: t }
+}
diff --git a/tests/cli/wit-with-all-features.wit.stdout b/tests/cli/wit-with-all-features.wit.stdout
new file mode 100644
index 00000000..a193ef77
--- /dev/null
+++ b/tests/cli/wit-with-all-features.wit.stdout
@@ -0,0 +1,20 @@
+/// RUN: component wit --all-features %
+package a:b;
+
+@unstable(feature = foo)
+interface foo {
+  @unstable(feature = foo)
+  type t = u32;
+}
+
+@unstable(feature = bar)
+interface bar {
+  @unstable(feature = baz)
+  use foo.{t};
+
+  @unstable(feature = qux)
+  record x {
+    y: t,
+  }
+}
+