Skip to content

Commit b9cf2ac

Browse files
committed
Add code from Rust renderer
1 parent f00f635 commit b9cf2ac

File tree

208 files changed

+47361
-6883
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

208 files changed

+47361
-6883
lines changed

.changeset/config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
33
"changelog": [
44
"@changesets/changelog-github",
5-
{ "repo": "codama-idl/renderers-demo" }
5+
{ "repo": "codama-idl/renderers-rust" }
66
],
77
"commit": false,
88
"access": "public",

.github/workflows/main.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ env:
99
# Among other things, opts out of Turborepo telemetry. See https://consoledonottrack.com/.
1010
DO_NOT_TRACK: '1'
1111
NODE_VERSION: 20
12+
SOLANA_VERSION: 2.1.9
1213

1314
jobs:
1415
lint:
@@ -43,6 +44,11 @@ jobs:
4344
- name: Git checkout
4445
uses: actions/checkout@v4
4546

47+
- name: Install Solana ${{ env.SOLANA_VERSION }}
48+
uses: solana-program/actions/install-solana@v1
49+
with:
50+
version: ${{ env.SOLANA_VERSION }}
51+
4652
- name: Install pnpm
4753
uses: pnpm/action-setup@v3
4854

@@ -102,7 +108,7 @@ jobs:
102108

103109
dependabot:
104110
runs-on: ubuntu-latest
105-
if: github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'codama-idl/renderers-demo'
111+
if: github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'codama-idl/renderers-rust'
106112
needs: [lint, tests]
107113
permissions:
108114
contents: write

.prettierignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
test/e2e/
1+
e2e/
22

33
.changeset/
44
.github/workflows/PULL_REQUEST_TEMPLATE.md

CHANGELOG.md

Lines changed: 523 additions & 3 deletions
Large diffs are not rendered by default.

LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
MIT License
22

33
Copyright (c) 2025 Codama
4+
Copyright (c) 2024 Metaplex Foundation
45

