From 5457e0f331fa9d92011a957aefad0ed7539daecf Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 05:37:50 -0600 Subject: [PATCH 1/7] feat: output json ast --- Cargo.toml | 5 ++ crates/gen-guest-js/src/lib.rs | 6 +- crates/gen-guest-rust/src/lib.rs | 2 +- crates/gen-guest-ts/src/lib.rs | 16 ++--- crates/gen-host/src/lib.rs | 2 +- crates/gen-js/src/lib.rs | 12 ++-- crates/gen-markdown/src/lib.rs | 16 ++--- crates/gen-rust/src/lib.rs | 10 ++-- crates/wit-parser/Cargo.toml | 2 + crates/wit-parser/src/lib.rs | 96 +++++++++++++++++++++++++----- crates/wit-parser/src/typecheck.rs | 18 ++++-- src/main.rs | 28 +++++++++ 12 files changed, 158 insertions(+), 55 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7d20be82..0e3a6828 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ serde = "1.0.188" quote = "1.0.33" proc-macro2 = "1.0.67" syn = "2.0.33" +schemars = "0.8.12" [dependencies] clap.workspace = true @@ -47,6 +48,10 @@ miette.workspace = true env_logger = "0.10.0" log.workspace = true clap_complete = "4.4.1" +serde_json = "1.0" + +[dev-dependencies] +schemars = { version = "0.8.12", features = ["impl_json_schema"] } [features] unstable = ["dep:tauri-bindgen-gen-markdown"] diff --git a/crates/gen-guest-js/src/lib.rs b/crates/gen-guest-js/src/lib.rs index 920125cb..12014f09 100644 --- a/crates/gen-guest-js/src/lib.rs +++ b/crates/gen-guest-js/src/lib.rs @@ -48,8 +48,8 @@ pub struct JavaScript { impl JavaScript { fn print_function(&self, intf_name: &str, func: &Function) -> String { let docs = self.print_docs(func); - let ident = func.ident.to_lower_camel_case(); - let name = func.ident.to_snake_case(); + let ident = func.id.to_lower_camel_case(); + let name = func.id.to_snake_case(); let params = print_function_params(&func.params); let deserialize_result = func @@ -91,7 +91,7 @@ export async function {ident} ({params}) {{ .iter() .map(|func| { let docs = self.print_docs(func); - let ident = func.ident.to_lower_camel_case(); + let ident = func.id.to_lower_camel_case(); let params = print_function_params(&func.params); format!( diff --git a/crates/gen-guest-rust/src/lib.rs b/crates/gen-guest-rust/src/lib.rs index b3fdc8a4..d99e1c1f 100644 --- a/crates/gen-guest-rust/src/lib.rs +++ b/crates/gen-guest-rust/src/lib.rs @@ -67,7 +67,7 @@ impl RustWasm { &BorrowMode::Owned, ); - let ident = func.ident.to_snake_case(); + let ident = func.id.to_snake_case(); let param_idents = func .params diff --git a/crates/gen-guest-ts/src/lib.rs b/crates/gen-guest-ts/src/lib.rs index 3db55494..7487eabf 100644 --- a/crates/gen-guest-ts/src/lib.rs +++ b/crates/gen-guest-ts/src/lib.rs @@ -57,8 +57,8 @@ impl TypeScript { pub fn print_function(&self, intf_name: &str, func: &Function) -> String { let docs = print_docs(&func.docs); - let ident = func.ident.to_lower_camel_case(); - let name = func.ident.to_snake_case(); + let ident = func.id.to_lower_camel_case(); + let name = func.id.to_snake_case(); let params = self.print_function_params(&func.params); @@ -204,7 +204,7 @@ export async function {ident} ({params}) : {result} {{ .iter() .map(|field| { let docs = print_docs(&field.docs); - let ident = field.ident.to_lower_camel_case(); + let ident = field.id.to_lower_camel_case(); let ty = self.print_type(&field.ty); format!("{docs}\n{ident}: {ty},\n") @@ -220,7 +220,7 @@ export async function {ident} ({params}) : {result} {{ .enumerate() .map(|(i, field)| { let docs = print_docs(&field.docs); - let ident = field.ident.to_upper_camel_case(); + let ident = field.id.to_upper_camel_case(); let value: u64 = 2 << i; format!("{docs}\n{ident} = {value},\n") @@ -236,7 +236,7 @@ export async function {ident} ({params}) : {result} {{ .enumerate() .map(|(i, case)| { let docs = print_docs(&case.docs); - let case_ident = case.ident.to_upper_camel_case(); + let case_ident = case.id.to_upper_camel_case(); let value = case .ty .as_ref() @@ -254,7 +254,7 @@ export async function {ident} ({params}) : {result} {{ .iter() .map(|case| { let docs = print_docs(&case.docs); - let case_ident = case.ident.to_upper_camel_case(); + let case_ident = case.id.to_upper_camel_case(); format!("{docs}\n{ident}{case_ident}") }) @@ -269,7 +269,7 @@ export async function {ident} ({params}) : {result} {{ .iter() .map(|case| { let docs = print_docs(&case.docs); - let ident = case.ident.to_upper_camel_case(); + let ident = case.id.to_upper_camel_case(); format!("{docs}\n{ident},\n") }) @@ -299,7 +299,7 @@ export async function {ident} ({params}) : {result} {{ .map(|func| { let docs = print_docs(&func.docs); - let ident = func.ident.to_lower_camel_case(); + let ident = func.id.to_lower_camel_case(); let params = self.print_function_params(&func.params); let result = func diff --git a/crates/gen-host/src/lib.rs b/crates/gen-host/src/lib.rs index ee9a4412..f0c0260b 100644 --- a/crates/gen-host/src/lib.rs +++ b/crates/gen-host/src/lib.rs @@ -299,7 +299,7 @@ impl Host { let mod_name = mod_ident.to_snake_case(); let functions = functions.map(|func| { - let func_name = func.ident.to_snake_case(); + let func_name = func.id.to_snake_case(); let func_ident = format_ident!("{}", func_name); let params = self.print_function_params(&func.params, &BorrowMode::Owned); diff --git a/crates/gen-js/src/lib.rs b/crates/gen-js/src/lib.rs index e5a230be..35ac3e4b 100644 --- a/crates/gen-js/src/lib.rs +++ b/crates/gen-js/src/lib.rs @@ -135,7 +135,7 @@ pub trait JavaScriptGenerator { let fields = fields .iter() .map(|field| { - let ident = field.ident.to_lower_camel_case(); + let ident = field.id.to_lower_camel_case(); format!("{ident}: {}", self.print_deserialize_ty(&field.ty)) }) @@ -177,7 +177,7 @@ pub trait JavaScriptGenerator { .as_ref() .map_or("null".to_string(), |ty| self.print_deserialize_ty(ty)); - let ident = case.ident.to_upper_camel_case(); + let ident = case.id.to_upper_camel_case(); format!( "case {tag}: @@ -205,7 +205,7 @@ pub trait JavaScriptGenerator { .iter() .enumerate() .map(|(tag, case)| { - let ident = case.ident.to_upper_camel_case(); + let ident = case.id.to_upper_camel_case(); format!( "case {tag}: return \"{ident}\" @@ -346,7 +346,7 @@ pub trait JavaScriptGenerator { fn print_serialize_record(&self, ident: &str, fields: &[RecordField]) -> String { let inner = fields .iter() - .map(|field| self.print_serialize_ty(&format!("val.{}", field.ident), &field.ty)) + .map(|field| self.print_serialize_ty(&format!("val.{}", field.id), &field.ty)) .collect::>() .join(",\n"); @@ -378,7 +378,7 @@ pub trait JavaScriptGenerator { .iter() .enumerate() .map(|(tag, case)| { - let prop_access = format!("val.{}", case.ident.to_upper_camel_case()); + let prop_access = format!("val.{}", case.id.to_upper_camel_case()); let inner = case.ty.as_ref().map_or(String::new(), |ty| { self.print_serialize_ty(&prop_access, ty) @@ -408,7 +408,7 @@ pub trait JavaScriptGenerator { .iter() .enumerate() .map(|(tag, case)| { - let ident = case.ident.to_upper_camel_case(); + let ident = case.id.to_upper_camel_case(); format!( "case \"{ident}\": serializeU32(out, {tag}) diff --git a/crates/gen-markdown/src/lib.rs b/crates/gen-markdown/src/lib.rs index 7314bbf5..03167ceb 100644 --- a/crates/gen-markdown/src/lib.rs +++ b/crates/gen-markdown/src/lib.rs @@ -88,7 +88,7 @@ impl Markdown { .map(|field| { format!( "#### {ident}: `{ty}`\n{docs}\n", - ident = field.ident, + ident = field.id, ty = self.print_ty(&field.ty), docs = field.docs ) @@ -103,7 +103,7 @@ impl Markdown { .map(|field| { format!( "#### {ident}\n{docs}\n", - ident = field.ident, + ident = field.id, docs = field.docs ) }) @@ -117,7 +117,7 @@ impl Markdown { .map(|case| { format!( "#### {ident}{ty}\n{docs}\n", - ident = case.ident, + ident = case.id, ty = case .ty .as_ref() @@ -134,11 +134,7 @@ impl Markdown { let cases = cases .iter() .map(|case| { - format!( - "#### {ident}\n{docs}\n", - ident = case.ident, - docs = case.docs - ) + format!("#### {ident}\n{docs}\n", ident = case.id, docs = case.docs) }) .collect::(); @@ -164,7 +160,7 @@ impl Markdown { .map(|func| { format!( "### Method {ident}\n\n`func {ident} ({params}){result}`\n\n{docs}", - ident = func.ident, + ident = func.id, params = self.print_named_types(&func.params), result = func .result @@ -184,7 +180,7 @@ impl Markdown { fn print_function(&self, func: &Function) -> String { format!( "### Function {ident}\n\n` func {ident} ({params}){result}`\n\n{docs}", - ident = func.ident, + ident = func.id, params = self.print_named_types(&func.params), result = func .result diff --git a/crates/gen-rust/src/lib.rs b/crates/gen-rust/src/lib.rs index de955391..33772020 100644 --- a/crates/gen-rust/src/lib.rs +++ b/crates/gen-rust/src/lib.rs @@ -223,7 +223,7 @@ pub trait RustGenerator { let borrow_attr = self .needs_borrow(&field.ty, mode) .then_some(quote! { #[serde(borrow)] }); - let ident = format_ident!("{}", field.ident.to_snake_case()); + let ident = format_ident!("{}", field.id.to_snake_case()); let ty = self.print_ty(&field.ty, mode); quote! { @@ -247,7 +247,7 @@ pub trait RustGenerator { let fields = fields .iter() .enumerate() - .map(|(i, FlagsField { docs, ident })| { + .map(|(i, FlagsField { docs, id: ident })| { let docs = self.print_docs(docs); let ident = format_ident!("{}", ident.TO_SHOUTY_SNEK_CASE()); let i = Literal::usize_unsuffixed(i); @@ -294,7 +294,7 @@ pub trait RustGenerator { fn print_variant_case(&self, case: &VariantCase, mode: &BorrowMode) -> TokenStream { let docs = self.print_docs(&case.docs); - let ident = format_ident!("{}", case.ident.to_upper_camel_case()); + let ident = format_ident!("{}", case.id.to_upper_camel_case()); let payload = case.ty.as_ref().map(|ty| { let ty = self.print_ty(ty, mode); @@ -331,7 +331,7 @@ pub trait RustGenerator { fn print_enum_case(&self, case: &EnumCase) -> TokenStream { let docs = self.print_docs(&case.docs); - let ident = format_ident!("{}", case.ident.to_upper_camel_case()); + let ident = format_ident!("{}", case.id.to_upper_camel_case()); quote! { #docs @@ -382,7 +382,7 @@ pub trait RustGenerator { results_mode: &BorrowMode, ) -> TokenStream { let docs = self.print_docs(&sig.func.docs); - let ident = format_ident!("{}", sig.func.ident.to_snake_case()); + let ident = format_ident!("{}", sig.func.id.to_snake_case()); let pub_ = (!sig.private).then_some(quote! { pub }); let unsafe_ = sig.unsafe_.then_some(quote! { unsafe }); diff --git a/crates/wit-parser/Cargo.toml b/crates/wit-parser/Cargo.toml index ee425eff..d234a3b2 100644 --- a/crates/wit-parser/Cargo.toml +++ b/crates/wit-parser/Cargo.toml @@ -13,6 +13,8 @@ id-arena = "2.2.1" miette.workspace = true distance = "0.4.0" log.workspace = true +serde = { workspace = true, features = ["derive"] } +schemars.workspace = true [dev-dependencies] pretty_assertions = "1.4.0" diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs index 9b4885ed..ab3cdb10 100644 --- a/crates/wit-parser/src/lib.rs +++ b/crates/wit-parser/src/lib.rs @@ -16,6 +16,8 @@ use id_arena::{Arena, Id}; use logos::Logos; use miette::{ErrReport, IntoDiagnostic, NamedSource}; use parse::FromTokens; +use schemars::JsonSchema; +use serde::{ser::SerializeSeq, Serialize}; use std::path::Path; use typecheck::Resolver; use util::detect_invalid_input; @@ -74,15 +76,19 @@ pub enum Int { U128, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] pub struct Interface { + #[serde(skip_serializing_if = "String::is_empty")] pub docs: String, pub ident: String, + #[serde(serialize_with = "serialize_typedefs")] + #[schemars(with = "Vec")] pub typedefs: Arena, pub functions: Vec, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] +#[serde(rename_all = "lowercase", tag = "type", content = "value")] pub enum Type { Bool, U8, @@ -106,17 +112,22 @@ pub enum Type { ok: Option>, err: Option>, }, + #[serde(serialize_with = "serialize_id")] + #[schemars(with = "u32")] Id(Id), } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] pub struct TypeDef { + #[serde(skip_serializing_if = "String::is_empty")] pub docs: String, pub ident: String, + #[serde(flatten)] pub kind: TypeDefKind, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] +#[serde(rename_all = "lowercase", tag = "type", content = "value")] pub enum TypeDefKind { Alias(Type), Record(Vec), @@ -127,42 +138,50 @@ pub enum TypeDefKind { Resource(Vec), } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] pub struct RecordField { + #[serde(skip_serializing_if = "String::is_empty")] pub docs: String, - pub ident: String, + pub id: String, pub ty: Type, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] pub struct FlagsField { + #[serde(skip_serializing_if = "String::is_empty")] pub docs: String, - pub ident: String, + pub id: String, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] pub struct VariantCase { + #[serde(skip_serializing_if = "String::is_empty")] pub docs: String, - pub ident: String, + pub id: String, pub ty: Option, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] pub struct EnumCase { + #[serde(skip_serializing_if = "String::is_empty")] pub docs: String, - pub ident: String, + pub id: String, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] pub struct UnionCase { + #[serde(skip_serializing_if = "String::is_empty")] pub docs: String, pub ty: Type, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] pub struct Function { + #[serde(skip_serializing_if = "String::is_empty")] pub docs: String, - pub ident: String, + pub id: String, + #[serde(serialize_with = "serialize_named_type_list")] + #[schemars(with = "Vec")] pub params: NamedTypeList, pub result: Option, } @@ -180,9 +199,12 @@ impl Function { pub type NamedTypeList = Vec<(String, Type)>; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] +#[serde(untagged)] pub enum FunctionResult { Anon(Type), + #[serde(serialize_with = "serialize_named_type_list")] + #[schemars(with = "Vec")] Named(NamedTypeList), } @@ -223,3 +245,45 @@ impl<'a> Iterator for ResultsTypeIter<'a> { } } } + +fn serialize_typedefs(typedefs: &Arena, s: S) -> std::result::Result +where + S: serde::Serializer, +{ + let mut s = s.serialize_seq(Some(typedefs.len()))?; + + for (_, typedef) in typedefs { + s.serialize_element(typedef)?; + } + + s.end() +} + +fn serialize_id(id: &Id, serializer: S) -> std::result::Result +where + S: serde::Serializer, +{ + serializer.serialize_u32(u32::try_from(id.index()).unwrap()) +} +#[derive(Serialize, JsonSchema)] +struct NamedType<'a> { + id: &'a str, + #[serde(flatten)] + r#type: &'a Type, +} + +fn serialize_named_type_list( + named_types: &Vec<(String, Type)>, + s: S, +) -> std::result::Result +where + S: serde::Serializer, +{ + let mut s = s.serialize_seq(Some(named_types.len()))?; + + for (id, r#type) in named_types { + s.serialize_element(&NamedType { id, r#type })?; + } + + s.end() +} diff --git a/crates/wit-parser/src/typecheck.rs b/crates/wit-parser/src/typecheck.rs index afe26c4c..bbbb3489 100644 --- a/crates/wit-parser/src/typecheck.rs +++ b/crates/wit-parser/src/typecheck.rs @@ -101,7 +101,11 @@ impl<'a> Resolver<'a> { let ident = self.resolve_ident(&field.ident).to_string(); let ty = self.resolve_type(&field.ty)?; - Ok(RecordField { docs, ident, ty }) + Ok(RecordField { + docs, + id: ident, + ty, + }) }) .partition_result::<_, Error>()?; @@ -112,7 +116,7 @@ impl<'a> Resolver<'a> { let docs = self.resolve_docs(&field.docs); let ident = self.resolve_ident(&field.ident).to_string(); - FlagsField { docs, ident } + FlagsField { docs, id: ident } }); TypeDefKind::Flags(fields.collect()) @@ -129,7 +133,11 @@ impl<'a> Resolver<'a> { .map(|ty| self.resolve_type(ty)) .transpose()?; - Ok(VariantCase { docs, ident, ty }) + Ok(VariantCase { + docs, + id: ident, + ty, + }) }) .partition_result::<_, Error>()?; @@ -140,7 +148,7 @@ impl<'a> Resolver<'a> { let docs = self.resolve_docs(&case.docs); let ident = self.resolve_ident(&case.ident).to_string(); - EnumCase { docs, ident } + EnumCase { docs, id: ident } }); TypeDefKind::Enum(cases.collect()) @@ -291,7 +299,7 @@ impl<'a> Resolver<'a> { Ok(Function { docs, - ident, + id: ident, params, result, }) diff --git a/src/main.rs b/src/main.rs index d6160514..578be76b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use clap::{ArgAction, Parser}; use miette::{bail, IntoDiagnostic, Result, WrapErr}; use std::{ collections::HashSet, + io::Write, path::{Path, PathBuf}, time::Instant, }; @@ -49,6 +50,14 @@ enum Command { #[clap(flatten)] world: WorldOpt, }, + #[cfg(feature = "unstable")] + Json { + /// Wether to prettify the generated JSON. + #[clap(short, long)] + pretty: bool, + #[clap(flatten)] + world: WorldOpt, + }, } #[derive(Debug, Parser)] @@ -150,6 +159,25 @@ fn run() -> Result<()> { write_file(&out_dir, &path, &contents)?; } + #[cfg(feature = "unstable")] + Command::Json { world, pretty } => { + if !world.wit.is_file() { + bail!("wit file `{}` does not exist", world.wit.display()); + } + + let skipset: HashSet = + world.skip.into_iter().collect(); + + let iface = wit_parser::parse_and_resolve_file(&world.wit, |t| skipset.contains(t))?; + + let mut stdout = std::io::stdout().lock(); + if pretty { + serde_json::to_writer_pretty(stdout, &iface).into_diagnostic()?; + } else { + serde_json::to_writer(stdout, &iface).into_diagnostic()?; + } + println!(); // print a newline for formatting + } }; log::info!(action = "Finished"; "in {:.2}s", Instant::now().duration_since(start).as_secs_f32()); From bcbe9300d2fe20f4f0efecbb453813d5e3f1a660 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 05:40:12 -0600 Subject: [PATCH 2/7] clippy --- src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 578be76b..c772c8e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ use clap::{ArgAction, Parser}; use miette::{bail, IntoDiagnostic, Result, WrapErr}; use std::{ collections::HashSet, - io::Write, path::{Path, PathBuf}, time::Instant, }; From bc1a53dcb7a551964f46d21f8b99502817ddbb61 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 05:53:10 -0600 Subject: [PATCH 3/7] generate schema --- Cargo.toml | 6 +- crates/wit-parser/Cargo.toml | 2 + crates/wit-parser/ast.json | 999 ++++++++++++++++++ .../wit-parser/tests/generate-json-schema.rs | 12 + 4 files changed, 1015 insertions(+), 4 deletions(-) create mode 100644 crates/wit-parser/ast.json create mode 100644 crates/wit-parser/tests/generate-json-schema.rs diff --git a/Cargo.toml b/Cargo.toml index 0e3a6828..2281aa03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ quote = "1.0.33" proc-macro2 = "1.0.67" syn = "2.0.33" schemars = "0.8.12" +serde_json = "1.0" [dependencies] clap.workspace = true @@ -48,10 +49,7 @@ miette.workspace = true env_logger = "0.10.0" log.workspace = true clap_complete = "4.4.1" -serde_json = "1.0" - -[dev-dependencies] -schemars = { version = "0.8.12", features = ["impl_json_schema"] } +serde_json.workspace = true [features] unstable = ["dep:tauri-bindgen-gen-markdown"] diff --git a/crates/wit-parser/Cargo.toml b/crates/wit-parser/Cargo.toml index d234a3b2..5e0ee067 100644 --- a/crates/wit-parser/Cargo.toml +++ b/crates/wit-parser/Cargo.toml @@ -18,3 +18,5 @@ schemars.workspace = true [dev-dependencies] pretty_assertions = "1.4.0" +schemars = { version = "0.8.12", features = ["impl_json_schema"] } +serde_json.workspace = true diff --git a/crates/wit-parser/ast.json b/crates/wit-parser/ast.json new file mode 100644 index 00000000..1342e12f --- /dev/null +++ b/crates/wit-parser/ast.json @@ -0,0 +1,999 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Interface", + "type": "object", + "required": [ + "docs", + "functions", + "ident", + "typedefs" + ], + "properties": { + "docs": { + "type": "string" + }, + "functions": { + "type": "array", + "items": { + "$ref": "#/definitions/Function" + } + }, + "ident": { + "type": "string" + }, + "typedefs": { + "type": "array", + "items": { + "$ref": "#/definitions/TypeDef" + } + } + }, + "definitions": { + "EnumCase": { + "type": "object", + "required": [ + "docs", + "id" + ], + "properties": { + "docs": { + "type": "string" + }, + "id": { + "type": "string" + } + } + }, + "FlagsField": { + "type": "object", + "required": [ + "docs", + "id" + ], + "properties": { + "docs": { + "type": "string" + }, + "id": { + "type": "string" + } + } + }, + "Function": { + "type": "object", + "required": [ + "docs", + "id", + "params" + ], + "properties": { + "docs": { + "type": "string" + }, + "id": { + "type": "string" + }, + "params": { + "type": "array", + "items": { + "$ref": "#/definitions/NamedType" + } + }, + "result": { + "anyOf": [ + { + "$ref": "#/definitions/FunctionResult" + }, + { + "type": "null" + } + ] + } + } + }, + "FunctionResult": { + "anyOf": [ + { + "$ref": "#/definitions/Type" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/NamedType" + } + } + ] + }, + "NamedType": { + "type": "object", + "oneOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "bool" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u8" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u16" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u32" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u64" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u128" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s8" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s16" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s32" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s64" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s128" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "float32" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "float64" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "char" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "string" + ] + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "list" + ] + }, + "value": { + "$ref": "#/definitions/Type" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "tuple" + ] + }, + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/Type" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "option" + ] + }, + "value": { + "$ref": "#/definitions/Type" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "result" + ] + }, + "value": { + "type": "object", + "properties": { + "err": { + "anyOf": [ + { + "$ref": "#/definitions/Type" + }, + { + "type": "null" + } + ] + }, + "ok": { + "anyOf": [ + { + "$ref": "#/definitions/Type" + }, + { + "type": "null" + } + ] + } + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "id" + ] + }, + "value": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + } + ], + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string" + } + } + }, + "RecordField": { + "type": "object", + "required": [ + "docs", + "id", + "ty" + ], + "properties": { + "docs": { + "type": "string" + }, + "id": { + "type": "string" + }, + "ty": { + "$ref": "#/definitions/Type" + } + } + }, + "Type": { + "oneOf": [ + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "bool" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u8" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u16" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u32" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u64" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "u128" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s8" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s16" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s32" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s64" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s128" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "float32" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "float64" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "char" + ] + } + } + }, + { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "string" + ] + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "list" + ] + }, + "value": { + "$ref": "#/definitions/Type" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "tuple" + ] + }, + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/Type" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "option" + ] + }, + "value": { + "$ref": "#/definitions/Type" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "result" + ] + }, + "value": { + "type": "object", + "properties": { + "err": { + "anyOf": [ + { + "$ref": "#/definitions/Type" + }, + { + "type": "null" + } + ] + }, + "ok": { + "anyOf": [ + { + "$ref": "#/definitions/Type" + }, + { + "type": "null" + } + ] + } + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "id" + ] + }, + "value": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + } + ] + }, + "TypeDef": { + "type": "object", + "oneOf": [ + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "alias" + ] + }, + "value": { + "$ref": "#/definitions/Type" + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "record" + ] + }, + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/RecordField" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "flags" + ] + }, + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/FlagsField" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "variant" + ] + }, + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/VariantCase" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "enum" + ] + }, + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/EnumCase" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "union" + ] + }, + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/UnionCase" + } + } + } + }, + { + "type": "object", + "required": [ + "type", + "value" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "resource" + ] + }, + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/Function" + } + } + } + } + ], + "required": [ + "docs", + "ident" + ], + "properties": { + "docs": { + "type": "string" + }, + "ident": { + "type": "string" + } + } + }, + "UnionCase": { + "type": "object", + "required": [ + "docs", + "ty" + ], + "properties": { + "docs": { + "type": "string" + }, + "ty": { + "$ref": "#/definitions/Type" + } + } + }, + "VariantCase": { + "type": "object", + "required": [ + "docs", + "id" + ], + "properties": { + "docs": { + "type": "string" + }, + "id": { + "type": "string" + }, + "ty": { + "anyOf": [ + { + "$ref": "#/definitions/Type" + }, + { + "type": "null" + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/crates/wit-parser/tests/generate-json-schema.rs b/crates/wit-parser/tests/generate-json-schema.rs new file mode 100644 index 00000000..aeb33259 --- /dev/null +++ b/crates/wit-parser/tests/generate-json-schema.rs @@ -0,0 +1,12 @@ +use schemars::schema_for; +use wit_parser::*; + +#[test] +fn main() -> Result<(), Box> { + let schema = schema_for!(Interface); + let str = serde_json::to_string_pretty(&schema)?; + + std::fs::write("ast.json", str)?; + + Ok(()) +} From 73cd95641fc211c7f7e4d266ac24829293df2235 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 05:53:16 -0600 Subject: [PATCH 4/7] cleanup --- .github/workflows/ci.yml | 2 +- src/main.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a16ecf25..b8385538 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,7 +74,7 @@ jobs: with: components: clippy - uses: Swatinem/rust-cache@v2 - - run: cargo clippy --workspace -- -Dclippy::all -Dclippy::pedantic + - run: cargo clippy --workspace --features unstable -- -Dclippy::all -Dclippy::pedantic rustfmt: name: Rustfmt diff --git a/src/main.rs b/src/main.rs index c772c8e7..ea40d4c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -156,7 +156,7 @@ fn run() -> Result<()> { Command::Markdown { builder, world } => { let (path, contents) = gen_interface(builder, world)?; - write_file(&out_dir, &path, &contents)?; + write_file(out_dir, &path, &contents)?; } #[cfg(feature = "unstable")] Command::Json { world, pretty } => { @@ -169,7 +169,7 @@ fn run() -> Result<()> { let iface = wit_parser::parse_and_resolve_file(&world.wit, |t| skipset.contains(t))?; - let mut stdout = std::io::stdout().lock(); + let stdout = std::io::stdout().lock(); if pretty { serde_json::to_writer_pretty(stdout, &iface).into_diagnostic()?; } else { From b6898b13b3e65bba3328f55651d0876c368a5bbb Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 06:56:27 -0600 Subject: [PATCH 5/7] clippy --- crates/gen-guest-rust/src/lib.rs | 2 +- crates/gen-host/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/gen-guest-rust/src/lib.rs b/crates/gen-guest-rust/src/lib.rs index 1938ce67..cde4f385 100644 --- a/crates/gen-guest-rust/src/lib.rs +++ b/crates/gen-guest-rust/src/lib.rs @@ -157,7 +157,7 @@ impl RustGenerator for RustWasm { ); let mod_ident = format!("{mod_ident}::resource::{}", ident.to_string().to_snake_case()); - let ident = func.ident.to_snake_case(); + let ident = func.id.to_snake_case(); let param_idents = func .params diff --git a/crates/gen-host/src/lib.rs b/crates/gen-host/src/lib.rs index acb6abe5..039f74e8 100644 --- a/crates/gen-host/src/lib.rs +++ b/crates/gen-host/src/lib.rs @@ -360,7 +360,7 @@ impl Host { }); let methods = methods.map(|(resource_name, method)| { - let func_name = method.ident.to_snake_case(); + let func_name = method.id.to_snake_case(); let func_ident = format_ident!("{}", func_name); let params = self.print_function_params(&method.params, &BorrowMode::Owned); From 3e6198a33e0e6772ca60c93fa2480c6cab914766 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 07:17:06 -0600 Subject: [PATCH 6/7] fix typo --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index ea40d4c8..748a334b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,7 +51,7 @@ enum Command { }, #[cfg(feature = "unstable")] Json { - /// Wether to prettify the generated JSON. + /// Whether to prettify the generated JSON. #[clap(short, long)] pretty: bool, #[clap(flatten)] From 85143005f2807e5e98b764ae794a4d7d7bed2c98 Mon Sep 17 00:00:00 2001 From: Jonas Kruckenberg Date: Thu, 14 Sep 2023 11:05:30 -0600 Subject: [PATCH 7/7] clippy --- crates/gen-host/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/gen-host/src/lib.rs b/crates/gen-host/src/lib.rs index dda46a67..b710951a 100644 --- a/crates/gen-host/src/lib.rs +++ b/crates/gen-host/src/lib.rs @@ -311,7 +311,7 @@ impl Host { } fn print_router_fn_definition(&self, mod_name: &str, func: &Function) -> TokenStream { - let func_name = func.ident.to_snake_case(); + let func_name = func.id.to_snake_case(); let func_ident = format_ident!("{}", func_name); let param_decl = match func.params.len() { @@ -378,7 +378,7 @@ impl Host { resource_name: &str, method: &Function, ) -> TokenStream { - let func_name = method.ident.to_snake_case(); + let func_name = method.id.to_snake_case(); let func_ident = format_ident!("{}", func_name); let param_decl = method