diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml new file mode 100644 index 00000000..87586de3 --- /dev/null +++ b/.github/workflows/docs.yaml @@ -0,0 +1,52 @@ +name: Docs + +on: + push: + branches: + - main + paths: + - "docs/**" + - ".github/workflows/docs.yaml" + +env: + # Repository specific variables + REPO_NAME: ts-codegen + DOCS_DEST_PATH: pages/ts-codegen + +jobs: + docs-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + enable-global-cache: true + + - name: Clone docs repository + run: git clone https://x-access-token:${{ secrets.GH_HYPERWEB_PAT }}@github.com/hyperweb-io/docs.hyperweb.io.git external-docs + + - name: Sync the docs and build + run: | + rsync -av --delete ./docs/ ./external-docs/${{ env.DOCS_DEST_PATH }}/ + cd external-docs + yarn install + yarn export + + - name: Git push + run: | + cd external-docs + git config user.name 'GitHub Action' + git config user.email 'action@github.com' + git add . + if git diff --cached --quiet; then + echo "No changes to commit." + else + git commit -m "Automated: Update ${{ env.REPO_NAME }} documentation" + git push + fi + diff --git a/docs/_meta.json b/docs/_meta.json new file mode 100644 index 00000000..86dc2c11 --- /dev/null +++ b/docs/_meta.json @@ -0,0 +1,4 @@ +{ + "index": "Introduction", + "developing": "Developing" +} diff --git a/docs/developing/_meta.json b/docs/developing/_meta.json new file mode 100644 index 00000000..d2d2c18e --- /dev/null +++ b/docs/developing/_meta.json @@ -0,0 +1,4 @@ +{ + "index": "Developing", + "ast": "Working with ASTs" +} \ No newline at end of file diff --git a/docs/developing/ast.mdx b/docs/developing/ast.mdx new file mode 100644 index 00000000..94877182 --- /dev/null +++ b/docs/developing/ast.mdx @@ -0,0 +1,128 @@ +## Working with ASTs + +### 1 edit the fixture + +edit `./scripts/fixture.ts`, for example: + +```js +// ./scripts/fixture.ts +export interface InstantiateMsg { + admin?: string | null; + members: Member[]; +} +``` + +### 2 run AST generator + +``` +yarn test:ast +``` + +### 3 look at the JSON produced + +``` +code ./scripts/test-output.json +``` + +We use the npm module `ast-stringify` to strip out unnecessary props, and generate a JSON for reference. + +You will see a `File` and `Program`... only concern yourself with the `body[]`: + +```json +{ + "type": "File", + "errors": [], + "program": { + "type": "Program", + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ExportNamedDeclaration", + "exportKind": "type", + "specifiers": [], + "source": null, + "declaration": { + "type": "TSInterfaceDeclaration", + "id": { + "type": "Identifier", + "name": "InstantiateMsg" + }, + "body": { + "type": "TSInterfaceBody", + "body": [ + { + "type": "TSPropertySignature", + "key": { + "type": "Identifier", + "name": "admin" + }, + "computed": false, + "optional": true, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSUnionType", + "types": [ + { + "type": "TSStringKeyword" + }, + { + "type": "TSNullKeyword" + } + ] + } + } + }, + { + "type": "TSPropertySignature", + "key": { + "type": "Identifier", + "name": "members" + }, + "computed": false, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "typeAnnotation": { + "type": "TSArrayType", + "elementType": { + "type": "TSTypeReference", + "typeName": { + "type": "Identifier", + "name": "Member" + } + } + } + } + } + ] + } + } + } + ], + "directives": [] + }, + "comments": [] +} +``` + +### 4 code with `@babel/types` using the JSON as a reference + +NOTE: 4 continued ideally you should be writing a test with your generator! + +```js +import * as t from '@babel/types'; + +export const createNewGenerator = () => { + return t.exportNamedDeclaration( + t.tsInterfaceDeclaration( + t.identifier('InstantiateMsg'), + null, + [], + t.tsInterfaceBody([ + // ... more code ... + ]) + ) + ); +}; +``` diff --git a/docs/developing/index.mdx b/docs/developing/index.mdx new file mode 100644 index 00000000..6bb0f025 --- /dev/null +++ b/docs/developing/index.mdx @@ -0,0 +1,27 @@ +# Developing + +## Initial setup + +``` +yarn +yarn bootstrap +``` + +## Building + +``` +yarn build +``` + +## Tests + +Then `cd` into a package and run the tests + +``` +cd ./packages/wasm-ast-types +yarn test:watch +``` + +## Working with ASTs + +See the [docs](/ts-codegen/developing/ast) in the `wasm-ast-types` package. diff --git a/docs/index.mdx b/docs/index.mdx new file mode 100644 index 00000000..cfbebb87 --- /dev/null +++ b/docs/index.mdx @@ -0,0 +1,688 @@ +import { DownloadButton } from '../../components/download-button'; + +# @cosmwasm/ts-codegen + +Generate TypeScript SDKs for your CosmWasm smart contracts + +