56
Permission is hereby granted, free of charge, to any person obtaining
67
a copy of this software and associated documentation files (the

README.md

Lines changed: 128 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
# Codama ➤ Renderers ➤ Demo
1+
# Codama ➤ Renderers ➤ Rust
22

33
[![npm][npm-image]][npm-url]
44
[![npm-downloads][npm-downloads-image]][npm-url]
55

6-
[npm-downloads-image]: https://img.shields.io/npm/dm/@codama/renderers-demo.svg?style=flat
7-
[npm-image]: https://img.shields.io/npm/v/@codama/renderers-demo.svg?style=flat&label=%40codama%2Frenderers-demo
8-
[npm-url]: https://www.npmjs.com/package/@codama/renderers-demo
6+
[npm-downloads-image]: https://img.shields.io/npm/dm/@codama/renderers-rust.svg?style=flat
7+
[npm-image]: https://img.shields.io/npm/v/@codama/renderers-rust.svg?style=flat&label=%40codama%2Frenderers-rust
8+
[npm-url]: https://www.npmjs.com/package/@codama/renderers-rust
99

10-
This package provides a demo implementation of a Codama renderer to help developers create their own.
10+
This package generates Rust clients from your Codama IDLs.
1111

1212
## Installation
1313

1414
```sh
15-
pnpm install @codama/renderers-demo
15+
pnpm install @codama/renderers-rust
1616
```
1717

1818
## Usage
@@ -22,10 +22,129 @@ Add the following script to your Codama configuration file.
2222
```json
2323
{
2424
"scripts": {
25-
"demo": {
26-
"from": "@codama/renderers-demo",
27-
"args": ["docs"]
25+
"rust": {
26+
"from": "@codama/renderers-rust",
27+
"args": ["clients/rust/src/generated"]
2828
}
2929
}
3030
}
3131
```
32+
33+
An object can be passed as a second argument to further configure the renderer. See the [Options](#options) section below for more details.
34+
35+
## Options
36+
37+
The `renderVisitor` accepts the following options.
38+
39+
| Name | Type | Default | Description |
40+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
41+
| `deleteFolderBeforeRendering` | `boolean` | `true` | Whether the base directory should be cleaned before generating new files. |
42+
| `formatCode` | `boolean` | `false` | Whether we should use `cargo fmt` to format the generated code. When set to `true`, the `crateFolder` option must be provided. |
43+
| `toolchain` | `string` | `"+stable"` | The toolchain to use when formatting the generated code. |
44+
| `crateFolder` | `string` | none | The path to the root folder of the Rust crate. This option is required when `formatCode` is set to `true`. |
45+
| `linkOverrides` | `Record<'accounts' \| 'definedTypes' \| 'instructions' \| 'pdas' \| 'programs' \| 'resolvers', Record<string, string>>` | `{}` | A object that overrides the import path of link nodes. For instance, `{ definedTypes: { counter: 'hooked' } }` uses the `hooked` folder to import any link node referring to the `counter` type. |
46+
| `dependencyMap` | `Record<string, string>` | `{}` | A mapping between import aliases and their actual crate name or path in Rust. |
47+
| `renderParentInstructions` | `boolean` | `false` | When using nested instructions, whether the parent instructions should also be rendered. When set to `false` (default), only the instruction leaves are being rendered. |
48+
| `traitOptions` | [`TraitOptions`](#trait-options) | `DEFAULT_TRAIT_OPTIONS` | A set of options that can be used to configure how traits are rendered for every Rust types. See [documentation below](#trait-options) for more information. |
49+
| `anchorTraits` | `boolean` | `true` | Whether to generate Anchor traits `impl` for account types. |
50+
51+
## Trait Options
52+
53+
The Rust renderer provides sensible default traits when generating the various Rust types you client will use. However, you may wish to configure these traits to better suit your needs. The `traitOptions` attribute is here to help you with that. Let's see the various settings it provides.
54+
55+
### Default traits
56+
57+
Using the `traitOptions` attribute, you may configure the default traits that will be applied to every Rust type. These default traits can be configured using 4 different attributes:
58+
59+
- `baseDefaults`: The default traits to implement for all types.
60+
- `dataEnumDefaults`: The default traits to implement for all data enum types, in addition to the `baseDefaults` traits. Data enums are enums with at least one non-unit variant — e.g. `pub enum Command { Write(String), Quit }`.
61+
- `scalarEnumDefaults`: The default traits to implement for all scalar enum types, in addition to the `baseDefaults` traits. Scalar enums are enums with unit variants only — e.g. `pub enum Feedback { Good, Bad }`.
62+
- `structDefaults`: The default traits to implement for all struct types, in addition to the `baseDefaults` traits.
63+
64+
Note that you must provide the fully qualified name of the traits you provide (e.g. `serde::Serialize`). Here are the default values for these attributes:
65+
66+
```ts
67+
const traitOptions = {
68+
baseDefaults: [
69+
'borsh::BorshSerialize',
70+
'borsh::BorshDeserialize',
71+
'serde::Serialize',
72+
'serde::Deserialize',
73+
'Clone',
74+
'Debug',
75+
'Eq',
76+
'PartialEq',
77+
],
78+
dataEnumDefaults: [],
79+
scalarEnumDefaults: ['Copy', 'PartialOrd', 'Hash', 'num_derive::FromPrimitive'],
80+
structDefaults: [],
81+
};
82+
```
83+
84+
### Overridden traits
85+
86+
In addition to configure the default traits, you may also override the traits for specific types. This will completely replace the default traits for the given type. To do so, you may use the `overrides` attribute of the `traitOptions` object.
87+
88+
This attribute is a map where the keys are the names of the types you want to override, and the values are the traits you want to apply to these types. Here is an example:
89+
90+
```ts
91+
const traitOptions = {
92+
overrides: {
93+
myCustomType: ['Clone', 'my::custom::Trait', 'my::custom::OtherTrait'],
94+
myTypeWithNoTraits: [],
95+
},
96+
};
97+
```
98+
99+
### Feature Flags
100+
101+
You may also configure which traits should be rendered under a feature flag by using the `featureFlags` attribute. This attribute is a map where the keys are feature flag names and the values are the traits that should be rendered under that feature flag. Here is an example:
102+
103+
```ts
104+
const traitOptions = {
105+
featureFlags: { fruits: ['fruits::Apple', 'fruits::Banana'] },
106+
};
107+
```
108+
109+
Now, if at any point, we encounter a `fruits::Apple` or `fruits::Banana` trait to be rendered (either as default traits or as overridden traits), they will be rendered under the `fruits` feature flag. For instance:
110+
111+
```rust
112+
#[cfg_attr(feature = "fruits", derive(fruits::Apple, fruits::Banana))]
113+
```
114+
115+
By default, the `featureFlags` option is set to the following:
116+
117+
```ts
118+
const traitOptions = {
119+
featureFlags: { serde: ['serde::Serialize', 'serde::Deserialize'] },
120+
};
121+
```
122+
123+
Note that for feature flags to be effective, they must be added to the `Cargo.toml` file of the generated Rust client.
124+
125+
### Using the Fully Qualified Name
126+
127+
By default, all traits are imported using the provided Fully Qualified Name which means their short name will be used within the `derive` attributes.
128+
129+
However, you may want to avoid importing these traits and use the Fully Qualified Name directly in the generated code. To do so, you may use the `useFullyQualifiedName` attribute of the `traitOptions` object by setting it to `true`:
130+
131+
```ts
132+
const traitOptions = {
133+
useFullyQualifiedName: true,
134+
};
135+
```
136+
137+
Here is an example of rendered traits with this option set to `true` and `false` (which is the default):
138+
139+
```rust
140+
// With `useFullyQualifiedName` set to `false` (default).
141+
use serde::Serialize;
142+
use serde::Deserialize;
143+
// ...
144+
#[derive(Serialize, Deserialize)]
145+
146+
// With `useFullyQualifiedName` set to `true`.
147+
#[derive(serde::Serialize, serde::Deserialize)]
148+
```
149+
150+
Note that any trait rendered under a feature flag will always use the Fully Qualified Name in order to ensure we only reference the trait when the feature is enabled.

0 commit comments

Comments
 (0)