From 40a1f1e6ac63ead3c94f9ccd0e5f6b50094516fa Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Mon, 8 Jul 2024 11:17:54 -0400 Subject: [PATCH] fix bindings error enum not showing message or docs (#1364) * fix bindings error enum not showing message or docs * clippy * clippy --------- Co-authored-by: Willem Wyndham --- cmd/crates/soroban-spec-typescript/src/lib.rs | 65 ++++++++++++------- .../test-wasms/custom_account/src/lib.rs | 24 +++++-- .../tests/it/integration/bindings.rs | 7 ++ 3 files changed, 66 insertions(+), 30 deletions(-) diff --git a/cmd/crates/soroban-spec-typescript/src/lib.rs b/cmd/crates/soroban-spec-typescript/src/lib.rs index 4ff925476..94b5bb192 100644 --- a/cmd/crates/soroban-spec-typescript/src/lib.rs +++ b/cmd/crates/soroban-spec-typescript/src/lib.rs @@ -106,17 +106,22 @@ pub fn generate(spec: &[ScSpecEntry]) -> String { format!("{top}\n\n{bottom}") } -fn doc_to_ts_doc(doc: &str, method: Option<&str>) -> String { +fn doc_to_ts_doc(doc: &str, method: Option<&str>, indent_level: usize) -> String { + let indent = " ".repeat(indent_level); if let Some(method) = method { let doc = if doc.is_empty() { String::new() } else { - format!(" *\n * {}", doc.split('\n').join("\n * ")) + format!( + "\n{} * {}", + indent, + doc.split('\n').join(&format!("\n{indent} * ")) + ) }; return format!( - r#"/** - * Construct and simulate a {method} transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.{doc} - */"# + r#"{indent}/** +{indent} * Construct and simulate a {method} transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.{doc} +{indent} */"# ); } @@ -124,11 +129,11 @@ fn doc_to_ts_doc(doc: &str, method: Option<&str>) -> String { return String::new(); } - let doc = doc.split('\n').join("\n * "); + let doc = doc.split('\n').join(&format!("\n{indent} * ")); format!( - r#"/** - * {doc} - */ + r#"{indent}/** +{indent} * {doc} +{indent} */ "# ) } @@ -188,7 +193,7 @@ pub fn entry_to_method_type(entry: &Entry) -> String { ) }) .unwrap_or_default(); - let doc = doc_to_ts_doc(doc, Some(name)); + let doc = doc_to_ts_doc(doc, Some(name), 0); let return_type = outputs_to_return_type(outputs); format!( r#" @@ -199,7 +204,7 @@ pub fn entry_to_method_type(entry: &Entry) -> String { } Entry::Struct { doc, name, fields } => { - let docs = doc_to_ts_doc(doc, None); + let docs = doc_to_ts_doc(doc, None, 0); let fields = fields.iter().map(field_to_ts).join("\n "); format!( r#" @@ -211,13 +216,13 @@ pub fn entry_to_method_type(entry: &Entry) -> String { } Entry::TupleStruct { doc, name, fields } => { - let docs = doc_to_ts_doc(doc, None); + let docs = doc_to_ts_doc(doc, None, 0); let fields = fields.iter().map(type_to_ts).join(", "); format!("{docs}export type {name} = readonly [{fields}];") } Entry::Union { name, doc, cases } => { - let doc = doc_to_ts_doc(doc, None); + let doc = doc_to_ts_doc(doc, None, 0); let cases = cases.iter().map(case_to_ts).join(" | "); format!( @@ -226,7 +231,7 @@ pub fn entry_to_method_type(entry: &Entry) -> String { ) } Entry::Enum { doc, name, cases } => { - let doc = doc_to_ts_doc(doc, None); + let doc = doc_to_ts_doc(doc, None, 0); let cases = cases.iter().map(enum_case_to_ts).join("\n "); let name = (name == "Error") .then(|| format!("{name}s")) @@ -239,16 +244,30 @@ pub fn entry_to_method_type(entry: &Entry) -> String { ) } Entry::ErrorEnum { doc, cases, .. } => { - let doc = doc_to_ts_doc(doc, None); + let doc = doc_to_ts_doc(doc, None, 0); let cases = cases .iter() - .map(|c| format!("{}: {{message:\"{}\"}}", c.value, c.doc)) - .join(",\n "); - format!( - r#"{doc}export const Errors = {{ - {cases} -}}"# - ) + .enumerate() + .map(|(i, c)| { + if c.doc.is_empty() { + format!( + "{} {}: {{message:\"{}\"}}", + if i == 0 { "" } else { "\n" }, + c.value, + c.name + ) + } else { + format!( + "{}{} {}: {{message:\"{}\"}}", + if i == 0 { "" } else { "\n" }, + doc_to_ts_doc(&c.doc, None, 1), + c.value, + c.name + ) + } + }) + .join(",\n"); + format!("{doc}export const Errors = {{\n{cases}\n}}") } } } @@ -270,7 +289,7 @@ fn case_to_ts(case: &types::UnionCase) -> String { fn field_to_ts(field: &types::StructField) -> String { let types::StructField { doc, name, value } = field; - let doc = doc_to_ts_doc(doc, None); + let doc = doc_to_ts_doc(doc, None, 0); let type_ = type_to_ts(value); format!("{doc}{name}: {type_};") } diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_account/src/lib.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_account/src/lib.rs index a9ed583d8..c71324110 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_account/src/lib.rs +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/custom_account/src/lib.rs @@ -11,17 +11,27 @@ pub struct Contract; #[contracterror] #[derive(Copy, Clone, Eq, PartialEq, Debug)] +/// Represents the different kinds of errors that can occur in the application. pub enum Error { + /// The requested item was not found. NotFound = 1, + + /// The operation was not permitted. NotPermitted = 2, + ClientDataJsonChallengeIncorrect = 3, - Secp256r1PublicKeyParse = 4, - Secp256r1SignatureParse = 5, - Secp256r1VerifyFailed = 6, - JsonParseError = 7, - InvalidContext = 8, - AlreadyInited = 9, - NotInited = 10, + + /// An error occurred while parsing JSON. + JsonParseError = 4, + + /// The provided context is invalid. + InvalidContext = 5, + + /// The system has already been initialized. + AlreadyInited = 6, + + /// The system has not been initialized yet. + NotInited = 7, } const SIGNERS: Symbol = symbol_short!("sigs"); diff --git a/cmd/crates/soroban-test/tests/it/integration/bindings.rs b/cmd/crates/soroban-test/tests/it/integration/bindings.rs index 7861759da..feb7f2ef8 100644 --- a/cmd/crates/soroban-test/tests/it/integration/bindings.rs +++ b/cmd/crates/soroban-test/tests/it/integration/bindings.rs @@ -72,4 +72,11 @@ async fn invoke_test_bindings_context_failure() { !content.contains("__check_auth"), "Test failed: `__check_auth` found in src/index.ts" ); + + // check enum message + doc working properly + assert!( + content.contains("The requested item was not found.") + && content.contains("1: {message:\"NotFound\"}"), + r#"Test failed: Error enum not properly formatted in src/index.ts"# + ); }