+ +

+ +
+ + + + + + + + + + + + + + + +
+ +``` +npm install -g @cosmwasm/ts-codegen +``` + +The quickest and easiest way to interact with CosmWasm Contracts. `@cosmwasm/ts-codegen` converts your CosmWasm smart contracts into dev-friendly TypeScript classes so you can focus on shipping code. + +🎥 [Checkout our video playlist](https://www.youtube.com/watch?v=D_A5V2PfNLA&list=PL-lMkVv7GZwz1KO3jANwr5W4MoziruXwK) to learn how to use `ts-codegen`! + + + +## Table of contents + +- [@cosmwasm/ts-codegen](https://www.npmjs.com/package/@cosmwasm/ts-codegen) + - [Table of contents](#table-of-contents) +- [QuickStart](#quickstart) +- [Usage](#usage) + - [Programmatic Usage](#programmatic-usage) + - [Types](#types) + - [TS Clients](#client) + - [React Query](#react-query) + - [Recoil](#recoil) + - [Message Composer](#message-composer) + - [Message Builder](#message-builder) + - [Use Contracts Hooks](#use-contracts-hooks) + - [Bundles](#bundles) + - [CLI Usage and Examples](#cli-usage-and-examples) + - [Advanced Usage](#advanced-usage) +- [Example Output](#example-output) +- [JSON Schema](#json-schema) + - [JSON Schema Generation](#json-schema-generation) + - [Exporting Schemas](#exporting-schemas) +- [Developing](#developing) +- [Related](#related) + +## Quickstart + +Clone your project and `cd` into your contracts folder + +```sh +git clone https://github.com/public-awesome/launchpad.git +cd launchpad/contracts/sg721-base/ +``` + +Run `cosmwasm-ts-codegen` to generate your code. + +```sh +cosmwasm-ts-codegen generate \ + --plugin client \ + --schema ./schema \ + --out ./ts \ + --name SG721 \ + --no-bundle +``` + +The output will be in the folder specified by `--out`, enjoy! + +## Usage + +You can get started quickly using our `cli` by globally installing via npm: + +``` +npm install -g @cosmwasm/ts-codegen +``` + +### Programmatic Usage + +For production usage, we recommend setting up a build script that uses the main entry point: + +```ts +import codegen from "@cosmwasm/ts-codegen"; + +codegen({ + contracts: [ + { + name: "SG721", + dir: "./path/to/sg721/schema", + }, + { + name: "Minter", + dir: "./path/to/Minter/schema", + }, + ], + outPath: "./path/to/code/src/", + + // options are completely optional ;) + options: { + bundle: { + bundleFile: "index.ts", + scope: "contracts", + }, + types: { + enabled: true, + }, + client: { + enabled: true, + }, + reactQuery: { + enabled: true, + optionalClient: true, + version: "v4", + mutations: true, + queryKeys: true, + queryFactory: true, + }, + recoil: { + enabled: false, + }, + messageComposer: { + enabled: false, + }, + messageBuilder: { + enabled: false, + }, + useContractsHooks: { + enabled: false, + }, + }, +}).then(() => { + console.log("✨ all done!"); +}); +``` + +#### Types + +Typescript types and interfaces are generated in separate files so they can be imported into various generated plugins. + +[see example output code](https://gist.github.com/pyramation/107d4e8e30dc5eb3ffc07bc3000f4dd0) + +#### Types Options + +| option | description | +| ------------------------ | --------------------------------------------------------------------- | +| `types.enabled` | enable type generation | +| `types.aliasExecuteMsg` | generate a type alias based on the contract name | +| `types.aliasEntryPoints` | generate type aliases for the entry points based on the contract name | + +### Client + +The `client` plugin will generate TS client classes for your contracts. This option generates a `QueryClient` for queries as well as a `Client` for queries and mutations. + +[see example output code](https://gist.github.com/pyramation/30508678b7563e286f06ccc5ac384817) + +#### Client Options + +| option | description | +| --------------------------- | ---------------------------------------------------- | +| `client.enabled` | generate TS client classes for your contracts | +| `client.execExtendsQuery` | execute should extend query message clients | +| `client.noImplicitOverride` | should match your tsconfig noImplicitOverride option | + +#### Client via CLI + +```sh +cosmwasm-ts-codegen generate \ + --plugin client + --schema ./schema \ + --out ./ts \ + --name MyContractName +``` + +### React Query + +Generate [react-query v3](https://react-query-v3.tanstack.com/) or [react-query v4](https://tanstack.com/query/v4/) bindings for your contracts with the `react-query` command. + +[see example output code](https://gist.github.com/pyramation/70aef28fd3af0ee164f7711704d3dfc0) + +#### React Query Options + +| option | description | +| --------------------------- | ---------------------------------------------------------------------------- | +| `reactQuery.enabled` | enable the react-query plugin | +| `reactQuery.optionalClient` | allows contract client to be undefined as the component renders | +| `reactQuery.queryKeys` | generates a const queryKeys object for use with invalidations and set values | +| `reactQuery.queryFactory` | generates a const queryFactory object for useQueries and prefetchQueries use | +| `reactQuery.version` | `v4` uses `@tanstack/react-query` and `v3` uses `react-query` | +| `reactQuery.mutations` | also generate mutations | +| `reactQuery.camelize` | use camelCase style for property names | + +#### React Query via CLI + +Here is an example without optional client, using v3 for `react-query`, without mutations: + +```sh +cosmwasm-ts-codegen generate \ + --plugin client \ + --plugin react-query \ + --schema ./schema \ + --out ./ts \ + --name MyContractName \ + --version v3 \ + --no-optionalClient \ + --no-mutations +``` + +Example with optional client, using v4, with mutations: + +```sh +cosmwasm-ts-codegen generate \ + --plugin react-query \ + --schema ./schema \ + --out ./ts \ + --name MyContractName \ + --optionalClient \ + --version v4 \ + --mutations +``` + +### Recoil + +Generate [recoil](https://recoiljs.org/) bindings for your contracts with the `recoil` command. + +[see example output code](https://gist.github.com/pyramation/a9520ccf131177b1841e02a97d7d3731) + +#### Recoil via CLI + +```sh +cosmwasm-ts-codegen generate \ + --plugin recoil \ + --schema ./schema \ + --out ./ts \ + --name MyContractName +``` + +#### Recoil Options + +| option | description | +| ---------------- | ------------------------ | +| `recoil.enabled` | enable the recoil plugin | + +### Message Composer + +Generate pure message objects with the proper `utf8` encoding and `typeUrl` configured that you can broadcast yourself via `cosmjs` with the `message-composer` command. + +[see example output code](https://gist.github.com/pyramation/43320e8b952751a0bd5a77dbc5b601f4) + +#### Message Composer via CLI + +```sh +cosmwasm-ts-codegen generate \ + --plugin message-composer \ + --schema ./schema \ + --out ./ts \ + --name MyContractName +``` + +#### Message Composer Options + +| option | description | +| ------------------------- | --------------------------------- | +| `messageComposer.enabled` | enable the messageComposer plugin | + +### Message Builder + +Generate raw message jsons for use in your application with the `message-builder` command. + +[see example output code](https://gist.github.com/adairrr/b394e62beb9856b0351883f776650f26) + +#### Message Builder via CLI + +```sh +cosmwasm-ts-codegen generate \ + --plugin message-builder \ + --schema ./schema \ + --out ./ts \ + --name MyContractName +``` + +#### Message Builder Options + +| option | description | +| ------------------------ | -------------------------------- | +| `messageBuilder.enabled` | enable the messageBuilder plugin | + +### Use Contracts Hooks + +| option | description | +| --------------------------- | -------------------------------- | +| `useContractsHooks.enabled` | enable the `useContracts` plugin | + +#### Use Contracts Provider Usage + +```tsx +import { useChain } from "@cosmos-kit/react"; +import { ContractsProvider } from "../path/to/codegen/contracts-context"; + +export default function YourComponent() { + const { address, getCosmWasmClient, getSigningCosmWasmClient } = + useChain(chainName); + + return ( + + + + ); +} +``` + +#### Use Contracts Provider Babel/TSC config + +If you're using Babel, please make sure include `'@babel/preset-react'` in devDeps and presets in `.babelrc.js`: + +```js +presets: ["@babel/typescript", "@babel/env", "@babel/preset-react"]; +``` + +For `tsc`, you should set the `jsx` option to `'react'` in your `tsconfig.json`. + +#### Use Contracts Hooks Usage + +Once enabled, you can get contracts very simply: + +```ts +const { marketplace } = useContracts(); +``` + +```ts +const marketplaceClient = marketplace.signingClient(marketplaceContract); +await marketplaceClient.updateAskPrice({ + collection: token.collectionAddr, + price: { + amount, + denom, + }, + tokenId, +}); +``` + +### Bundles + +The bundler will make a nice package of all your contracts. For example: + +```ts +const { MinterQueryClient, useMinterConfigQuery } = contracts.Minter; + +const { CwAdminFactoryClient } = contracts.CwAdminFactory; +``` + +#### Bundler Options + +| option | description | +| ------------------- | -------------------------------------------------------------------------------- | +| `bundle.enabled` | enable the bundler plugin | +| `bundle.scope` | name of the scope, defaults to `contracts` (you can use `.` to make more scopes) | +| `bundle.bundleFile` | name of the bundle file | + +#### Coding Style + +| option | description | default | +| ------------------ | ----------------------------------- | ------- | +| `useShorthandCtor` | Enable using shorthand constructor. | true | + +Using shorthand constructor (Might not be transpiled correctly with babel): + +```ts + constructor( + protected address: string | undefined, + protected cosmWasmClient: CosmWasmClient | undefined, + protected signingCosmWasmClient: SigningCosmWasmClient | undefined, + private TSign?: new ( + client: SigningCosmWasmClient, + sender: string, + contractAddress: string + ) => TSign, + private TQuery?: new ( + client: CosmWasmClient, + contractAddress: string + ) => TQuery, + private TMsgComposer?: new ( + sender: string, + contractAddress: string + ) => TMsgComposer + ) {} +``` + +Without using shorthand constructor: + +```ts + address: string | undefined; + ... + TMsgComposer?: new ( + sender: string, + contractAddress: string + ) => TMsgComposer; + + constructor( + address: string | undefined, + ... + TMsgComposer?: new ( + sender: string, + contractAddress: string + ) => TMsgComposer + ) { + this.address = address; + ... + this.TMsgComposer = TMsgComposer; + } +``` + +### CLI Usage and Examples + +#### Interactive prompt + +The CLI is interactive, and if you don't specify an option, it will interactively prompt you. + +```sh +cosmwasm-ts-codegen generate +? [plugin] which plugins? (Press to select, to toggle all, to invert selection) +❯◯ client + ◯ recoil + ◯ react-query + ◯ message-composer +``` + +In this example, you can press space bar to select a number of plugins you wish you enable. + +#### Specifying Plugins + +Additionally, it will also show you the name of the field (in this case `plugin`) so you can specify the parameter (for example when using CI/CD) on the comand line. Here is an exampl with `--plugin` set to `client` via CLI: + +```sh +cosmwasm-ts-codegen generate \ + --plugin client + --schema ./schema \ + --out ./ts \ + --name MyContractName +``` + +You can specify multiple `--plugin` options using the `generate` command: + +```sh +cosmwasm-ts-codegen generate \ + --plugin client \ + --plugin recoil \ + --schema ./schema \ + --out ./ts \ + --name SG721 +``` + +#### Bypassing the Prompt + +All options can be provided so you can bypass the prompt. + +For confirm options, you can pass `--no-` to set the value to false. Here is an example without optional client, using v3 for `react-query`, without mutations: + +```sh +cosmwasm-ts-codegen generate \ + --plugin client \ + --plugin react-query \ + --schema ./schema \ + --out ./ts \ + --name MyContractName \ + --version v3 \ + --no-optionalClient \ + --no-mutations +``` + +Example with optional client, using v4, with mutations: + +```sh +cosmwasm-ts-codegen generate \ + --plugin react-query \ + --schema ./schema \ + --out ./ts \ + --name MyContractName \ + --optionalClient \ + --version v4 \ + --mutations +``` + +#### Types Only Option + +If needed, you can generate only the types with the `typesOnly` option; + +```sh +cosmwasm-ts-codegen generate \ + --typesOnly \ + --schema ./schema \ + --out ./ts \ + --name SG721 +``` + +### Advanced Usage + +for lower-level access, you can import the various plugins directly: + +```ts +import { + generateTypes, + generateClient, + generateReactQuery, + generateRecoil, + generateMessageComposer, +} from "@cosmwasm/ts-codegen"; +``` + +### Example Output + +- `cosmwasm-ts-codegen generate --typesOnly` + +https://gist.github.com/pyramation/107d4e8e30dc5eb3ffc07bc3000f4dd0 + +- `cosmwasm-ts-codegen generate --plugin client` + +https://gist.github.com/pyramation/30508678b7563e286f06ccc5ac384817 + +- `cosmwasm-ts-codegen generate --plugin react-query` + +https://gist.github.com/pyramation/70aef28fd3af0ee164f7711704d3dfc0 + +- `cosmwasm-ts-codegen generate --plugin recoil` + +https://gist.github.com/pyramation/a9520ccf131177b1841e02a97d7d3731 + +- `cosmwasm-ts-codegen generate --plugin message-composer` + +https://gist.github.com/pyramation/43320e8b952751a0bd5a77dbc5b601f4 + +- `cosmwasm-ts-codegen generate --plugin message-builder` + +https://gist.github.com/adairrr/b394e62beb9856b0351883f776650f26 + +### JSON Schema + +We generate code from the [JSON Schema](https://json-schema.org/) exported from CosmWasm smart contracts. + +### JSON Schema Generation + +Currently you have to have the JSON Schema output. Here is an example to start. + +First, get the Rust contracts and run `cargo build`: + +```sh +git clone git@github.com:public-awesome/stargaze-contracts.git +cd stargaze-contracts +cargo build +``` + +now build the schema with `cargo schema` + +```sh +cd contracts/sg721/ +cargo schema +``` + +### Exporting Schemas + +#### `cosmwasm v1.1` Example + +Using the new `write_api` method, you can export schemas: + +```rs +use cosmwasm_schema::write_api; + +use cw4_group::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; + +fn main() { + write_api! { + instantiate: InstantiateMsg, + execute: ExecuteMsg, + query: QueryMsg, + } +} +``` + +#### `cosmwasm_std` Example + +Here is a legacy example: + +```rs +use cosmwasm_std::{Addr, CosmosMsg, Empty}; + +export_schema_with_title(&schema_for!(MinterData), &out_dir, "MinterResponse"); +export_schema_with_title(&schema_for!(Addr), &out_dir, "StakingResponse"); +export_schema_with_title(&schema_for!(Addr), &out_dir, "DaoResponse"); +export_schema_with_title( + &schema_for!(CosmosMsg), + &out_dir, + "CosmosMsg_for_Empty", +); +``` + +## Developing + +### Initial setup + +``` +yarn +yarn bootstrap +``` + +### Building + +``` +yarn build +``` + +### Tests + +Then `cd` into a package and run the tests + +``` +cd ./packages/wasm-ast-types +yarn test:watch +``` + +### Working with ASTs + +See the [docs](https://github.com/CosmWasm/ts-codegen/blob/main/packages/ast/README.md) in the `ast` package. + +## Related + +Checkout these related projects: + +- [@cosmology/telescope](https://github.com/hyperweb-io/telescope) a "babel for the Cosmos", Telescope is a TypeScript Transpiler for Cosmos Protobufs. +- [chain-registry](https://github.com/hyperweb-io/chain-registry) an npm module for the official Cosmos chain-registry. +- [cosmos-kit](https://github.com/hyperweb-io/cosmos-kit) A wallet connector for the Cosmos ⚛️ +- [create-cosmos-app](https://github.com/hyperweb-io/create-cosmos-app) set up a modern Cosmos app by running one command. +- [starship](https://github.com/hyperweb-io/starship) a k8s-based unified development environment for Cosmos Ecosystem \ No newline at end of file