diff --git a/README.md b/README.md index 120c9d3b9..9f0a365e5 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,28 @@ # Stellar CLI (stellar-cli) +[![Apache 2.0 licensed](https://img.shields.io/badge/license-apache%202.0-blue.svg)] + This repo is home to the Stellar CLI, the command-line multi-tool for running and deploying Stellar contracts on the Stellar network. + +## Table of Contents + +- [Documentation](#documentation) +- [Installation](#installation) +- [Installation with Experimental Features](#installation-with-experiemental-features) +- [Autocomplete](#autocomplete) +- [Latest Release](#latest-release) +- [Upcoming Features](#upcoming-features) +- [To Contribute](#to-contribute) +- [Additional Developer Resources](#additional-developer-resources) + + + ## Documentation For installation options see below, for usage instructions [see the full help docs](FULL_HELP_DOCS.md). -## Install +## Installation Install the latest version from source: ``` cargo install --locked stellar-cli --features opt @@ -24,13 +40,15 @@ Install with Homebrew: brew install stellar/tap/stellar-cli ``` -## Install Experimental Features +## Installation with Experimental Features To use the potentially unreleased bleeding edge CLI functionalities, install from git: ``` -cargo install --locked stellar-cli --features opt --git git@github.com:stellar/stellar-cli.git +cargo install --locked stellar-cli --features opt --git https://github.com/stellar/stellar-cli.git ``` -## Setup Autocomplete +## Autocomplete +The Stellar CLI supports some autocompletion. To set up, run the following commands: + ``` stellar completion --shell ``` @@ -47,7 +65,7 @@ echo "source <(stellar completion --shell bash)" >> ~/.bashrc ``` ## Latest Release -For latest releases, see [releases](https://github.com/stellar/stellar-cli/releases). +For the latest release, see [releases](https://github.com/stellar/stellar-cli/releases). ## Upcoming Features For upcoming features, please see the [project board](https://github.com/orgs/stellar/projects/50). @@ -55,6 +73,6 @@ For upcoming features, please see the [project board](https://github.com/orgs/st ## To Contribute Find issues to contribute to [here](https://github.com/stellar/stellar-cli/contribute) and review [CONTRIBUTING.md](/CONTRIBUTING.md). -Developer Docs: https://developers.stellar.org/docs - -Developer Docs CLI Examples: https://developers.stellar.org/docs/smart-contracts/guides/cli +## Additional Developer Resources +- Developer Docs CLI Examples: https://developers.stellar.org/docs/smart-contracts/guides/cli +- Video Tutorial: https://developers.stellar.org/meetings/2024/06/27 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"# + ); }