From 567466c26ad7ba1970dac140a39a7b6d5200534b Mon Sep 17 00:00:00 2001 From: febo Date: Fri, 1 Nov 2024 12:21:23 +0000 Subject: [PATCH 01/24] [wip]: Add renderer skeleton --- packages/renderers-pinocchio/.gitignore | 1 + packages/renderers-pinocchio/.prettierignore | 5 + packages/renderers-pinocchio/LICENSE | 22 + packages/renderers-pinocchio/README.md | 139 ++++++ packages/renderers-pinocchio/package.json | 67 +++ .../public/templates/definedTypesMod.njk | 13 + .../public/templates/definedTypesPage.njk | 15 + .../public/templates/instructionPage.njk | 46 ++ .../public/templates/instructionsMod.njk | 13 + .../public/templates/layout.njk | 7 + .../public/templates/macros.njk | 6 + .../public/templates/programsMod.njk | 14 + .../public/templates/rootMod.njk | 17 + packages/renderers-pinocchio/src/ImportMap.ts | 83 ++++ .../src/getRenderMapVisitor.ts | 231 ++++++++++ .../src/getTypeManifestVisitor.ts | 434 ++++++++++++++++++ packages/renderers-pinocchio/src/index.ts | 4 + .../src/renderValueNodeVisitor.ts | 164 +++++++ .../renderers-pinocchio/src/renderVisitor.ts | 49 ++ .../renderers-pinocchio/src/types/global.d.ts | 6 + .../renderers-pinocchio/src/utils/codecs.ts | 16 + .../renderers-pinocchio/src/utils/index.ts | 4 + .../src/utils/linkOverrides.ts | 70 +++ .../renderers-pinocchio/src/utils/render.ts | 25 + .../src/utils/traitOptions.ts | 166 +++++++ .../tsconfig.declarations.json | 10 + packages/renderers-pinocchio/tsconfig.json | 7 + 27 files changed, 1634 insertions(+) create mode 100644 packages/renderers-pinocchio/.gitignore create mode 100644 packages/renderers-pinocchio/.prettierignore create mode 100644 packages/renderers-pinocchio/LICENSE create mode 100644 packages/renderers-pinocchio/README.md create mode 100644 packages/renderers-pinocchio/package.json create mode 100644 packages/renderers-pinocchio/public/templates/definedTypesMod.njk create mode 100644 packages/renderers-pinocchio/public/templates/definedTypesPage.njk create mode 100644 packages/renderers-pinocchio/public/templates/instructionPage.njk create mode 100644 packages/renderers-pinocchio/public/templates/instructionsMod.njk create mode 100644 packages/renderers-pinocchio/public/templates/layout.njk create mode 100644 packages/renderers-pinocchio/public/templates/macros.njk create mode 100644 packages/renderers-pinocchio/public/templates/programsMod.njk create mode 100644 packages/renderers-pinocchio/public/templates/rootMod.njk create mode 100644 packages/renderers-pinocchio/src/ImportMap.ts create mode 100644 packages/renderers-pinocchio/src/getRenderMapVisitor.ts create mode 100644 packages/renderers-pinocchio/src/getTypeManifestVisitor.ts create mode 100644 packages/renderers-pinocchio/src/index.ts create mode 100644 packages/renderers-pinocchio/src/renderValueNodeVisitor.ts create mode 100644 packages/renderers-pinocchio/src/renderVisitor.ts create mode 100644 packages/renderers-pinocchio/src/types/global.d.ts create mode 100644 packages/renderers-pinocchio/src/utils/codecs.ts create mode 100644 packages/renderers-pinocchio/src/utils/index.ts create mode 100644 packages/renderers-pinocchio/src/utils/linkOverrides.ts create mode 100644 packages/renderers-pinocchio/src/utils/render.ts create mode 100644 packages/renderers-pinocchio/src/utils/traitOptions.ts create mode 100644 packages/renderers-pinocchio/tsconfig.declarations.json create mode 100644 packages/renderers-pinocchio/tsconfig.json diff --git a/packages/renderers-pinocchio/.gitignore b/packages/renderers-pinocchio/.gitignore new file mode 100644 index 000000000..849ddff3b --- /dev/null +++ b/packages/renderers-pinocchio/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/packages/renderers-pinocchio/.prettierignore b/packages/renderers-pinocchio/.prettierignore new file mode 100644 index 000000000..3d73fdedb --- /dev/null +++ b/packages/renderers-pinocchio/.prettierignore @@ -0,0 +1,5 @@ +dist/ +e2e/ +test-ledger/ +target/ +CHANGELOG.md diff --git a/packages/renderers-pinocchio/LICENSE b/packages/renderers-pinocchio/LICENSE new file mode 100644 index 000000000..22fd7b02c --- /dev/null +++ b/packages/renderers-pinocchio/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2024 Codama + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/renderers-pinocchio/README.md b/packages/renderers-pinocchio/README.md new file mode 100644 index 000000000..c37e38437 --- /dev/null +++ b/packages/renderers-pinocchio/README.md @@ -0,0 +1,139 @@ +# Codama ➤ Renderers ➤ Pinocchio + +[![npm][npm-image]][npm-url] +[![npm-downloads][npm-downloads-image]][npm-url] + +[npm-downloads-image]: https://img.shields.io/npm/dm/@codama/renderers-rust.svg?style=flat +[npm-image]: https://img.shields.io/npm/v/@codama/renderers-rust.svg?style=flat&label=%40codama%2Frenderers-pinocchio +[npm-url]: https://www.npmjs.com/package/@codama/renderers-pinocchio + +This package generates Pinocchio-based Rust clients from your Codama IDLs. + +## Installation + +```sh +pnpm install @codama/renderers-pinocchio +``` + +> [!NOTE] +> This package is **not** included in the main [`codama`](../library) package. +> +> However, note that the [`renderers`](../renderers) package re-exports the `renderVisitor` function of this package as `renderRustVisitor`. + +## Usage + +Once you have a Codama IDL, you can use the `renderVisitor` of this package to generate Rust clients. You will need to provide the base directory where the generated files will be saved and an optional set of options to customize the output. + +```ts +// node ./codama.mjs +import { renderVisitor } from '@codama/renderers-pinocchio'; + +const pathToGeneratedFolder = path.join(__dirname, 'clients', 'pinocchio', 'src', 'generated'); +const options = {}; // See below. +codama.accept(renderVisitor(pathToGeneratedFolder, options)); +``` + +## Options + +The `renderVisitor` accepts the following options. + +| Name | Type | Default | Description | +| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `deleteFolderBeforeRendering` | `boolean` | `true` | Whether the base directory should be cleaned before generating new files. | +| `formatCode` | `boolean` | `false` | Whether we should use `cargo fmt` to format the generated code. When set to `true`, the `crateFolder` option must be provided. | +| `toolchain` | `string` | `"+stable"` | The toolchain to use when formatting the generated code. | +| `crateFolder` | `string` | none | The path to the root folder of the Rust crate. This option is required when `formatCode` is set to `true`. | +| `linkOverrides` | `Record<'accounts' \| 'definedTypes' \| 'instructions' \| 'pdas' \| 'programs' \| 'resolvers', Record>` | `{}` | 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. | +| `dependencyMap` | `Record` | `{}` | A mapping between import aliases and their actual crate name or path in Rust. | +| `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. | +| `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. | +| `anchorTraits` | `boolean` | `true` | Whether to generate Anchor traits `impl` for account types. | + +## Trait Options + +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. + +### Default traits + +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: + +- `baseDefaults`: The default traits to implement for all types. +- `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 }`. +- `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 }`. +- `structDefaults`: The default traits to implement for all struct types, in addition to the `baseDefaults` traits. + +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: + +```ts +const traitOptions = { + baseDefaults: [ + 'Clone', + 'Debug', + 'Eq', + 'PartialEq', + ], + dataEnumDefaults: [], + scalarEnumDefaults: ['Copy', 'PartialOrd', 'Hash', 'num_derive::FromPrimitive'], + structDefaults: [], +}; +``` + +### Overridden traits + +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. + +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: + +```ts +const traitOptions = { + overrides: { + myCustomType: ['Clone', 'my::custom::Trait', 'my::custom::OtherTrait'], + myTypeWithNoTraits: [], + }, +}; +``` + +### Feature Flags + +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: + +```ts +const traitOptions = { + featureFlags: { fruits: ['fruits::Apple', 'fruits::Banana'] }, +}; +``` + +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: + +```rust +#[cfg_attr(feature = "fruits", derive(fruits::Apple, fruits::Banana))] +``` + +Note that for feature flags to be effective, they must be added to the `Cargo.toml` file of the generated Rust client. + +### Using the Fully Qualified Name + +By default, all traits are imported using the provided Fully Qualified Name which means their short name will be used within the `derive` attributes. + +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`: + +```ts +const traitOptions = { + useFullyQualifiedName: true, +}; +``` + +Here is an example of rendered traits with this option set to `true` and `false` (which is the default): + +```rust +// With `useFullyQualifiedName` set to `false` (default). +use serde::Serialize; +use serde::Deserialize; +// ... +#[derive(Serialize, Deserialize)] + +// With `useFullyQualifiedName` set to `true`. +#[derive(serde::Serialize, serde::Deserialize)] +``` + +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. diff --git a/packages/renderers-pinocchio/package.json b/packages/renderers-pinocchio/package.json new file mode 100644 index 000000000..4fc37ca68 --- /dev/null +++ b/packages/renderers-pinocchio/package.json @@ -0,0 +1,67 @@ +{ + "name": "@codama/renderers-pinocchio", + "version": "0.1.0", + "description": "Renders Pinocchio-based Rust clients for your programs", + "exports": { + "types": "./dist/types/index.d.ts", + "node": { + "import": "./dist/index.node.mjs", + "require": "./dist/index.node.cjs" + } + }, + "main": "./dist/index.node.cjs", + "module": "./dist/index.node.mjs", + "types": "./dist/types/index.d.ts", + "type": "commonjs", + "files": [ + "./dist/templates", + "./dist/types", + "./dist/index.*" + ], + "sideEffects": false, + "keywords": [ + "solana", + "framework", + "standard", + "renderers", + "rust", + "client" + ], + "scripts": { + "build": "rimraf dist && pnpm build:src && pnpm build:types", + "build:src": "zx ../../node_modules/@codama/internals/scripts/build-src.mjs node", + "build:types": "zx ../../node_modules/@codama/internals/scripts/build-types.mjs", + "dev": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs node --watch", + "lint": "zx ../../node_modules/@codama/internals/scripts/lint.mjs", + "lint:fix": "zx ../../node_modules/@codama/internals/scripts/lint.mjs --fix", + "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:node && pnpm test:e2e && pnpm test:exports", + "test:e2e": "./e2e/test.sh", + "test:exports": "node ./test/exports/module.mjs && node ./test/exports/commonjs.cjs", + "test:node": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs node", + "test:treeshakability": "zx ../../node_modules/@codama/internals/scripts/test-treeshakability.mjs", + "test:types": "zx ../../node_modules/@codama/internals/scripts/test-types.mjs" + }, + "dependencies": { + "@codama/errors": "workspace:*", + "@codama/nodes": "workspace:*", + "@codama/renderers-core": "workspace:*", + "@codama/visitors-core": "workspace:*", + "@solana/codecs-strings": "rc", + "nunjucks": "^3.2.4" + }, + "devDependencies": { + "@types/nunjucks": "^3.2.6" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/codama-idl/codama" + }, + "bugs": { + "url": "http://github.com/codama-idl/codama/issues" + }, + "browserslist": [ + "supports bigint and not dead", + "maintained node versions" + ] +} diff --git a/packages/renderers-pinocchio/public/templates/definedTypesMod.njk b/packages/renderers-pinocchio/public/templates/definedTypesMod.njk new file mode 100644 index 000000000..cff97f064 --- /dev/null +++ b/packages/renderers-pinocchio/public/templates/definedTypesMod.njk @@ -0,0 +1,13 @@ +{% extends "layout.njk" %} + +{% block main %} + +{% for definedType in definedTypesToExport | sort(false, false, 'name') %} + pub(crate) mod r#{{ definedType.name | snakeCase }}; +{% endfor %} + +{% for definedType in definedTypesToExport | sort(false, false, 'name') %} + pub use self::r#{{ definedType.name | snakeCase }}::*; +{% endfor %} + +{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/definedTypesPage.njk b/packages/renderers-pinocchio/public/templates/definedTypesPage.njk new file mode 100644 index 000000000..cb9876903 --- /dev/null +++ b/packages/renderers-pinocchio/public/templates/definedTypesPage.njk @@ -0,0 +1,15 @@ +{% extends "layout.njk" %} +{% import "macros.njk" as macros %} + +{% block main %} + +{{ imports }} + +{{ macros.docblock(definedType.docs) }} +{{- typeManifest.type }} + +{% for nestedStruct in typeManifest.nestedStructs %} +{{ nestedStruct }} +{% endfor %} + +{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/instructionPage.njk b/packages/renderers-pinocchio/public/templates/instructionPage.njk new file mode 100644 index 000000000..06f017a98 --- /dev/null +++ b/packages/renderers-pinocchio/public/templates/instructionPage.njk @@ -0,0 +1,46 @@ +{% extends "layout.njk" %} +{% import "macros.njk" as macros %} + +{% block main %} + +{{ imports }} + +/// `{{ instruction.name | snakeCase }}` CPI helper. +pub struct {{ instruction.name | pascalCase }}{{ '<\'a>' if instruction.accounts.length > 0 }} { + {# Accounts #} + {% for account in instruction.accounts %} + {% if account.docs.length > 0 %} + {{ macros.docblock(account.docs) }} + {% endif %} + + {% if account.isSigner === 'either' %} + {% set type = '(&\'a pinocchio::account_info::AccountInfo, bool)' %} + {% else %} + {% set type = '&\'a pinocchio::account_info::AccountInfo' %} + {% endif %} + + {% if account.isOptional %} + pub {{ account.name | snakeCase }}: Option<{{ type }}>, + {% else %} + pub {{ account.name | snakeCase }}: {{ type }}, + {% endif %} + {% endfor %} + {% for arg in instructionArgs %} + {% if not arg.default %} + pub {{ arg.name | snakeCase }}: {{ arg.type }}, + {% endif %} + {% endfor %} +} + +impl{{ '<\'a>' if instruction.accounts.length > 0 }} {{ instruction.name | pascalCase }}{{ '<\'a>' if instruction.accounts.length > 0 }} { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed(&self, _signers: &[pinocchio::instruction::Signer]) -> pinocchio::ProgramResult { + Ok(()) + } +} + +{% endblock %} \ No newline at end of file diff --git a/packages/renderers-pinocchio/public/templates/instructionsMod.njk b/packages/renderers-pinocchio/public/templates/instructionsMod.njk new file mode 100644 index 000000000..36dd2b6c6 --- /dev/null +++ b/packages/renderers-pinocchio/public/templates/instructionsMod.njk @@ -0,0 +1,13 @@ +{% extends "layout.njk" %} + +{% block main %} + +{% for instruction in instructionsToExport | sort(false, false, 'name') %} + pub(crate) mod r#{{ instruction.name | snakeCase }}; +{% endfor %} + +{% for instruction in instructionsToExport | sort(false, false, 'name') %} + pub use self::r#{{ instruction.name | snakeCase }}::*; +{% endfor %} + +{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/layout.njk b/packages/renderers-pinocchio/public/templates/layout.njk new file mode 100644 index 000000000..30674b24d --- /dev/null +++ b/packages/renderers-pinocchio/public/templates/layout.njk @@ -0,0 +1,7 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! +{% block main %}{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/macros.njk b/packages/renderers-pinocchio/public/templates/macros.njk new file mode 100644 index 000000000..fafbe0d30 --- /dev/null +++ b/packages/renderers-pinocchio/public/templates/macros.njk @@ -0,0 +1,6 @@ +{# Write a docblock from an array of strings. #} +{% macro docblock(docs) %} +{% for doc in docs %} +/// {{ doc }} +{% endfor %} +{% endmacro %} diff --git a/packages/renderers-pinocchio/public/templates/programsMod.njk b/packages/renderers-pinocchio/public/templates/programsMod.njk new file mode 100644 index 000000000..0226b1748 --- /dev/null +++ b/packages/renderers-pinocchio/public/templates/programsMod.njk @@ -0,0 +1,14 @@ +{% extends "layout.njk" %} + +{% block main %} + +use pinocchio::pubkey::Pubkey; +use pinocchio_pubkey::pubkey; + +{% for program in programsToExport | sort(false, false, 'name') %} + + /// `{{ program.name | snakeCase }}` program ID. + pub const {{ program.name | snakeCase | upper }}_ID: Pubkey = pubkey!("{{ program.publicKey }}"); +{% endfor %} + +{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/rootMod.njk b/packages/renderers-pinocchio/public/templates/rootMod.njk new file mode 100644 index 000000000..977b722f5 --- /dev/null +++ b/packages/renderers-pinocchio/public/templates/rootMod.njk @@ -0,0 +1,17 @@ +{% extends "layout.njk" %} + +{% block main %} + +{% if hasAnythingToExport %} + {% if instructionsToExport.length > 0 %} + pub mod instructions; + {% endif %} + {% if programsToExport.length > 0 %} + pub mod programs; + {% endif %} + {% if definedTypesToExport.length > 0 %} + pub mod types; + {% endif %} +{% endif %} + +{% endblock %} diff --git a/packages/renderers-pinocchio/src/ImportMap.ts b/packages/renderers-pinocchio/src/ImportMap.ts new file mode 100644 index 000000000..4600e0df1 --- /dev/null +++ b/packages/renderers-pinocchio/src/ImportMap.ts @@ -0,0 +1,83 @@ +import { TypeManifest } from './getTypeManifestVisitor'; + +const DEFAULT_MODULE_MAP: Record = { + generated: 'crate::generated', + generatedAccounts: 'crate::generated::accounts', + generatedErrors: 'crate::generated::errors', + generatedInstructions: 'crate::generated::instructions', + generatedTypes: 'crate::generated::types', + hooked: 'crate::hooked', + mplEssentials: 'mpl_toolbox', + mplToolbox: 'mpl_toolbox', +}; + +export class ImportMap { + protected readonly _imports: Set = new Set(); + + protected readonly _aliases: Map = new Map(); + + get imports(): Set { + return this._imports; + } + + get aliases(): Map { + return this._aliases; + } + + add(imports: Set | string[] | string): ImportMap { + const newImports = typeof imports === 'string' ? [imports] : imports; + newImports.forEach(i => this._imports.add(i)); + return this; + } + + remove(imports: Set | string[] | string): ImportMap { + const importsToRemove = typeof imports === 'string' ? [imports] : imports; + importsToRemove.forEach(i => this._imports.delete(i)); + return this; + } + + mergeWith(...others: ImportMap[]): ImportMap { + others.forEach(other => { + this.add(other._imports); + other._aliases.forEach((alias, importName) => this.addAlias(importName, alias)); + }); + return this; + } + + mergeWithManifest(manifest: TypeManifest): ImportMap { + return this.mergeWith(manifest.imports); + } + + addAlias(importName: string, alias: string): ImportMap { + this._aliases.set(importName, alias); + return this; + } + + isEmpty(): boolean { + return this._imports.size === 0; + } + + resolveDependencyMap(dependencies: Record): ImportMap { + const dependencyMap = { ...DEFAULT_MODULE_MAP, ...dependencies }; + const newImportMap = new ImportMap(); + const resolveDependency = (i: string): string => { + const dependencyKey = Object.keys(dependencyMap).find(key => i.startsWith(`${key}::`)); + if (!dependencyKey) return i; + const dependencyValue = dependencyMap[dependencyKey]; + return dependencyValue + i.slice(dependencyKey.length); + }; + this._imports.forEach(i => newImportMap.add(resolveDependency(i))); + this._aliases.forEach((alias, i) => newImportMap.addAlias(resolveDependency(i), alias)); + return newImportMap; + } + + toString(dependencies: Record): string { + const resolvedMap = this.resolveDependencyMap(dependencies); + const importStatements = [...resolvedMap.imports].map(i => { + const alias = resolvedMap.aliases.get(i); + if (alias) return `use ${i} as ${alias};`; + return `use ${i};`; + }); + return importStatements.join('\n'); + } +} diff --git a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts new file mode 100644 index 000000000..0c0ec88b5 --- /dev/null +++ b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts @@ -0,0 +1,231 @@ +import { logWarn } from '@codama/errors'; +import { + getAllAccounts, + getAllDefinedTypes, + getAllInstructionsWithSubs, + getAllPrograms, + InstructionNode, + isNode, + pascalCase, + ProgramNode, + snakeCase, + structTypeNodeFromInstructionArgumentNodes, + VALUE_NODES, +} from '@codama/nodes'; +import { RenderMap } from '@codama/renderers-core'; +import { + extendVisitor, + LinkableDictionary, + pipe, + recordLinkablesVisitor, + staticVisitor, + visit, +} from '@codama/visitors-core'; + +import { getTypeManifestVisitor } from './getTypeManifestVisitor'; +import { ImportMap } from './ImportMap'; +import { renderValueNode } from './renderValueNodeVisitor'; +import { getImportFromFactory, getTraitsFromNodeFactory, LinkOverrides, render, TraitOptions } from './utils'; + +export type GetRenderMapOptions = { + anchorTraits?: boolean; + defaultTraitOverrides?: string[]; + dependencyMap?: Record; + linkOverrides?: LinkOverrides; + renderParentInstructions?: boolean; + traitOptions?: TraitOptions; +}; + +export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { + const linkables = new LinkableDictionary(); + let program: ProgramNode | null = null; + + const renderParentInstructions = options.renderParentInstructions ?? false; + const dependencyMap = options.dependencyMap ?? {}; + const getImportFrom = getImportFromFactory(options.linkOverrides ?? {}); + const getTraitsFromNode = getTraitsFromNodeFactory(options.traitOptions); + const typeManifestVisitor = getTypeManifestVisitor({ getImportFrom, getTraitsFromNode }); + + return pipe( + staticVisitor( + () => new RenderMap(), + ['rootNode', 'programNode', 'instructionNode', 'accountNode', 'definedTypeNode'], + ), + v => + extendVisitor(v, { + visitDefinedType(node) { + const typeManifest = visit(node, typeManifestVisitor); + const imports = new ImportMap().mergeWithManifest(typeManifest); + + return new RenderMap().add( + `types/${snakeCase(node.name)}.rs`, + render('definedTypesPage.njk', { + definedType: node, + imports: imports.remove(`generatedTypes::${pascalCase(node.name)}`).toString(dependencyMap), + typeManifest, + }), + ); + }, + + visitInstruction(node) { + // Imports. + const imports = new ImportMap(); + + // canMergeAccountsAndArgs + const accountsAndArgsConflicts = getConflictsForInstructionAccountsAndArgs(node); + if (accountsAndArgsConflicts.length > 0) { + logWarn( + `[Rust] Accounts and args of instruction [${node.name}] have the following ` + + `conflicting attributes [${accountsAndArgsConflicts.join(', ')}]. ` + + `Thus, the conflicting arguments will be suffixed with "_arg". ` + + 'You may want to rename the conflicting attributes.', + ); + } + + // Instruction args. + const instructionArgs: { + default: boolean; + innerOptionType: string | null; + name: string; + optional: boolean; + type: string; + value: string | null; + }[] = []; + let hasArgs = false; + let hasOptional = false; + + node.arguments.forEach(argument => { + const argumentVisitor = getTypeManifestVisitor({ + getImportFrom, + getTraitsFromNode, + nestedStruct: true, + parentName: `${pascalCase(node.name)}InstructionData`, + }); + const manifest = visit(argument.type, argumentVisitor); + imports.mergeWith(manifest.imports); + const innerOptionType = isNode(argument.type, 'optionTypeNode') + ? manifest.type.slice('Option<'.length, -1) + : null; + + const hasDefaultValue = !!argument.defaultValue && isNode(argument.defaultValue, VALUE_NODES); + let renderValue: string | null = null; + if (hasDefaultValue) { + const { imports: argImports, render: value } = renderValueNode( + argument.defaultValue, + getImportFrom, + ); + imports.mergeWith(argImports); + renderValue = value; + } + + hasArgs = hasArgs || argument.defaultValueStrategy !== 'omitted'; + hasOptional = hasOptional || (hasDefaultValue && argument.defaultValueStrategy !== 'omitted'); + + const name = accountsAndArgsConflicts.includes(argument.name) + ? `${argument.name}_arg` + : argument.name; + + instructionArgs.push({ + default: hasDefaultValue && argument.defaultValueStrategy === 'omitted', + innerOptionType, + name, + optional: hasDefaultValue && argument.defaultValueStrategy !== 'omitted', + type: manifest.type, + value: renderValue, + }); + }); + + const struct = structTypeNodeFromInstructionArgumentNodes(node.arguments); + const structVisitor = getTypeManifestVisitor({ + getImportFrom, + getTraitsFromNode, + parentName: `${pascalCase(node.name)}InstructionData`, + }); + const typeManifest = visit(struct, structVisitor); + + return new RenderMap().add( + `instructions/${snakeCase(node.name)}.rs`, + render('instructionPage.njk', { + hasArgs, + hasOptional, + imports: imports + .remove(`generatedInstructions::${pascalCase(node.name)}`) + .toString(dependencyMap), + instruction: node, + instructionArgs, + program, + typeManifest, + }), + ); + }, + + visitProgram(node, { self }) { + program = node; + const renderMap = new RenderMap() + .mergeWith(...node.accounts.map(account => visit(account, self))) + .mergeWith(...node.definedTypes.map(type => visit(type, self))) + .mergeWith( + ...getAllInstructionsWithSubs(node, { + leavesOnly: !renderParentInstructions, + }).map(ix => visit(ix, self)), + ); + + program = null; + return renderMap; + }, + + visitRoot(node, { self }) { + const programsToExport = getAllPrograms(node); + const accountsToExport = getAllAccounts(node); + const instructionsToExport = getAllInstructionsWithSubs(node, { + leavesOnly: !renderParentInstructions, + }); + const definedTypesToExport = getAllDefinedTypes(node); + const hasAnythingToExport = + programsToExport.length > 0 || + accountsToExport.length > 0 || + instructionsToExport.length > 0 || + definedTypesToExport.length > 0; + + const ctx = { + accountsToExport, + definedTypesToExport, + hasAnythingToExport, + instructionsToExport, + programsToExport, + root: node, + }; + + const map = new RenderMap(); + if (programsToExport.length > 0) { + map.add('programs.rs', render('programsMod.njk', ctx)); + } + /* + if (accountsToExport.length > 0) { + map.add('accounts/mod.rs', render('accountsMod.njk', ctx)); + } + */ + if (definedTypesToExport.length > 0) { + map.add('types/mod.rs', render('definedTypesMod.njk', ctx)); + } + if (instructionsToExport.length > 0) { + map.add('instructions/mod.rs', render('instructionsMod.njk', ctx)); + } + + return map + .add('mod.rs', render('rootMod.njk', ctx)) + .mergeWith(...getAllPrograms(node).map(p => visit(p, self))); + }, + }), + v => recordLinkablesVisitor(v, linkables), + ); +} + +function getConflictsForInstructionAccountsAndArgs(instruction: InstructionNode): string[] { + const allNames = [ + ...instruction.accounts.map(account => account.name), + ...instruction.arguments.map(argument => argument.name), + ]; + const duplicates = allNames.filter((e, i, a) => a.indexOf(e) !== i); + return [...new Set(duplicates)]; +} diff --git a/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts b/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts new file mode 100644 index 000000000..ed07e9dc4 --- /dev/null +++ b/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts @@ -0,0 +1,434 @@ +import { CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, CodamaError } from '@codama/errors'; +import { + arrayTypeNode, + CountNode, + definedTypeNode, + fixedCountNode, + isNode, + NumberTypeNode, + numberTypeNode, + pascalCase, + prefixedCountNode, + REGISTERED_TYPE_NODE_KINDS, + remainderCountNode, + resolveNestedTypeNode, + snakeCase, +} from '@codama/nodes'; +import { extendVisitor, mergeVisitor, pipe, visit } from '@codama/visitors-core'; + +import { ImportMap } from './ImportMap'; +import { GetImportFromFunction, GetTraitsFromNodeFunction, rustDocblock } from './utils'; + +export type TypeManifest = { + imports: ImportMap; + nestedStructs: string[]; + type: string; +}; + +export function getTypeManifestVisitor(options: { + getImportFrom: GetImportFromFunction; + getTraitsFromNode: GetTraitsFromNodeFunction; + nestedStruct?: boolean; + parentName?: string | null; +}) { + const { getImportFrom, getTraitsFromNode } = options; + let parentName: string | null = options.parentName ?? null; + let nestedStruct: boolean = options.nestedStruct ?? false; + let inlineStruct: boolean = false; + let parentSize: NumberTypeNode | number | null = null; + + return pipe( + mergeVisitor( + (): TypeManifest => ({ imports: new ImportMap(), nestedStructs: [], type: '' }), + (_, values) => ({ + ...mergeManifests(values), + type: values.map(v => v.type).join('\n'), + }), + [...REGISTERED_TYPE_NODE_KINDS, 'definedTypeLinkNode', 'definedTypeNode', 'accountNode'], + ), + v => + extendVisitor(v, { + visitAccount(account, { self }) { + parentName = pascalCase(account.name); + const manifest = visit(account.data, self); + const traits = getTraitsFromNode(account); + manifest.imports.mergeWith(traits.imports); + parentName = null; + return { + ...manifest, + type: traits.render + manifest.type, + }; + }, + + visitArrayType(arrayType, { self }) { + const childManifest = visit(arrayType.item, self); + + if (isNode(arrayType.count, 'fixedCountNode')) { + return { + ...childManifest, + type: `[${childManifest.type}; ${arrayType.count.value}]`, + }; + } + + // TODO: Add to the Rust validator. + throw new Error('Array size currently not supported.'); + }, + + visitBooleanType(booleanType) { + const resolvedSize = resolveNestedTypeNode(booleanType.size); + if (resolvedSize.format === 'u8' && resolvedSize.endian === 'le') { + return { + imports: new ImportMap(), + nestedStructs: [], + type: 'bool', + }; + } + + // TODO: Add to the Rust validator. + throw new Error('Bool size currently not supported.'); + }, + + visitBytesType(_bytesType, { self }) { + let arraySize: CountNode = remainderCountNode(); + if (typeof parentSize === 'number') { + arraySize = fixedCountNode(parentSize); + } else if (parentSize && typeof parentSize === 'object') { + arraySize = prefixedCountNode(parentSize); + } + const arrayType = arrayTypeNode(numberTypeNode('u8'), arraySize); + return visit(arrayType, self); + }, + + visitDefinedType(definedType, { self }) { + parentName = pascalCase(definedType.name); + const manifest = visit(definedType.type, self); + const traits = getTraitsFromNode(definedType); + manifest.imports.mergeWith(traits.imports); + parentName = null; + + const renderedType = isNode(definedType.type, ['enumTypeNode', 'structTypeNode']) + ? manifest.type + : `pub type ${pascalCase(definedType.name)} = ${manifest.type};`; + + return { ...manifest, type: `${traits.render}${renderedType}` }; + }, + + visitDefinedTypeLink(node) { + const pascalCaseDefinedType = pascalCase(node.name); + const importFrom = getImportFrom(node); + return { + imports: new ImportMap().add(`${importFrom}::${pascalCaseDefinedType}`), + nestedStructs: [], + type: pascalCaseDefinedType, + }; + }, + + visitEnumEmptyVariantType(enumEmptyVariantType) { + const name = pascalCase(enumEmptyVariantType.name); + return { + imports: new ImportMap(), + nestedStructs: [], + type: `${name},`, + }; + }, + + visitEnumStructVariantType(enumStructVariantType, { self }) { + const name = pascalCase(enumStructVariantType.name); + const originalParentName = parentName; + + if (!originalParentName) { + throw new Error('Enum struct variant type must have a parent name.'); + } + + inlineStruct = true; + parentName = pascalCase(originalParentName) + name; + const typeManifest = visit(enumStructVariantType.struct, self); + inlineStruct = false; + parentName = originalParentName; + + return { + ...typeManifest, + type: `${name} ${typeManifest.type},`, + }; + }, + + visitEnumTupleVariantType(enumTupleVariantType, { self }) { + const name = pascalCase(enumTupleVariantType.name); + const originalParentName = parentName; + + if (!originalParentName) { + throw new Error('Enum struct variant type must have a parent name.'); + } + + parentName = pascalCase(originalParentName) + name; + const childManifest = visit(enumTupleVariantType.tuple, self); + parentName = originalParentName; + + let derive = ''; + if (childManifest.type === '(Pubkey)') { + derive = + '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))]\n'; + } else if (childManifest.type === '(Vec)') { + derive = + '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::>"))]\n'; + } + + return { + ...childManifest, + type: `${derive}${name}${childManifest.type},`, + }; + }, + + visitEnumType(enumType, { self }) { + const originalParentName = parentName; + if (!originalParentName) { + // TODO: Add to the Rust validator. + throw new Error('Enum type must have a parent name.'); + } + + const variants = enumType.variants.map(variant => visit(variant, self)); + const variantNames = variants.map(variant => variant.type).join('\n'); + const mergedManifest = mergeManifests(variants); + + return { + ...mergedManifest, + type: `pub enum ${pascalCase(originalParentName)} {\n${variantNames}\n}`, + }; + }, + + visitFixedSizeType(fixedSizeType, { self }) { + parentSize = fixedSizeType.size; + const manifest = visit(fixedSizeType.type, self); + parentSize = null; + return manifest; + }, + + visitMapType(mapType, { self }) { + const key = visit(mapType.key, self); + const value = visit(mapType.value, self); + const mergedManifest = mergeManifests([key, value]); + mergedManifest.imports.add('std::collections::HashMap'); + return { + ...mergedManifest, + type: `HashMap<${key.type}, ${value.type}>`, + }; + }, + + visitNumberType(numberType) { + if (numberType.endian !== 'le') { + // TODO: Add to the Rust validator. + throw new Error('Number endianness currently not supported.'); + } + + if (numberType.format === 'shortU16') { + return { + imports: new ImportMap().add('solana_program::short_vec::ShortU16'), + nestedStructs: [], + type: 'ShortU16', + }; + } + + return { + imports: new ImportMap(), + nestedStructs: [], + type: numberType.format, + }; + }, + + visitOptionType(optionType, { self }) { + const childManifest = visit(optionType.item, self); + + const optionPrefix = resolveNestedTypeNode(optionType.prefix); + if (optionPrefix.format === 'u8' && optionPrefix.endian === 'le') { + return { + ...childManifest, + type: `Option<${childManifest.type}>`, + }; + } + + // TODO: Add to the Rust validator. + throw new Error('Option size currently not supported.'); + }, + + visitPublicKeyType() { + return { + imports: new ImportMap().add('pinocchio::pubkey::Pubkey'), + nestedStructs: [], + type: 'Pubkey', + }; + }, + + visitRemainderOptionType(node) { + throw new CodamaError(CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, { kind: node.kind, node }); + }, + + visitSetType(setType, { self }) { + const childManifest = visit(setType.item, self); + childManifest.imports.add('std::collections::HashSet'); + return { + ...childManifest, + type: `HashSet<${childManifest.type}>`, + }; + }, + + visitSizePrefixType(sizePrefixType, { self }) { + parentSize = resolveNestedTypeNode(sizePrefixType.prefix); + const manifest = visit(sizePrefixType.type, self); + parentSize = null; + return manifest; + }, + + visitStringType() { + if (!parentSize) { + return { + imports: new ImportMap(), + nestedStructs: [], + type: `str`, + }; + } + + if (typeof parentSize === 'number') { + return { + imports: new ImportMap(), + nestedStructs: [], + type: `[u8; ${parentSize}]`, + }; + } + + if (isNode(parentSize, 'numberTypeNode') && parentSize.endian === 'le') { + switch (parentSize.format) { + case 'u32': + return { + imports: new ImportMap(), + nestedStructs: [], + type: 'String', + }; + case 'u8': + case 'u16': + case 'u64': { + const prefix = parentSize.format.toUpperCase(); + return { + imports: new ImportMap().add(`kaigan::types::${prefix}PrefixString`), + nestedStructs: [], + type: `${prefix}PrefixString`, + }; + } + default: + throw new Error(`String size not supported: ${parentSize.format}`); + } + } + + // TODO: Add to the Rust validator. + throw new Error(`String size currently not supported: ${parentSize}`); + }, + + visitStructFieldType(structFieldType, { self }) { + const originalParentName = parentName; + const originalInlineStruct = inlineStruct; + const originalNestedStruct = nestedStruct; + + if (!originalParentName) { + throw new Error('Struct field type must have a parent name.'); + } + + parentName = pascalCase(originalParentName) + pascalCase(structFieldType.name); + nestedStruct = true; + inlineStruct = false; + + const fieldManifest = visit(structFieldType.type, self); + + parentName = originalParentName; + inlineStruct = originalInlineStruct; + nestedStruct = originalNestedStruct; + + const fieldName = snakeCase(structFieldType.name); + const docblock = rustDocblock(structFieldType.docs); + const resolvedNestedType = resolveNestedTypeNode(structFieldType.type); + + let derive = ''; + if (fieldManifest.type === 'Pubkey') { + derive = + '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))]\n'; + } else if (fieldManifest.type === 'Vec') { + derive = + '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::>"))]\n'; + } else if ( + (isNode(resolvedNestedType, 'arrayTypeNode') && + isNode(resolvedNestedType.count, 'fixedCountNode') && + resolvedNestedType.count.value > 32) || + (isNode(resolvedNestedType, ['bytesTypeNode', 'stringTypeNode']) && + isNode(structFieldType.type, 'fixedSizeTypeNode') && + structFieldType.type.size > 32) + ) { + derive = + '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))]\n'; + } + + return { + ...fieldManifest, + type: inlineStruct + ? `${docblock}${derive}${fieldName}: ${fieldManifest.type},` + : `${docblock}${derive}pub ${fieldName}: ${fieldManifest.type},`, + }; + }, + + visitStructType(structType, { self }) { + const originalParentName = parentName; + + if (!originalParentName) { + // TODO: Add to the Rust validator. + throw new Error('Struct type must have a parent name.'); + } + + const fields = structType.fields.map(field => visit(field, self)); + const fieldTypes = fields.map(field => field.type).join('\n'); + const mergedManifest = mergeManifests(fields); + + if (nestedStruct) { + const nestedTraits = getTraitsFromNode( + definedTypeNode({ name: originalParentName, type: structType }), + ); + mergedManifest.imports.mergeWith(nestedTraits.imports); + return { + ...mergedManifest, + nestedStructs: [ + ...mergedManifest.nestedStructs, + `${nestedTraits.render}pub struct ${pascalCase(originalParentName)} {\n${fieldTypes}\n}`, + ], + type: pascalCase(originalParentName), + }; + } + + if (inlineStruct) { + return { ...mergedManifest, type: `{\n${fieldTypes}\n}` }; + } + + return { + ...mergedManifest, + type: `pub struct ${pascalCase(originalParentName)} {\n${fieldTypes}\n}`, + }; + }, + + visitTupleType(tupleType, { self }) { + const items = tupleType.items.map(item => visit(item, self)); + const mergedManifest = mergeManifests(items); + + return { + ...mergedManifest, + type: `(${items.map(item => item.type).join(', ')})`, + }; + }, + + visitZeroableOptionType(node) { + throw new CodamaError(CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, { kind: node.kind, node }); + }, + }), + ); +} + +function mergeManifests(manifests: TypeManifest[]): Pick { + return { + imports: new ImportMap().mergeWith(...manifests.map(td => td.imports)), + nestedStructs: manifests.flatMap(m => m.nestedStructs), + }; +} diff --git a/packages/renderers-pinocchio/src/index.ts b/packages/renderers-pinocchio/src/index.ts new file mode 100644 index 000000000..f5fa040b7 --- /dev/null +++ b/packages/renderers-pinocchio/src/index.ts @@ -0,0 +1,4 @@ +export * from './ImportMap'; +export * from './getRenderMapVisitor'; +export * from './getTypeManifestVisitor'; +export * from './renderVisitor'; diff --git a/packages/renderers-pinocchio/src/renderValueNodeVisitor.ts b/packages/renderers-pinocchio/src/renderValueNodeVisitor.ts new file mode 100644 index 000000000..320678b6c --- /dev/null +++ b/packages/renderers-pinocchio/src/renderValueNodeVisitor.ts @@ -0,0 +1,164 @@ +import { + arrayValueNode, + bytesValueNode, + isNode, + numberValueNode, + pascalCase, + RegisteredValueNode, + ValueNode, +} from '@codama/nodes'; +import { visit, Visitor } from '@codama/visitors-core'; + +import { ImportMap } from './ImportMap'; +import { getBytesFromBytesValueNode, GetImportFromFunction } from './utils'; + +export function renderValueNode( + value: ValueNode, + getImportFrom: GetImportFromFunction, + useStr: boolean = false, +): { + imports: ImportMap; + render: string; +} { + return visit(value, renderValueNodeVisitor(getImportFrom, useStr)); +} + +export function renderValueNodeVisitor( + getImportFrom: GetImportFromFunction, + useStr: boolean = false, +): Visitor< + { + imports: ImportMap; + render: string; + }, + RegisteredValueNode['kind'] +> { + return { + visitArrayValue(node) { + const list = node.items.map(v => visit(v, this)); + return { + imports: new ImportMap().mergeWith(...list.map(c => c.imports)), + render: `[${list.map(c => c.render).join(', ')}]`, + }; + }, + visitBooleanValue(node) { + return { + imports: new ImportMap(), + render: JSON.stringify(node.boolean), + }; + }, + visitBytesValue(node) { + const bytes = getBytesFromBytesValueNode(node); + const numbers = Array.from(bytes).map(numberValueNode); + return visit(arrayValueNode(numbers), this); + }, + visitConstantValue(node) { + if (isNode(node.value, 'bytesValueNode')) { + return visit(node.value, this); + } + if (isNode(node.type, 'stringTypeNode') && isNode(node.value, 'stringValueNode')) { + return visit(bytesValueNode(node.type.encoding, node.value.string), this); + } + if (isNode(node.type, 'numberTypeNode') && isNode(node.value, 'numberValueNode')) { + const numberManifest = visit(node.value, this); + const { format, endian } = node.type; + const byteFunction = endian === 'le' ? 'to_le_bytes' : 'to_be_bytes'; + numberManifest.render = `${numberManifest.render}${format}.${byteFunction}()`; + return numberManifest; + } + throw new Error('Unsupported constant value type.'); + }, + visitEnumValue(node) { + const imports = new ImportMap(); + const enumName = pascalCase(node.enum.name); + const variantName = pascalCase(node.variant); + const importFrom = getImportFrom(node.enum); + imports.add(`${importFrom}::${enumName}`); + if (!node.value) { + return { imports, render: `${enumName}::${variantName}` }; + } + const enumValue = visit(node.value, this); + const fields = enumValue.render; + return { + imports: imports.mergeWith(enumValue.imports), + render: `${enumName}::${variantName} ${fields}`, + }; + }, + visitMapEntryValue(node) { + const mapKey = visit(node.key, this); + const mapValue = visit(node.value, this); + return { + imports: mapKey.imports.mergeWith(mapValue.imports), + render: `[${mapKey.render}, ${mapValue.render}]`, + }; + }, + visitMapValue(node) { + const map = node.entries.map(entry => visit(entry, this)); + const imports = new ImportMap().add('std::collection::HashMap'); + return { + imports: imports.mergeWith(...map.map(c => c.imports)), + render: `HashMap::from([${map.map(c => c.render).join(', ')}])`, + }; + }, + visitNoneValue() { + return { + imports: new ImportMap(), + render: 'None', + }; + }, + visitNumberValue(node) { + return { + imports: new ImportMap(), + render: node.number.toString(), + }; + }, + visitPublicKeyValue(node) { + return { + imports: new ImportMap().add('solana_program::pubkey'), + render: `pubkey!("${node.publicKey}")`, + }; + }, + visitSetValue(node) { + const set = node.items.map(v => visit(v, this)); + const imports = new ImportMap().add('std::collection::HashSet'); + return { + imports: imports.mergeWith(...set.map(c => c.imports)), + render: `HashSet::from([${set.map(c => c.render).join(', ')}])`, + }; + }, + visitSomeValue(node) { + const child = visit(node.value, this); + return { + ...child, + render: `Some(${child.render})`, + }; + }, + visitStringValue(node) { + return { + imports: new ImportMap(), + render: useStr ? `${JSON.stringify(node.string)}` : `String::from(${JSON.stringify(node.string)})`, + }; + }, + visitStructFieldValue(node) { + const structValue = visit(node.value, this); + return { + imports: structValue.imports, + render: `${node.name}: ${structValue.render}`, + }; + }, + visitStructValue(node) { + const struct = node.fields.map(field => visit(field, this)); + return { + imports: new ImportMap().mergeWith(...struct.map(c => c.imports)), + render: `{ ${struct.map(c => c.render).join(', ')} }`, + }; + }, + visitTupleValue(node) { + const tuple = node.items.map(v => visit(v, this)); + return { + imports: new ImportMap().mergeWith(...tuple.map(c => c.imports)), + render: `(${tuple.map(c => c.render).join(', ')})`, + }; + }, + }; +} diff --git a/packages/renderers-pinocchio/src/renderVisitor.ts b/packages/renderers-pinocchio/src/renderVisitor.ts new file mode 100644 index 000000000..2260b2796 --- /dev/null +++ b/packages/renderers-pinocchio/src/renderVisitor.ts @@ -0,0 +1,49 @@ +import { logError, logWarn } from '@codama/errors'; +import { deleteDirectory, writeRenderMapVisitor } from '@codama/renderers-core'; +import { rootNodeVisitor, visit } from '@codama/visitors-core'; +import { spawnSync } from 'child_process'; + +import { GetRenderMapOptions, getRenderMapVisitor } from './getRenderMapVisitor'; + +export type RenderOptions = GetRenderMapOptions & { + crateFolder?: string; + deleteFolderBeforeRendering?: boolean; + formatCode?: boolean; + toolchain?: string; +}; + +export function renderVisitor(path: string, options: RenderOptions = {}) { + return rootNodeVisitor(root => { + // Delete existing generated folder. + if (options.deleteFolderBeforeRendering ?? true) { + deleteDirectory(path); + } + + // Render the new files. + visit(root, writeRenderMapVisitor(getRenderMapVisitor(options), path)); + + // format the code + if (options.formatCode) { + if (options.crateFolder) { + const toolchain = options.toolchain ?? '+stable'; + runFormatter('cargo', [toolchain, 'fmt', '--manifest-path', `${options.crateFolder}/Cargo.toml`]); + } else { + logWarn('No crate folder specified, skipping formatting.'); + } + } + }); +} + +function runFormatter(cmd: string, args: string[]) { + const { stdout, stderr, error } = spawnSync(cmd, args); + if (error?.message?.includes('ENOENT')) { + logWarn(`Could not find ${cmd}, skipping formatting.`); + return; + } + if (stdout.length > 0) { + logWarn(`(cargo-fmt) ${stdout || error}`); + } + if (stderr.length > 0) { + logError(`(cargo-fmt) ${stderr || error}`); + } +} diff --git a/packages/renderers-pinocchio/src/types/global.d.ts b/packages/renderers-pinocchio/src/types/global.d.ts new file mode 100644 index 000000000..13de8a7ce --- /dev/null +++ b/packages/renderers-pinocchio/src/types/global.d.ts @@ -0,0 +1,6 @@ +declare const __BROWSER__: boolean; +declare const __ESM__: boolean; +declare const __NODEJS__: boolean; +declare const __REACTNATIVE__: boolean; +declare const __TEST__: boolean; +declare const __VERSION__: string; diff --git a/packages/renderers-pinocchio/src/utils/codecs.ts b/packages/renderers-pinocchio/src/utils/codecs.ts new file mode 100644 index 000000000..3a524c015 --- /dev/null +++ b/packages/renderers-pinocchio/src/utils/codecs.ts @@ -0,0 +1,16 @@ +import { BytesValueNode } from '@codama/nodes'; +import { getBase16Encoder, getBase58Encoder, getBase64Encoder, getUtf8Encoder } from '@solana/codecs-strings'; + +export function getBytesFromBytesValueNode(node: BytesValueNode): Uint8Array { + switch (node.encoding) { + case 'utf8': + return getUtf8Encoder().encode(node.data) as Uint8Array; + case 'base16': + return getBase16Encoder().encode(node.data) as Uint8Array; + case 'base58': + return getBase58Encoder().encode(node.data) as Uint8Array; + case 'base64': + default: + return getBase64Encoder().encode(node.data) as Uint8Array; + } +} diff --git a/packages/renderers-pinocchio/src/utils/index.ts b/packages/renderers-pinocchio/src/utils/index.ts new file mode 100644 index 000000000..4de9615fb --- /dev/null +++ b/packages/renderers-pinocchio/src/utils/index.ts @@ -0,0 +1,4 @@ +export * from './codecs'; +export * from './linkOverrides'; +export * from './render'; +export * from './traitOptions'; diff --git a/packages/renderers-pinocchio/src/utils/linkOverrides.ts b/packages/renderers-pinocchio/src/utils/linkOverrides.ts new file mode 100644 index 000000000..a7a43a3ec --- /dev/null +++ b/packages/renderers-pinocchio/src/utils/linkOverrides.ts @@ -0,0 +1,70 @@ +import { CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError } from '@codama/errors'; +import { + AccountLinkNode, + DefinedTypeLinkNode, + InstructionLinkNode, + PdaLinkNode, + ProgramLinkNode, + ResolverValueNode, +} from '@codama/nodes'; + +export type LinkOverrides = { + accounts?: Record; + definedTypes?: Record; + instructions?: Record; + pdas?: Record; + programs?: Record; + resolvers?: Record; +}; + +type OverridableNodes = + | AccountLinkNode + | DefinedTypeLinkNode + | InstructionLinkNode + | PdaLinkNode + | ProgramLinkNode + | ResolverValueNode; + +export type GetImportFromFunction = (node: OverridableNodes, fallback?: string) => string; + +export function getImportFromFactory(overrides: LinkOverrides): GetImportFromFunction { + const linkOverrides = { + accounts: overrides.accounts ?? {}, + definedTypes: overrides.definedTypes ?? {}, + instructions: overrides.instructions ?? {}, + pdas: overrides.pdas ?? {}, + programs: overrides.programs ?? {}, + resolvers: overrides.resolvers ?? {}, + }; + + return (node: OverridableNodes) => { + const kind = node.kind; + switch (kind) { + case 'accountLinkNode': + return linkOverrides.accounts[node.name] ?? 'generatedAccounts'; + case 'definedTypeLinkNode': + return linkOverrides.definedTypes[node.name] ?? 'generatedTypes'; + case 'instructionLinkNode': + return linkOverrides.instructions[node.name] ?? 'generatedInstructions'; + case 'pdaLinkNode': + return linkOverrides.pdas[node.name] ?? 'generatedAccounts'; + case 'programLinkNode': + return linkOverrides.programs[node.name] ?? 'generatedPrograms'; + case 'resolverValueNode': + return linkOverrides.resolvers[node.name] ?? 'hooked'; + default: + throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { + expectedKinds: [ + 'AccountLinkNode', + 'DefinedTypeLinkNode', + 'InstructionLinkNode', + 'PdaLinkNode', + 'ProgramLinkNode', + 'resolverValueNode', + ], + kind: kind satisfies never, + node, + }); + } + }; +} diff --git a/packages/renderers-pinocchio/src/utils/render.ts b/packages/renderers-pinocchio/src/utils/render.ts new file mode 100644 index 000000000..fa14c0d62 --- /dev/null +++ b/packages/renderers-pinocchio/src/utils/render.ts @@ -0,0 +1,25 @@ +import { dirname as pathDirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { camelCase, kebabCase, pascalCase, snakeCase, titleCase } from '@codama/nodes'; +import nunjucks, { ConfigureOptions as NunJucksOptions } from 'nunjucks'; + +export function rustDocblock(docs: string[]): string { + if (docs.length <= 0) return ''; + const lines = docs.map(doc => `/// ${doc}`); + return `${lines.join('\n')}\n`; +} + +export const render = (template: string, context?: object, options?: NunJucksOptions): string => { + // @ts-expect-error import.meta will be used in the right environment. + const dirname = __ESM__ ? pathDirname(fileURLToPath(import.meta.url)) : __dirname; + const templates = __TEST__ ? join(dirname, '..', '..', 'public', 'templates') : join(dirname, 'templates'); // Path to templates from bundled output file. + const env = nunjucks.configure(templates, { autoescape: false, trimBlocks: true, ...options }); + env.addFilter('pascalCase', pascalCase); + env.addFilter('camelCase', camelCase); + env.addFilter('snakeCase', snakeCase); + env.addFilter('kebabCase', kebabCase); + env.addFilter('titleCase', titleCase); + env.addFilter('rustDocblock', rustDocblock); + return env.render(template, context); +}; diff --git a/packages/renderers-pinocchio/src/utils/traitOptions.ts b/packages/renderers-pinocchio/src/utils/traitOptions.ts new file mode 100644 index 000000000..7bb925605 --- /dev/null +++ b/packages/renderers-pinocchio/src/utils/traitOptions.ts @@ -0,0 +1,166 @@ +import { AccountNode, assertIsNode, camelCase, DefinedTypeNode, isNode, isScalarEnum } from '@codama/nodes'; + +import { ImportMap } from '../ImportMap'; + +export type TraitOptions = { + /** The default traits to implement for all types. */ + baseDefaults?: string[]; + /** + * The default traits to implement for data enums only — on top of the base defaults. + * Data enums are enums with at least one non-unit variant. + */ + dataEnumDefaults?: string[]; + /** + * The mapping of feature flags to traits. + * For each entry, the traits will be rendered within a + * `#[cfg_attr(feature = "feature_name", derive(Traits))]` attribute. + */ + featureFlags?: Record; + /** The complete trait overrides of specific types. */ + overrides?: Record; + /** + * The default traits to implement for scalar enums only — on top of the base defaults. + * Scalar enums are enums with no variants or only unit variants. + */ + scalarEnumDefaults?: string[]; + /** The default traits to implement for structs only — on top of the base defaults. */ + structDefaults?: string[]; + /** Whether or not to use the fully qualified name for traits, instead of importing them. */ + useFullyQualifiedName?: boolean; +}; + +export const DEFAULT_TRAIT_OPTIONS: Required = { + baseDefaults: [ + 'borsh::BorshSerialize', + 'borsh::BorshDeserialize', + 'serde::Serialize', + 'serde::Deserialize', + 'Clone', + 'Debug', + 'Eq', + 'PartialEq', + ], + dataEnumDefaults: [], + featureFlags: { + borsh: ['borsh::BorshSerialize', 'borsh::BorshDeserialize'], + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + overrides: {}, + scalarEnumDefaults: ['Copy', 'PartialOrd', 'Hash', 'num_derive::FromPrimitive'], + structDefaults: [], + useFullyQualifiedName: false, +}; + +export type GetTraitsFromNodeFunction = (node: AccountNode | DefinedTypeNode) => { imports: ImportMap; render: string }; + +export function getTraitsFromNodeFactory(options: TraitOptions = {}): GetTraitsFromNodeFunction { + return node => getTraitsFromNode(node, options); +} + +export function getTraitsFromNode( + node: AccountNode | DefinedTypeNode, + userOptions: TraitOptions = {}, +): { imports: ImportMap; render: string } { + assertIsNode(node, ['accountNode', 'definedTypeNode']); + const options: Required = { ...DEFAULT_TRAIT_OPTIONS, ...userOptions }; + + // Get the node type and return early if it's a type alias. + const nodeType = getNodeType(node); + if (nodeType === 'alias') { + return { imports: new ImportMap(), render: '' }; + } + + // Find all the FQN traits for the node. + const sanitizedOverrides = Object.fromEntries( + Object.entries(options.overrides).map(([key, value]) => [camelCase(key), value]), + ); + const nodeOverrides: string[] | undefined = sanitizedOverrides[node.name]; + const allTraits = nodeOverrides === undefined ? getDefaultTraits(nodeType, options) : nodeOverrides; + + // Wrap the traits in feature flags if necessary. + const partitionedTraits = partitionTraitsInFeatures(allTraits, options.featureFlags); + let unfeaturedTraits = partitionedTraits[0]; + const featuredTraits = partitionedTraits[1]; + + // Import the traits if necessary. + const imports = new ImportMap(); + if (!options.useFullyQualifiedName) { + unfeaturedTraits = extractFullyQualifiedNames(unfeaturedTraits, imports); + } + + // Render the trait lines. + const traitLines: string[] = [ + ...(unfeaturedTraits.length > 0 ? [`#[derive(${unfeaturedTraits.join(', ')})]\n`] : []), + ...Object.entries(featuredTraits).map(([feature, traits]) => { + return `#[cfg_attr(feature = "${feature}", derive(${traits.join(', ')}))]\n`; + }), + ]; + + return { imports, render: traitLines.join('') }; +} + +function getNodeType(node: AccountNode | DefinedTypeNode): 'alias' | 'dataEnum' | 'scalarEnum' | 'struct' { + if (isNode(node, 'accountNode')) return 'struct'; + if (isNode(node.type, 'structTypeNode')) return 'struct'; + if (isNode(node.type, 'enumTypeNode')) { + return isScalarEnum(node.type) ? 'scalarEnum' : 'dataEnum'; + } + return 'alias'; +} + +function getDefaultTraits( + nodeType: 'dataEnum' | 'scalarEnum' | 'struct', + options: Pick< + Required, + 'baseDefaults' | 'dataEnumDefaults' | 'scalarEnumDefaults' | 'structDefaults' + >, +): string[] { + switch (nodeType) { + case 'dataEnum': + return [...options.baseDefaults, ...options.dataEnumDefaults]; + case 'scalarEnum': + return [...options.baseDefaults, ...options.scalarEnumDefaults]; + case 'struct': + return [...options.baseDefaults, ...options.structDefaults]; + } +} + +function partitionTraitsInFeatures( + traits: string[], + featureFlags: Record, +): [string[], Record] { + // Reverse the feature flags option for quick lookup. + // If there are any duplicate traits, the first one encountered will be used. + const reverseFeatureFlags = Object.entries(featureFlags).reduce( + (acc, [feature, traits]) => { + for (const trait of traits) { + if (!acc[trait]) acc[trait] = feature; + } + return acc; + }, + {} as Record, + ); + + const unfeaturedTraits: string[] = []; + const featuredTraits: Record = {}; + for (const trait of traits) { + const feature: string | undefined = reverseFeatureFlags[trait]; + if (feature === undefined) { + unfeaturedTraits.push(trait); + } else { + if (!featuredTraits[feature]) featuredTraits[feature] = []; + featuredTraits[feature].push(trait); + } + } + + return [unfeaturedTraits, featuredTraits]; +} + +function extractFullyQualifiedNames(traits: string[], imports: ImportMap): string[] { + return traits.map(trait => { + const index = trait.lastIndexOf('::'); + if (index === -1) return trait; + imports.add(trait); + return trait.slice(index + 2); + }); +} diff --git a/packages/renderers-pinocchio/tsconfig.declarations.json b/packages/renderers-pinocchio/tsconfig.declarations.json new file mode 100644 index 000000000..dc2d27bb0 --- /dev/null +++ b/packages/renderers-pinocchio/tsconfig.declarations.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "./dist/types" + }, + "extends": "./tsconfig.json", + "include": ["src/index.ts", "src/types"] +} diff --git a/packages/renderers-pinocchio/tsconfig.json b/packages/renderers-pinocchio/tsconfig.json new file mode 100644 index 000000000..e3e899910 --- /dev/null +++ b/packages/renderers-pinocchio/tsconfig.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { "lib": [] }, + "display": "@codama/renderers-rust", + "extends": "../internals/tsconfig.base.json", + "include": ["src", "test"] +} From 4eb480e02da764bb193213108a91f7910931d0cc Mon Sep 17 00:00:00 2001 From: febo Date: Fri, 1 Nov 2024 12:21:47 +0000 Subject: [PATCH 02/24] [wip]: Add tests --- .../renderers-pinocchio/e2e/dummy/Cargo.lock | 49 + .../renderers-pinocchio/e2e/dummy/Cargo.toml | 14 + .../renderers-pinocchio/e2e/dummy/idl.json | 149 +++ .../generated/instructions/instruction1.rs | 23 + .../generated/instructions/instruction2.rs | 23 + .../generated/instructions/instruction3.rs | 23 + .../generated/instructions/instruction4.rs | 25 + .../generated/instructions/instruction5.rs | 25 + .../generated/instructions/instruction6.rs | 25 + .../generated/instructions/instruction7.rs | 25 + .../dummy/src/generated/instructions/mod.rs | 22 + .../e2e/dummy/src/generated/mod.rs | 9 + .../e2e/dummy/src/generated/programs.rs | 12 + .../renderers-pinocchio/e2e/dummy/src/lib.rs | 4 + packages/renderers-pinocchio/e2e/generate.cjs | 35 + .../renderers-pinocchio/e2e/memo/Cargo.lock | 49 + .../renderers-pinocchio/e2e/memo/Cargo.toml | 14 + .../renderers-pinocchio/e2e/memo/idl.json | 44 + .../src/generated/instructions/add_memo.rs | 25 + .../memo/src/generated/instructions/mod.rs | 10 + .../e2e/memo/src/generated/mod.rs | 9 + .../e2e/memo/src/generated/programs.rs | 12 + .../renderers-pinocchio/e2e/memo/src/lib.rs | 4 + .../renderers-pinocchio/e2e/system/Cargo.lock | 713 +++++++++++ .../renderers-pinocchio/e2e/system/Cargo.toml | 21 + .../renderers-pinocchio/e2e/system/idl.json | 1042 +++++++++++++++++ .../instructions/advance_nonce_account.rs | 29 + .../src/generated/instructions/allocate.rs | 26 + .../instructions/allocate_with_seed.rs | 33 + .../src/generated/instructions/assign.rs | 28 + .../instructions/assign_with_seed.rs | 32 + .../instructions/authorize_nonce_account.rs | 30 + .../generated/instructions/create_account.rs | 32 + .../instructions/create_account_with_seed.rs | 36 + .../instructions/initialize_nonce_account.rs | 32 + .../system/src/generated/instructions/mod.rs | 34 + .../generated/instructions/transfer_sol.rs | 28 + .../instructions/transfer_sol_with_seed.rs | 34 + .../instructions/upgrade_nonce_account.rs | 25 + .../instructions/withdraw_nonce_account.rs | 34 + .../e2e/system/src/generated/mod.rs | 10 + .../e2e/system/src/generated/programs.rs | 12 + .../e2e/system/src/generated/types/mod.rs | 12 + .../system/src/generated/types/nonce_state.rs | 19 + .../src/generated/types/nonce_version.rs | 19 + .../renderers-pinocchio/e2e/system/src/lib.rs | 4 + packages/renderers-pinocchio/e2e/test.sh | 12 + packages/renderers-pinocchio/test/_setup.ts | 23 + .../test/definedTypesPage.test.ts | 98 ++ .../test/exports/commonjs.cjs | 7 + .../test/exports/module.mjs | 10 + .../test/instructionsPage.test.ts | 21 + .../test/types/number.test.ts | 44 + .../test/utils/traitOptions.test.ts | 359 ++++++ 54 files changed, 3489 insertions(+) create mode 100644 packages/renderers-pinocchio/e2e/dummy/Cargo.lock create mode 100644 packages/renderers-pinocchio/e2e/dummy/Cargo.toml create mode 100644 packages/renderers-pinocchio/e2e/dummy/idl.json create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/mod.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/mod.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/generated/programs.rs create mode 100644 packages/renderers-pinocchio/e2e/dummy/src/lib.rs create mode 100755 packages/renderers-pinocchio/e2e/generate.cjs create mode 100644 packages/renderers-pinocchio/e2e/memo/Cargo.lock create mode 100644 packages/renderers-pinocchio/e2e/memo/Cargo.toml create mode 100644 packages/renderers-pinocchio/e2e/memo/idl.json create mode 100644 packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs create mode 100644 packages/renderers-pinocchio/e2e/memo/src/generated/instructions/mod.rs create mode 100644 packages/renderers-pinocchio/e2e/memo/src/generated/mod.rs create mode 100644 packages/renderers-pinocchio/e2e/memo/src/generated/programs.rs create mode 100644 packages/renderers-pinocchio/e2e/memo/src/lib.rs create mode 100644 packages/renderers-pinocchio/e2e/system/Cargo.lock create mode 100644 packages/renderers-pinocchio/e2e/system/Cargo.toml create mode 100644 packages/renderers-pinocchio/e2e/system/idl.json create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/mod.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/mod.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/programs.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/types/mod.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_state.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_version.rs create mode 100644 packages/renderers-pinocchio/e2e/system/src/lib.rs create mode 100755 packages/renderers-pinocchio/e2e/test.sh create mode 100644 packages/renderers-pinocchio/test/_setup.ts create mode 100644 packages/renderers-pinocchio/test/definedTypesPage.test.ts create mode 100644 packages/renderers-pinocchio/test/exports/commonjs.cjs create mode 100644 packages/renderers-pinocchio/test/exports/module.mjs create mode 100644 packages/renderers-pinocchio/test/instructionsPage.test.ts create mode 100644 packages/renderers-pinocchio/test/types/number.test.ts create mode 100644 packages/renderers-pinocchio/test/utils/traitOptions.test.ts diff --git a/packages/renderers-pinocchio/e2e/dummy/Cargo.lock b/packages/renderers-pinocchio/e2e/dummy/Cargo.lock new file mode 100644 index 000000000..3b416fa0c --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/Cargo.lock @@ -0,0 +1,49 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "codama-renderers-rust-e2e-dummy" +version = "0.0.0" +dependencies = [ + "assert_matches", + "pinocchio", + "pinocchio-pubkey", +] + +[[package]] +name = "five8_const" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" + +[[package]] +name = "pinocchio" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9f716de2190437efa787dd7414f4bcea88d22c2f81bbeecabb7db6d9cc326bd" + +[[package]] +name = "pinocchio-pubkey" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4800103b9bea24df2e78f161403fc8f8c2286cb5f874b2e5feebe6c5c4fb35a" +dependencies = [ + "five8_const", + "pinocchio", +] diff --git a/packages/renderers-pinocchio/e2e/dummy/Cargo.toml b/packages/renderers-pinocchio/e2e/dummy/Cargo.toml new file mode 100644 index 000000000..7666bed19 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "codama-renderers-rust-e2e-dummy" +version = "0.0.0" +edition = "2021" + +[features] +test-sbf = [] + +[dependencies] +pinocchio = "0.6" +pinocchio-pubkey = "0.2" + +[dev-dependencies] +assert_matches = "1.5.0" diff --git a/packages/renderers-pinocchio/e2e/dummy/idl.json b/packages/renderers-pinocchio/e2e/dummy/idl.json new file mode 100644 index 000000000..b81b84d79 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/idl.json @@ -0,0 +1,149 @@ +{ + "kind": "rootNode", + "program": { + "kind": "programNode", + "pdas": [], + "accounts": [], + "instructions": [ + { + "kind": "instructionNode", + "name": "instruction1", + "optionalAccountStrategy": "programId", + "docs": ["Testing instructions with no accounts or arguments"], + "accounts": [], + "arguments": [], + "remainingAccounts": [] + }, + { + "kind": "instructionNode", + "name": "instruction2", + "optionalAccountStrategy": "programId", + "docs": ["Testing instructions with remaining accounts only"], + "accounts": [], + "arguments": [], + "remainingAccounts": [ + { + "kind": "instructionRemainingAccountsNode", + "value": { + "kind": "argumentValueNode", + "name": "remainingAccounts" + }, + "isOptional": true, + "isSigner": false + } + ] + }, + { + "kind": "instructionNode", + "name": "instruction3", + "optionalAccountStrategy": "programId", + "docs": ["Testing instructions with discriminator only"], + "accounts": [], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 42 }, + "defaultValueStrategy": "omitted" + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "instruction4", + "optionalAccountStrategy": "programId", + "docs": ["Testing instructions with arguments only"], + "accounts": [], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "myArgument", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + } + ] + }, + { + "kind": "instructionNode", + "name": "instruction5", + "optionalAccountStrategy": "programId", + "docs": ["Testing instructions with optional arguments only"], + "accounts": [], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "myArgument", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "defaultValue": { "kind": "numberValueNode", "number": 42 }, + "docs": [] + } + ] + }, + { + "kind": "instructionNode", + "name": "instruction6", + "optionalAccountStrategy": "programId", + "docs": ["Testing instructions with accounts only"], + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "myAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + } + ], + "arguments": [] + }, + { + "kind": "instructionNode", + "name": "instruction7", + "optionalAccountStrategy": "programId", + "docs": ["Testing instructions with optional accounts only"], + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "myAccount", + "isWritable": true, + "isSigner": false, + "isOptional": true, + "docs": [] + } + ], + "arguments": [] + } + ], + "definedTypes": [], + "errors": [], + "name": "dummy", + "prefix": "", + "publicKey": "Dummy11111111111111111111111111111111111111", + "version": "3.0.1", + "origin": "shank" + }, + "additionalPrograms": [], + "standard": "codama", + "version": "1.0.0" + } \ No newline at end of file diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs new file mode 100644 index 000000000..e102ba224 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs @@ -0,0 +1,23 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `instruction1` CPI helper. +pub struct Instruction1 {} + +impl Instruction1 { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs new file mode 100644 index 000000000..39bb6df65 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs @@ -0,0 +1,23 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `instruction2` CPI helper. +pub struct Instruction2 {} + +impl Instruction2 { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs new file mode 100644 index 000000000..6d2a9e453 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs @@ -0,0 +1,23 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `instruction3` CPI helper. +pub struct Instruction3 {} + +impl Instruction3 { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs new file mode 100644 index 000000000..f76a440fa --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs @@ -0,0 +1,25 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `instruction4` CPI helper. +pub struct Instruction4 { + pub my_argument: u64, +} + +impl Instruction4 { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs new file mode 100644 index 000000000..795155ad8 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs @@ -0,0 +1,25 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `instruction5` CPI helper. +pub struct Instruction5 { + pub my_argument: u64, +} + +impl Instruction5 { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs new file mode 100644 index 000000000..b42bdf8c8 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs @@ -0,0 +1,25 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `instruction6` CPI helper. +pub struct Instruction6<'a> { + pub my_account: &'a pinocchio::account_info::AccountInfo, +} + +impl<'a> Instruction6<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs new file mode 100644 index 000000000..aff4ef78a --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs @@ -0,0 +1,25 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `instruction7` CPI helper. +pub struct Instruction7<'a> { + pub my_account: Option<&'a pinocchio::account_info::AccountInfo>, +} + +impl<'a> Instruction7<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/mod.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/mod.rs new file mode 100644 index 000000000..a0205b0c4 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/mod.rs @@ -0,0 +1,22 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#instruction1; +pub(crate) mod r#instruction2; +pub(crate) mod r#instruction3; +pub(crate) mod r#instruction4; +pub(crate) mod r#instruction5; +pub(crate) mod r#instruction6; +pub(crate) mod r#instruction7; + +pub use self::r#instruction1::*; +pub use self::r#instruction2::*; +pub use self::r#instruction3::*; +pub use self::r#instruction4::*; +pub use self::r#instruction5::*; +pub use self::r#instruction6::*; +pub use self::r#instruction7::*; diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/mod.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/mod.rs new file mode 100644 index 000000000..69cb087f7 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/mod.rs @@ -0,0 +1,9 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub mod instructions; +pub mod programs; diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/programs.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/programs.rs new file mode 100644 index 000000000..4b970e0f4 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/programs.rs @@ -0,0 +1,12 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; +use pinocchio_pubkey::pubkey; + +/// `dummy` program ID. +pub const DUMMY_ID: Pubkey = pubkey!("Dummy11111111111111111111111111111111111111"); diff --git a/packages/renderers-pinocchio/e2e/dummy/src/lib.rs b/packages/renderers-pinocchio/e2e/dummy/src/lib.rs new file mode 100644 index 000000000..03cae8387 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/dummy/src/lib.rs @@ -0,0 +1,4 @@ +mod generated; + +pub use generated::programs::DUMMY_ID as ID; +pub use generated::*; diff --git a/packages/renderers-pinocchio/e2e/generate.cjs b/packages/renderers-pinocchio/e2e/generate.cjs new file mode 100755 index 000000000..f30672c7f --- /dev/null +++ b/packages/renderers-pinocchio/e2e/generate.cjs @@ -0,0 +1,35 @@ +#!/usr/bin/env -S node + +const path = require('node:path'); +const process = require('node:process'); + +const { rootNode } = require('@codama/nodes'); +const { readJson } = require('@codama/renderers-core'); +const { visit } = require('@codama/visitors-core'); + +const { renderVisitor } = require('../dist/index.node.cjs'); + +async function main() { + const project = process.argv.slice(2)[0] ?? undefined; + if (project === undefined) { + throw new Error('Project name is required.'); + } + await generateProject(project); +} + +async function generateProject(project) { + const idl = readJson(path.join(__dirname, project, 'idl.json')); + const node = rootNode(idl.program); + visit( + node, + renderVisitor(path.join(__dirname, project, 'src', 'generated'), { + crateFolder: path.join(__dirname, project), + formatCode: true, + }), + ); +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/packages/renderers-pinocchio/e2e/memo/Cargo.lock b/packages/renderers-pinocchio/e2e/memo/Cargo.lock new file mode 100644 index 000000000..a9bceca4d --- /dev/null +++ b/packages/renderers-pinocchio/e2e/memo/Cargo.lock @@ -0,0 +1,49 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "codama-renderers-rust-e2e-memo" +version = "0.0.0" +dependencies = [ + "assert_matches", + "pinocchio", + "pinocchio-pubkey", +] + +[[package]] +name = "five8_const" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" + +[[package]] +name = "pinocchio" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9f716de2190437efa787dd7414f4bcea88d22c2f81bbeecabb7db6d9cc326bd" + +[[package]] +name = "pinocchio-pubkey" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4800103b9bea24df2e78f161403fc8f8c2286cb5f874b2e5feebe6c5c4fb35a" +dependencies = [ + "five8_const", + "pinocchio", +] diff --git a/packages/renderers-pinocchio/e2e/memo/Cargo.toml b/packages/renderers-pinocchio/e2e/memo/Cargo.toml new file mode 100644 index 000000000..e71b5b2d2 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/memo/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "codama-renderers-rust-e2e-memo" +version = "0.0.0" +edition = "2021" + +[features] +test-sbf = [] + +[dependencies] +pinocchio = "0.6" +pinocchio-pubkey = "0.2" + +[dev-dependencies] +assert_matches = "1.5.0" diff --git a/packages/renderers-pinocchio/e2e/memo/idl.json b/packages/renderers-pinocchio/e2e/memo/idl.json new file mode 100644 index 000000000..f25afa6af --- /dev/null +++ b/packages/renderers-pinocchio/e2e/memo/idl.json @@ -0,0 +1,44 @@ +{ + "kind": "rootNode", + "program": { + "kind": "programNode", + "pdas": [], + "accounts": [], + "instructions": [ + { + "kind": "instructionNode", + "accounts": [], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "memo", + "type": { "kind": "stringTypeNode", "encoding": "utf8" }, + "docs": [] + } + ], + "remainingAccounts": [ + { + "kind": "instructionRemainingAccountsNode", + "value": { "kind": "argumentValueNode", "name": "signers" }, + "isOptional": true, + "isSigner": true + } + ], + "name": "addMemo", + "idlName": "addMemo", + "docs": [], + "optionalAccountStrategy": "programId" + } + ], + "definedTypes": [], + "errors": [], + "name": "memo", + "prefix": "", + "publicKey": "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr", + "version": "3.0.1", + "origin": "shank" + }, + "additionalPrograms": [], + "standard": "codama", + "version": "1.0.0" +} diff --git a/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs b/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs new file mode 100644 index 000000000..667f6859c --- /dev/null +++ b/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs @@ -0,0 +1,25 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `add_memo` CPI helper. +pub struct AddMemo { + pub memo: str, +} + +impl AddMemo { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/mod.rs b/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/mod.rs new file mode 100644 index 000000000..c1c3f1794 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/mod.rs @@ -0,0 +1,10 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#add_memo; + +pub use self::r#add_memo::*; diff --git a/packages/renderers-pinocchio/e2e/memo/src/generated/mod.rs b/packages/renderers-pinocchio/e2e/memo/src/generated/mod.rs new file mode 100644 index 000000000..69cb087f7 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/memo/src/generated/mod.rs @@ -0,0 +1,9 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub mod instructions; +pub mod programs; diff --git a/packages/renderers-pinocchio/e2e/memo/src/generated/programs.rs b/packages/renderers-pinocchio/e2e/memo/src/generated/programs.rs new file mode 100644 index 000000000..2e42a6da9 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/memo/src/generated/programs.rs @@ -0,0 +1,12 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; +use pinocchio_pubkey::pubkey; + +/// `memo` program ID. +pub const MEMO_ID: Pubkey = pubkey!("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"); diff --git a/packages/renderers-pinocchio/e2e/memo/src/lib.rs b/packages/renderers-pinocchio/e2e/memo/src/lib.rs new file mode 100644 index 000000000..44c77a499 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/memo/src/lib.rs @@ -0,0 +1,4 @@ +mod generated; + +pub use generated::programs::MEMO_ID as ID; +pub use generated::*; diff --git a/packages/renderers-pinocchio/e2e/system/Cargo.lock b/packages/renderers-pinocchio/e2e/system/Cargo.lock new file mode 100644 index 000000000..7fe2a7e46 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/Cargo.lock @@ -0,0 +1,713 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cc" +version = "1.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets", +] + +[[package]] +name = "codama-renderers-rust-e2e-system" +version = "0.0.0" +dependencies = [ + "assert_matches", + "borsh", + "num-derive", + "num-traits", + "pinocchio", + "pinocchio-pubkey", + "serde", + "serde_with", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.85", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "five8_const" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "pinocchio" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9f716de2190437efa787dd7414f4bcea88d22c2f81bbeecabb7db6d9cc326bd" + +[[package]] +name = "pinocchio-pubkey" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4800103b9bea24df2e78f161403fc8f8c2286cb5f874b2e5feebe6c5c4fb35a" +dependencies = [ + "five8_const", + "pinocchio", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.6.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.85", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.85", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", +] diff --git a/packages/renderers-pinocchio/e2e/system/Cargo.toml b/packages/renderers-pinocchio/e2e/system/Cargo.toml new file mode 100644 index 000000000..328022e7b --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "codama-renderers-rust-e2e-system" +version = "0.0.0" +edition = "2021" + +[features] +borsh = ["dep:borsh"] +serde = ["dep:serde", "dep:serde_with"] +test-sbf = [] + +[dependencies] +borsh = { version = "^0.10", optional = true } +num-derive = "^0.3" +num-traits = "^0.2" +pinocchio = "0.6" +pinocchio-pubkey = "0.2" +serde = { version = "^1.0", features = ["derive"], optional = true } +serde_with = { version = "^3.0", optional = true } + +[dev-dependencies] +assert_matches = "1.5.0" diff --git a/packages/renderers-pinocchio/e2e/system/idl.json b/packages/renderers-pinocchio/e2e/system/idl.json new file mode 100644 index 000000000..d488b69fd --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/idl.json @@ -0,0 +1,1042 @@ +{ + "kind": "rootNode", + "program": { + "kind": "programNode", + "pdas": [], + "accounts": [ + { + "kind": "accountNode", + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "version", + "type": { "kind": "definedTypeLinkNode", "name": "nonceVersion" }, + "docs": [] + }, + { + "kind": "structFieldTypeNode", + "name": "state", + "type": { "kind": "definedTypeLinkNode", "name": "nonceState" }, + "docs": [] + }, + { + "kind": "structFieldTypeNode", + "name": "authority", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + }, + { + "kind": "structFieldTypeNode", + "name": "blockhash", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + }, + { + "kind": "structFieldTypeNode", + "name": "lamportsPerSignature", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + } + ] + }, + "name": "nonce", + "idlName": "Nonce", + "docs": [], + "size": 80 + } + ], + "instructions": [ + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { "kind": "payerValueNode" } + }, + { + "kind": "instructionAccountNode", + "name": "newAccount", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 0 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "lamports", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "space", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "programAddress", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + } + ], + "byteDeltas": [ + { + "kind": "instructionByteDeltaNode", + "value": { "kind": "argumentValueNode", "name": "space" }, + "withHeader": true + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "createAccount", + "idlName": "CreateAccount", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "account", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 1 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "programAddress", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "assign", + "idlName": "Assign", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "source", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "destination", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 2 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "amount", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "transferSol", + "idlName": "TransferSol", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { "kind": "payerValueNode" } + }, + { + "kind": "instructionAccountNode", + "name": "newAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "baseAccount", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 3 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "base", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "seed", + "type": { + "kind": "sizePrefixTypeNode", + "type": { "kind": "stringTypeNode", "encoding": "utf8" }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "amount", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "space", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "programAddress", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "createAccountWithSeed", + "idlName": "CreateAccountWithSeed", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "nonceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "recentBlockhashesSysvar", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "SysvarRecentB1ockHashes11111111111111111111" + } + }, + { + "kind": "instructionAccountNode", + "name": "nonceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 4 }, + "defaultValueStrategy": "omitted" + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "advanceNonceAccount", + "idlName": "AdvanceNonceAccount", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "nonceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "recipientAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "recentBlockhashesSysvar", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "SysvarRecentB1ockHashes11111111111111111111" + } + }, + { + "kind": "instructionAccountNode", + "name": "rentSysvar", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "SysvarRent111111111111111111111111111111111" + } + }, + { + "kind": "instructionAccountNode", + "name": "nonceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 5 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "withdrawAmount", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "withdrawNonceAccount", + "idlName": "WithdrawNonceAccount", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "nonceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "recentBlockhashesSysvar", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "SysvarRecentB1ockHashes11111111111111111111" + } + }, + { + "kind": "instructionAccountNode", + "name": "rentSysvar", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "SysvarRent111111111111111111111111111111111" + } + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 6 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "nonceAuthority", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "initializeNonceAccount", + "idlName": "InitializeNonceAccount", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "nonceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "nonceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 7 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "newNonceAuthority", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "authorizeNonceAccount", + "idlName": "AuthorizeNonceAccount", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "newAccount", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 8 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "space", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "allocate", + "idlName": "Allocate", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "newAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "baseAccount", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 9 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "base", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "seed", + "type": { + "kind": "sizePrefixTypeNode", + "type": { "kind": "stringTypeNode", "encoding": "utf8" }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "space", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "programAddress", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "allocateWithSeed", + "idlName": "AllocateWithSeed", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "account", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "baseAccount", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 10 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "base", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "seed", + "type": { + "kind": "sizePrefixTypeNode", + "type": { "kind": "stringTypeNode", "encoding": "utf8" }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "programAddress", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "assignWithSeed", + "idlName": "AssignWithSeed", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "source", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "baseAccount", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "destination", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 11 }, + "defaultValueStrategy": "omitted" + }, + { + "kind": "instructionArgumentNode", + "name": "amount", + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "fromSeed", + "type": { + "kind": "sizePrefixTypeNode", + "type": { "kind": "stringTypeNode", "encoding": "utf8" }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + "docs": [] + }, + { + "kind": "instructionArgumentNode", + "name": "fromOwner", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "transferSolWithSeed", + "idlName": "TransferSolWithSeed", + "docs": [], + "optionalAccountStrategy": "programId" + }, + { + "kind": "instructionNode", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "nonceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "docs": [], + "defaultValue": { "kind": "numberValueNode", "number": 12 }, + "defaultValueStrategy": "omitted" + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "name": "upgradeNonceAccount", + "idlName": "UpgradeNonceAccount", + "docs": [], + "optionalAccountStrategy": "programId" + } + ], + "definedTypes": [ + { + "kind": "definedTypeNode", + "name": "nonceVersion", + "type": { + "kind": "enumTypeNode", + "variants": [ + { "kind": "enumEmptyVariantTypeNode", "name": "legacy" }, + { "kind": "enumEmptyVariantTypeNode", "name": "current" } + ], + "size": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } + }, + "idlName": "NonceVersion", + "docs": [] + }, + { + "kind": "definedTypeNode", + "name": "nonceState", + "type": { + "kind": "enumTypeNode", + "variants": [ + { "kind": "enumEmptyVariantTypeNode", "name": "uninitialized" }, + { "kind": "enumEmptyVariantTypeNode", "name": "initialized" } + ], + "size": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } + }, + "idlName": "NonceState", + "docs": [] + } + ], + "errors": [ + { + "kind": "errorNode", + "name": "accountAlreadyInUse", + "idlName": "AccountAlreadyInUse", + "code": 0, + "message": "an account with the same address already exists", + "docs": ["AccountAlreadyInUse: an account with the same address already exists"] + }, + { + "kind": "errorNode", + "name": "resultWithNegativeLamports", + "idlName": "ResultWithNegativeLamports", + "code": 1, + "message": "account does not have enough SOL to perform the operation", + "docs": ["ResultWithNegativeLamports: account does not have enough SOL to perform the operation"] + }, + { + "kind": "errorNode", + "name": "invalidProgramId", + "idlName": "InvalidProgramId", + "code": 2, + "message": "cannot assign account to this program id", + "docs": ["InvalidProgramId: cannot assign account to this program id"] + }, + { + "kind": "errorNode", + "name": "invalidAccountDataLength", + "idlName": "InvalidAccountDataLength", + "code": 3, + "message": "cannot allocate account data of this length", + "docs": ["InvalidAccountDataLength: cannot allocate account data of this length"] + }, + { + "kind": "errorNode", + "name": "maxSeedLengthExceeded", + "idlName": "MaxSeedLengthExceeded", + "code": 4, + "message": "length of requested seed is too long", + "docs": ["MaxSeedLengthExceeded: length of requested seed is too long"] + }, + { + "kind": "errorNode", + "name": "addressWithSeedMismatch", + "idlName": "AddressWithSeedMismatch", + "code": 5, + "message": "provided address does not match addressed derived from seed", + "docs": ["AddressWithSeedMismatch: provided address does not match addressed derived from seed"] + }, + { + "kind": "errorNode", + "name": "nonceNoRecentBlockhashes", + "idlName": "NonceNoRecentBlockhashes", + "code": 6, + "message": "advancing stored nonce requires a populated RecentBlockhashes sysvar", + "docs": [ + "NonceNoRecentBlockhashes: advancing stored nonce requires a populated RecentBlockhashes sysvar" + ] + }, + { + "kind": "errorNode", + "name": "nonceBlockhashNotExpired", + "idlName": "NonceBlockhashNotExpired", + "code": 7, + "message": "stored nonce is still in recent_blockhashes", + "docs": ["NonceBlockhashNotExpired: stored nonce is still in recent_blockhashes"] + }, + { + "kind": "errorNode", + "name": "nonceUnexpectedBlockhashValue", + "idlName": "NonceUnexpectedBlockhashValue", + "code": 8, + "message": "specified nonce does not match stored nonce", + "docs": ["NonceUnexpectedBlockhashValue: specified nonce does not match stored nonce"] + } + ], + "name": "system", + "prefix": "", + "publicKey": "11111111111111111111111111111111", + "version": "0.0.1", + "origin": "shank" + }, + "additionalPrograms": [], + "standard": "codama", + "version": "0.20.0" +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs new file mode 100644 index 000000000..aa27e7078 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs @@ -0,0 +1,29 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `advance_nonce_account` CPI helper. +pub struct AdvanceNonceAccount<'a> { + pub nonce_account: &'a pinocchio::account_info::AccountInfo, + + pub recent_blockhashes_sysvar: &'a pinocchio::account_info::AccountInfo, + + pub nonce_authority: &'a pinocchio::account_info::AccountInfo, +} + +impl<'a> AdvanceNonceAccount<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs new file mode 100644 index 000000000..bfb2da8d9 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs @@ -0,0 +1,26 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `allocate` CPI helper. +pub struct Allocate<'a> { + pub new_account: &'a pinocchio::account_info::AccountInfo, + pub space: u64, +} + +impl<'a> Allocate<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs new file mode 100644 index 000000000..c2bf06d5f --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs @@ -0,0 +1,33 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; + +/// `allocate_with_seed` CPI helper. +pub struct AllocateWithSeed<'a> { + pub new_account: &'a pinocchio::account_info::AccountInfo, + + pub base_account: &'a pinocchio::account_info::AccountInfo, + pub base: Pubkey, + pub seed: String, + pub space: u64, + pub program_address: Pubkey, +} + +impl<'a> AllocateWithSeed<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs new file mode 100644 index 000000000..4ede3f697 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs @@ -0,0 +1,28 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; + +/// `assign` CPI helper. +pub struct Assign<'a> { + pub account: &'a pinocchio::account_info::AccountInfo, + pub program_address: Pubkey, +} + +impl<'a> Assign<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs new file mode 100644 index 000000000..16c506122 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs @@ -0,0 +1,32 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; + +/// `assign_with_seed` CPI helper. +pub struct AssignWithSeed<'a> { + pub account: &'a pinocchio::account_info::AccountInfo, + + pub base_account: &'a pinocchio::account_info::AccountInfo, + pub base: Pubkey, + pub seed: String, + pub program_address: Pubkey, +} + +impl<'a> AssignWithSeed<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs new file mode 100644 index 000000000..158bd7bb9 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs @@ -0,0 +1,30 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; + +/// `authorize_nonce_account` CPI helper. +pub struct AuthorizeNonceAccount<'a> { + pub nonce_account: &'a pinocchio::account_info::AccountInfo, + + pub nonce_authority: &'a pinocchio::account_info::AccountInfo, + pub new_nonce_authority: Pubkey, +} + +impl<'a> AuthorizeNonceAccount<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs new file mode 100644 index 000000000..8db94862f --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs @@ -0,0 +1,32 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; + +/// `create_account` CPI helper. +pub struct CreateAccount<'a> { + pub payer: &'a pinocchio::account_info::AccountInfo, + + pub new_account: &'a pinocchio::account_info::AccountInfo, + pub lamports: u64, + pub space: u64, + pub program_address: Pubkey, +} + +impl<'a> CreateAccount<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs new file mode 100644 index 000000000..de189c18d --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs @@ -0,0 +1,36 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; + +/// `create_account_with_seed` CPI helper. +pub struct CreateAccountWithSeed<'a> { + pub payer: &'a pinocchio::account_info::AccountInfo, + + pub new_account: &'a pinocchio::account_info::AccountInfo, + + pub base_account: &'a pinocchio::account_info::AccountInfo, + pub base: Pubkey, + pub seed: String, + pub amount: u64, + pub space: u64, + pub program_address: Pubkey, +} + +impl<'a> CreateAccountWithSeed<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs new file mode 100644 index 000000000..8fa5e288e --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs @@ -0,0 +1,32 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; + +/// `initialize_nonce_account` CPI helper. +pub struct InitializeNonceAccount<'a> { + pub nonce_account: &'a pinocchio::account_info::AccountInfo, + + pub recent_blockhashes_sysvar: &'a pinocchio::account_info::AccountInfo, + + pub rent_sysvar: &'a pinocchio::account_info::AccountInfo, + pub nonce_authority: Pubkey, +} + +impl<'a> InitializeNonceAccount<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/mod.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/mod.rs new file mode 100644 index 000000000..85422fddb --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/mod.rs @@ -0,0 +1,34 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#advance_nonce_account; +pub(crate) mod r#allocate; +pub(crate) mod r#allocate_with_seed; +pub(crate) mod r#assign; +pub(crate) mod r#assign_with_seed; +pub(crate) mod r#authorize_nonce_account; +pub(crate) mod r#create_account; +pub(crate) mod r#create_account_with_seed; +pub(crate) mod r#initialize_nonce_account; +pub(crate) mod r#transfer_sol; +pub(crate) mod r#transfer_sol_with_seed; +pub(crate) mod r#upgrade_nonce_account; +pub(crate) mod r#withdraw_nonce_account; + +pub use self::r#advance_nonce_account::*; +pub use self::r#allocate::*; +pub use self::r#allocate_with_seed::*; +pub use self::r#assign::*; +pub use self::r#assign_with_seed::*; +pub use self::r#authorize_nonce_account::*; +pub use self::r#create_account::*; +pub use self::r#create_account_with_seed::*; +pub use self::r#initialize_nonce_account::*; +pub use self::r#transfer_sol::*; +pub use self::r#transfer_sol_with_seed::*; +pub use self::r#upgrade_nonce_account::*; +pub use self::r#withdraw_nonce_account::*; diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs new file mode 100644 index 000000000..44b9e7e59 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs @@ -0,0 +1,28 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `transfer_sol` CPI helper. +pub struct TransferSol<'a> { + pub source: &'a pinocchio::account_info::AccountInfo, + + pub destination: &'a pinocchio::account_info::AccountInfo, + pub amount: u64, +} + +impl<'a> TransferSol<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs new file mode 100644 index 000000000..269910d20 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs @@ -0,0 +1,34 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; + +/// `transfer_sol_with_seed` CPI helper. +pub struct TransferSolWithSeed<'a> { + pub source: &'a pinocchio::account_info::AccountInfo, + + pub base_account: &'a pinocchio::account_info::AccountInfo, + + pub destination: &'a pinocchio::account_info::AccountInfo, + pub amount: u64, + pub from_seed: String, + pub from_owner: Pubkey, +} + +impl<'a> TransferSolWithSeed<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs new file mode 100644 index 000000000..3b25894f1 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs @@ -0,0 +1,25 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `upgrade_nonce_account` CPI helper. +pub struct UpgradeNonceAccount<'a> { + pub nonce_account: &'a pinocchio::account_info::AccountInfo, +} + +impl<'a> UpgradeNonceAccount<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs new file mode 100644 index 000000000..5609c87d5 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs @@ -0,0 +1,34 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +/// `withdraw_nonce_account` CPI helper. +pub struct WithdrawNonceAccount<'a> { + pub nonce_account: &'a pinocchio::account_info::AccountInfo, + + pub recipient_account: &'a pinocchio::account_info::AccountInfo, + + pub recent_blockhashes_sysvar: &'a pinocchio::account_info::AccountInfo, + + pub rent_sysvar: &'a pinocchio::account_info::AccountInfo, + + pub nonce_authority: &'a pinocchio::account_info::AccountInfo, + pub withdraw_amount: u64, +} + +impl<'a> WithdrawNonceAccount<'a> { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed( + &self, + _signers: &[pinocchio::instruction::Signer], + ) -> pinocchio::ProgramResult { + Ok(()) + } +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/mod.rs b/packages/renderers-pinocchio/e2e/system/src/generated/mod.rs new file mode 100644 index 000000000..b04b2e846 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/mod.rs @@ -0,0 +1,10 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub mod instructions; +pub mod programs; +pub mod types; diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/programs.rs b/packages/renderers-pinocchio/e2e/system/src/generated/programs.rs new file mode 100644 index 000000000..31c24093f --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/programs.rs @@ -0,0 +1,12 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use pinocchio::pubkey::Pubkey; +use pinocchio_pubkey::pubkey; + +/// `system` program ID. +pub const SYSTEM_ID: Pubkey = pubkey!("11111111111111111111111111111111"); diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/types/mod.rs b/packages/renderers-pinocchio/e2e/system/src/generated/types/mod.rs new file mode 100644 index 000000000..396fe1865 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/types/mod.rs @@ -0,0 +1,12 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#nonce_state; +pub(crate) mod r#nonce_version; + +pub use self::r#nonce_state::*; +pub use self::r#nonce_version::*; diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_state.rs b/packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_state.rs new file mode 100644 index 000000000..b504b41a0 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_state.rs @@ -0,0 +1,19 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use num_derive::FromPrimitive; + +#[derive(Clone, Debug, Eq, PartialEq, Copy, PartialOrd, Hash, FromPrimitive)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum NonceState { + Uninitialized, + Initialized, +} diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_version.rs b/packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_version.rs new file mode 100644 index 000000000..5f85b93a5 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_version.rs @@ -0,0 +1,19 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use num_derive::FromPrimitive; + +#[derive(Clone, Debug, Eq, PartialEq, Copy, PartialOrd, Hash, FromPrimitive)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum NonceVersion { + Legacy, + Current, +} diff --git a/packages/renderers-pinocchio/e2e/system/src/lib.rs b/packages/renderers-pinocchio/e2e/system/src/lib.rs new file mode 100644 index 000000000..45066cdd6 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/system/src/lib.rs @@ -0,0 +1,4 @@ +mod generated; + +pub use generated::programs::SYSTEM_ID as ID; +pub use generated::*; diff --git a/packages/renderers-pinocchio/e2e/test.sh b/packages/renderers-pinocchio/e2e/test.sh new file mode 100755 index 000000000..e524b8c50 --- /dev/null +++ b/packages/renderers-pinocchio/e2e/test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +function test_project() { + ./e2e/generate.cjs $1 + cd e2e/$1 + cargo check + cd ../.. +} + +test_project dummy +test_project system +test_project memo diff --git a/packages/renderers-pinocchio/test/_setup.ts b/packages/renderers-pinocchio/test/_setup.ts new file mode 100644 index 000000000..beb4f1d90 --- /dev/null +++ b/packages/renderers-pinocchio/test/_setup.ts @@ -0,0 +1,23 @@ +import { expect } from 'vitest'; + +export function codeContains(actual: string, expected: (RegExp | string)[] | RegExp | string) { + const expectedArray = Array.isArray(expected) ? expected : [expected]; + expectedArray.forEach(e => { + if (typeof e === 'string') { + expect(actual).toContain(e); + } else { + expect(actual).toMatch(e); + } + }); +} + +export function codeDoesNotContains(actual: string, expected: (RegExp | string)[] | RegExp | string) { + const expectedArray = Array.isArray(expected) ? expected : [expected]; + expectedArray.forEach(e => { + if (typeof e === 'string') { + expect(actual).not.toContain(e); + } else { + expect(actual).not.toMatch(e); + } + }); +} diff --git a/packages/renderers-pinocchio/test/definedTypesPage.test.ts b/packages/renderers-pinocchio/test/definedTypesPage.test.ts new file mode 100644 index 000000000..e19a763a8 --- /dev/null +++ b/packages/renderers-pinocchio/test/definedTypesPage.test.ts @@ -0,0 +1,98 @@ +import { + definedTypeNode, + enumEmptyVariantTypeNode, + enumStructVariantTypeNode, + enumTypeNode, + numberTypeNode, + programNode, + sizePrefixTypeNode, + stringTypeNode, + structFieldTypeNode, + structTypeNode, +} from '@codama/nodes'; +import { visit } from '@codama/visitors-core'; +import { test } from 'vitest'; + +import { getRenderMapVisitor } from '../src'; +import { codeContains, codeDoesNotContains } from './_setup'; + +test('it renders a prefix string on a defined type', () => { + // Given the following program with 1 defined type using a prefixed size string. + const node = programNode({ + definedTypes: [ + definedTypeNode({ + name: 'blob', + type: structTypeNode([ + structFieldTypeNode({ + name: 'contentType', + type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u8')), + }), + ]), + }), + ], + name: 'splToken', + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect the following use and identifier to be rendered. + codeContains(renderMap.get('types/blob.rs'), [ + `use kaigan::types::U8PrefixString;`, + `content_type: U8PrefixString,`, + ]); +}); + +test('it renders a scalar enum with Copy derive', () => { + // Given the following program with 1 defined type using a prefixed size string. + const node = programNode({ + definedTypes: [ + definedTypeNode({ + name: 'tag', + type: enumTypeNode([enumEmptyVariantTypeNode('Uninitialized'), enumEmptyVariantTypeNode('Account')]), + }), + ], + name: 'splToken', + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect the following use and identifier to be rendered. + codeContains(renderMap.get('types/tag.rs'), [`#[derive(`, `Copy`, `pub enum Tag`]); +}); + +test('it renders a non-scalar enum without Copy derive', () => { + // Given the following program with 1 defined type using a prefixed size string. + const node = programNode({ + definedTypes: [ + definedTypeNode({ + name: 'tagWithStruct', + type: enumTypeNode([ + enumEmptyVariantTypeNode('Uninitialized'), + enumStructVariantTypeNode( + 'Account', + structTypeNode([ + structFieldTypeNode({ + name: 'contentType', + type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u8')), + }), + ]), + ), + ]), + }), + ], + name: 'splToken', + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect the following use and identifier to be rendered. + codeContains(renderMap.get('types/tag_with_struct.rs'), [`#[derive(`, `pub enum TagWithStruct`]); + // And we expect the Copy derive to be missing. + codeDoesNotContains(renderMap.get('types/tag_with_struct.rs'), `Copy`); +}); diff --git a/packages/renderers-pinocchio/test/exports/commonjs.cjs b/packages/renderers-pinocchio/test/exports/commonjs.cjs new file mode 100644 index 000000000..a091a74b1 --- /dev/null +++ b/packages/renderers-pinocchio/test/exports/commonjs.cjs @@ -0,0 +1,7 @@ +const { definedTypeNode, numberTypeNode } = require('@codama/nodes'); +const { visit } = require('@codama/visitors-core'); + +const { getRenderMapVisitor } = require('../../dist/index.node.cjs'); + +const node = definedTypeNode({ name: 'answerToLife', type: numberTypeNode('u8') }); +visit(node, getRenderMapVisitor()); diff --git a/packages/renderers-pinocchio/test/exports/module.mjs b/packages/renderers-pinocchio/test/exports/module.mjs new file mode 100644 index 000000000..87c6ff631 --- /dev/null +++ b/packages/renderers-pinocchio/test/exports/module.mjs @@ -0,0 +1,10 @@ +// This ensures that we do not rely on `__dirname` in ES modules even when it is polyfilled. +globalThis.__dirname = 'DO_NOT_USE'; + +import { definedTypeNode, numberTypeNode } from '@codama/nodes'; +import { visit } from '@codama/visitors-core'; + +import { getRenderMapVisitor } from '../../dist/index.node.mjs'; + +const node = definedTypeNode({ name: 'answerToLife', type: numberTypeNode('u8') }); +visit(node, getRenderMapVisitor()); diff --git a/packages/renderers-pinocchio/test/instructionsPage.test.ts b/packages/renderers-pinocchio/test/instructionsPage.test.ts new file mode 100644 index 000000000..0bbfb8ed0 --- /dev/null +++ b/packages/renderers-pinocchio/test/instructionsPage.test.ts @@ -0,0 +1,21 @@ +import { instructionNode, programNode } from '@codama/nodes'; +import { visit } from '@codama/visitors-core'; +import { test } from 'vitest'; + +import { getRenderMapVisitor } from '../src'; +import { codeContains } from './_setup'; + +test('it renders a public instruction data struct', () => { + // Given the following program with 1 instruction. + const node = programNode({ + instructions: [instructionNode({ name: 'mintTokens' })], + name: 'splToken', + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect the following pub struct. + codeContains(renderMap.get('instructions/mint_tokens.rs'), [`pub struct MintTokens`]); +}); diff --git a/packages/renderers-pinocchio/test/types/number.test.ts b/packages/renderers-pinocchio/test/types/number.test.ts new file mode 100644 index 000000000..e53c1136b --- /dev/null +++ b/packages/renderers-pinocchio/test/types/number.test.ts @@ -0,0 +1,44 @@ +import { definedTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode } from '@codama/nodes'; +import { visit } from '@codama/visitors-core'; +import { test } from 'vitest'; + +import { getRenderMapVisitor } from '../../src'; +import { codeContains, codeDoesNotContains } from '../_setup'; + +test('it exports short u16 numbers', () => { + // Given a shortU16 number. + const node = definedTypeNode({ + name: 'myShortU16', + type: numberTypeNode('shortU16'), + }); + + // When we render the number. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect a short u16 to be exported. + codeContains(renderMap.get('types/my_short_u16.rs'), [ + /pub type MyShortU16 = ShortU16/, + /use solana_program::short_vec::ShortU16/, + ]); + codeDoesNotContains(renderMap.get('types/my_short_u16.rs'), [ + /use borsh::BorshSerialize/, + /use borsh::BorshDeserialize/, + ]); +}); + +test('it exports short u16 numbers as struct fields', () => { + // Given a shortU16 number. + const node = definedTypeNode({ + name: 'myShortU16', + type: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('shortU16') })]), + }); + + // When we render the number. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect a short u16 to be exported as a struct field. + codeContains(renderMap.get('types/my_short_u16.rs'), [ + /pub value: ShortU16/, + /use solana_program::short_vec::ShortU16/, + ]); +}); diff --git a/packages/renderers-pinocchio/test/utils/traitOptions.test.ts b/packages/renderers-pinocchio/test/utils/traitOptions.test.ts new file mode 100644 index 000000000..82bc8d792 --- /dev/null +++ b/packages/renderers-pinocchio/test/utils/traitOptions.test.ts @@ -0,0 +1,359 @@ +import { + accountNode, + definedTypeNode, + enumEmptyVariantTypeNode, + enumStructVariantTypeNode, + enumTypeNode, + numberTypeNode, + structFieldTypeNode, + structTypeNode, +} from '@codama/nodes'; +import { describe, expect, test } from 'vitest'; + +import { getTraitsFromNode, TraitOptions } from '../../src/utils'; + +describe('default values', () => { + test('it defaults to a set of traits for data enums', () => { + // Given a data enum defined type. + const node = definedTypeNode({ + name: 'Command', + type: enumTypeNode([ + enumStructVariantTypeNode( + 'Play', + structTypeNode([structFieldTypeNode({ name: 'guess', type: numberTypeNode('u16') })]), + ), + enumEmptyVariantTypeNode('Quit'), + ]), + }); + + // When we get the traits from the node using the default options. + const { render, imports } = getTraitsFromNode(node); + + // Then we expect the following traits to be rendered. + expect(render).toBe( + `#[derive(Clone, Debug, Eq, PartialEq)]\n` + + `#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]\n` + + `#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]\n`, + ); + + // And no additional imports. + expect(imports.isEmpty()); + }); + + test('it defaults to a set of traits for scalar enums', () => { + // Given a scalar enum defined type. + const node = definedTypeNode({ + name: 'Feedback', + type: enumTypeNode([enumEmptyVariantTypeNode('Good'), enumEmptyVariantTypeNode('Bad')]), + }); + + // When we get the traits from the node using the default options. + const { render, imports } = getTraitsFromNode(node); + + // Then we expect the following traits to be rendered. + expect(render).toBe( + `#[derive(Clone, Debug, Eq, PartialEq, Copy, PartialOrd, Hash, FromPrimitive)]\n` + + `#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]\n` + + `#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]\n`, + ); + + // And the following imports to be used. + expect([...imports.imports]).toStrictEqual(['num_derive::FromPrimitive']); + }); + + test('it defaults to a set of traits for structs', () => { + // Given an account node. + const node = accountNode({ + data: structTypeNode([ + structFieldTypeNode({ name: 'x', type: numberTypeNode('u64') }), + structFieldTypeNode({ name: 'y', type: numberTypeNode('u64') }), + ]), + name: 'Coordinates', + }); + + // When we get the traits from the node using the default options. + const { render, imports } = getTraitsFromNode(node); + + // Then we expect the following traits to be rendered. + expect(render).toBe( + `#[derive(Clone, Debug, Eq, PartialEq)]\n` + + `#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]\n` + + `#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]\n`, + ); + + // And no additional imports. + expect(imports.isEmpty()); + }); + + test('it does not use default traits if they are overridden', () => { + // Given a defined type node that should use custom traits. + const node = accountNode({ + data: structTypeNode([ + structFieldTypeNode({ name: 'x', type: numberTypeNode('u64') }), + structFieldTypeNode({ name: 'y', type: numberTypeNode('u64') }), + ]), + name: 'Coordinates', + }); + + // When we get the traits from the node using the + // default options with the overrides attribute. + const { render, imports } = getTraitsFromNode(node, { + overrides: { coordinates: ['My', 'special::Traits'] }, + }); + + // Then we expect the following traits to be rendered. + expect(render).toBe(`#[derive(My, Traits)]\n`); + + // And the following imports to be used. + expect([...imports.imports]).toStrictEqual(['special::Traits']); + }); + + test('it still uses feature flags for overridden traits', () => { + // Given a defined type node that should use custom traits. + const node = accountNode({ + data: structTypeNode([ + structFieldTypeNode({ name: 'x', type: numberTypeNode('u64') }), + structFieldTypeNode({ name: 'y', type: numberTypeNode('u64') }), + ]), + name: 'Coordinates', + }); + + // When we get the traits from the node using custom traits + // such that some are part of the feature flag defaults. + const { render } = getTraitsFromNode(node, { + overrides: { coordinates: ['My', 'special::Traits', 'serde::Serialize'] }, + }); + + // Then we expect the following traits to be rendered. + expect(render).toBe(`#[derive(My, Traits)]\n#[cfg_attr(feature = "serde", derive(serde::Serialize))]\n`); + }); +}); + +const RESET_OPTIONS: Required = { + baseDefaults: [], + dataEnumDefaults: [], + featureFlags: {}, + overrides: {}, + scalarEnumDefaults: [], + structDefaults: [], + useFullyQualifiedName: false, +}; + +describe('base traits', () => { + test('it uses both the base and data enum traits', () => { + // Given a data enum defined type. + const node = definedTypeNode({ + name: 'Command', + type: enumTypeNode([ + enumStructVariantTypeNode( + 'Play', + structTypeNode([structFieldTypeNode({ name: 'guess', type: numberTypeNode('u16') })]), + ), + enumEmptyVariantTypeNode('Quit'), + ]), + }); + + // When we get the traits from the node using custom base and data enum defaults. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['MyBaseTrait'], + dataEnumDefaults: ['MyDataEnumTrait'], + }); + + // Then we expect both the base and data enum traits to be rendered. + expect(render).toBe(`#[derive(MyBaseTrait, MyDataEnumTrait)]\n`); + }); + + test('it uses both the base and scalar enum traits', () => { + // Given a scalar enum defined type. + const node = definedTypeNode({ + name: 'Feedback', + type: enumTypeNode([enumEmptyVariantTypeNode('Good'), enumEmptyVariantTypeNode('Bad')]), + }); + + // When we get the traits from the node using custom base and scalar enum defaults. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['MyBaseTrait'], + scalarEnumDefaults: ['MyScalarEnumTrait'], + }); + + // Then we expect both the base and scalar enum traits to be rendered. + expect(render).toBe(`#[derive(MyBaseTrait, MyScalarEnumTrait)]\n`); + }); + + test('it uses both the base and struct traits', () => { + // Given an account node. + const node = accountNode({ + data: structTypeNode([ + structFieldTypeNode({ name: 'x', type: numberTypeNode('u64') }), + structFieldTypeNode({ name: 'y', type: numberTypeNode('u64') }), + ]), + name: 'Coordinates', + }); + + // When we get the traits from the node using custom base and struct defaults. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['MyBaseTrait'], + structDefaults: ['MyStructTrait'], + }); + + // Then we expect both the base and struct traits to be rendered. + expect(render).toBe(`#[derive(MyBaseTrait, MyStructTrait)]\n`); + }); + + test('it never uses traits for type aliases', () => { + // Given a defined type node that is not an enum or struct. + const node = definedTypeNode({ + name: 'Score', + type: numberTypeNode('u64'), + }); + + // When we get the traits from the node such that we have base defaults. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['MyBaseTrait'], + }); + + // Then we expect no traits to be rendered. + expect(render).toBe(''); + }); + + test('it identifies feature flags under all default traits', () => { + // Given a scalar enum defined type. + const node = definedTypeNode({ + name: 'Feedback', + type: enumTypeNode([enumEmptyVariantTypeNode('Good'), enumEmptyVariantTypeNode('Bad')]), + }); + + // When we get the traits from the node such that: + // - We provide custom base and scalar enum defaults. + // - We provide custom feature flags for traits in both categories. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['MyBaseTrait', 'MyNonFeatureTrait'], + featureFlags: { + base: ['MyBaseTrait'], + enum: ['MyScalarEnumTrait'], + }, + scalarEnumDefaults: ['MyScalarEnumTrait'], + }); + + // Then we expect both the base and enum traits to be rendered as separate feature flags. + expect(render).toBe( + `#[derive(MyNonFeatureTrait)]\n` + + `#[cfg_attr(feature = "base", derive(MyBaseTrait))]\n` + + `#[cfg_attr(feature = "enum", derive(MyScalarEnumTrait))]\n`, + ); + }); + + test('it renders traits correctly when they are all under feature flags', () => { + // Given a scalar enum defined type. + const node = definedTypeNode({ + name: 'Feedback', + type: enumTypeNode([enumEmptyVariantTypeNode('Good'), enumEmptyVariantTypeNode('Bad')]), + }); + + // When we get the traits from the node such that + // all traits are under feature flags. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['MyBaseTrait'], + featureFlags: { + base: ['MyBaseTrait'], + enum: ['MyScalarEnumTrait'], + }, + scalarEnumDefaults: ['MyScalarEnumTrait'], + }); + + // Then we expect the following traits to be rendered. + expect(render).toBe( + `#[cfg_attr(feature = "base", derive(MyBaseTrait))]\n#[cfg_attr(feature = "enum", derive(MyScalarEnumTrait))]\n`, + ); + }); +}); + +describe('overridden traits', () => { + test('it replaces all default traits with the overridden traits', () => { + // Given a scalar enum defined type. + const node = definedTypeNode({ + name: 'Feedback', + type: enumTypeNode([enumEmptyVariantTypeNode('Good'), enumEmptyVariantTypeNode('Bad')]), + }); + + // When we get the traits from the node such that: + // - We provide custom base and enum defaults. + // - We override the feedback type with custom traits. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['MyBaseTrait'], + overrides: { feedback: ['MyFeedbackTrait'] }, + scalarEnumDefaults: ['MyScalarEnumTrait'], + }); + + // Then we expect only the feedback traits to be rendered. + expect(render).toBe(`#[derive(MyFeedbackTrait)]\n`); + }); + + test('it finds traits to override when using pascal case', () => { + // Given a scalar enum defined type. + const node = definedTypeNode({ + name: 'Feedback', + type: enumTypeNode([enumEmptyVariantTypeNode('Good'), enumEmptyVariantTypeNode('Bad')]), + }); + + // When we get the traits from the node such that + // we use PascalCase for the type name. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + overrides: { Feedback: ['MyFeedbackTrait'] }, + }); + + // Then we still expect the custom feedback traits to be rendered. + expect(render).toBe(`#[derive(MyFeedbackTrait)]\n`); + }); + + test('it identifies feature flags under all overridden traits', () => { + // Given a scalar enum defined type. + const node = definedTypeNode({ + name: 'Feedback', + type: enumTypeNode([enumEmptyVariantTypeNode('Good'), enumEmptyVariantTypeNode('Bad')]), + }); + + // When we get the traits from the node such that: + // - We override the feedback type with custom traits. + // - We provide custom feature flags for these some of these custom traits. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + featureFlags: { custom: ['MyFeedbackTrait'] }, + overrides: { feedback: ['MyFeedbackTrait', 'MyNonFeatureTrait'] }, + }); + + // Then we expect some of the overridden traits to be rendered under feature flags. + expect(render).toBe(`#[derive(MyNonFeatureTrait)]\n#[cfg_attr(feature = "custom", derive(MyFeedbackTrait))]\n`); + }); +}); + +describe('fully qualified name traits', () => { + test('it can use fully qualified names for traits instead of importing them', () => { + // Given a scalar enum defined type. + const node = definedTypeNode({ + name: 'Feedback', + type: enumTypeNode([enumEmptyVariantTypeNode('Good'), enumEmptyVariantTypeNode('Bad')]), + }); + + // When we get the traits from the node such that we use fully qualified names. + const { render, imports } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['fruits::Apple', 'fruits::Banana', 'vegetables::Carrot'], + useFullyQualifiedName: true, + }); + + // Then we expect the fully qualified names to be used for the traits. + expect(render).toBe(`#[derive(fruits::Apple, fruits::Banana, vegetables::Carrot)]\n`); + + // And no imports should be used. + expect([...imports.imports]).toStrictEqual([]); + }); +}); From 02b86d578eaa2d351a02642bbc7b982152c38cfc Mon Sep 17 00:00:00 2001 From: febo Date: Fri, 5 Sep 2025 20:01:47 +0100 Subject: [PATCH 03/24] [wip]: Add account meta --- .../generated/instructions/instruction1.rs | 3 + .../generated/instructions/instruction2.rs | 3 + .../generated/instructions/instruction3.rs | 3 + .../generated/instructions/instruction4.rs | 3 + .../generated/instructions/instruction5.rs | 3 + .../generated/instructions/instruction6.rs | 8 + .../generated/instructions/instruction7.rs | 8 + .../src/generated/instructions/add_memo.rs | 3 + .../instructions/advance_nonce_account.rs | 11 + .../src/generated/instructions/allocate.rs | 8 + .../instructions/allocate_with_seed.rs | 6 + .../src/generated/instructions/assign.rs | 8 + .../instructions/assign_with_seed.rs | 6 + .../instructions/authorize_nonce_account.rs | 6 + .../generated/instructions/create_account.rs | 6 + .../instructions/create_account_with_seed.rs | 7 + .../instructions/initialize_nonce_account.rs | 11 + .../generated/instructions/transfer_sol.rs | 6 + .../instructions/transfer_sol_with_seed.rs | 7 + .../instructions/upgrade_nonce_account.rs | 8 + .../instructions/withdraw_nonce_account.rs | 13 ++ .../public/templates/instructionPage.njk | 12 ++ .../src/getRenderMapVisitor.ts | 65 +++--- .../src/getTypeManifestVisitor.ts | 5 +- .../test/definedTypesPage.test.ts | 9 +- .../test/instructionsPage.test.ts | 6 +- pnpm-lock.yaml | 191 +++++++++++------- 27 files changed, 325 insertions(+), 100 deletions(-) diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs index e102ba224..82e1b8b2d 100644 --- a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs @@ -18,6 +18,9 @@ impl Instruction1 { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs index 39bb6df65..902c6dd5a 100644 --- a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs @@ -18,6 +18,9 @@ impl Instruction2 { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs index 6d2a9e453..ab90a24b6 100644 --- a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs @@ -18,6 +18,9 @@ impl Instruction3 { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs index f76a440fa..52a29cfc1 100644 --- a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs @@ -20,6 +20,9 @@ impl Instruction4 { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs index 795155ad8..6c6f7ec86 100644 --- a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs @@ -20,6 +20,9 @@ impl Instruction5 { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs index b42bdf8c8..caccd56f8 100644 --- a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs @@ -20,6 +20,14 @@ impl<'a> Instruction6<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 1] = + [pinocchio::instruction::AccountMeta::new( + self.my_account.key(), + true, + false, + )]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs index aff4ef78a..2fc7fce9a 100644 --- a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs +++ b/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs @@ -20,6 +20,14 @@ impl<'a> Instruction7<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 1] = + [pinocchio::instruction::AccountMeta::new( + self.my_account.key(), + true, + false, + )]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs b/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs index 667f6859c..72bd55334 100644 --- a/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs +++ b/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs @@ -20,6 +20,9 @@ impl AddMemo { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs index aa27e7078..5d4e0c415 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs @@ -24,6 +24,17 @@ impl<'a> AdvanceNonceAccount<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 3] = [ + pinocchio::instruction::AccountMeta::new(self.nonce_account.key(), true, false), + pinocchio::instruction::AccountMeta::new( + self.recent_blockhashes_sysvar.key(), + false, + false, + ), + pinocchio::instruction::AccountMeta::new(self.nonce_authority.key(), false, true), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs index bfb2da8d9..a8f9d33d8 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs @@ -21,6 +21,14 @@ impl<'a> Allocate<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 1] = + [pinocchio::instruction::AccountMeta::new( + self.new_account.key(), + true, + true, + )]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs index c2bf06d5f..25449e713 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs @@ -28,6 +28,12 @@ impl<'a> AllocateWithSeed<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ + pinocchio::instruction::AccountMeta::new(self.new_account.key(), true, false), + pinocchio::instruction::AccountMeta::new(self.base_account.key(), false, true), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs index 4ede3f697..cde5299ee 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs @@ -23,6 +23,14 @@ impl<'a> Assign<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 1] = + [pinocchio::instruction::AccountMeta::new( + self.account.key(), + true, + true, + )]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs index 16c506122..f6c2b1cdf 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs @@ -27,6 +27,12 @@ impl<'a> AssignWithSeed<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ + pinocchio::instruction::AccountMeta::new(self.account.key(), true, false), + pinocchio::instruction::AccountMeta::new(self.base_account.key(), false, true), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs index 158bd7bb9..6830d221f 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs @@ -25,6 +25,12 @@ impl<'a> AuthorizeNonceAccount<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ + pinocchio::instruction::AccountMeta::new(self.nonce_account.key(), true, false), + pinocchio::instruction::AccountMeta::new(self.nonce_authority.key(), false, true), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs index 8db94862f..9f8f91284 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs @@ -27,6 +27,12 @@ impl<'a> CreateAccount<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ + pinocchio::instruction::AccountMeta::new(self.payer.key(), true, true), + pinocchio::instruction::AccountMeta::new(self.new_account.key(), true, true), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs index de189c18d..76c42441f 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs @@ -31,6 +31,13 @@ impl<'a> CreateAccountWithSeed<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 3] = [ + pinocchio::instruction::AccountMeta::new(self.payer.key(), true, true), + pinocchio::instruction::AccountMeta::new(self.new_account.key(), true, false), + pinocchio::instruction::AccountMeta::new(self.base_account.key(), false, true), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs index 8fa5e288e..9e872d601 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs @@ -27,6 +27,17 @@ impl<'a> InitializeNonceAccount<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 3] = [ + pinocchio::instruction::AccountMeta::new(self.nonce_account.key(), true, false), + pinocchio::instruction::AccountMeta::new( + self.recent_blockhashes_sysvar.key(), + false, + false, + ), + pinocchio::instruction::AccountMeta::new(self.rent_sysvar.key(), false, false), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs index 44b9e7e59..3a844be79 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs @@ -23,6 +23,12 @@ impl<'a> TransferSol<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ + pinocchio::instruction::AccountMeta::new(self.source.key(), true, true), + pinocchio::instruction::AccountMeta::new(self.destination.key(), true, false), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs index 269910d20..aedb0c8bc 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs @@ -29,6 +29,13 @@ impl<'a> TransferSolWithSeed<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 3] = [ + pinocchio::instruction::AccountMeta::new(self.source.key(), true, false), + pinocchio::instruction::AccountMeta::new(self.base_account.key(), false, true), + pinocchio::instruction::AccountMeta::new(self.destination.key(), true, false), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs index 3b25894f1..443d4a6fa 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs @@ -20,6 +20,14 @@ impl<'a> UpgradeNonceAccount<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 1] = + [pinocchio::instruction::AccountMeta::new( + self.nonce_account.key(), + true, + false, + )]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs index 5609c87d5..4b2d03dbe 100644 --- a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs +++ b/packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs @@ -29,6 +29,19 @@ impl<'a> WithdrawNonceAccount<'a> { &self, _signers: &[pinocchio::instruction::Signer], ) -> pinocchio::ProgramResult { + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; 5] = [ + pinocchio::instruction::AccountMeta::new(self.nonce_account.key(), true, false), + pinocchio::instruction::AccountMeta::new(self.recipient_account.key(), true, false), + pinocchio::instruction::AccountMeta::new( + self.recent_blockhashes_sysvar.key(), + false, + false, + ), + pinocchio::instruction::AccountMeta::new(self.rent_sysvar.key(), false, false), + pinocchio::instruction::AccountMeta::new(self.nonce_authority.key(), false, true), + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/public/templates/instructionPage.njk b/packages/renderers-pinocchio/public/templates/instructionPage.njk index 06f017a98..e58e660b4 100644 --- a/packages/renderers-pinocchio/public/templates/instructionPage.njk +++ b/packages/renderers-pinocchio/public/templates/instructionPage.njk @@ -39,6 +39,18 @@ impl{{ '<\'a>' if instruction.accounts.length > 0 }} {{ instruction.name | pasca } pub fn invoke_signed(&self, _signers: &[pinocchio::instruction::Signer]) -> pinocchio::ProgramResult { + + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; {{ instruction.accounts.length }}] = [ + {% for account in instruction.accounts %} + {% if account.isSigner === 'either' %} + pinocchio::instruction::AccountMeta::new(self.{{ account.name | snakeCase }}.0.key(), {{ account.isWritable }}, self.{{ account.name | snakeCase }}.1), + {% else %} + pinocchio::instruction::AccountMeta::new(self.{{ account.name | snakeCase }}.key(), {{ account.isWritable }}, {{ account.isSigner }}), + {% endif %} + {% endfor %} + ]; + Ok(()) } } diff --git a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts index 0c0ec88b5..615ff2802 100644 --- a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts +++ b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts @@ -12,12 +12,13 @@ import { structTypeNodeFromInstructionArgumentNodes, VALUE_NODES, } from '@codama/nodes'; -import { RenderMap } from '@codama/renderers-core'; +import { addToRenderMap, mergeRenderMaps, renderMap } from '@codama/renderers-core'; import { extendVisitor, + getByteSizeVisitor, LinkableDictionary, pipe, - recordLinkablesVisitor, + recordLinkablesOnFirstVisitVisitor, staticVisitor, visit, } from '@codama/visitors-core'; @@ -45,19 +46,20 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const getImportFrom = getImportFromFactory(options.linkOverrides ?? {}); const getTraitsFromNode = getTraitsFromNodeFactory(options.traitOptions); const typeManifestVisitor = getTypeManifestVisitor({ getImportFrom, getTraitsFromNode }); + const byteSizeVisitor = getByteSizeVisitor(linkables); return pipe( - staticVisitor( - () => new RenderMap(), - ['rootNode', 'programNode', 'instructionNode', 'accountNode', 'definedTypeNode'], - ), + staticVisitor(() => renderMap(), { + keys: ['rootNode', 'programNode', 'instructionNode', 'accountNode', 'definedTypeNode'], + }), v => extendVisitor(v, { visitDefinedType(node) { const typeManifest = visit(node, typeManifestVisitor); const imports = new ImportMap().mergeWithManifest(typeManifest); - return new RenderMap().add( + return addToRenderMap( + renderMap(), `types/${snakeCase(node.name)}.rs`, render('definedTypesPage.njk', { definedType: node, @@ -88,6 +90,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { innerOptionType: string | null; name: string; optional: boolean; + size: number; type: string; value: string | null; }[] = []; @@ -130,6 +133,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { innerOptionType, name, optional: hasDefaultValue && argument.defaultValueStrategy !== 'omitted', + size: visit(argument.type, byteSizeVisitor) as number, // We fail later if the whole data is variable. type: manifest.type, value: renderValue, }); @@ -142,8 +146,19 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { parentName: `${pascalCase(node.name)}InstructionData`, }); const typeManifest = visit(struct, structVisitor); + const instructionSize = visit(struct, byteSizeVisitor); - return new RenderMap().add( + /* + if (instructionSize === null) { + throw new Error( + `[Rust] Cannot compute static byte size for instruction [${node.name}]. ` + + 'Consider using types with static size for instruction arguments.', + ); + } + */ + + return addToRenderMap( + renderMap(), `instructions/${snakeCase(node.name)}.rs`, render('instructionPage.njk', { hasArgs, @@ -155,20 +170,20 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { instructionArgs, program, typeManifest, + instructionSize, }), ); }, visitProgram(node, { self }) { program = node; - const renderMap = new RenderMap() - .mergeWith(...node.accounts.map(account => visit(account, self))) - .mergeWith(...node.definedTypes.map(type => visit(type, self))) - .mergeWith( - ...getAllInstructionsWithSubs(node, { - leavesOnly: !renderParentInstructions, - }).map(ix => visit(ix, self)), - ); + let renderMap = mergeRenderMaps([ + ...node.accounts.map(account => visit(account, self)), + ...node.definedTypes.map(type => visit(type, self)), + ...getAllInstructionsWithSubs(node, { + leavesOnly: !renderParentInstructions, + }).map(ix => visit(ix, self)), + ]); program = null; return renderMap; @@ -196,9 +211,9 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { root: node, }; - const map = new RenderMap(); + let renders = renderMap(); if (programsToExport.length > 0) { - map.add('programs.rs', render('programsMod.njk', ctx)); + renders = addToRenderMap(renders, 'programs.rs', render('programsMod.njk', ctx)); } /* if (accountsToExport.length > 0) { @@ -206,18 +221,20 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { } */ if (definedTypesToExport.length > 0) { - map.add('types/mod.rs', render('definedTypesMod.njk', ctx)); + renders = addToRenderMap(renders, 'types/mod.rs', render('definedTypesMod.njk', ctx)); } if (instructionsToExport.length > 0) { - map.add('instructions/mod.rs', render('instructionsMod.njk', ctx)); + renders = addToRenderMap(renders, 'instructions/mod.rs', render('instructionsMod.njk', ctx)); } - return map - .add('mod.rs', render('rootMod.njk', ctx)) - .mergeWith(...getAllPrograms(node).map(p => visit(p, self))); + return pipe( + renders, + r => addToRenderMap(r, 'mod.rs', render('rootMod.njk', ctx)), + r => mergeRenderMaps([r, ...getAllPrograms(node).map(p => visit(p, self))]), + ); }, }), - v => recordLinkablesVisitor(v, linkables), + v => recordLinkablesOnFirstVisitVisitor(v, linkables), ); } diff --git a/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts b/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts index ed07e9dc4..ea45de0b1 100644 --- a/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts +++ b/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts @@ -7,6 +7,7 @@ import { isNode, NumberTypeNode, numberTypeNode, + parseDocs, pascalCase, prefixedCountNode, REGISTERED_TYPE_NODE_KINDS, @@ -44,7 +45,7 @@ export function getTypeManifestVisitor(options: { ...mergeManifests(values), type: values.map(v => v.type).join('\n'), }), - [...REGISTERED_TYPE_NODE_KINDS, 'definedTypeLinkNode', 'definedTypeNode', 'accountNode'], + { keys: [...REGISTERED_TYPE_NODE_KINDS, 'definedTypeLinkNode', 'definedTypeNode', 'accountNode'] }, ), v => extendVisitor(v, { @@ -342,7 +343,7 @@ export function getTypeManifestVisitor(options: { nestedStruct = originalNestedStruct; const fieldName = snakeCase(structFieldType.name); - const docblock = rustDocblock(structFieldType.docs); + const docblock = rustDocblock(parseDocs(structFieldType.docs)); const resolvedNestedType = resolveNestedTypeNode(structFieldType.type); let derive = ''; diff --git a/packages/renderers-pinocchio/test/definedTypesPage.test.ts b/packages/renderers-pinocchio/test/definedTypesPage.test.ts index e19a763a8..e34e51339 100644 --- a/packages/renderers-pinocchio/test/definedTypesPage.test.ts +++ b/packages/renderers-pinocchio/test/definedTypesPage.test.ts @@ -15,6 +15,7 @@ import { test } from 'vitest'; import { getRenderMapVisitor } from '../src'; import { codeContains, codeDoesNotContains } from './_setup'; +import { getFromRenderMap } from '@codama/renderers-core'; test('it renders a prefix string on a defined type', () => { // Given the following program with 1 defined type using a prefixed size string. @@ -38,7 +39,7 @@ test('it renders a prefix string on a defined type', () => { const renderMap = visit(node, getRenderMapVisitor()); // Then we expect the following use and identifier to be rendered. - codeContains(renderMap.get('types/blob.rs'), [ + codeContains(getFromRenderMap(renderMap, 'types/blob.rs'), [ `use kaigan::types::U8PrefixString;`, `content_type: U8PrefixString,`, ]); @@ -61,7 +62,7 @@ test('it renders a scalar enum with Copy derive', () => { const renderMap = visit(node, getRenderMapVisitor()); // Then we expect the following use and identifier to be rendered. - codeContains(renderMap.get('types/tag.rs'), [`#[derive(`, `Copy`, `pub enum Tag`]); + codeContains(getFromRenderMap(renderMap, 'types/tag.rs'), [`#[derive(`, `Copy`, `pub enum Tag`]); }); test('it renders a non-scalar enum without Copy derive', () => { @@ -92,7 +93,7 @@ test('it renders a non-scalar enum without Copy derive', () => { const renderMap = visit(node, getRenderMapVisitor()); // Then we expect the following use and identifier to be rendered. - codeContains(renderMap.get('types/tag_with_struct.rs'), [`#[derive(`, `pub enum TagWithStruct`]); + codeContains(getFromRenderMap(renderMap, 'types/tag_with_struct.rs'), [`#[derive(`, `pub enum TagWithStruct`]); // And we expect the Copy derive to be missing. - codeDoesNotContains(renderMap.get('types/tag_with_struct.rs'), `Copy`); + codeDoesNotContains(getFromRenderMap(renderMap, 'types/tag_with_struct.rs'), `Copy`); }); diff --git a/packages/renderers-pinocchio/test/instructionsPage.test.ts b/packages/renderers-pinocchio/test/instructionsPage.test.ts index 0bbfb8ed0..e27658103 100644 --- a/packages/renderers-pinocchio/test/instructionsPage.test.ts +++ b/packages/renderers-pinocchio/test/instructionsPage.test.ts @@ -4,6 +4,7 @@ import { test } from 'vitest'; import { getRenderMapVisitor } from '../src'; import { codeContains } from './_setup'; +import { getFromRenderMap } from '@codama/renderers-core'; test('it renders a public instruction data struct', () => { // Given the following program with 1 instruction. @@ -17,5 +18,8 @@ test('it renders a public instruction data struct', () => { const renderMap = visit(node, getRenderMapVisitor()); // Then we expect the following pub struct. - codeContains(renderMap.get('instructions/mint_tokens.rs'), [`pub struct MintTokens`]); + codeContains(getFromRenderMap(renderMap, 'instructions/mint_tokens.rs'), [ + `pub struct MintTokensInstructionData`, + `pub fn new(`, + ]); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e559c75d9..60c5faa7a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -313,6 +313,56 @@ importers: specifier: ^3.2.6 version: 3.2.6 + packages/renderers-pinocchio: + dependencies: + '@codama/errors': + specifier: workspace:* + version: link:../errors + '@codama/nodes': + specifier: workspace:* + version: link:../nodes + '@codama/renderers-core': + specifier: workspace:* + version: link:../renderers-core + '@codama/visitors-core': + specifier: workspace:* + version: link:../visitors-core + '@solana/codecs-strings': + specifier: rc + version: 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + nunjucks: + specifier: ^3.2.4 + version: 3.2.4(chokidar@3.6.0) + devDependencies: + '@types/nunjucks': + specifier: ^3.2.6 + version: 3.2.6 + + packages/renderers-rust: + dependencies: + '@codama/errors': + specifier: workspace:* + version: link:../errors + '@codama/nodes': + specifier: workspace:* + version: link:../nodes + '@codama/renderers-core': + specifier: workspace:* + version: link:../renderers-core + '@codama/visitors-core': + specifier: workspace:* + version: link:../visitors-core + '@solana/codecs-strings': + specifier: rc + version: 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + nunjucks: + specifier: ^3.2.4 + version: 3.2.4(chokidar@3.6.0) + devDependencies: + '@types/nunjucks': + specifier: ^3.2.6 + version: 3.2.6 + packages/renderers-rust: dependencies: '@codama/errors': @@ -1379,67 +1429,63 @@ packages: cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.43.0': - resolution: {integrity: sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==} - cpu: [x64] - os: [win32] - - '@sinclair/typebox@0.33.22': - resolution: {integrity: sha512-auUj4k+f4pyrIVf4GW5UKquSZFHJWri06QgARy9C0t9ZTjJLIuNIrr1yl9bWcJWJ1Gz1vOvYN1D+QPaIlNMVkQ==} - - '@sinonjs/commons@3.0.1': - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - - '@sinonjs/fake-timers@11.3.1': - resolution: {integrity: sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==} + '@solana/codecs-core@2.0.0-rc.1': + resolution: {integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==} + peerDependencies: + typescript: '>=5' - '@solana/codecs-core@3.0.2': - resolution: {integrity: sha512-vpy8ySWgPF8+APwpeEr4dQbU/EyHjisd/TywIw3rymguWeZ9/wcThS0WDRi08Z44W6InCIbtI08RdtuHQZoSag==} + '@solana/codecs-core@2.0.0-rc.4': + resolution: {integrity: sha512-JIrTSps032mSE3wBxW3bXOqWfoy4CMy1CX/XeVCijyh5kLVxZTSDIdRTYdePdL1yzaOZF1Xysvt1DhOUgBdM+A==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.3.3' + typescript: '>=5' - '@solana/codecs-data-structures@3.0.2': - resolution: {integrity: sha512-07L3czS7xughfCSx2pTC4/3amyjuCd3kOW4m4RJoXqWVzyg5lX4vCIVrlQE4MtM7/5SLLvGHXbCPHcp92esGcQ==} - engines: {node: '>=20.18.0'} + '@solana/codecs-numbers@2.0.0-rc.1': + resolution: {integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==} peerDependencies: - typescript: '>=5.3.3' + typescript: '>=5' - '@solana/codecs-numbers@3.0.2': - resolution: {integrity: sha512-Yr9kWo2BF4Wdu9mhceUQ3ksA6ZTi2CvQr8GWkRh9DQjvmrdqE2vwxwWWcmnzGDzwbta5o4tAr8JjtAtmwpiLEg==} + '@solana/codecs-numbers@2.0.0-rc.4': + resolution: {integrity: sha512-ZJR7TaUO65+3Hzo3YOOUCS0wlzh17IW+j0MZC2LCk1R0woaypRpHKj4iSMYeQOZkMxsd9QT3WNvjFrPC2qA6Sw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.3.3' + typescript: '>=5' - '@solana/codecs-strings@3.0.2': - resolution: {integrity: sha512-V7Ivy3TjdrLL4E3wT2d32MpGYQFWM1UKnevLXPib/Aqws4nP/bGMHq6gSIJ4b9HrkFfrlEgSjusOyEJbRBBFag==} - engines: {node: '>=20.18.0'} + '@solana/codecs-strings@2.0.0-rc.1': + resolution: {integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5.3.3' + typescript: '>=5' - '@solana/codecs@3.0.2': - resolution: {integrity: sha512-ihsmK+OnwuVd5le66lIDqsj0BQiHiYbL3pv4kUCVacxoo8pgqxGHTPh1/Ei1GNSm2N7LF/kwPvnZVECgY+ZaJg==} + '@solana/codecs-strings@2.0.0-rc.4': + resolution: {integrity: sha512-LGfK2RL0BKjYYUfzu2FG/gTgCsYOMz9FKVs2ntji6WneZygPxJTV5W98K3J8Rl0JewpCSCFQH3xjLSHBJUS0fA==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.3.3' + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5' - '@solana/errors@3.0.2': - resolution: {integrity: sha512-0B4y9JUsX8/DzflhdSXSAF+UPUKyo1R1rrQ/ShS/8ApCOIWIFqZlve0TPatuTOGGNBememoukPOvDVtFy0ZYpg==} + '@solana/errors@2.0.0-rc.1': + resolution: {integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==} + hasBin: true + peerDependencies: + typescript: '>=5' + + '@solana/errors@2.0.0-rc.4': + resolution: {integrity: sha512-0PPaMyB81keEHG/1pnyEuiBVKctbXO641M2w3CIOrYT/wzjunfF0FTxsqq9wYJeYo0AyiefCKGgSPs6wiY2PpQ==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: - typescript: '>=5.3.3' + typescript: '>=5' - '@solana/eslint-config-solana@5.0.0': - resolution: {integrity: sha512-DPsoloOpVf/4JD7m3j394BvJX8mCKTSQ1xJrP0tyyeLEZN7x09OL9uj2bo2Ma4UTYZsyV97p2eiuiHmJVA0Kfw==} + '@solana/eslint-config-solana@3.0.3': + resolution: {integrity: sha512-yTaeCbOBwjmK4oUkknixOpwOzzAK8+4YWvJEJFNHuueESetieDnAeEHV7rzJllFgHEWa9nXps9Q3aD4/XJp71A==} peerDependencies: - '@eslint/js': ^9.13.0 - '@types/eslint__js': ^8.42.3 - eslint: ^9.13.0 - eslint-plugin-jest: ^29.0.0 - eslint-plugin-react-hooks: ^5.0.0 - eslint-plugin-simple-import-sort: ^12.1.1 + '@typescript-eslint/eslint-plugin': ^6.0.0 + '@typescript-eslint/parser': ^6.0.0 + eslint: ^8.45.0 + eslint-plugin-jest: ^27.2.3 + eslint-plugin-react-hooks: ^4.6.0 + eslint-plugin-simple-import-sort: ^10.0.0 eslint-plugin-sort-keys-fix: ^1.1.2 eslint-plugin-typescript-sort-keys: ^3.3.0 globals: ^15.11.0 @@ -1979,6 +2025,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + commander@14.0.0: resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} engines: {node: '>=20'} @@ -4608,47 +4658,50 @@ snapshots: type-detect: 4.0.8 '@sinonjs/fake-timers@11.3.1': + '@solana/codecs-core@2.0.0-rc.4(typescript@5.6.3)': dependencies: - '@sinonjs/commons': 3.0.1 + '@solana/errors': 2.0.0-rc.4(typescript@5.6.3) + typescript: 5.6.3 - '@solana/codecs-core@3.0.2(typescript@5.9.2)': + '@solana/codecs-numbers@2.0.0-rc.1(typescript@5.6.3)': dependencies: - '@solana/errors': 3.0.2(typescript@5.9.2) - typescript: 5.9.2 + '@sinonjs/commons': 3.0.1 - '@solana/codecs-data-structures@3.0.2(typescript@5.9.2)': + '@solana/codecs-numbers@2.0.0-rc.4(typescript@5.6.3)': dependencies: - '@solana/codecs-core': 3.0.2(typescript@5.9.2) - '@solana/codecs-numbers': 3.0.2(typescript@5.9.2) - '@solana/errors': 3.0.2(typescript@5.9.2) - typescript: 5.9.2 + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.6.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.6.3) + typescript: 5.6.3 - '@solana/codecs-numbers@3.0.2(typescript@5.9.2)': + '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': dependencies: - '@solana/codecs-core': 3.0.2(typescript@5.9.2) - '@solana/errors': 3.0.2(typescript@5.9.2) + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.6.3) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.6.3) + '@solana/errors': 2.0.0-rc.1(typescript@5.6.3) + fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.2 - '@solana/codecs-strings@3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/codecs-strings@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': dependencies: - '@solana/codecs-core': 3.0.2(typescript@5.9.2) - '@solana/codecs-numbers': 3.0.2(typescript@5.9.2) - '@solana/errors': 3.0.2(typescript@5.9.2) + '@solana/codecs-core': 2.0.0-rc.4(typescript@5.6.3) + '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.6.3) + '@solana/errors': 2.0.0-rc.4(typescript@5.6.3) fastestsmallesttextencoderdecoder: 1.0.22 - typescript: 5.9.2 + typescript: 5.6.3 - '@solana/codecs@3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/errors@2.0.0-rc.1(typescript@5.6.3)': dependencies: - '@solana/codecs-core': 3.0.2(typescript@5.9.2) - '@solana/codecs-data-structures': 3.0.2(typescript@5.9.2) - '@solana/codecs-numbers': 3.0.2(typescript@5.9.2) - '@solana/codecs-strings': 3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/options': 3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder + chalk: 5.3.0 + commander: 12.1.0 + typescript: 5.6.3 + + '@solana/errors@2.0.0-rc.4(typescript@5.6.3)': + dependencies: + chalk: 5.3.0 + commander: 12.1.0 + typescript: 5.6.3 - '@solana/errors@3.0.2(typescript@5.9.2)': + '@solana/eslint-config-solana@3.0.3(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-react-hooks@4.6.0(eslint@8.57.1))(eslint-plugin-simple-import-sort@10.0.0(eslint@8.57.1))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': dependencies: chalk: 5.6.0 commander: 14.0.0 @@ -5306,7 +5359,7 @@ snapshots: color-name@1.1.4: {} - commander@14.0.0: {} + commander@12.1.0: {} commander@4.1.1: {} From 3ee7f4a8bc428dce8843ff0a614eaf3275059b18 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Sep 2025 09:21:31 +0100 Subject: [PATCH 04/24] Add fragment utility --- packages/renderers-pinocchio/package.json | 2 +- .../renderers-pinocchio/src/utils/fragment.ts | 60 ++++ .../renderers-pinocchio/src/utils/index.ts | 1 + pnpm-lock.yaml | 281 +++++++++--------- 4 files changed, 208 insertions(+), 136 deletions(-) create mode 100644 packages/renderers-pinocchio/src/utils/fragment.ts diff --git a/packages/renderers-pinocchio/package.json b/packages/renderers-pinocchio/package.json index 4fc37ca68..cdde830d9 100644 --- a/packages/renderers-pinocchio/package.json +++ b/packages/renderers-pinocchio/package.json @@ -46,7 +46,7 @@ "@codama/nodes": "workspace:*", "@codama/renderers-core": "workspace:*", "@codama/visitors-core": "workspace:*", - "@solana/codecs-strings": "rc", + "@solana/codecs-strings": "^3.0.2", "nunjucks": "^3.2.4" }, "devDependencies": { diff --git a/packages/renderers-pinocchio/src/utils/fragment.ts b/packages/renderers-pinocchio/src/utils/fragment.ts new file mode 100644 index 000000000..93a470b31 --- /dev/null +++ b/packages/renderers-pinocchio/src/utils/fragment.ts @@ -0,0 +1,60 @@ +import { BaseFragment } from '@codama/renderers-core'; + +import { ImportMap } from '../ImportMap'; + +export type FragmentFeature = 'instruction:resolverScopeVariable'; + +export type Fragment = BaseFragment & Readonly<{ imports: ImportMap }>; + +function isFragment(value: unknown): value is Fragment { + return typeof value === 'object' && value !== null && 'content' in value && 'imports' in value; +} + +export function fragment(template: TemplateStringsArray, items: unknown[]): Fragment { + return createFragmentTemplate(template, items, isFragment, mergeFragments); +} + +export function mergeFragments(fragments: Fragment[], mergeContent: (contents: string[]) => string) { + return Object.freeze({ + content: mergeContent(fragments.map(fragment => fragment.content)), + imports: new ImportMap().mergeWith(...fragments.map(f => f.imports)), + }); +} + +export function mergeFragmentImports(fragment: Fragment, importMaps: ImportMap[]): Fragment { + return Object.freeze({ + ...fragment, + imports: new ImportMap().mergeWith(fragment.imports, ...importMaps), + }); +} + +export function addFragmentImports(fragment: Fragment, imports: string[]): Fragment { + return Object.freeze({ + ...fragment, + imports: new ImportMap().mergeWith(fragment.imports).add(imports), + }); +} + +export function addFragmentImportAlias(fragment: Fragment, importName: string, alias: string): Fragment { + return Object.freeze({ + ...fragment, + imports: new ImportMap().mergeWith(fragment.imports).addAlias(importName, alias), + }); +} + +// TODO: Will be part of renderers-core soon. +function createFragmentTemplate( + template: TemplateStringsArray, + items: unknown[], + isFragment: (value: unknown) => value is TFragment, + mergeFragments: (fragments: TFragment[], mergeContent: (contents: string[]) => string) => TFragment, +): TFragment { + const fragments = items.filter(isFragment); + const zippedItems = items.map((item, i) => { + const itemPrefix = template[i]; + if (typeof item === 'undefined') return itemPrefix; + if (isFragment(item)) return itemPrefix + item.content; + return itemPrefix + String(item); + }); + return mergeFragments(fragments, () => zippedItems.join('') + template[template.length - 1]); +} diff --git a/packages/renderers-pinocchio/src/utils/index.ts b/packages/renderers-pinocchio/src/utils/index.ts index 4de9615fb..335c4db86 100644 --- a/packages/renderers-pinocchio/src/utils/index.ts +++ b/packages/renderers-pinocchio/src/utils/index.ts @@ -1,4 +1,5 @@ export * from './codecs'; +export * from './fragment'; export * from './linkOverrides'; export * from './render'; export * from './traitOptions'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60c5faa7a..cfd2af891 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 0.5.1 '@changesets/cli': specifier: ^2.29.6 - version: 2.29.6(@types/node@24.3.1) + version: 2.29.6(@types/node@24.3.0) '@codama/internals': specifier: workspace:* version: link:packages/internals @@ -25,13 +25,13 @@ importers: version: 0.13.2 '@solana/eslint-config-solana': specifier: ^5.0.0 - version: 5.0.0(@eslint/js@9.34.0)(@types/eslint__js@8.42.3)(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(jest@30.0.0-alpha.6(@types/node@24.3.1))(typescript@5.9.2))(eslint-plugin-react-hooks@4.6.0(eslint@9.34.0))(eslint-plugin-simple-import-sort@12.1.1(eslint@9.34.0))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(globals@14.0.0)(jest@30.0.0-alpha.6(@types/node@24.3.1))(typescript-eslint@8.16.0(eslint@9.34.0)(typescript@5.9.2))(typescript@5.9.2) + version: 5.0.0(@eslint/js@9.34.0)(@types/eslint__js@8.42.3)(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(jest@30.0.0-alpha.6(@types/node@24.3.0))(typescript@5.9.2))(eslint-plugin-react-hooks@4.6.0(eslint@9.34.0))(eslint-plugin-simple-import-sort@12.1.1(eslint@9.34.0))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(globals@14.0.0)(jest@30.0.0-alpha.6(@types/node@24.3.0))(typescript-eslint@8.16.0(eslint@9.34.0)(typescript@5.9.2))(typescript@5.9.2) '@solana/prettier-config-solana': specifier: 0.0.5 version: 0.0.5(prettier@3.6.2) '@types/node': specifier: ^24 - version: 24.3.1 + version: 24.3.0 '@typescript-eslint/eslint-plugin': specifier: ^8.42.0 version: 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2) @@ -73,7 +73,7 @@ importers: version: 5.9.2 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.3.1)(happy-dom@18.0.1) + version: 3.2.4(@types/node@24.3.0)(happy-dom@18.0.1) zx: specifier: ^8.8.1 version: 8.8.1 @@ -328,33 +328,8 @@ importers: specifier: workspace:* version: link:../visitors-core '@solana/codecs-strings': - specifier: rc - version: 2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) - nunjucks: - specifier: ^3.2.4 - version: 3.2.4(chokidar@3.6.0) - devDependencies: - '@types/nunjucks': - specifier: ^3.2.6 - version: 3.2.6 - - packages/renderers-rust: - dependencies: - '@codama/errors': - specifier: workspace:* - version: link:../errors - '@codama/nodes': - specifier: workspace:* - version: link:../nodes - '@codama/renderers-core': - specifier: workspace:* - version: link:../renderers-core - '@codama/visitors-core': - specifier: workspace:* - version: link:../visitors-core - '@solana/codecs-strings': - specifier: rc - version: 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3) + specifier: ^3.0.2 + version: 3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) nunjucks: specifier: ^3.2.4 version: 3.2.4(chokidar@3.6.0) @@ -1429,63 +1404,67 @@ packages: cpu: [x64] os: [win32] - '@solana/codecs-core@2.0.0-rc.1': - resolution: {integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==} - peerDependencies: - typescript: '>=5' + '@rollup/rollup-win32-x64-msvc@4.43.0': + resolution: {integrity: sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==} + cpu: [x64] + os: [win32] - '@solana/codecs-core@2.0.0-rc.4': - resolution: {integrity: sha512-JIrTSps032mSE3wBxW3bXOqWfoy4CMy1CX/XeVCijyh5kLVxZTSDIdRTYdePdL1yzaOZF1Xysvt1DhOUgBdM+A==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5' + '@sinclair/typebox@0.33.22': + resolution: {integrity: sha512-auUj4k+f4pyrIVf4GW5UKquSZFHJWri06QgARy9C0t9ZTjJLIuNIrr1yl9bWcJWJ1Gz1vOvYN1D+QPaIlNMVkQ==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@11.3.1': + resolution: {integrity: sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==} - '@solana/codecs-numbers@2.0.0-rc.1': - resolution: {integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==} + '@solana/codecs-core@3.0.2': + resolution: {integrity: sha512-vpy8ySWgPF8+APwpeEr4dQbU/EyHjisd/TywIw3rymguWeZ9/wcThS0WDRi08Z44W6InCIbtI08RdtuHQZoSag==} + engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5' + typescript: '>=5.3.3' - '@solana/codecs-numbers@2.0.0-rc.4': - resolution: {integrity: sha512-ZJR7TaUO65+3Hzo3YOOUCS0wlzh17IW+j0MZC2LCk1R0woaypRpHKj4iSMYeQOZkMxsd9QT3WNvjFrPC2qA6Sw==} + '@solana/codecs-data-structures@3.0.2': + resolution: {integrity: sha512-07L3czS7xughfCSx2pTC4/3amyjuCd3kOW4m4RJoXqWVzyg5lX4vCIVrlQE4MtM7/5SLLvGHXbCPHcp92esGcQ==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5' + typescript: '>=5.3.3' - '@solana/codecs-strings@2.0.0-rc.1': - resolution: {integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==} + '@solana/codecs-numbers@3.0.2': + resolution: {integrity: sha512-Yr9kWo2BF4Wdu9mhceUQ3ksA6ZTi2CvQr8GWkRh9DQjvmrdqE2vwxwWWcmnzGDzwbta5o4tAr8JjtAtmwpiLEg==} + engines: {node: '>=20.18.0'} peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5' + typescript: '>=5.3.3' - '@solana/codecs-strings@2.0.0-rc.4': - resolution: {integrity: sha512-LGfK2RL0BKjYYUfzu2FG/gTgCsYOMz9FKVs2ntji6WneZygPxJTV5W98K3J8Rl0JewpCSCFQH3xjLSHBJUS0fA==} + '@solana/codecs-strings@3.0.2': + resolution: {integrity: sha512-V7Ivy3TjdrLL4E3wT2d32MpGYQFWM1UKnevLXPib/Aqws4nP/bGMHq6gSIJ4b9HrkFfrlEgSjusOyEJbRBBFag==} engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5' + typescript: '>=5.3.3' - '@solana/errors@2.0.0-rc.1': - resolution: {integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==} - hasBin: true + '@solana/codecs@3.0.2': + resolution: {integrity: sha512-ihsmK+OnwuVd5le66lIDqsj0BQiHiYbL3pv4kUCVacxoo8pgqxGHTPh1/Ei1GNSm2N7LF/kwPvnZVECgY+ZaJg==} + engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5' + typescript: '>=5.3.3' - '@solana/errors@2.0.0-rc.4': - resolution: {integrity: sha512-0PPaMyB81keEHG/1pnyEuiBVKctbXO641M2w3CIOrYT/wzjunfF0FTxsqq9wYJeYo0AyiefCKGgSPs6wiY2PpQ==} + '@solana/errors@3.0.2': + resolution: {integrity: sha512-0B4y9JUsX8/DzflhdSXSAF+UPUKyo1R1rrQ/ShS/8ApCOIWIFqZlve0TPatuTOGGNBememoukPOvDVtFy0ZYpg==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: - typescript: '>=5' + typescript: '>=5.3.3' - '@solana/eslint-config-solana@3.0.3': - resolution: {integrity: sha512-yTaeCbOBwjmK4oUkknixOpwOzzAK8+4YWvJEJFNHuueESetieDnAeEHV7rzJllFgHEWa9nXps9Q3aD4/XJp71A==} + '@solana/eslint-config-solana@5.0.0': + resolution: {integrity: sha512-DPsoloOpVf/4JD7m3j394BvJX8mCKTSQ1xJrP0tyyeLEZN7x09OL9uj2bo2Ma4UTYZsyV97p2eiuiHmJVA0Kfw==} peerDependencies: - '@typescript-eslint/eslint-plugin': ^6.0.0 - '@typescript-eslint/parser': ^6.0.0 - eslint: ^8.45.0 - eslint-plugin-jest: ^27.2.3 - eslint-plugin-react-hooks: ^4.6.0 - eslint-plugin-simple-import-sort: ^10.0.0 + '@eslint/js': ^9.13.0 + '@types/eslint__js': ^8.42.3 + eslint: ^9.13.0 + eslint-plugin-jest: ^29.0.0 + eslint-plugin-react-hooks: ^5.0.0 + eslint-plugin-simple-import-sort: ^12.1.1 eslint-plugin-sort-keys-fix: ^1.1.2 eslint-plugin-typescript-sort-keys: ^3.3.0 globals: ^15.11.0 @@ -1562,12 +1541,15 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@20.19.13': - resolution: {integrity: sha512-yCAeZl7a0DxgNVteXFHt9+uyFbqXGy/ShC4BlcHkoE0AfGXYv/BUiplV72DjMYXHDBXFjhvr6DD1NiRVfB4j8g==} + '@types/node@20.19.11': + resolution: {integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==} '@types/node@22.12.0': resolution: {integrity: sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==} + '@types/node@24.3.0': + resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} + '@types/node@24.3.1': resolution: {integrity: sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==} @@ -1962,8 +1944,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001741: - resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==} + caniuse-lite@1.0.30001739: + resolution: {integrity: sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==} chai@5.2.0: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} @@ -2025,10 +2007,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} - engines: {node: '>=18'} - commander@14.0.0: resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} engines: {node: '>=20'} @@ -3914,7 +3892,7 @@ snapshots: transitivePeerDependencies: - encoding - '@changesets/cli@2.29.6(@types/node@24.3.1)': + '@changesets/cli@2.29.6(@types/node@24.3.0)': dependencies: '@changesets/apply-release-plan': 7.0.12 '@changesets/assemble-release-plan': 6.0.9 @@ -3930,7 +3908,7 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.1(@types/node@24.3.1) + '@inquirer/external-editor': 1.0.1(@types/node@24.3.0) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 ci-info: 3.9.0 @@ -4257,12 +4235,12 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inquirer/external-editor@1.0.1(@types/node@24.3.1)': + '@inquirer/external-editor@1.0.1(@types/node@24.3.0)': dependencies: chardet: 2.1.0 iconv-lite: 0.6.3 optionalDependencies: - '@types/node': 24.3.1 + '@types/node': 24.3.0 '@isaacs/balanced-match@4.0.1': {} @@ -4658,67 +4636,64 @@ snapshots: type-detect: 4.0.8 '@sinonjs/fake-timers@11.3.1': - '@solana/codecs-core@2.0.0-rc.4(typescript@5.6.3)': - dependencies: - '@solana/errors': 2.0.0-rc.4(typescript@5.6.3) - typescript: 5.6.3 - - '@solana/codecs-numbers@2.0.0-rc.1(typescript@5.6.3)': dependencies: '@sinonjs/commons': 3.0.1 - '@solana/codecs-numbers@2.0.0-rc.4(typescript@5.6.3)': + '@solana/codecs-core@3.0.2(typescript@5.9.2)': dependencies: - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.6.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.6.3) - typescript: 5.6.3 + '@solana/errors': 3.0.2(typescript@5.9.2) + typescript: 5.9.2 - '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/codecs-data-structures@3.0.2(typescript@5.9.2)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.6.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.6.3) - fastestsmallesttextencoderdecoder: 1.0.22 + '@solana/codecs-core': 3.0.2(typescript@5.9.2) + '@solana/codecs-numbers': 3.0.2(typescript@5.9.2) + '@solana/errors': 3.0.2(typescript@5.9.2) typescript: 5.9.2 - '@solana/codecs-strings@2.0.0-rc.4(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.6.3)': + '@solana/codecs-numbers@3.0.2(typescript@5.9.2)': dependencies: - '@solana/codecs-core': 2.0.0-rc.4(typescript@5.6.3) - '@solana/codecs-numbers': 2.0.0-rc.4(typescript@5.6.3) - '@solana/errors': 2.0.0-rc.4(typescript@5.6.3) - fastestsmallesttextencoderdecoder: 1.0.22 - typescript: 5.6.3 + '@solana/codecs-core': 3.0.2(typescript@5.9.2) + '@solana/errors': 3.0.2(typescript@5.9.2) + typescript: 5.9.2 - '@solana/errors@2.0.0-rc.1(typescript@5.6.3)': + '@solana/codecs-strings@3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: - chalk: 5.3.0 - commander: 12.1.0 - typescript: 5.6.3 + '@solana/codecs-core': 3.0.2(typescript@5.9.2) + '@solana/codecs-numbers': 3.0.2(typescript@5.9.2) + '@solana/errors': 3.0.2(typescript@5.9.2) + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 5.9.2 - '@solana/errors@2.0.0-rc.4(typescript@5.6.3)': + '@solana/codecs@3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: - chalk: 5.3.0 - commander: 12.1.0 - typescript: 5.6.3 + '@solana/codecs-core': 3.0.2(typescript@5.9.2) + '@solana/codecs-data-structures': 3.0.2(typescript@5.9.2) + '@solana/codecs-numbers': 3.0.2(typescript@5.9.2) + '@solana/codecs-strings': 3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) + '@solana/options': 3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) + typescript: 5.9.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - '@solana/eslint-config-solana@3.0.3(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint-plugin-react-hooks@4.6.0(eslint@8.57.1))(eslint-plugin-simple-import-sort@10.0.0(eslint@8.57.1))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': + '@solana/errors@3.0.2(typescript@5.9.2)': dependencies: chalk: 5.6.0 commander: 14.0.0 typescript: 5.9.2 - '@solana/eslint-config-solana@5.0.0(@eslint/js@9.34.0)(@types/eslint__js@8.42.3)(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(jest@30.0.0-alpha.6(@types/node@24.3.1))(typescript@5.9.2))(eslint-plugin-react-hooks@4.6.0(eslint@9.34.0))(eslint-plugin-simple-import-sort@12.1.1(eslint@9.34.0))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(globals@14.0.0)(jest@30.0.0-alpha.6(@types/node@24.3.1))(typescript-eslint@8.16.0(eslint@9.34.0)(typescript@5.9.2))(typescript@5.9.2)': + '@solana/eslint-config-solana@5.0.0(@eslint/js@9.34.0)(@types/eslint__js@8.42.3)(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(jest@30.0.0-alpha.6(@types/node@24.3.0))(typescript@5.9.2))(eslint-plugin-react-hooks@4.6.0(eslint@9.34.0))(eslint-plugin-simple-import-sort@12.1.1(eslint@9.34.0))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(globals@14.0.0)(jest@30.0.0-alpha.6(@types/node@24.3.0))(typescript-eslint@8.16.0(eslint@9.34.0)(typescript@5.9.2))(typescript@5.9.2)': dependencies: '@eslint/js': 9.34.0 '@types/eslint__js': 8.42.3 eslint: 9.34.0 - eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(jest@30.0.0-alpha.6(@types/node@24.3.1))(typescript@5.9.2) + eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(jest@30.0.0-alpha.6(@types/node@24.3.0))(typescript@5.9.2) eslint-plugin-react-hooks: 4.6.0(eslint@9.34.0) eslint-plugin-simple-import-sort: 12.1.1(eslint@9.34.0) eslint-plugin-sort-keys-fix: 1.1.2 eslint-plugin-typescript-sort-keys: 3.3.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2) globals: 14.0.0 - jest: 30.0.0-alpha.6(@types/node@24.3.1) + jest: 30.0.0-alpha.6(@types/node@24.3.0) typescript: 5.9.2 typescript-eslint: 8.16.0(eslint@9.34.0)(typescript@5.9.2) @@ -4803,7 +4778,7 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@20.19.13': + '@types/node@20.19.11': dependencies: undici-types: 6.21.0 @@ -4811,6 +4786,10 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/node@24.3.0': + dependencies: + undici-types: 7.10.0 + '@types/node@24.3.1': dependencies: undici-types: 7.10.0 @@ -5068,13 +5047,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@24.3.1))': + '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@24.3.0))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.3.5(@types/node@24.3.1) + vite: 6.3.5(@types/node@24.3.0) '@vitest/pretty-format@3.2.4': dependencies: @@ -5251,7 +5230,7 @@ snapshots: browserslist@4.25.4: dependencies: - caniuse-lite: 1.0.30001741 + caniuse-lite: 1.0.30001739 electron-to-chromium: 1.5.214 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.4) @@ -5297,7 +5276,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001741: {} + caniuse-lite@1.0.30001739: {} chai@5.2.0: dependencies: @@ -5359,7 +5338,7 @@ snapshots: color-name@1.1.4: {} - commander@12.1.0: {} + commander@14.0.0: {} commander@4.1.1: {} @@ -5512,13 +5491,13 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(jest@30.0.0-alpha.6(@types/node@24.3.1))(typescript@5.9.2): + eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(jest@30.0.0-alpha.6(@types/node@24.3.0))(typescript@5.9.2): dependencies: '@typescript-eslint/utils': 5.62.0(eslint@9.34.0)(typescript@5.9.2) eslint: 9.34.0 optionalDependencies: '@typescript-eslint/eslint-plugin': 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2) - jest: 30.0.0-alpha.6(@types/node@24.3.1) + jest: 30.0.0-alpha.6(@types/node@24.3.0) transitivePeerDependencies: - supports-color - typescript @@ -5849,7 +5828,7 @@ snapshots: happy-dom@18.0.1: dependencies: - '@types/node': 20.19.13 + '@types/node': 20.19.11 '@types/whatwg-mimetype': 3.0.2 whatwg-mimetype: 3.0.0 @@ -6008,7 +5987,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.0.0-alpha.6(@types/node@24.3.1): + jest-cli@30.0.0-alpha.6(@types/node@24.3.0): dependencies: '@jest/core': 30.0.0-alpha.6 '@jest/test-result': 30.0.0-alpha.6 @@ -6016,7 +5995,7 @@ snapshots: chalk: 4.1.2 exit: 0.1.2 import-local: 3.2.0 - jest-config: 30.0.0-alpha.6(@types/node@24.3.1) + jest-config: 30.0.0-alpha.6(@types/node@24.3.0) jest-util: 30.0.0-alpha.6 jest-validate: 30.0.0-alpha.6 yargs: 17.7.2 @@ -6027,6 +6006,38 @@ snapshots: - supports-color - ts-node + jest-config@30.0.0-alpha.6(@types/node@24.3.0): + dependencies: + '@babel/core': 7.28.3 + '@jest/pattern': 30.0.0-alpha.6 + '@jest/test-sequencer': 30.0.0-alpha.6 + '@jest/types': 30.0.0-alpha.6 + babel-jest: 30.0.0-alpha.6(@babel/core@7.28.3) + chalk: 4.1.2 + ci-info: 4.3.0 + deepmerge: 4.3.1 + glob: 10.4.5 + graceful-fs: 4.2.11 + jest-circus: 30.0.0-alpha.6 + jest-docblock: 30.0.0-alpha.6 + jest-environment-node: 30.0.0-alpha.6 + jest-get-type: 30.0.0-alpha.6 + jest-regex-util: 30.0.0-alpha.6 + jest-resolve: 30.0.0-alpha.6 + jest-runner: 30.0.0-alpha.6 + jest-util: 30.0.0-alpha.6 + jest-validate: 30.0.0-alpha.6 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 30.0.0-alpha.6 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 24.3.0 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-config@30.0.0-alpha.6(@types/node@24.3.1): dependencies: '@babel/core': 7.28.3 @@ -6275,12 +6286,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@30.0.0-alpha.6(@types/node@24.3.1): + jest@30.0.0-alpha.6(@types/node@24.3.0): dependencies: '@jest/core': 30.0.0-alpha.6 '@jest/types': 30.0.0-alpha.6 import-local: 3.2.0 - jest-cli: 30.0.0-alpha.6(@types/node@24.3.1) + jest-cli: 30.0.0-alpha.6(@types/node@24.3.0) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -7005,13 +7016,13 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - vite-node@3.2.4(@types/node@24.3.1): + vite-node@3.2.4(@types/node@24.3.0): dependencies: cac: 6.7.14 debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.3.5(@types/node@24.3.1) + vite: 6.3.5(@types/node@24.3.0) transitivePeerDependencies: - '@types/node' - jiti @@ -7026,7 +7037,7 @@ snapshots: - tsx - yaml - vite@6.3.5(@types/node@24.3.1): + vite@6.3.5(@types/node@24.3.0): dependencies: esbuild: 0.25.5 fdir: 6.4.6(picomatch@4.0.2) @@ -7035,14 +7046,14 @@ snapshots: rollup: 4.43.0 tinyglobby: 0.2.14 optionalDependencies: - '@types/node': 24.3.1 + '@types/node': 24.3.0 fsevents: 2.3.3 - vitest@3.2.4(@types/node@24.3.1)(happy-dom@18.0.1): + vitest@3.2.4(@types/node@24.3.0)(happy-dom@18.0.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@24.3.1)) + '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@24.3.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -7060,11 +7071,11 @@ snapshots: tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.3.5(@types/node@24.3.1) - vite-node: 3.2.4(@types/node@24.3.1) + vite: 6.3.5(@types/node@24.3.0) + vite-node: 3.2.4(@types/node@24.3.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.3.1 + '@types/node': 24.3.0 happy-dom: 18.0.1 transitivePeerDependencies: - jiti From 43b3d9eba47dd6b5f951428dfd66971ec771f016 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Sep 2025 09:59:34 +0100 Subject: [PATCH 05/24] Create fragments for mod pages --- .../public/templates/definedTypesMod.njk | 13 ----- .../public/templates/instructionsMod.njk | 13 ----- .../public/templates/programsMod.njk | 14 ----- .../public/templates/rootMod.njk | 17 ------ .../src/fragments/index.ts | 1 + .../src/fragments/modPage.ts | 20 +++++++ .../src/fragments/programModPage.ts | 25 ++++++++ .../src/fragments/rootModPage.ts | 23 ++++++++ .../src/getRenderMapVisitor.ts | 58 ++++++------------- .../renderers-pinocchio/src/utils/fragment.ts | 25 ++++++-- 10 files changed, 106 insertions(+), 103 deletions(-) delete mode 100644 packages/renderers-pinocchio/public/templates/definedTypesMod.njk delete mode 100644 packages/renderers-pinocchio/public/templates/instructionsMod.njk delete mode 100644 packages/renderers-pinocchio/public/templates/programsMod.njk delete mode 100644 packages/renderers-pinocchio/public/templates/rootMod.njk create mode 100644 packages/renderers-pinocchio/src/fragments/index.ts create mode 100644 packages/renderers-pinocchio/src/fragments/modPage.ts create mode 100644 packages/renderers-pinocchio/src/fragments/programModPage.ts create mode 100644 packages/renderers-pinocchio/src/fragments/rootModPage.ts diff --git a/packages/renderers-pinocchio/public/templates/definedTypesMod.njk b/packages/renderers-pinocchio/public/templates/definedTypesMod.njk deleted file mode 100644 index cff97f064..000000000 --- a/packages/renderers-pinocchio/public/templates/definedTypesMod.njk +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "layout.njk" %} - -{% block main %} - -{% for definedType in definedTypesToExport | sort(false, false, 'name') %} - pub(crate) mod r#{{ definedType.name | snakeCase }}; -{% endfor %} - -{% for definedType in definedTypesToExport | sort(false, false, 'name') %} - pub use self::r#{{ definedType.name | snakeCase }}::*; -{% endfor %} - -{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/instructionsMod.njk b/packages/renderers-pinocchio/public/templates/instructionsMod.njk deleted file mode 100644 index 36dd2b6c6..000000000 --- a/packages/renderers-pinocchio/public/templates/instructionsMod.njk +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "layout.njk" %} - -{% block main %} - -{% for instruction in instructionsToExport | sort(false, false, 'name') %} - pub(crate) mod r#{{ instruction.name | snakeCase }}; -{% endfor %} - -{% for instruction in instructionsToExport | sort(false, false, 'name') %} - pub use self::r#{{ instruction.name | snakeCase }}::*; -{% endfor %} - -{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/programsMod.njk b/packages/renderers-pinocchio/public/templates/programsMod.njk deleted file mode 100644 index 0226b1748..000000000 --- a/packages/renderers-pinocchio/public/templates/programsMod.njk +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "layout.njk" %} - -{% block main %} - -use pinocchio::pubkey::Pubkey; -use pinocchio_pubkey::pubkey; - -{% for program in programsToExport | sort(false, false, 'name') %} - - /// `{{ program.name | snakeCase }}` program ID. - pub const {{ program.name | snakeCase | upper }}_ID: Pubkey = pubkey!("{{ program.publicKey }}"); -{% endfor %} - -{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/rootMod.njk b/packages/renderers-pinocchio/public/templates/rootMod.njk deleted file mode 100644 index 977b722f5..000000000 --- a/packages/renderers-pinocchio/public/templates/rootMod.njk +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "layout.njk" %} - -{% block main %} - -{% if hasAnythingToExport %} - {% if instructionsToExport.length > 0 %} - pub mod instructions; - {% endif %} - {% if programsToExport.length > 0 %} - pub mod programs; - {% endif %} - {% if definedTypesToExport.length > 0 %} - pub mod types; - {% endif %} -{% endif %} - -{% endblock %} diff --git a/packages/renderers-pinocchio/src/fragments/index.ts b/packages/renderers-pinocchio/src/fragments/index.ts new file mode 100644 index 000000000..cfba20401 --- /dev/null +++ b/packages/renderers-pinocchio/src/fragments/index.ts @@ -0,0 +1 @@ +export * from './rootModPage'; diff --git a/packages/renderers-pinocchio/src/fragments/modPage.ts b/packages/renderers-pinocchio/src/fragments/modPage.ts new file mode 100644 index 000000000..d95fb2b84 --- /dev/null +++ b/packages/renderers-pinocchio/src/fragments/modPage.ts @@ -0,0 +1,20 @@ +import { CamelCaseString, snakeCase } from '@codama/nodes'; + +import { Fragment, fragment, getPageFragment, mergeFragments } from '../utils'; + +export function getModPageFragment(scope: { items: { name: CamelCaseString }[] }): Fragment | undefined { + const { items } = scope; + if (items.length === 0) return; + + const sortedItems = items.slice().sort((a, b) => a.name.localeCompare(b.name)); + const modStatements = mergeFragments( + sortedItems.map(item => fragment`pub mod r#${snakeCase(item.name)};`), + cs => cs.join('\n'), + ); + const useStatements = mergeFragments( + sortedItems.map(item => fragment`pub use self::r#${snakeCase(item.name)}::*;`), + cs => cs.join('\n'), + ); + + return getPageFragment(mergeFragments([modStatements, useStatements], cs => cs.join('\n\n'))); +} diff --git a/packages/renderers-pinocchio/src/fragments/programModPage.ts b/packages/renderers-pinocchio/src/fragments/programModPage.ts new file mode 100644 index 000000000..e4dfa6c1b --- /dev/null +++ b/packages/renderers-pinocchio/src/fragments/programModPage.ts @@ -0,0 +1,25 @@ +import { ProgramNode, snakeCase } from '@codama/nodes'; +import { pipe } from '@codama/visitors-core'; + +import { addFragmentImports, Fragment, fragment, getPageFragment, mergeFragments } from '../utils'; + +export function getProgramModPageFragment(scope: { programsToExport: ProgramNode[] }): Fragment | undefined { + const programsToExport = scope.programsToExport; + if (programsToExport.length === 0) return; + + const programAddresses = programsToExport.map(getProgramAddressFragment); + return getPageFragment(mergeFragments(programAddresses, cs => cs.join('\n'))); +} + +function getProgramAddressFragment(program: ProgramNode): Fragment { + const name = snakeCase(program.name); + return mergeFragments( + [ + fragment`/// \`${name}\` program ID.`, + pipe(fragment`pub const ${name.toUpperCase()}_ID: Pubkey = pubkey!("${program.publicKey}");`, f => + addFragmentImports(f, ['pinocchio::pubkey::Pubkey', 'pinocchio_pubkey::pubkey']), + ), + ], + cs => cs.join('\n'), + ); +} diff --git a/packages/renderers-pinocchio/src/fragments/rootModPage.ts b/packages/renderers-pinocchio/src/fragments/rootModPage.ts new file mode 100644 index 000000000..a0ea785fe --- /dev/null +++ b/packages/renderers-pinocchio/src/fragments/rootModPage.ts @@ -0,0 +1,23 @@ +import { InstructionNode, ProgramNode } from '@codama/nodes'; + +import { Fragment, fragment, getPageFragment, mergeFragments } from '../utils'; + +export function getRootModPageFragment(scope: { + instructionsToExport: InstructionNode[]; + programsToExport: ProgramNode[]; +}): Fragment | undefined { + const hasPrograms = scope.programsToExport.length > 0; + const hasInstructions = scope.instructionsToExport.length > 0; + const hasAnythingToExport = hasPrograms || hasInstructions; + if (!hasAnythingToExport) return; + + return getPageFragment( + mergeFragments( + [ + hasInstructions ? fragment`pub mod instructions;` : undefined, + hasPrograms ? fragment`pub mod programs;` : undefined, + ], + cs => cs.join('\n'), + ), + ); +} diff --git a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts index 615ff2802..1efbfbdf8 100644 --- a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts +++ b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts @@ -1,7 +1,5 @@ import { logWarn } from '@codama/errors'; import { - getAllAccounts, - getAllDefinedTypes, getAllInstructionsWithSubs, getAllPrograms, InstructionNode, @@ -12,7 +10,7 @@ import { structTypeNodeFromInstructionArgumentNodes, VALUE_NODES, } from '@codama/nodes'; -import { addToRenderMap, mergeRenderMaps, renderMap } from '@codama/renderers-core'; +import { addToRenderMap, fragmentToRenderMap, mergeRenderMaps, renderMap } from '@codama/renderers-core'; import { extendVisitor, getByteSizeVisitor, @@ -23,6 +21,9 @@ import { visit, } from '@codama/visitors-core'; +import { getRootModPageFragment } from './fragments'; +import { getModPageFragment } from './fragments/modPage'; +import { getProgramModPageFragment } from './fragments/programModPage'; import { getTypeManifestVisitor } from './getTypeManifestVisitor'; import { ImportMap } from './ImportMap'; import { renderValueNode } from './renderValueNodeVisitor'; @@ -191,47 +192,24 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { visitRoot(node, { self }) { const programsToExport = getAllPrograms(node); - const accountsToExport = getAllAccounts(node); const instructionsToExport = getAllInstructionsWithSubs(node, { leavesOnly: !renderParentInstructions, }); - const definedTypesToExport = getAllDefinedTypes(node); - const hasAnythingToExport = - programsToExport.length > 0 || - accountsToExport.length > 0 || - instructionsToExport.length > 0 || - definedTypesToExport.length > 0; - - const ctx = { - accountsToExport, - definedTypesToExport, - hasAnythingToExport, - instructionsToExport, - programsToExport, - root: node, - }; - - let renders = renderMap(); - if (programsToExport.length > 0) { - renders = addToRenderMap(renders, 'programs.rs', render('programsMod.njk', ctx)); - } - /* - if (accountsToExport.length > 0) { - map.add('accounts/mod.rs', render('accountsMod.njk', ctx)); - } - */ - if (definedTypesToExport.length > 0) { - renders = addToRenderMap(renders, 'types/mod.rs', render('definedTypesMod.njk', ctx)); - } - if (instructionsToExport.length > 0) { - renders = addToRenderMap(renders, 'instructions/mod.rs', render('instructionsMod.njk', ctx)); - } - return pipe( - renders, - r => addToRenderMap(r, 'mod.rs', render('rootMod.njk', ctx)), - r => mergeRenderMaps([r, ...getAllPrograms(node).map(p => visit(p, self))]), - ); + const rootMod = getRootModPageFragment({ instructionsToExport, programsToExport }); + const programsMod = getProgramModPageFragment({ programsToExport }); + const instructionsMod = getModPageFragment({ items: instructionsToExport }); + + return mergeRenderMaps([ + // mod.rs + ...(rootMod ? [fragmentToRenderMap(rootMod, 'mod.rs')] : []), + // programs/mod.rs + ...(programsMod ? [fragmentToRenderMap(programsMod, 'programs/mod.rs')] : []), + // instructions/mod.rs + ...(instructionsMod ? [fragmentToRenderMap(instructionsMod, 'instructions/mod.rs')] : []), + // Rest of the generated content. + ...programsToExport.map(p => visit(p, self)), + ]); }, }), v => recordLinkablesOnFirstVisitVisitor(v, linkables), diff --git a/packages/renderers-pinocchio/src/utils/fragment.ts b/packages/renderers-pinocchio/src/utils/fragment.ts index 93a470b31..34f2562ff 100644 --- a/packages/renderers-pinocchio/src/utils/fragment.ts +++ b/packages/renderers-pinocchio/src/utils/fragment.ts @@ -2,22 +2,21 @@ import { BaseFragment } from '@codama/renderers-core'; import { ImportMap } from '../ImportMap'; -export type FragmentFeature = 'instruction:resolverScopeVariable'; - export type Fragment = BaseFragment & Readonly<{ imports: ImportMap }>; function isFragment(value: unknown): value is Fragment { return typeof value === 'object' && value !== null && 'content' in value && 'imports' in value; } -export function fragment(template: TemplateStringsArray, items: unknown[]): Fragment { +export function fragment(template: TemplateStringsArray, ...items: unknown[]): Fragment { return createFragmentTemplate(template, items, isFragment, mergeFragments); } -export function mergeFragments(fragments: Fragment[], mergeContent: (contents: string[]) => string) { +export function mergeFragments(fragments: (Fragment | undefined)[], mergeContent: (contents: string[]) => string) { + const filteredFragments = fragments.filter((f): f is Fragment => typeof f !== 'undefined'); return Object.freeze({ - content: mergeContent(fragments.map(fragment => fragment.content)), - imports: new ImportMap().mergeWith(...fragments.map(f => f.imports)), + content: mergeContent(filteredFragments.map(f => f.content)), + imports: new ImportMap().mergeWith(...filteredFragments.map(f => f.imports)), }); } @@ -42,6 +41,20 @@ export function addFragmentImportAlias(fragment: Fragment, importName: string, a }); } +export function getDocblockFragment(): Fragment { + //! This code was AUTOGENERATED using the codama library. + //! Please DO NOT EDIT THIS FILE, instead use visitors + //! to add features, then rerun codama to update it. + //! + //! + //! + return fragment`TODO`; // TODO +} + +export function getPageFragment(page: Fragment): Fragment { + return page; // TODO +} + // TODO: Will be part of renderers-core soon. function createFragmentTemplate( template: TemplateStringsArray, From b1687633e5d33c6a8c8b43fe42658534d4dfe144 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Sep 2025 10:22:13 +0100 Subject: [PATCH 06/24] Setup page fragment wrapper and render scope --- .../src/fragments/modPage.ts | 11 ++++-- .../src/fragments/programModPage.ts | 11 ++++-- .../src/fragments/rootModPage.ts | 13 ++++--- .../src/getRenderMapVisitor.ts | 37 +++++++++++-------- .../src/getTypeManifestVisitor.ts | 2 + .../renderers-pinocchio/src/renderVisitor.ts | 10 +---- .../renderers-pinocchio/src/utils/fragment.ts | 29 ++++++++++----- .../renderers-pinocchio/src/utils/index.ts | 1 + .../renderers-pinocchio/src/utils/options.ts | 30 +++++++++++++++ 9 files changed, 99 insertions(+), 45 deletions(-) create mode 100644 packages/renderers-pinocchio/src/utils/options.ts diff --git a/packages/renderers-pinocchio/src/fragments/modPage.ts b/packages/renderers-pinocchio/src/fragments/modPage.ts index d95fb2b84..638a3a289 100644 --- a/packages/renderers-pinocchio/src/fragments/modPage.ts +++ b/packages/renderers-pinocchio/src/fragments/modPage.ts @@ -1,8 +1,10 @@ import { CamelCaseString, snakeCase } from '@codama/nodes'; -import { Fragment, fragment, getPageFragment, mergeFragments } from '../utils'; +import { Fragment, fragment, getPageFragment, mergeFragments, RenderScope } from '../utils'; -export function getModPageFragment(scope: { items: { name: CamelCaseString }[] }): Fragment | undefined { +export function getModPageFragment( + scope: Pick & { items: { name: CamelCaseString }[] }, +): Fragment | undefined { const { items } = scope; if (items.length === 0) return; @@ -16,5 +18,8 @@ export function getModPageFragment(scope: { items: { name: CamelCaseString }[] } cs => cs.join('\n'), ); - return getPageFragment(mergeFragments([modStatements, useStatements], cs => cs.join('\n\n'))); + return getPageFragment( + mergeFragments([modStatements, useStatements], cs => cs.join('\n\n')), + scope, + ); } diff --git a/packages/renderers-pinocchio/src/fragments/programModPage.ts b/packages/renderers-pinocchio/src/fragments/programModPage.ts index e4dfa6c1b..4416d2bdb 100644 --- a/packages/renderers-pinocchio/src/fragments/programModPage.ts +++ b/packages/renderers-pinocchio/src/fragments/programModPage.ts @@ -1,14 +1,19 @@ import { ProgramNode, snakeCase } from '@codama/nodes'; import { pipe } from '@codama/visitors-core'; -import { addFragmentImports, Fragment, fragment, getPageFragment, mergeFragments } from '../utils'; +import { addFragmentImports, Fragment, fragment, getPageFragment, mergeFragments, RenderScope } from '../utils'; -export function getProgramModPageFragment(scope: { programsToExport: ProgramNode[] }): Fragment | undefined { +export function getProgramModPageFragment( + scope: Pick & { programsToExport: ProgramNode[] }, +): Fragment | undefined { const programsToExport = scope.programsToExport; if (programsToExport.length === 0) return; const programAddresses = programsToExport.map(getProgramAddressFragment); - return getPageFragment(mergeFragments(programAddresses, cs => cs.join('\n'))); + return getPageFragment( + mergeFragments(programAddresses, cs => cs.join('\n')), + scope, + ); } function getProgramAddressFragment(program: ProgramNode): Fragment { diff --git a/packages/renderers-pinocchio/src/fragments/rootModPage.ts b/packages/renderers-pinocchio/src/fragments/rootModPage.ts index a0ea785fe..5fc648526 100644 --- a/packages/renderers-pinocchio/src/fragments/rootModPage.ts +++ b/packages/renderers-pinocchio/src/fragments/rootModPage.ts @@ -1,11 +1,13 @@ import { InstructionNode, ProgramNode } from '@codama/nodes'; -import { Fragment, fragment, getPageFragment, mergeFragments } from '../utils'; +import { Fragment, fragment, getPageFragment, mergeFragments, RenderScope } from '../utils'; -export function getRootModPageFragment(scope: { - instructionsToExport: InstructionNode[]; - programsToExport: ProgramNode[]; -}): Fragment | undefined { +export function getRootModPageFragment( + scope: Pick & { + instructionsToExport: InstructionNode[]; + programsToExport: ProgramNode[]; + }, +): Fragment | undefined { const hasPrograms = scope.programsToExport.length > 0; const hasInstructions = scope.instructionsToExport.length > 0; const hasAnythingToExport = hasPrograms || hasInstructions; @@ -19,5 +21,6 @@ export function getRootModPageFragment(scope: { ], cs => cs.join('\n'), ), + scope, ); } diff --git a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts index 1efbfbdf8..ead444856 100644 --- a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts +++ b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts @@ -15,8 +15,10 @@ import { extendVisitor, getByteSizeVisitor, LinkableDictionary, + NodeStack, pipe, recordLinkablesOnFirstVisitVisitor, + recordNodeStackVisitor, staticVisitor, visit, } from '@codama/visitors-core'; @@ -27,19 +29,11 @@ import { getProgramModPageFragment } from './fragments/programModPage'; import { getTypeManifestVisitor } from './getTypeManifestVisitor'; import { ImportMap } from './ImportMap'; import { renderValueNode } from './renderValueNodeVisitor'; -import { getImportFromFactory, getTraitsFromNodeFactory, LinkOverrides, render, TraitOptions } from './utils'; - -export type GetRenderMapOptions = { - anchorTraits?: boolean; - defaultTraitOverrides?: string[]; - dependencyMap?: Record; - linkOverrides?: LinkOverrides; - renderParentInstructions?: boolean; - traitOptions?: TraitOptions; -}; +import { getImportFromFactory, GetRenderMapOptions, getTraitsFromNodeFactory, render, RenderScope } from './utils'; export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const linkables = new LinkableDictionary(); + const stack = new NodeStack(); let program: ProgramNode | null = null; const renderParentInstructions = options.renderParentInstructions ?? false; @@ -47,7 +41,16 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const getImportFrom = getImportFromFactory(options.linkOverrides ?? {}); const getTraitsFromNode = getTraitsFromNodeFactory(options.traitOptions); const typeManifestVisitor = getTypeManifestVisitor({ getImportFrom, getTraitsFromNode }); - const byteSizeVisitor = getByteSizeVisitor(linkables); + const byteSizeVisitor = getByteSizeVisitor(linkables, { stack }); + + const renderScope: RenderScope = { + byteSizeVisitor, + dependencyMap, + getImportFrom, + linkables, + renderParentInstructions, + typeManifestVisitor, + }; return pipe( staticVisitor(() => renderMap(), { @@ -169,16 +172,16 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { .toString(dependencyMap), instruction: node, instructionArgs, + instructionSize, program, typeManifest, - instructionSize, }), ); }, visitProgram(node, { self }) { program = node; - let renderMap = mergeRenderMaps([ + const renderMap = mergeRenderMaps([ ...node.accounts.map(account => visit(account, self)), ...node.definedTypes.map(type => visit(type, self)), ...getAllInstructionsWithSubs(node, { @@ -195,10 +198,11 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const instructionsToExport = getAllInstructionsWithSubs(node, { leavesOnly: !renderParentInstructions, }); + const scope = { ...renderScope, instructionsToExport, programsToExport }; - const rootMod = getRootModPageFragment({ instructionsToExport, programsToExport }); - const programsMod = getProgramModPageFragment({ programsToExport }); - const instructionsMod = getModPageFragment({ items: instructionsToExport }); + const rootMod = getRootModPageFragment(scope); + const programsMod = getProgramModPageFragment(scope); + const instructionsMod = getModPageFragment({ ...renderScope, items: instructionsToExport }); return mergeRenderMaps([ // mod.rs @@ -212,6 +216,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { ]); }, }), + v => recordNodeStackVisitor(v, stack), v => recordLinkablesOnFirstVisitVisitor(v, linkables), ); } diff --git a/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts b/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts index ea45de0b1..b28f6d9ff 100644 --- a/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts +++ b/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts @@ -26,6 +26,8 @@ export type TypeManifest = { type: string; }; +export type TypeManifestVisitor = ReturnType; + export function getTypeManifestVisitor(options: { getImportFrom: GetImportFromFunction; getTraitsFromNode: GetTraitsFromNodeFunction; diff --git a/packages/renderers-pinocchio/src/renderVisitor.ts b/packages/renderers-pinocchio/src/renderVisitor.ts index 2260b2796..108fec228 100644 --- a/packages/renderers-pinocchio/src/renderVisitor.ts +++ b/packages/renderers-pinocchio/src/renderVisitor.ts @@ -3,14 +3,8 @@ import { deleteDirectory, writeRenderMapVisitor } from '@codama/renderers-core'; import { rootNodeVisitor, visit } from '@codama/visitors-core'; import { spawnSync } from 'child_process'; -import { GetRenderMapOptions, getRenderMapVisitor } from './getRenderMapVisitor'; - -export type RenderOptions = GetRenderMapOptions & { - crateFolder?: string; - deleteFolderBeforeRendering?: boolean; - formatCode?: boolean; - toolchain?: string; -}; +import { getRenderMapVisitor } from './getRenderMapVisitor'; +import { RenderOptions } from './utils'; export function renderVisitor(path: string, options: RenderOptions = {}) { return rootNodeVisitor(root => { diff --git a/packages/renderers-pinocchio/src/utils/fragment.ts b/packages/renderers-pinocchio/src/utils/fragment.ts index 34f2562ff..df77dc488 100644 --- a/packages/renderers-pinocchio/src/utils/fragment.ts +++ b/packages/renderers-pinocchio/src/utils/fragment.ts @@ -1,6 +1,8 @@ +import { Docs } from '@codama/nodes'; import { BaseFragment } from '@codama/renderers-core'; import { ImportMap } from '../ImportMap'; +import { RenderScope } from './options'; export type Fragment = BaseFragment & Readonly<{ imports: ImportMap }>; @@ -41,18 +43,25 @@ export function addFragmentImportAlias(fragment: Fragment, importName: string, a }); } -export function getDocblockFragment(): Fragment { - //! This code was AUTOGENERATED using the codama library. - //! Please DO NOT EDIT THIS FILE, instead use visitors - //! to add features, then rerun codama to update it. - //! - //! - //! - return fragment`TODO`; // TODO +export function getDocblockFragment(lines: Docs, withLineJump = false, internal = false): Fragment { + const prefix = internal ? '//!' : '///'; + const lineJump = withLineJump ? '\n' : ''; + if (lines.length === 0) return fragment``; + const prefixedLines = lines.map(line => (line ? `${prefix} ${line}` : prefix)); + return fragment`${prefixedLines.join('\n')}${lineJump}`; } -export function getPageFragment(page: Fragment): Fragment { - return page; // TODO +export function getPageFragment(page: Fragment, scope: Pick): Fragment { + const docs = [ + 'This code was AUTOGENERATED using the Codama library.', + 'Please DO NOT EDIT THIS FILE, instead use visitors', + 'to add features, then rerun Codama to update it.', + '', + '', + ]; + const header = getDocblockFragment(docs, false, true); + const imports = page.imports.isEmpty() ? undefined : fragment`${page.imports.toString(scope.dependencyMap)}`; + return mergeFragments([header, imports, page], cs => cs.join('\n\n')); } // TODO: Will be part of renderers-core soon. diff --git a/packages/renderers-pinocchio/src/utils/index.ts b/packages/renderers-pinocchio/src/utils/index.ts index 335c4db86..687aa59ee 100644 --- a/packages/renderers-pinocchio/src/utils/index.ts +++ b/packages/renderers-pinocchio/src/utils/index.ts @@ -1,5 +1,6 @@ export * from './codecs'; export * from './fragment'; export * from './linkOverrides'; +export * from './options'; export * from './render'; export * from './traitOptions'; diff --git a/packages/renderers-pinocchio/src/utils/options.ts b/packages/renderers-pinocchio/src/utils/options.ts new file mode 100644 index 000000000..c273c391b --- /dev/null +++ b/packages/renderers-pinocchio/src/utils/options.ts @@ -0,0 +1,30 @@ +import { getByteSizeVisitor, LinkableDictionary } from '@codama/visitors-core'; + +import { TypeManifestVisitor } from '../getTypeManifestVisitor'; +import { GetImportFromFunction, LinkOverrides } from './linkOverrides'; +import { TraitOptions } from './traitOptions'; + +export type RenderOptions = GetRenderMapOptions & { + crateFolder?: string; + deleteFolderBeforeRendering?: boolean; + formatCode?: boolean; + toolchain?: string; +}; + +export type GetRenderMapOptions = { + anchorTraits?: boolean; + defaultTraitOverrides?: string[]; + dependencyMap?: Record; + linkOverrides?: LinkOverrides; + renderParentInstructions?: boolean; + traitOptions?: TraitOptions; +}; + +export type RenderScope = { + byteSizeVisitor: ReturnType; + dependencyMap: Record; + getImportFrom: GetImportFromFunction; + linkables: LinkableDictionary; + renderParentInstructions: boolean; + typeManifestVisitor: TypeManifestVisitor; +}; From 6a8c06882315fcd79cdb667d14e2d91143591c34 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Sep 2025 11:14:08 +0100 Subject: [PATCH 07/24] Use Fragments in TypeManifestVisitor --- .../public/templates/definedTypesPage.njk | 15 -- .../public/templates/instructionPage.njk | 9 - .../public/templates/layout.njk | 7 - .../public/templates/macros.njk | 6 - .../src/fragments/index.ts | 3 + .../src/fragments/instructionPage.ts | 117 +++++++++++++ .../src/getRenderMapVisitor.ts | 159 +----------------- .../src/getTypeManifestVisitor.ts | 143 +++++++--------- .../renderers-pinocchio/src/renderVisitor.ts | 2 + .../renderers-pinocchio/src/utils/options.ts | 3 +- .../src/utils/traitOptions.ts | 14 +- 11 files changed, 199 insertions(+), 279 deletions(-) delete mode 100644 packages/renderers-pinocchio/public/templates/definedTypesPage.njk delete mode 100644 packages/renderers-pinocchio/public/templates/layout.njk delete mode 100644 packages/renderers-pinocchio/public/templates/macros.njk create mode 100644 packages/renderers-pinocchio/src/fragments/instructionPage.ts diff --git a/packages/renderers-pinocchio/public/templates/definedTypesPage.njk b/packages/renderers-pinocchio/public/templates/definedTypesPage.njk deleted file mode 100644 index cb9876903..000000000 --- a/packages/renderers-pinocchio/public/templates/definedTypesPage.njk +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "layout.njk" %} -{% import "macros.njk" as macros %} - -{% block main %} - -{{ imports }} - -{{ macros.docblock(definedType.docs) }} -{{- typeManifest.type }} - -{% for nestedStruct in typeManifest.nestedStructs %} -{{ nestedStruct }} -{% endfor %} - -{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/instructionPage.njk b/packages/renderers-pinocchio/public/templates/instructionPage.njk index e58e660b4..c3b2ed1c8 100644 --- a/packages/renderers-pinocchio/public/templates/instructionPage.njk +++ b/packages/renderers-pinocchio/public/templates/instructionPage.njk @@ -1,10 +1,3 @@ -{% extends "layout.njk" %} -{% import "macros.njk" as macros %} - -{% block main %} - -{{ imports }} - /// `{{ instruction.name | snakeCase }}` CPI helper. pub struct {{ instruction.name | pascalCase }}{{ '<\'a>' if instruction.accounts.length > 0 }} { {# Accounts #} @@ -54,5 +47,3 @@ impl{{ '<\'a>' if instruction.accounts.length > 0 }} {{ instruction.name | pasca Ok(()) } } - -{% endblock %} \ No newline at end of file diff --git a/packages/renderers-pinocchio/public/templates/layout.njk b/packages/renderers-pinocchio/public/templates/layout.njk deleted file mode 100644 index 30674b24d..000000000 --- a/packages/renderers-pinocchio/public/templates/layout.njk +++ /dev/null @@ -1,7 +0,0 @@ -//! This code was AUTOGENERATED using the codama library. -//! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. -//! -//! -//! -{% block main %}{% endblock %} diff --git a/packages/renderers-pinocchio/public/templates/macros.njk b/packages/renderers-pinocchio/public/templates/macros.njk deleted file mode 100644 index fafbe0d30..000000000 --- a/packages/renderers-pinocchio/public/templates/macros.njk +++ /dev/null @@ -1,6 +0,0 @@ -{# Write a docblock from an array of strings. #} -{% macro docblock(docs) %} -{% for doc in docs %} -/// {{ doc }} -{% endfor %} -{% endmacro %} diff --git a/packages/renderers-pinocchio/src/fragments/index.ts b/packages/renderers-pinocchio/src/fragments/index.ts index cfba20401..a0e106d1e 100644 --- a/packages/renderers-pinocchio/src/fragments/index.ts +++ b/packages/renderers-pinocchio/src/fragments/index.ts @@ -1 +1,4 @@ +export * from './instructionPage'; +export * from './modPage'; +export * from './programModPage'; export * from './rootModPage'; diff --git a/packages/renderers-pinocchio/src/fragments/instructionPage.ts b/packages/renderers-pinocchio/src/fragments/instructionPage.ts new file mode 100644 index 000000000..de7a7e108 --- /dev/null +++ b/packages/renderers-pinocchio/src/fragments/instructionPage.ts @@ -0,0 +1,117 @@ +import { logWarn } from '@codama/errors'; +import { + InstructionArgumentNode, + InstructionNode, + isNode, + pascalCase, + structTypeNodeFromInstructionArgumentNodes, + VALUE_NODES, +} from '@codama/nodes'; +import { getLastNodeFromPath, NodePath, visit } from '@codama/visitors-core'; + +import { getTypeManifestVisitor, TypeManifestVisitor } from '../getTypeManifestVisitor'; +import { renderValueNode } from '../renderValueNodeVisitor'; +import { Fragment, fragment, getPageFragment, RenderScope } from '../utils'; + +export function getInstructionPageFragment( + scope: Pick & { + instructionPath: NodePath; + }, +): Fragment { + const instructionNode = getLastNodeFromPath(scope.instructionPath); + + // canMergeAccountsAndArgs + const accountsAndArgsConflicts = getConflictsBetweenAccountsAndArguments(instructionNode); + if (accountsAndArgsConflicts.length > 0) { + logWarn( + `[Rust] Accounts and args of instruction [${instructionNode.name}] have the following ` + + `conflicting attributes [${accountsAndArgsConflicts.join(', ')}]. ` + + `Thus, the conflicting arguments will be suffixed with "_arg". ` + + 'You may want to rename the conflicting attributes.', + ); + } + + // Instruction args. + const instructionArgs: { + default: boolean; + innerOptionType: string | null; + name: string; + optional: boolean; + size: number; + type: string; + value: string | null; + }[] = []; + // let hasArgs = false; + // let hasOptional = false; + // hasArgs = hasArgs || argument.defaultValueStrategy !== 'omitted'; + // hasOptional = hasOptional || (hasDefaultValue && argument.defaultValueStrategy !== 'omitted'); + + const argumentVisitor = getTypeManifestVisitor({ + ...scope, + nestedStruct: true, + parentName: `${pascalCase(instructionNode.name)}InstructionData`, + }); + + const struct = structTypeNodeFromInstructionArgumentNodes(instructionNode.arguments); + const structVisitor = getTypeManifestVisitor({ + ...scope, + parentName: `${pascalCase(instructionNode.name)}InstructionData`, + }); + const typeManifest = visit(struct, structVisitor); + const instructionSize = visit(struct, scope.byteSizeVisitor); + + // imports: imports + // .remove(`generatedInstructions::${pascalCase(node.name)}`) + // .toString(dependencyMap), + + return getPageFragment(fragment``, scope); +} + +type ParsedInstructionArgument = InstructionArgumentNode & { + default: boolean; + innerOptionType: string | null; + name: string; + optional: boolean; + size: number; + type: string; + value: string | null; +}; + +function getParsedInstructionArgument( + argument: InstructionArgumentNode, + argumentVisitor: TypeManifestVisitor, + accountsAndArgsConflicts: string[], +): ParsedInstructionArgument { + const manifest = visit(argument.type, argumentVisitor); + imports.mergeWith(manifest.imports); + const innerOptionType = isNode(argument.type, 'optionTypeNode') ? manifest.type.slice('Option<'.length, -1) : null; + + const hasDefaultValue = !!argument.defaultValue && isNode(argument.defaultValue, VALUE_NODES); + let renderValue: string | null = null; + if (hasDefaultValue) { + const { imports: argImports, render: value } = renderValueNode(argument.defaultValue, scope.getImportFrom); + imports.mergeWith(argImports); + renderValue = value; + } + + const name = accountsAndArgsConflicts.includes(argument.name) ? `${argument.name}_arg` : argument.name; + + return { + default: hasDefaultValue && argument.defaultValueStrategy === 'omitted', + innerOptionType, + name, + optional: hasDefaultValue && argument.defaultValueStrategy !== 'omitted', + size: visit(argument.type, scope.byteSizeVisitor) as number, // We fail later if the whole data is variable. + type: manifest.type, + value: renderValue, + }; +} + +function getConflictsBetweenAccountsAndArguments(instructionNode: InstructionNode): string[] { + const allNames = [ + ...instructionNode.accounts.map(account => account.name), + ...instructionNode.arguments.map(argument => argument.name), + ]; + const duplicates = allNames.filter((e, i, a) => a.indexOf(e) !== i); + return [...new Set(duplicates)]; +} diff --git a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts index ead444856..6c242349d 100644 --- a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts +++ b/packages/renderers-pinocchio/src/getRenderMapVisitor.ts @@ -1,16 +1,5 @@ -import { logWarn } from '@codama/errors'; -import { - getAllInstructionsWithSubs, - getAllPrograms, - InstructionNode, - isNode, - pascalCase, - ProgramNode, - snakeCase, - structTypeNodeFromInstructionArgumentNodes, - VALUE_NODES, -} from '@codama/nodes'; -import { addToRenderMap, fragmentToRenderMap, mergeRenderMaps, renderMap } from '@codama/renderers-core'; +import { getAllInstructionsWithSubs, getAllPrograms, snakeCase } from '@codama/nodes'; +import { fragmentToRenderMap, mergeRenderMaps, renderMap } from '@codama/renderers-core'; import { extendVisitor, getByteSizeVisitor, @@ -23,18 +12,15 @@ import { visit, } from '@codama/visitors-core'; -import { getRootModPageFragment } from './fragments'; +import { getInstructionPageFragment, getRootModPageFragment } from './fragments'; import { getModPageFragment } from './fragments/modPage'; import { getProgramModPageFragment } from './fragments/programModPage'; import { getTypeManifestVisitor } from './getTypeManifestVisitor'; -import { ImportMap } from './ImportMap'; -import { renderValueNode } from './renderValueNodeVisitor'; -import { getImportFromFactory, GetRenderMapOptions, getTraitsFromNodeFactory, render, RenderScope } from './utils'; +import { getImportFromFactory, GetRenderMapOptions, getTraitsFromNodeFactory, RenderScope } from './utils'; export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const linkables = new LinkableDictionary(); const stack = new NodeStack(); - let program: ProgramNode | null = null; const renderParentInstructions = options.renderParentInstructions ?? false; const dependencyMap = options.dependencyMap ?? {}; @@ -47,6 +33,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { byteSizeVisitor, dependencyMap, getImportFrom, + getTraitsFromNode, linkables, renderParentInstructions, typeManifestVisitor, @@ -58,139 +45,20 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { }), v => extendVisitor(v, { - visitDefinedType(node) { - const typeManifest = visit(node, typeManifestVisitor); - const imports = new ImportMap().mergeWithManifest(typeManifest); - - return addToRenderMap( - renderMap(), - `types/${snakeCase(node.name)}.rs`, - render('definedTypesPage.njk', { - definedType: node, - imports: imports.remove(`generatedTypes::${pascalCase(node.name)}`).toString(dependencyMap), - typeManifest, - }), - ); - }, - visitInstruction(node) { - // Imports. - const imports = new ImportMap(); - - // canMergeAccountsAndArgs - const accountsAndArgsConflicts = getConflictsForInstructionAccountsAndArgs(node); - if (accountsAndArgsConflicts.length > 0) { - logWarn( - `[Rust] Accounts and args of instruction [${node.name}] have the following ` + - `conflicting attributes [${accountsAndArgsConflicts.join(', ')}]. ` + - `Thus, the conflicting arguments will be suffixed with "_arg". ` + - 'You may want to rename the conflicting attributes.', - ); - } - - // Instruction args. - const instructionArgs: { - default: boolean; - innerOptionType: string | null; - name: string; - optional: boolean; - size: number; - type: string; - value: string | null; - }[] = []; - let hasArgs = false; - let hasOptional = false; - - node.arguments.forEach(argument => { - const argumentVisitor = getTypeManifestVisitor({ - getImportFrom, - getTraitsFromNode, - nestedStruct: true, - parentName: `${pascalCase(node.name)}InstructionData`, - }); - const manifest = visit(argument.type, argumentVisitor); - imports.mergeWith(manifest.imports); - const innerOptionType = isNode(argument.type, 'optionTypeNode') - ? manifest.type.slice('Option<'.length, -1) - : null; - - const hasDefaultValue = !!argument.defaultValue && isNode(argument.defaultValue, VALUE_NODES); - let renderValue: string | null = null; - if (hasDefaultValue) { - const { imports: argImports, render: value } = renderValueNode( - argument.defaultValue, - getImportFrom, - ); - imports.mergeWith(argImports); - renderValue = value; - } - - hasArgs = hasArgs || argument.defaultValueStrategy !== 'omitted'; - hasOptional = hasOptional || (hasDefaultValue && argument.defaultValueStrategy !== 'omitted'); - - const name = accountsAndArgsConflicts.includes(argument.name) - ? `${argument.name}_arg` - : argument.name; - - instructionArgs.push({ - default: hasDefaultValue && argument.defaultValueStrategy === 'omitted', - innerOptionType, - name, - optional: hasDefaultValue && argument.defaultValueStrategy !== 'omitted', - size: visit(argument.type, byteSizeVisitor) as number, // We fail later if the whole data is variable. - type: manifest.type, - value: renderValue, - }); - }); - - const struct = structTypeNodeFromInstructionArgumentNodes(node.arguments); - const structVisitor = getTypeManifestVisitor({ - getImportFrom, - getTraitsFromNode, - parentName: `${pascalCase(node.name)}InstructionData`, - }); - const typeManifest = visit(struct, structVisitor); - const instructionSize = visit(struct, byteSizeVisitor); - - /* - if (instructionSize === null) { - throw new Error( - `[Rust] Cannot compute static byte size for instruction [${node.name}]. ` + - 'Consider using types with static size for instruction arguments.', - ); - } - */ - - return addToRenderMap( - renderMap(), + const instructionPath = stack.getPath('instructionNode'); + return fragmentToRenderMap( + getInstructionPageFragment({ ...renderScope, instructionPath }), `instructions/${snakeCase(node.name)}.rs`, - render('instructionPage.njk', { - hasArgs, - hasOptional, - imports: imports - .remove(`generatedInstructions::${pascalCase(node.name)}`) - .toString(dependencyMap), - instruction: node, - instructionArgs, - instructionSize, - program, - typeManifest, - }), ); }, visitProgram(node, { self }) { - program = node; - const renderMap = mergeRenderMaps([ - ...node.accounts.map(account => visit(account, self)), - ...node.definedTypes.map(type => visit(type, self)), + return mergeRenderMaps([ ...getAllInstructionsWithSubs(node, { leavesOnly: !renderParentInstructions, }).map(ix => visit(ix, self)), ]); - - program = null; - return renderMap; }, visitRoot(node, { self }) { @@ -220,12 +88,3 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { v => recordLinkablesOnFirstVisitVisitor(v, linkables), ); } - -function getConflictsForInstructionAccountsAndArgs(instruction: InstructionNode): string[] { - const allNames = [ - ...instruction.accounts.map(account => account.name), - ...instruction.arguments.map(argument => argument.name), - ]; - const duplicates = allNames.filter((e, i, a) => a.indexOf(e) !== i); - return [...new Set(duplicates)]; -} diff --git a/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts b/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts index b28f6d9ff..de64a92bc 100644 --- a/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts +++ b/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts @@ -17,13 +17,19 @@ import { } from '@codama/nodes'; import { extendVisitor, mergeVisitor, pipe, visit } from '@codama/visitors-core'; -import { ImportMap } from './ImportMap'; -import { GetImportFromFunction, GetTraitsFromNodeFunction, rustDocblock } from './utils'; +import { + addFragmentImports, + Fragment, + fragment, + GetImportFromFunction, + GetTraitsFromNodeFunction, + mergeFragments, + rustDocblock, +} from './utils'; export type TypeManifest = { - imports: ImportMap; - nestedStructs: string[]; - type: string; + nestedStructs: Fragment[]; + type: Fragment; }; export type TypeManifestVisitor = ReturnType; @@ -42,11 +48,8 @@ export function getTypeManifestVisitor(options: { return pipe( mergeVisitor( - (): TypeManifest => ({ imports: new ImportMap(), nestedStructs: [], type: '' }), - (_, values) => ({ - ...mergeManifests(values), - type: values.map(v => v.type).join('\n'), - }), + (): TypeManifest => ({ nestedStructs: [], type: fragment`` }), + (_, manifests) => mergeManifests(manifests), { keys: [...REGISTERED_TYPE_NODE_KINDS, 'definedTypeLinkNode', 'definedTypeNode', 'accountNode'] }, ), v => @@ -55,12 +58,8 @@ export function getTypeManifestVisitor(options: { parentName = pascalCase(account.name); const manifest = visit(account.data, self); const traits = getTraitsFromNode(account); - manifest.imports.mergeWith(traits.imports); parentName = null; - return { - ...manifest, - type: traits.render + manifest.type, - }; + return { ...manifest, type: fragment`${traits}${manifest.type}` }; }, visitArrayType(arrayType, { self }) { @@ -69,7 +68,7 @@ export function getTypeManifestVisitor(options: { if (isNode(arrayType.count, 'fixedCountNode')) { return { ...childManifest, - type: `[${childManifest.type}; ${arrayType.count.value}]`, + type: fragment`[${childManifest.type}; ${arrayType.count.value}]`, }; } @@ -80,11 +79,7 @@ export function getTypeManifestVisitor(options: { visitBooleanType(booleanType) { const resolvedSize = resolveNestedTypeNode(booleanType.size); if (resolvedSize.format === 'u8' && resolvedSize.endian === 'le') { - return { - imports: new ImportMap(), - nestedStructs: [], - type: 'bool', - }; + return { nestedStructs: [], type: fragment`bool` }; } // TODO: Add to the Rust validator. @@ -106,33 +101,29 @@ export function getTypeManifestVisitor(options: { parentName = pascalCase(definedType.name); const manifest = visit(definedType.type, self); const traits = getTraitsFromNode(definedType); - manifest.imports.mergeWith(traits.imports); parentName = null; const renderedType = isNode(definedType.type, ['enumTypeNode', 'structTypeNode']) ? manifest.type - : `pub type ${pascalCase(definedType.name)} = ${manifest.type};`; + : fragment`pub type ${pascalCase(definedType.name)} = ${manifest.type};`; - return { ...manifest, type: `${traits.render}${renderedType}` }; + return { ...manifest, type: fragment`${traits}${renderedType}` }; }, visitDefinedTypeLink(node) { const pascalCaseDefinedType = pascalCase(node.name); const importFrom = getImportFrom(node); return { - imports: new ImportMap().add(`${importFrom}::${pascalCaseDefinedType}`), nestedStructs: [], - type: pascalCaseDefinedType, + type: addFragmentImports(fragment`${pascalCaseDefinedType}`, [ + `${importFrom}::${pascalCaseDefinedType}`, + ]), }; }, visitEnumEmptyVariantType(enumEmptyVariantType) { const name = pascalCase(enumEmptyVariantType.name); - return { - imports: new ImportMap(), - nestedStructs: [], - type: `${name},`, - }; + return { nestedStructs: [], type: fragment`${name},` }; }, visitEnumStructVariantType(enumStructVariantType, { self }) { @@ -151,7 +142,7 @@ export function getTypeManifestVisitor(options: { return { ...typeManifest, - type: `${name} ${typeManifest.type},`, + type: fragment`${name} ${typeManifest.type},`, }; }, @@ -168,17 +159,17 @@ export function getTypeManifestVisitor(options: { parentName = originalParentName; let derive = ''; - if (childManifest.type === '(Pubkey)') { + if (childManifest.type.content === '(Pubkey)') { derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))]\n'; - } else if (childManifest.type === '(Vec)') { + } else if (childManifest.type.content === '(Vec)') { derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::>"))]\n'; } return { ...childManifest, - type: `${derive}${name}${childManifest.type},`, + type: fragment`${derive}${name}${childManifest.type},`, }; }, @@ -190,12 +181,11 @@ export function getTypeManifestVisitor(options: { } const variants = enumType.variants.map(variant => visit(variant, self)); - const variantNames = variants.map(variant => variant.type).join('\n'); const mergedManifest = mergeManifests(variants); return { ...mergedManifest, - type: `pub enum ${pascalCase(originalParentName)} {\n${variantNames}\n}`, + type: fragment`pub enum ${pascalCase(originalParentName)} {\n${mergedManifest.type}\n}`, }; }, @@ -210,10 +200,11 @@ export function getTypeManifestVisitor(options: { const key = visit(mapType.key, self); const value = visit(mapType.value, self); const mergedManifest = mergeManifests([key, value]); - mergedManifest.imports.add('std::collections::HashMap'); return { ...mergedManifest, - type: `HashMap<${key.type}, ${value.type}>`, + type: addFragmentImports(fragment`HashMap<${key.type}, ${value.type}>`, [ + 'std::collections::HashMap', + ]), }; }, @@ -225,17 +216,12 @@ export function getTypeManifestVisitor(options: { if (numberType.format === 'shortU16') { return { - imports: new ImportMap().add('solana_program::short_vec::ShortU16'), nestedStructs: [], - type: 'ShortU16', + type: addFragmentImports(fragment`ShortU16`, ['solana_program::short_vec::ShortU16']), }; } - return { - imports: new ImportMap(), - nestedStructs: [], - type: numberType.format, - }; + return { nestedStructs: [], type: fragment`${numberType.format}` }; }, visitOptionType(optionType, { self }) { @@ -245,7 +231,7 @@ export function getTypeManifestVisitor(options: { if (optionPrefix.format === 'u8' && optionPrefix.endian === 'le') { return { ...childManifest, - type: `Option<${childManifest.type}>`, + type: fragment`Option<${childManifest.type}>`, }; } @@ -255,9 +241,8 @@ export function getTypeManifestVisitor(options: { visitPublicKeyType() { return { - imports: new ImportMap().add('pinocchio::pubkey::Pubkey'), nestedStructs: [], - type: 'Pubkey', + type: addFragmentImports(fragment`Pubkey`, ['pinocchio::pubkey::Pubkey']), }; }, @@ -267,10 +252,11 @@ export function getTypeManifestVisitor(options: { visitSetType(setType, { self }) { const childManifest = visit(setType.item, self); - childManifest.imports.add('std::collections::HashSet'); return { ...childManifest, - type: `HashSet<${childManifest.type}>`, + type: addFragmentImports(fragment`HashSet<${childManifest.type}>`, [ + 'std::collections::HashSet', + ]), }; }, @@ -283,37 +269,26 @@ export function getTypeManifestVisitor(options: { visitStringType() { if (!parentSize) { - return { - imports: new ImportMap(), - nestedStructs: [], - type: `str`, - }; + return { nestedStructs: [], type: fragment`str` }; } if (typeof parentSize === 'number') { - return { - imports: new ImportMap(), - nestedStructs: [], - type: `[u8; ${parentSize}]`, - }; + return { nestedStructs: [], type: fragment`[u8; ${parentSize}]` }; } if (isNode(parentSize, 'numberTypeNode') && parentSize.endian === 'le') { switch (parentSize.format) { case 'u32': - return { - imports: new ImportMap(), - nestedStructs: [], - type: 'String', - }; + return { nestedStructs: [], type: fragment`String` }; case 'u8': case 'u16': case 'u64': { const prefix = parentSize.format.toUpperCase(); return { - imports: new ImportMap().add(`kaigan::types::${prefix}PrefixString`), nestedStructs: [], - type: `${prefix}PrefixString`, + type: addFragmentImports(fragment`${prefix}PrefixString`, [ + `kaigan::types::${prefix}PrefixString`, + ]), }; } default: @@ -322,7 +297,7 @@ export function getTypeManifestVisitor(options: { } // TODO: Add to the Rust validator. - throw new Error(`String size currently not supported: ${parentSize}`); + throw new Error(`String size currently not supported: ${parentSize.format}`); }, visitStructFieldType(structFieldType, { self }) { @@ -349,10 +324,10 @@ export function getTypeManifestVisitor(options: { const resolvedNestedType = resolveNestedTypeNode(structFieldType.type); let derive = ''; - if (fieldManifest.type === 'Pubkey') { + if (fieldManifest.type.content === 'Pubkey') { derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))]\n'; - } else if (fieldManifest.type === 'Vec') { + } else if (fieldManifest.type.content === 'Vec') { derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::>"))]\n'; } else if ( @@ -370,8 +345,8 @@ export function getTypeManifestVisitor(options: { return { ...fieldManifest, type: inlineStruct - ? `${docblock}${derive}${fieldName}: ${fieldManifest.type},` - : `${docblock}${derive}pub ${fieldName}: ${fieldManifest.type},`, + ? fragment`${docblock}${derive}${fieldName}: ${fieldManifest.type},` + : fragment`${docblock}${derive}pub ${fieldName}: ${fieldManifest.type},`, }; }, @@ -384,31 +359,29 @@ export function getTypeManifestVisitor(options: { } const fields = structType.fields.map(field => visit(field, self)); - const fieldTypes = fields.map(field => field.type).join('\n'); const mergedManifest = mergeManifests(fields); if (nestedStruct) { const nestedTraits = getTraitsFromNode( definedTypeNode({ name: originalParentName, type: structType }), ); - mergedManifest.imports.mergeWith(nestedTraits.imports); return { ...mergedManifest, nestedStructs: [ ...mergedManifest.nestedStructs, - `${nestedTraits.render}pub struct ${pascalCase(originalParentName)} {\n${fieldTypes}\n}`, + fragment`${nestedTraits}pub struct ${pascalCase(originalParentName)} {\n${mergedManifest.type}\n}`, ], - type: pascalCase(originalParentName), + type: fragment`${pascalCase(originalParentName)}`, }; } if (inlineStruct) { - return { ...mergedManifest, type: `{\n${fieldTypes}\n}` }; + return { ...mergedManifest, type: fragment`{\n${mergedManifest.type}\n}` }; } return { ...mergedManifest, - type: `pub struct ${pascalCase(originalParentName)} {\n${fieldTypes}\n}`, + type: fragment`pub struct ${pascalCase(originalParentName)} {\n${mergedManifest.type}\n}`, }; }, @@ -418,7 +391,10 @@ export function getTypeManifestVisitor(options: { return { ...mergedManifest, - type: `(${items.map(item => item.type).join(', ')})`, + type: mergeFragments( + items.map(i => i.type), + cs => `(${cs.join(', ')})`, + ), }; }, @@ -429,9 +405,12 @@ export function getTypeManifestVisitor(options: { ); } -function mergeManifests(manifests: TypeManifest[]): Pick { +function mergeManifests(manifests: TypeManifest[]): TypeManifest { return { - imports: new ImportMap().mergeWith(...manifests.map(td => td.imports)), nestedStructs: manifests.flatMap(m => m.nestedStructs), + type: mergeFragments( + manifests.map(m => m.type), + cs => cs.join('\n'), + ), }; } diff --git a/packages/renderers-pinocchio/src/renderVisitor.ts b/packages/renderers-pinocchio/src/renderVisitor.ts index 108fec228..a47301a84 100644 --- a/packages/renderers-pinocchio/src/renderVisitor.ts +++ b/packages/renderers-pinocchio/src/renderVisitor.ts @@ -35,9 +35,11 @@ function runFormatter(cmd: string, args: string[]) { return; } if (stdout.length > 0) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions logWarn(`(cargo-fmt) ${stdout || error}`); } if (stderr.length > 0) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions logError(`(cargo-fmt) ${stderr || error}`); } } diff --git a/packages/renderers-pinocchio/src/utils/options.ts b/packages/renderers-pinocchio/src/utils/options.ts index c273c391b..2c69adc62 100644 --- a/packages/renderers-pinocchio/src/utils/options.ts +++ b/packages/renderers-pinocchio/src/utils/options.ts @@ -2,7 +2,7 @@ import { getByteSizeVisitor, LinkableDictionary } from '@codama/visitors-core'; import { TypeManifestVisitor } from '../getTypeManifestVisitor'; import { GetImportFromFunction, LinkOverrides } from './linkOverrides'; -import { TraitOptions } from './traitOptions'; +import { GetTraitsFromNodeFunction, TraitOptions } from './traitOptions'; export type RenderOptions = GetRenderMapOptions & { crateFolder?: string; @@ -24,6 +24,7 @@ export type RenderScope = { byteSizeVisitor: ReturnType; dependencyMap: Record; getImportFrom: GetImportFromFunction; + getTraitsFromNode: GetTraitsFromNodeFunction; linkables: LinkableDictionary; renderParentInstructions: boolean; typeManifestVisitor: TypeManifestVisitor; diff --git a/packages/renderers-pinocchio/src/utils/traitOptions.ts b/packages/renderers-pinocchio/src/utils/traitOptions.ts index 7bb925605..0bfcb14a6 100644 --- a/packages/renderers-pinocchio/src/utils/traitOptions.ts +++ b/packages/renderers-pinocchio/src/utils/traitOptions.ts @@ -1,6 +1,7 @@ import { AccountNode, assertIsNode, camelCase, DefinedTypeNode, isNode, isScalarEnum } from '@codama/nodes'; import { ImportMap } from '../ImportMap'; +import { Fragment, fragment, mergeFragmentImports } from './fragment'; export type TraitOptions = { /** The default traits to implement for all types. */ @@ -51,24 +52,19 @@ export const DEFAULT_TRAIT_OPTIONS: Required = { useFullyQualifiedName: false, }; -export type GetTraitsFromNodeFunction = (node: AccountNode | DefinedTypeNode) => { imports: ImportMap; render: string }; +export type GetTraitsFromNodeFunction = (node: AccountNode | DefinedTypeNode) => Fragment; export function getTraitsFromNodeFactory(options: TraitOptions = {}): GetTraitsFromNodeFunction { return node => getTraitsFromNode(node, options); } -export function getTraitsFromNode( - node: AccountNode | DefinedTypeNode, - userOptions: TraitOptions = {}, -): { imports: ImportMap; render: string } { +export function getTraitsFromNode(node: AccountNode | DefinedTypeNode, userOptions: TraitOptions = {}): Fragment { assertIsNode(node, ['accountNode', 'definedTypeNode']); const options: Required = { ...DEFAULT_TRAIT_OPTIONS, ...userOptions }; // Get the node type and return early if it's a type alias. const nodeType = getNodeType(node); - if (nodeType === 'alias') { - return { imports: new ImportMap(), render: '' }; - } + if (nodeType === 'alias') return fragment``; // Find all the FQN traits for the node. const sanitizedOverrides = Object.fromEntries( @@ -96,7 +92,7 @@ export function getTraitsFromNode( }), ]; - return { imports, render: traitLines.join('') }; + return mergeFragmentImports(fragment`${traitLines.join('')}`, [imports]); } function getNodeType(node: AccountNode | DefinedTypeNode): 'alias' | 'dataEnum' | 'scalarEnum' | 'struct' { From 05ad4b46704eb273cdaa5f9286af21fe8482356a Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Sep 2025 11:30:15 +0100 Subject: [PATCH 08/24] Use Fragments in ValueVisitor --- .../src/fragments/instructionPage.ts | 16 +- .../src/renderValueNodeVisitor.ts | 150 ++++++++---------- 2 files changed, 67 insertions(+), 99 deletions(-) diff --git a/packages/renderers-pinocchio/src/fragments/instructionPage.ts b/packages/renderers-pinocchio/src/fragments/instructionPage.ts index de7a7e108..d76bad0ad 100644 --- a/packages/renderers-pinocchio/src/fragments/instructionPage.ts +++ b/packages/renderers-pinocchio/src/fragments/instructionPage.ts @@ -32,15 +32,7 @@ export function getInstructionPageFragment( } // Instruction args. - const instructionArgs: { - default: boolean; - innerOptionType: string | null; - name: string; - optional: boolean; - size: number; - type: string; - value: string | null; - }[] = []; + const instructionArgs: ParsedInstructionArgument[] = []; // let hasArgs = false; // let hasOptional = false; // hasArgs = hasArgs || argument.defaultValueStrategy !== 'omitted'; @@ -81,10 +73,12 @@ function getParsedInstructionArgument( argument: InstructionArgumentNode, argumentVisitor: TypeManifestVisitor, accountsAndArgsConflicts: string[], + scope: Pick, ): ParsedInstructionArgument { const manifest = visit(argument.type, argumentVisitor); - imports.mergeWith(manifest.imports); - const innerOptionType = isNode(argument.type, 'optionTypeNode') ? manifest.type.slice('Option<'.length, -1) : null; + const innerOptionType = isNode(argument.type, 'optionTypeNode') + ? manifest.type.content.slice('Option<'.length, -1) + : null; const hasDefaultValue = !!argument.defaultValue && isNode(argument.defaultValue, VALUE_NODES); let renderValue: string | null = null; diff --git a/packages/renderers-pinocchio/src/renderValueNodeVisitor.ts b/packages/renderers-pinocchio/src/renderValueNodeVisitor.ts index 320678b6c..d21720d43 100644 --- a/packages/renderers-pinocchio/src/renderValueNodeVisitor.ts +++ b/packages/renderers-pinocchio/src/renderValueNodeVisitor.ts @@ -9,49 +9,45 @@ import { } from '@codama/nodes'; import { visit, Visitor } from '@codama/visitors-core'; -import { ImportMap } from './ImportMap'; -import { getBytesFromBytesValueNode, GetImportFromFunction } from './utils'; +import { + addFragmentImports, + Fragment, + fragment, + getBytesFromBytesValueNode, + GetImportFromFunction, + mergeFragments, +} from './utils'; export function renderValueNode( value: ValueNode, getImportFrom: GetImportFromFunction, useStr: boolean = false, -): { - imports: ImportMap; - render: string; -} { +): Fragment { return visit(value, renderValueNodeVisitor(getImportFrom, useStr)); } export function renderValueNodeVisitor( getImportFrom: GetImportFromFunction, useStr: boolean = false, -): Visitor< - { - imports: ImportMap; - render: string; - }, - RegisteredValueNode['kind'] -> { +): Visitor { return { visitArrayValue(node) { - const list = node.items.map(v => visit(v, this)); - return { - imports: new ImportMap().mergeWith(...list.map(c => c.imports)), - render: `[${list.map(c => c.render).join(', ')}]`, - }; + return mergeFragments( + node.items.map(v => visit(v, this)), + cs => `[${cs.join(', ')}]`, + ); }, + visitBooleanValue(node) { - return { - imports: new ImportMap(), - render: JSON.stringify(node.boolean), - }; + return fragment`${JSON.stringify(node.boolean)}`; }, + visitBytesValue(node) { const bytes = getBytesFromBytesValueNode(node); const numbers = Array.from(bytes).map(numberValueNode); return visit(arrayValueNode(numbers), this); }, + visitConstantValue(node) { if (isNode(node.value, 'bytesValueNode')) { return visit(node.value, this); @@ -60,105 +56,83 @@ export function renderValueNodeVisitor( return visit(bytesValueNode(node.type.encoding, node.value.string), this); } if (isNode(node.type, 'numberTypeNode') && isNode(node.value, 'numberValueNode')) { - const numberManifest = visit(node.value, this); + const child = visit(node.value, this); const { format, endian } = node.type; const byteFunction = endian === 'le' ? 'to_le_bytes' : 'to_be_bytes'; - numberManifest.render = `${numberManifest.render}${format}.${byteFunction}()`; - return numberManifest; + return fragment`${child}${format}.${byteFunction}()`; } throw new Error('Unsupported constant value type.'); }, + visitEnumValue(node) { - const imports = new ImportMap(); - const enumName = pascalCase(node.enum.name); const variantName = pascalCase(node.variant); - const importFrom = getImportFrom(node.enum); - imports.add(`${importFrom}::${enumName}`); - if (!node.value) { - return { imports, render: `${enumName}::${variantName}` }; - } - const enumValue = visit(node.value, this); - const fields = enumValue.render; - return { - imports: imports.mergeWith(enumValue.imports), - render: `${enumName}::${variantName} ${fields}`, - }; + const enumName = addFragmentImports(fragment`${pascalCase(node.enum.name)}`, [ + `${getImportFrom(node.enum)}::${pascalCase(node.enum.name)}`, + ]); + if (!node.value) return fragment`${enumName}::${variantName}`; + + const fields = visit(node.value, this); + return fragment`${enumName}::${variantName} ${fields}`; }, + visitMapEntryValue(node) { const mapKey = visit(node.key, this); const mapValue = visit(node.value, this); - return { - imports: mapKey.imports.mergeWith(mapValue.imports), - render: `[${mapKey.render}, ${mapValue.render}]`, - }; + return fragment`[${mapKey}, ${mapValue}]`; }, + visitMapValue(node) { - const map = node.entries.map(entry => visit(entry, this)); - const imports = new ImportMap().add('std::collection::HashMap'); - return { - imports: imports.mergeWith(...map.map(c => c.imports)), - render: `HashMap::from([${map.map(c => c.render).join(', ')}])`, - }; + const entries = node.entries.map(entry => visit(entry, this)); + return addFragmentImports( + mergeFragments(entries, cs => `HashMap::from([${cs.join(', ')}])`), + ['std::collection::HashMap'], + ); }, + visitNoneValue() { - return { - imports: new ImportMap(), - render: 'None', - }; + return fragment`None`; }, + visitNumberValue(node) { - return { - imports: new ImportMap(), - render: node.number.toString(), - }; + return fragment`${node.number}`; }, + visitPublicKeyValue(node) { - return { - imports: new ImportMap().add('solana_program::pubkey'), - render: `pubkey!("${node.publicKey}")`, - }; + return addFragmentImports(fragment`pubkey!("${node.publicKey}")`, ['solana_program::pubkey']); }, + visitSetValue(node) { - const set = node.items.map(v => visit(v, this)); - const imports = new ImportMap().add('std::collection::HashSet'); - return { - imports: imports.mergeWith(...set.map(c => c.imports)), - render: `HashSet::from([${set.map(c => c.render).join(', ')}])`, - }; + const items = node.items.map(v => visit(v, this)); + return addFragmentImports( + mergeFragments(items, cs => `HashSet::from([${cs.join(', ')}])`), + ['std::collection::HashSet'], + ); }, + visitSomeValue(node) { const child = visit(node.value, this); - return { - ...child, - render: `Some(${child.render})`, - }; + return fragment`Some(${child})`; }, + visitStringValue(node) { - return { - imports: new ImportMap(), - render: useStr ? `${JSON.stringify(node.string)}` : `String::from(${JSON.stringify(node.string)})`, - }; + return useStr + ? fragment`${JSON.stringify(node.string)}` + : fragment`String::from(${JSON.stringify(node.string)})`; }, + visitStructFieldValue(node) { const structValue = visit(node.value, this); - return { - imports: structValue.imports, - render: `${node.name}: ${structValue.render}`, - }; + return fragment`${node.name}: ${structValue}`; }, + visitStructValue(node) { - const struct = node.fields.map(field => visit(field, this)); - return { - imports: new ImportMap().mergeWith(...struct.map(c => c.imports)), - render: `{ ${struct.map(c => c.render).join(', ')} }`, - }; + const fields = node.fields.map(field => visit(field, this)); + return mergeFragments(fields, cs => `{ ${cs.join(', ')} }`); }, + visitTupleValue(node) { - const tuple = node.items.map(v => visit(v, this)); - return { - imports: new ImportMap().mergeWith(...tuple.map(c => c.imports)), - render: `(${tuple.map(c => c.render).join(', ')})`, - }; + const items = node.items.map(v => visit(v, this)); + return mergeFragments(items, cs => `(${cs.join(', ')})`); }, }; } From ba1a4b13686cec06b53de752b1771cad60700c5d Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Sep 2025 11:45:49 +0100 Subject: [PATCH 09/24] Implement ix argument parsing --- .../src/fragments/instructionPage.ts | 86 +++++++++---------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/packages/renderers-pinocchio/src/fragments/instructionPage.ts b/packages/renderers-pinocchio/src/fragments/instructionPage.ts index d76bad0ad..a59b7ae1c 100644 --- a/packages/renderers-pinocchio/src/fragments/instructionPage.ts +++ b/packages/renderers-pinocchio/src/fragments/instructionPage.ts @@ -4,12 +4,14 @@ import { InstructionNode, isNode, pascalCase, + snakeCase, + SnakeCaseString, structTypeNodeFromInstructionArgumentNodes, VALUE_NODES, } from '@codama/nodes'; import { getLastNodeFromPath, NodePath, visit } from '@codama/visitors-core'; -import { getTypeManifestVisitor, TypeManifestVisitor } from '../getTypeManifestVisitor'; +import { getTypeManifestVisitor, TypeManifest } from '../getTypeManifestVisitor'; import { renderValueNode } from '../renderValueNodeVisitor'; import { Fragment, fragment, getPageFragment, RenderScope } from '../utils'; @@ -32,17 +34,11 @@ export function getInstructionPageFragment( } // Instruction args. - const instructionArgs: ParsedInstructionArgument[] = []; - // let hasArgs = false; - // let hasOptional = false; - // hasArgs = hasArgs || argument.defaultValueStrategy !== 'omitted'; - // hasOptional = hasOptional || (hasDefaultValue && argument.defaultValueStrategy !== 'omitted'); - - const argumentVisitor = getTypeManifestVisitor({ - ...scope, - nestedStruct: true, - parentName: `${pascalCase(instructionNode.name)}InstructionData`, - }); + const instructionArguments = getParsedInstructionArguments(instructionNode, accountsAndArgsConflicts, scope); + const hasArgs = instructionArguments.some(arg => arg.defaultValueStrategy !== 'omitted'); + const hasOptional = instructionArguments.some( + arg => !arg.resolvedDefaultValue && arg.defaultValueStrategy !== 'omitted', + ); const struct = structTypeNodeFromInstructionArgumentNodes(instructionNode.arguments); const structVisitor = getTypeManifestVisitor({ @@ -60,45 +56,41 @@ export function getInstructionPageFragment( } type ParsedInstructionArgument = InstructionArgumentNode & { - default: boolean; - innerOptionType: string | null; - name: string; - optional: boolean; - size: number; - type: string; - value: string | null; + displayName: SnakeCaseString; + fixedSize: number | null; + manifest: TypeManifest; + resolvedDefaultValue: Fragment | null; + resolvedInnerOptionType: Fragment | null; }; -function getParsedInstructionArgument( - argument: InstructionArgumentNode, - argumentVisitor: TypeManifestVisitor, +function getParsedInstructionArguments( + instructionNode: InstructionNode, accountsAndArgsConflicts: string[], - scope: Pick, -): ParsedInstructionArgument { - const manifest = visit(argument.type, argumentVisitor); - const innerOptionType = isNode(argument.type, 'optionTypeNode') - ? manifest.type.content.slice('Option<'.length, -1) - : null; - - const hasDefaultValue = !!argument.defaultValue && isNode(argument.defaultValue, VALUE_NODES); - let renderValue: string | null = null; - if (hasDefaultValue) { - const { imports: argImports, render: value } = renderValueNode(argument.defaultValue, scope.getImportFrom); - imports.mergeWith(argImports); - renderValue = value; - } - - const name = accountsAndArgsConflicts.includes(argument.name) ? `${argument.name}_arg` : argument.name; + scope: Pick, +): ParsedInstructionArgument[] { + const argumentVisitor = getTypeManifestVisitor({ + ...scope, + nestedStruct: true, + parentName: `${pascalCase(instructionNode.name)}InstructionData`, + }); - return { - default: hasDefaultValue && argument.defaultValueStrategy === 'omitted', - innerOptionType, - name, - optional: hasDefaultValue && argument.defaultValueStrategy !== 'omitted', - size: visit(argument.type, scope.byteSizeVisitor) as number, // We fail later if the whole data is variable. - type: manifest.type, - value: renderValue, - }; + return instructionNode.arguments.map(argument => { + return { + ...argument, + displayName: accountsAndArgsConflicts.includes(argument.name) + ? (`${snakeCase(argument.name)}_arg` as SnakeCaseString) + : snakeCase(argument.name), + fixedSize: visit(argument.type, scope.byteSizeVisitor), + manifest: visit(argument.type, argumentVisitor), + resolvedDefaultValue: + !!argument.defaultValue && isNode(argument.defaultValue, VALUE_NODES) + ? renderValueNode(argument.defaultValue, scope.getImportFrom) + : null, + resolvedInnerOptionType: isNode(argument.type, 'optionTypeNode') + ? visit(argument.type.item, argumentVisitor).type + : null, + }; + }); } function getConflictsBetweenAccountsAndArguments(instructionNode: InstructionNode): string[] { From e4b2c42c4564eab0447fa1512802248cc023e840 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Sep 2025 12:11:03 +0100 Subject: [PATCH 10/24] Implement instruction page fragment --- .../public/templates/instructionPage.njk | 49 -------- .../src/fragments/instructionPage.ts | 109 +++++++++++++++--- 2 files changed, 95 insertions(+), 63 deletions(-) delete mode 100644 packages/renderers-pinocchio/public/templates/instructionPage.njk diff --git a/packages/renderers-pinocchio/public/templates/instructionPage.njk b/packages/renderers-pinocchio/public/templates/instructionPage.njk deleted file mode 100644 index c3b2ed1c8..000000000 --- a/packages/renderers-pinocchio/public/templates/instructionPage.njk +++ /dev/null @@ -1,49 +0,0 @@ -/// `{{ instruction.name | snakeCase }}` CPI helper. -pub struct {{ instruction.name | pascalCase }}{{ '<\'a>' if instruction.accounts.length > 0 }} { - {# Accounts #} - {% for account in instruction.accounts %} - {% if account.docs.length > 0 %} - {{ macros.docblock(account.docs) }} - {% endif %} - - {% if account.isSigner === 'either' %} - {% set type = '(&\'a pinocchio::account_info::AccountInfo, bool)' %} - {% else %} - {% set type = '&\'a pinocchio::account_info::AccountInfo' %} - {% endif %} - - {% if account.isOptional %} - pub {{ account.name | snakeCase }}: Option<{{ type }}>, - {% else %} - pub {{ account.name | snakeCase }}: {{ type }}, - {% endif %} - {% endfor %} - {% for arg in instructionArgs %} - {% if not arg.default %} - pub {{ arg.name | snakeCase }}: {{ arg.type }}, - {% endif %} - {% endfor %} -} - -impl{{ '<\'a>' if instruction.accounts.length > 0 }} {{ instruction.name | pascalCase }}{{ '<\'a>' if instruction.accounts.length > 0 }} { - #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { - self.invoke_signed(&[]) - } - - pub fn invoke_signed(&self, _signers: &[pinocchio::instruction::Signer]) -> pinocchio::ProgramResult { - - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; {{ instruction.accounts.length }}] = [ - {% for account in instruction.accounts %} - {% if account.isSigner === 'either' %} - pinocchio::instruction::AccountMeta::new(self.{{ account.name | snakeCase }}.0.key(), {{ account.isWritable }}, self.{{ account.name | snakeCase }}.1), - {% else %} - pinocchio::instruction::AccountMeta::new(self.{{ account.name | snakeCase }}.key(), {{ account.isWritable }}, {{ account.isSigner }}), - {% endif %} - {% endfor %} - ]; - - Ok(()) - } -} diff --git a/packages/renderers-pinocchio/src/fragments/instructionPage.ts b/packages/renderers-pinocchio/src/fragments/instructionPage.ts index a59b7ae1c..b96e6e6dd 100644 --- a/packages/renderers-pinocchio/src/fragments/instructionPage.ts +++ b/packages/renderers-pinocchio/src/fragments/instructionPage.ts @@ -6,14 +6,21 @@ import { pascalCase, snakeCase, SnakeCaseString, - structTypeNodeFromInstructionArgumentNodes, VALUE_NODES, } from '@codama/nodes'; import { getLastNodeFromPath, NodePath, visit } from '@codama/visitors-core'; import { getTypeManifestVisitor, TypeManifest } from '../getTypeManifestVisitor'; import { renderValueNode } from '../renderValueNodeVisitor'; -import { Fragment, fragment, getPageFragment, RenderScope } from '../utils'; +import { + addFragmentImports, + Fragment, + fragment, + getDocblockFragment, + getPageFragment, + mergeFragments, + RenderScope, +} from '../utils'; export function getInstructionPageFragment( scope: Pick & { @@ -33,26 +40,100 @@ export function getInstructionPageFragment( ); } - // Instruction args. + // Instruction arguments. const instructionArguments = getParsedInstructionArguments(instructionNode, accountsAndArgsConflicts, scope); const hasArgs = instructionArguments.some(arg => arg.defaultValueStrategy !== 'omitted'); const hasOptional = instructionArguments.some( arg => !arg.resolvedDefaultValue && arg.defaultValueStrategy !== 'omitted', ); - const struct = structTypeNodeFromInstructionArgumentNodes(instructionNode.arguments); - const structVisitor = getTypeManifestVisitor({ - ...scope, - parentName: `${pascalCase(instructionNode.name)}InstructionData`, - }); - const typeManifest = visit(struct, structVisitor); - const instructionSize = visit(struct, scope.byteSizeVisitor); + // Helpers. + const instructionFixedSize = visit(instructionNode, scope.byteSizeVisitor); + const lifetime = instructionNode.accounts.length > 0 ? "<'a>" : ''; - // imports: imports - // .remove(`generatedInstructions::${pascalCase(node.name)}`) - // .toString(dependencyMap), + return getPageFragment( + mergeFragments( + [ + getInstructionStructFragment(instructionNode, instructionArguments, lifetime), + getInstructionImplFragment(instructionNode, instructionArguments, lifetime), + ], + cs => cs.join('\n\n'), + ), + scope, + ); +} + +function getInstructionStructFragment( + instructionNode: InstructionNode, + instructionArguments: ParsedInstructionArgument[], + lifetime: string, +) { + const accountsFragment = mergeFragments( + instructionNode.accounts.map(account => { + const docs = getDocblockFragment(account.docs ?? [], true); + const name = snakeCase(account.name); + const type = addFragmentImports( + account.isSigner === 'either' ? fragment`(&'a AccountInfo, bool)` : fragment`&'a AccountInfo`, + ['pinocchio::account_info::AccountInfo'], + ); + return account.isOptional + ? fragment`${docs}pub ${name}: Option<${type}>,` + : fragment`${docs}pub ${name}: ${type},`; + }), + cs => cs.join('\n'), + ); + + const argumentsFragment = mergeFragments( + instructionArguments + .filter(arg => !arg.resolvedDefaultValue) + .map(arg => { + const docs = getDocblockFragment(arg.docs ?? [], true); + return fragment`${docs}pub ${arg.displayName}: ${arg.manifest.type},`; + }), + cs => cs.join('\n'), + ); - return getPageFragment(fragment``, scope); + return fragment`/// \`${snakeCase(instructionNode.name)}\` CPI helper. +pub struct ${pascalCase(instructionNode.name)}${lifetime} { + ${accountsFragment} + ${argumentsFragment} +}`; +} + +function getInstructionImplFragment( + instructionNode: InstructionNode, + _instructionArguments: ParsedInstructionArgument[], + lifetime: string, +) { + const accountsFragment = mergeFragments( + instructionNode.accounts.map(account => { + const name = snakeCase(account.name); + const isWritable = account.isWritable ? 'true' : 'false'; + const accountMetaArguments = + account.isSigner === 'either' + ? fragment`self.${name}.0.key(), ${isWritable}, self.${name}.1` + : fragment`self.${name}.key(), ${isWritable}, ${account.isSigner}`; + return fragment`pinocchio::instruction::AccountMeta::new(${accountMetaArguments}),`; + }), + cs => cs.join('\n'), + ); + + return fragment`impl${lifetime} ${pascalCase(instructionNode.name)}${lifetime} { + #[inline(always)] + pub fn invoke(&self) -> pinocchio::ProgramResult { + self.invoke_signed(&[]) + } + + pub fn invoke_signed(&self, _signers: &[pinocchio::instruction::Signer]) -> pinocchio::ProgramResult { + + // account metadata + let account_metas: [pinocchio::instruction::AccountMeta; {{ instruction.accounts.length }}] = [ + ${accountsFragment} + ]; + + Ok(()) + } +}`; } type ParsedInstructionArgument = InstructionArgumentNode & { From e309c6142c35d7dc11a490bcd5ddf3c10b23e849 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Sep 2025 12:14:58 +0100 Subject: [PATCH 11/24] Reorganise folder structure --- .../src/fragments/instructionPage.ts | 4 ++-- packages/renderers-pinocchio/src/index.ts | 7 +++---- packages/renderers-pinocchio/src/utils/fragment.ts | 2 +- .../src/{ImportMap.ts => utils/importMap.ts} | 6 ------ packages/renderers-pinocchio/src/utils/index.ts | 1 + packages/renderers-pinocchio/src/utils/options.ts | 2 +- .../renderers-pinocchio/src/utils/traitOptions.ts | 2 +- .../src/{ => visitors}/getRenderMapVisitor.ts | 11 +++++++---- .../src/{ => visitors}/getTypeManifestVisitor.ts | 2 +- packages/renderers-pinocchio/src/visitors/index.ts | 4 ++++ .../src/{ => visitors}/renderValueNodeVisitor.ts | 2 +- .../src/{ => visitors}/renderVisitor.ts | 2 +- 12 files changed, 23 insertions(+), 22 deletions(-) rename packages/renderers-pinocchio/src/{ImportMap.ts => utils/importMap.ts} (94%) rename packages/renderers-pinocchio/src/{ => visitors}/getRenderMapVisitor.ts (93%) rename packages/renderers-pinocchio/src/{ => visitors}/getTypeManifestVisitor.ts (99%) create mode 100644 packages/renderers-pinocchio/src/visitors/index.ts rename packages/renderers-pinocchio/src/{ => visitors}/renderValueNodeVisitor.ts (99%) rename packages/renderers-pinocchio/src/{ => visitors}/renderVisitor.ts (97%) diff --git a/packages/renderers-pinocchio/src/fragments/instructionPage.ts b/packages/renderers-pinocchio/src/fragments/instructionPage.ts index b96e6e6dd..02bba7c14 100644 --- a/packages/renderers-pinocchio/src/fragments/instructionPage.ts +++ b/packages/renderers-pinocchio/src/fragments/instructionPage.ts @@ -10,8 +10,8 @@ import { } from '@codama/nodes'; import { getLastNodeFromPath, NodePath, visit } from '@codama/visitors-core'; -import { getTypeManifestVisitor, TypeManifest } from '../getTypeManifestVisitor'; -import { renderValueNode } from '../renderValueNodeVisitor'; +import { getTypeManifestVisitor, TypeManifest } from '../visitors/getTypeManifestVisitor'; +import { renderValueNode } from '../visitors/renderValueNodeVisitor'; import { addFragmentImports, Fragment, diff --git a/packages/renderers-pinocchio/src/index.ts b/packages/renderers-pinocchio/src/index.ts index f5fa040b7..97b95cc06 100644 --- a/packages/renderers-pinocchio/src/index.ts +++ b/packages/renderers-pinocchio/src/index.ts @@ -1,4 +1,3 @@ -export * from './ImportMap'; -export * from './getRenderMapVisitor'; -export * from './getTypeManifestVisitor'; -export * from './renderVisitor'; +export * from './visitors'; + +export { renderVisitor as default } from './visitors/renderVisitor'; diff --git a/packages/renderers-pinocchio/src/utils/fragment.ts b/packages/renderers-pinocchio/src/utils/fragment.ts index df77dc488..6034e5889 100644 --- a/packages/renderers-pinocchio/src/utils/fragment.ts +++ b/packages/renderers-pinocchio/src/utils/fragment.ts @@ -1,7 +1,7 @@ import { Docs } from '@codama/nodes'; import { BaseFragment } from '@codama/renderers-core'; -import { ImportMap } from '../ImportMap'; +import { ImportMap } from './importMap'; import { RenderScope } from './options'; export type Fragment = BaseFragment & Readonly<{ imports: ImportMap }>; diff --git a/packages/renderers-pinocchio/src/ImportMap.ts b/packages/renderers-pinocchio/src/utils/importMap.ts similarity index 94% rename from packages/renderers-pinocchio/src/ImportMap.ts rename to packages/renderers-pinocchio/src/utils/importMap.ts index 4600e0df1..51b2fb84d 100644 --- a/packages/renderers-pinocchio/src/ImportMap.ts +++ b/packages/renderers-pinocchio/src/utils/importMap.ts @@ -1,5 +1,3 @@ -import { TypeManifest } from './getTypeManifestVisitor'; - const DEFAULT_MODULE_MAP: Record = { generated: 'crate::generated', generatedAccounts: 'crate::generated::accounts', @@ -44,10 +42,6 @@ export class ImportMap { return this; } - mergeWithManifest(manifest: TypeManifest): ImportMap { - return this.mergeWith(manifest.imports); - } - addAlias(importName: string, alias: string): ImportMap { this._aliases.set(importName, alias); return this; diff --git a/packages/renderers-pinocchio/src/utils/index.ts b/packages/renderers-pinocchio/src/utils/index.ts index 687aa59ee..b6381ccc0 100644 --- a/packages/renderers-pinocchio/src/utils/index.ts +++ b/packages/renderers-pinocchio/src/utils/index.ts @@ -2,5 +2,6 @@ export * from './codecs'; export * from './fragment'; export * from './linkOverrides'; export * from './options'; +export * from './importMap'; export * from './render'; export * from './traitOptions'; diff --git a/packages/renderers-pinocchio/src/utils/options.ts b/packages/renderers-pinocchio/src/utils/options.ts index 2c69adc62..6cc7582d6 100644 --- a/packages/renderers-pinocchio/src/utils/options.ts +++ b/packages/renderers-pinocchio/src/utils/options.ts @@ -1,6 +1,6 @@ import { getByteSizeVisitor, LinkableDictionary } from '@codama/visitors-core'; -import { TypeManifestVisitor } from '../getTypeManifestVisitor'; +import { TypeManifestVisitor } from '../visitors/getTypeManifestVisitor'; import { GetImportFromFunction, LinkOverrides } from './linkOverrides'; import { GetTraitsFromNodeFunction, TraitOptions } from './traitOptions'; diff --git a/packages/renderers-pinocchio/src/utils/traitOptions.ts b/packages/renderers-pinocchio/src/utils/traitOptions.ts index 0bfcb14a6..2714aa47c 100644 --- a/packages/renderers-pinocchio/src/utils/traitOptions.ts +++ b/packages/renderers-pinocchio/src/utils/traitOptions.ts @@ -1,7 +1,7 @@ import { AccountNode, assertIsNode, camelCase, DefinedTypeNode, isNode, isScalarEnum } from '@codama/nodes'; -import { ImportMap } from '../ImportMap'; import { Fragment, fragment, mergeFragmentImports } from './fragment'; +import { ImportMap } from './importMap'; export type TraitOptions = { /** The default traits to implement for all types. */ diff --git a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts b/packages/renderers-pinocchio/src/visitors/getRenderMapVisitor.ts similarity index 93% rename from packages/renderers-pinocchio/src/getRenderMapVisitor.ts rename to packages/renderers-pinocchio/src/visitors/getRenderMapVisitor.ts index 6c242349d..386594e73 100644 --- a/packages/renderers-pinocchio/src/getRenderMapVisitor.ts +++ b/packages/renderers-pinocchio/src/visitors/getRenderMapVisitor.ts @@ -12,11 +12,14 @@ import { visit, } from '@codama/visitors-core'; -import { getInstructionPageFragment, getRootModPageFragment } from './fragments'; -import { getModPageFragment } from './fragments/modPage'; -import { getProgramModPageFragment } from './fragments/programModPage'; +import { + getInstructionPageFragment, + getModPageFragment, + getProgramModPageFragment, + getRootModPageFragment, +} from '../fragments'; +import { getImportFromFactory, GetRenderMapOptions, getTraitsFromNodeFactory, RenderScope } from '../utils'; import { getTypeManifestVisitor } from './getTypeManifestVisitor'; -import { getImportFromFactory, GetRenderMapOptions, getTraitsFromNodeFactory, RenderScope } from './utils'; export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const linkables = new LinkableDictionary(); diff --git a/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts b/packages/renderers-pinocchio/src/visitors/getTypeManifestVisitor.ts similarity index 99% rename from packages/renderers-pinocchio/src/getTypeManifestVisitor.ts rename to packages/renderers-pinocchio/src/visitors/getTypeManifestVisitor.ts index de64a92bc..fef0a7f36 100644 --- a/packages/renderers-pinocchio/src/getTypeManifestVisitor.ts +++ b/packages/renderers-pinocchio/src/visitors/getTypeManifestVisitor.ts @@ -25,7 +25,7 @@ import { GetTraitsFromNodeFunction, mergeFragments, rustDocblock, -} from './utils'; +} from '../utils'; export type TypeManifest = { nestedStructs: Fragment[]; diff --git a/packages/renderers-pinocchio/src/visitors/index.ts b/packages/renderers-pinocchio/src/visitors/index.ts new file mode 100644 index 000000000..4f77dda46 --- /dev/null +++ b/packages/renderers-pinocchio/src/visitors/index.ts @@ -0,0 +1,4 @@ +export * from './getRenderMapVisitor'; +export * from './getTypeManifestVisitor'; +export * from './renderValueNodeVisitor'; +export * from './renderVisitor'; diff --git a/packages/renderers-pinocchio/src/renderValueNodeVisitor.ts b/packages/renderers-pinocchio/src/visitors/renderValueNodeVisitor.ts similarity index 99% rename from packages/renderers-pinocchio/src/renderValueNodeVisitor.ts rename to packages/renderers-pinocchio/src/visitors/renderValueNodeVisitor.ts index d21720d43..f94527eda 100644 --- a/packages/renderers-pinocchio/src/renderValueNodeVisitor.ts +++ b/packages/renderers-pinocchio/src/visitors/renderValueNodeVisitor.ts @@ -16,7 +16,7 @@ import { getBytesFromBytesValueNode, GetImportFromFunction, mergeFragments, -} from './utils'; +} from '../utils'; export function renderValueNode( value: ValueNode, diff --git a/packages/renderers-pinocchio/src/renderVisitor.ts b/packages/renderers-pinocchio/src/visitors/renderVisitor.ts similarity index 97% rename from packages/renderers-pinocchio/src/renderVisitor.ts rename to packages/renderers-pinocchio/src/visitors/renderVisitor.ts index a47301a84..bc9fa1d0b 100644 --- a/packages/renderers-pinocchio/src/renderVisitor.ts +++ b/packages/renderers-pinocchio/src/visitors/renderVisitor.ts @@ -3,8 +3,8 @@ import { deleteDirectory, writeRenderMapVisitor } from '@codama/renderers-core'; import { rootNodeVisitor, visit } from '@codama/visitors-core'; import { spawnSync } from 'child_process'; +import { RenderOptions } from '../utils'; import { getRenderMapVisitor } from './getRenderMapVisitor'; -import { RenderOptions } from './utils'; export function renderVisitor(path: string, options: RenderOptions = {}) { return rootNodeVisitor(root => { From 0c9ad16f2e5a1fb853351b64061f36647096f07b Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sat, 6 Sep 2025 12:26:32 +0100 Subject: [PATCH 12/24] Display nested structs --- .../src/fragments/instructionPage.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/renderers-pinocchio/src/fragments/instructionPage.ts b/packages/renderers-pinocchio/src/fragments/instructionPage.ts index 02bba7c14..28c451027 100644 --- a/packages/renderers-pinocchio/src/fragments/instructionPage.ts +++ b/packages/renderers-pinocchio/src/fragments/instructionPage.ts @@ -10,8 +10,6 @@ import { } from '@codama/nodes'; import { getLastNodeFromPath, NodePath, visit } from '@codama/visitors-core'; -import { getTypeManifestVisitor, TypeManifest } from '../visitors/getTypeManifestVisitor'; -import { renderValueNode } from '../visitors/renderValueNodeVisitor'; import { addFragmentImports, Fragment, @@ -21,6 +19,8 @@ import { mergeFragments, RenderScope, } from '../utils'; +import { getTypeManifestVisitor, TypeManifest } from '../visitors/getTypeManifestVisitor'; +import { renderValueNode } from '../visitors/renderValueNodeVisitor'; export function getInstructionPageFragment( scope: Pick & { @@ -56,6 +56,7 @@ export function getInstructionPageFragment( [ getInstructionStructFragment(instructionNode, instructionArguments, lifetime), getInstructionImplFragment(instructionNode, instructionArguments, lifetime), + getInstructionNestedStructsFragment(instructionArguments), ], cs => cs.join('\n\n'), ), @@ -136,6 +137,13 @@ function getInstructionImplFragment( }`; } +function getInstructionNestedStructsFragment(instructionArguments: ParsedInstructionArgument[]): Fragment { + return mergeFragments( + instructionArguments.flatMap(arg => arg.manifest.nestedStructs), + cs => cs.join('\n\n'), + ); +} + type ParsedInstructionArgument = InstructionArgumentNode & { displayName: SnakeCaseString; fixedSize: number | null; From ba99180beee78052e372e5f896099b682393a206 Mon Sep 17 00:00:00 2001 From: febo Date: Sat, 6 Sep 2025 14:52:11 +0100 Subject: [PATCH 13/24] Renamed --- .../{renderers-pinocchio => renderers-rust-cpi}/.gitignore | 0 .../.prettierignore | 0 packages/{renderers-pinocchio => renderers-rust-cpi}/LICENSE | 0 .../{renderers-pinocchio => renderers-rust-cpi}/README.md | 0 .../e2e/dummy/Cargo.lock | 0 .../e2e/dummy/Cargo.toml | 0 .../e2e/dummy/idl.json | 0 .../e2e/dummy/src/generated/instructions/instruction1.rs | 0 .../e2e/dummy/src/generated/instructions/instruction2.rs | 0 .../e2e/dummy/src/generated/instructions/instruction3.rs | 0 .../e2e/dummy/src/generated/instructions/instruction4.rs | 0 .../e2e/dummy/src/generated/instructions/instruction5.rs | 0 .../e2e/dummy/src/generated/instructions/instruction6.rs | 0 .../e2e/dummy/src/generated/instructions/instruction7.rs | 0 .../e2e/dummy/src/generated/instructions/mod.rs | 0 .../e2e/dummy/src/generated/mod.rs | 0 .../e2e/dummy/src/generated/programs.rs | 0 .../e2e/dummy/src/lib.rs | 0 .../e2e/generate.cjs | 0 .../e2e/memo/Cargo.lock | 0 .../e2e/memo/Cargo.toml | 0 .../e2e/memo/idl.json | 0 .../e2e/memo/src/generated/instructions/add_memo.rs | 0 .../e2e/memo/src/generated/instructions/mod.rs | 0 .../e2e/memo/src/generated/mod.rs | 0 .../e2e/memo/src/generated/programs.rs | 0 .../e2e/memo/src/lib.rs | 0 .../e2e/system/Cargo.lock | 0 .../e2e/system/Cargo.toml | 0 .../e2e/system/idl.json | 0 .../src/generated/instructions/advance_nonce_account.rs | 0 .../e2e/system/src/generated/instructions/allocate.rs | 0 .../system/src/generated/instructions/allocate_with_seed.rs | 0 .../e2e/system/src/generated/instructions/assign.rs | 0 .../e2e/system/src/generated/instructions/assign_with_seed.rs | 0 .../src/generated/instructions/authorize_nonce_account.rs | 0 .../e2e/system/src/generated/instructions/create_account.rs | 0 .../src/generated/instructions/create_account_with_seed.rs | 0 .../src/generated/instructions/initialize_nonce_account.rs | 0 .../e2e/system/src/generated/instructions/mod.rs | 0 .../e2e/system/src/generated/instructions/transfer_sol.rs | 0 .../src/generated/instructions/transfer_sol_with_seed.rs | 0 .../src/generated/instructions/upgrade_nonce_account.rs | 0 .../src/generated/instructions/withdraw_nonce_account.rs | 0 .../e2e/system/src/generated/mod.rs | 0 .../e2e/system/src/generated/programs.rs | 0 .../e2e/system/src/generated/types/mod.rs | 0 .../e2e/system/src/generated/types/nonce_state.rs | 0 .../e2e/system/src/generated/types/nonce_version.rs | 0 .../e2e/system/src/lib.rs | 0 .../{renderers-pinocchio => renderers-rust-cpi}/e2e/test.sh | 0 .../{renderers-pinocchio => renderers-rust-cpi}/package.json | 4 ++-- .../src/fragments/index.ts | 0 .../src/fragments/instructionPage.ts | 0 .../src/fragments/modPage.ts | 0 .../src/fragments/programModPage.ts | 0 .../src/fragments/rootModPage.ts | 0 .../{renderers-pinocchio => renderers-rust-cpi}/src/index.ts | 0 .../src/types/global.d.ts | 0 .../src/utils/codecs.ts | 0 .../src/utils/fragment.ts | 0 .../src/utils/importMap.ts | 0 .../src/utils/index.ts | 0 .../src/utils/linkOverrides.ts | 0 .../src/utils/options.ts | 0 .../src/utils/render.ts | 0 .../src/utils/traitOptions.ts | 0 .../src/visitors/getRenderMapVisitor.ts | 0 .../src/visitors/getTypeManifestVisitor.ts | 0 .../src/visitors/index.ts | 0 .../src/visitors/renderValueNodeVisitor.ts | 0 .../src/visitors/renderVisitor.ts | 0 .../test/_setup.ts | 0 .../test/definedTypesPage.test.ts | 0 .../test/exports/commonjs.cjs | 0 .../test/exports/module.mjs | 0 .../test/instructionsPage.test.ts | 0 .../test/types/number.test.ts | 0 .../test/utils/traitOptions.test.ts | 0 .../tsconfig.declarations.json | 0 .../{renderers-pinocchio => renderers-rust-cpi}/tsconfig.json | 0 81 files changed, 2 insertions(+), 2 deletions(-) rename packages/{renderers-pinocchio => renderers-rust-cpi}/.gitignore (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/.prettierignore (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/LICENSE (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/README.md (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/Cargo.lock (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/Cargo.toml (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/idl.json (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/instructions/instruction1.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/instructions/instruction2.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/instructions/instruction3.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/instructions/instruction4.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/instructions/instruction5.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/instructions/instruction6.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/instructions/instruction7.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/instructions/mod.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/mod.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/generated/programs.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/dummy/src/lib.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/generate.cjs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/memo/Cargo.lock (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/memo/Cargo.toml (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/memo/idl.json (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/memo/src/generated/instructions/add_memo.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/memo/src/generated/instructions/mod.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/memo/src/generated/mod.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/memo/src/generated/programs.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/memo/src/lib.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/Cargo.lock (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/Cargo.toml (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/idl.json (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/advance_nonce_account.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/allocate.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/allocate_with_seed.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/assign.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/assign_with_seed.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/authorize_nonce_account.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/create_account.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/create_account_with_seed.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/initialize_nonce_account.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/mod.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/transfer_sol.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/upgrade_nonce_account.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/instructions/withdraw_nonce_account.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/mod.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/programs.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/types/mod.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/types/nonce_state.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/generated/types/nonce_version.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/system/src/lib.rs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/e2e/test.sh (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/package.json (95%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/fragments/index.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/fragments/instructionPage.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/fragments/modPage.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/fragments/programModPage.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/fragments/rootModPage.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/index.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/types/global.d.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/utils/codecs.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/utils/fragment.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/utils/importMap.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/utils/index.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/utils/linkOverrides.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/utils/options.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/utils/render.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/utils/traitOptions.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/visitors/getRenderMapVisitor.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/visitors/getTypeManifestVisitor.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/visitors/index.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/visitors/renderValueNodeVisitor.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/src/visitors/renderVisitor.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/test/_setup.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/test/definedTypesPage.test.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/test/exports/commonjs.cjs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/test/exports/module.mjs (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/test/instructionsPage.test.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/test/types/number.test.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/test/utils/traitOptions.test.ts (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/tsconfig.declarations.json (100%) rename packages/{renderers-pinocchio => renderers-rust-cpi}/tsconfig.json (100%) diff --git a/packages/renderers-pinocchio/.gitignore b/packages/renderers-rust-cpi/.gitignore similarity index 100% rename from packages/renderers-pinocchio/.gitignore rename to packages/renderers-rust-cpi/.gitignore diff --git a/packages/renderers-pinocchio/.prettierignore b/packages/renderers-rust-cpi/.prettierignore similarity index 100% rename from packages/renderers-pinocchio/.prettierignore rename to packages/renderers-rust-cpi/.prettierignore diff --git a/packages/renderers-pinocchio/LICENSE b/packages/renderers-rust-cpi/LICENSE similarity index 100% rename from packages/renderers-pinocchio/LICENSE rename to packages/renderers-rust-cpi/LICENSE diff --git a/packages/renderers-pinocchio/README.md b/packages/renderers-rust-cpi/README.md similarity index 100% rename from packages/renderers-pinocchio/README.md rename to packages/renderers-rust-cpi/README.md diff --git a/packages/renderers-pinocchio/e2e/dummy/Cargo.lock b/packages/renderers-rust-cpi/e2e/dummy/Cargo.lock similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/Cargo.lock rename to packages/renderers-rust-cpi/e2e/dummy/Cargo.lock diff --git a/packages/renderers-pinocchio/e2e/dummy/Cargo.toml b/packages/renderers-rust-cpi/e2e/dummy/Cargo.toml similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/Cargo.toml rename to packages/renderers-rust-cpi/e2e/dummy/Cargo.toml diff --git a/packages/renderers-pinocchio/e2e/dummy/idl.json b/packages/renderers-rust-cpi/e2e/dummy/idl.json similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/idl.json rename to packages/renderers-rust-cpi/e2e/dummy/idl.json diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction1.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction2.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction3.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction4.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction5.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction6.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/instruction7.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/mod.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/mod.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/instructions/mod.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/mod.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/mod.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/mod.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/mod.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/mod.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/generated/programs.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/programs.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/generated/programs.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/programs.rs diff --git a/packages/renderers-pinocchio/e2e/dummy/src/lib.rs b/packages/renderers-rust-cpi/e2e/dummy/src/lib.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/dummy/src/lib.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/lib.rs diff --git a/packages/renderers-pinocchio/e2e/generate.cjs b/packages/renderers-rust-cpi/e2e/generate.cjs similarity index 100% rename from packages/renderers-pinocchio/e2e/generate.cjs rename to packages/renderers-rust-cpi/e2e/generate.cjs diff --git a/packages/renderers-pinocchio/e2e/memo/Cargo.lock b/packages/renderers-rust-cpi/e2e/memo/Cargo.lock similarity index 100% rename from packages/renderers-pinocchio/e2e/memo/Cargo.lock rename to packages/renderers-rust-cpi/e2e/memo/Cargo.lock diff --git a/packages/renderers-pinocchio/e2e/memo/Cargo.toml b/packages/renderers-rust-cpi/e2e/memo/Cargo.toml similarity index 100% rename from packages/renderers-pinocchio/e2e/memo/Cargo.toml rename to packages/renderers-rust-cpi/e2e/memo/Cargo.toml diff --git a/packages/renderers-pinocchio/e2e/memo/idl.json b/packages/renderers-rust-cpi/e2e/memo/idl.json similarity index 100% rename from packages/renderers-pinocchio/e2e/memo/idl.json rename to packages/renderers-rust-cpi/e2e/memo/idl.json diff --git a/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs b/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/memo/src/generated/instructions/add_memo.rs rename to packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs diff --git a/packages/renderers-pinocchio/e2e/memo/src/generated/instructions/mod.rs b/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/mod.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/memo/src/generated/instructions/mod.rs rename to packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/mod.rs diff --git a/packages/renderers-pinocchio/e2e/memo/src/generated/mod.rs b/packages/renderers-rust-cpi/e2e/memo/src/generated/mod.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/memo/src/generated/mod.rs rename to packages/renderers-rust-cpi/e2e/memo/src/generated/mod.rs diff --git a/packages/renderers-pinocchio/e2e/memo/src/generated/programs.rs b/packages/renderers-rust-cpi/e2e/memo/src/generated/programs.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/memo/src/generated/programs.rs rename to packages/renderers-rust-cpi/e2e/memo/src/generated/programs.rs diff --git a/packages/renderers-pinocchio/e2e/memo/src/lib.rs b/packages/renderers-rust-cpi/e2e/memo/src/lib.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/memo/src/lib.rs rename to packages/renderers-rust-cpi/e2e/memo/src/lib.rs diff --git a/packages/renderers-pinocchio/e2e/system/Cargo.lock b/packages/renderers-rust-cpi/e2e/system/Cargo.lock similarity index 100% rename from packages/renderers-pinocchio/e2e/system/Cargo.lock rename to packages/renderers-rust-cpi/e2e/system/Cargo.lock diff --git a/packages/renderers-pinocchio/e2e/system/Cargo.toml b/packages/renderers-rust-cpi/e2e/system/Cargo.toml similarity index 100% rename from packages/renderers-pinocchio/e2e/system/Cargo.toml rename to packages/renderers-rust-cpi/e2e/system/Cargo.toml diff --git a/packages/renderers-pinocchio/e2e/system/idl.json b/packages/renderers-rust-cpi/e2e/system/idl.json similarity index 100% rename from packages/renderers-pinocchio/e2e/system/idl.json rename to packages/renderers-rust-cpi/e2e/system/idl.json diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/advance_nonce_account.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/allocate_with_seed.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/assign_with_seed.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/authorize_nonce_account.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/create_account_with_seed.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/initialize_nonce_account.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/mod.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/mod.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/mod.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/mod.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/upgrade_nonce_account.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/instructions/withdraw_nonce_account.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/mod.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/mod.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/mod.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/mod.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/programs.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/programs.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/programs.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/programs.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/types/mod.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/types/mod.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/types/mod.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/types/mod.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_state.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_state.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_state.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_state.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_version.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_version.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/generated/types/nonce_version.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_version.rs diff --git a/packages/renderers-pinocchio/e2e/system/src/lib.rs b/packages/renderers-rust-cpi/e2e/system/src/lib.rs similarity index 100% rename from packages/renderers-pinocchio/e2e/system/src/lib.rs rename to packages/renderers-rust-cpi/e2e/system/src/lib.rs diff --git a/packages/renderers-pinocchio/e2e/test.sh b/packages/renderers-rust-cpi/e2e/test.sh similarity index 100% rename from packages/renderers-pinocchio/e2e/test.sh rename to packages/renderers-rust-cpi/e2e/test.sh diff --git a/packages/renderers-pinocchio/package.json b/packages/renderers-rust-cpi/package.json similarity index 95% rename from packages/renderers-pinocchio/package.json rename to packages/renderers-rust-cpi/package.json index cdde830d9..5cbd4ecde 100644 --- a/packages/renderers-pinocchio/package.json +++ b/packages/renderers-rust-cpi/package.json @@ -1,7 +1,7 @@ { - "name": "@codama/renderers-pinocchio", + "name": "@codama/renderers-rust-cpi", "version": "0.1.0", - "description": "Renders Pinocchio-based Rust clients for your programs", + "description": "Renders CPI clients for your programs", "exports": { "types": "./dist/types/index.d.ts", "node": { diff --git a/packages/renderers-pinocchio/src/fragments/index.ts b/packages/renderers-rust-cpi/src/fragments/index.ts similarity index 100% rename from packages/renderers-pinocchio/src/fragments/index.ts rename to packages/renderers-rust-cpi/src/fragments/index.ts diff --git a/packages/renderers-pinocchio/src/fragments/instructionPage.ts b/packages/renderers-rust-cpi/src/fragments/instructionPage.ts similarity index 100% rename from packages/renderers-pinocchio/src/fragments/instructionPage.ts rename to packages/renderers-rust-cpi/src/fragments/instructionPage.ts diff --git a/packages/renderers-pinocchio/src/fragments/modPage.ts b/packages/renderers-rust-cpi/src/fragments/modPage.ts similarity index 100% rename from packages/renderers-pinocchio/src/fragments/modPage.ts rename to packages/renderers-rust-cpi/src/fragments/modPage.ts diff --git a/packages/renderers-pinocchio/src/fragments/programModPage.ts b/packages/renderers-rust-cpi/src/fragments/programModPage.ts similarity index 100% rename from packages/renderers-pinocchio/src/fragments/programModPage.ts rename to packages/renderers-rust-cpi/src/fragments/programModPage.ts diff --git a/packages/renderers-pinocchio/src/fragments/rootModPage.ts b/packages/renderers-rust-cpi/src/fragments/rootModPage.ts similarity index 100% rename from packages/renderers-pinocchio/src/fragments/rootModPage.ts rename to packages/renderers-rust-cpi/src/fragments/rootModPage.ts diff --git a/packages/renderers-pinocchio/src/index.ts b/packages/renderers-rust-cpi/src/index.ts similarity index 100% rename from packages/renderers-pinocchio/src/index.ts rename to packages/renderers-rust-cpi/src/index.ts diff --git a/packages/renderers-pinocchio/src/types/global.d.ts b/packages/renderers-rust-cpi/src/types/global.d.ts similarity index 100% rename from packages/renderers-pinocchio/src/types/global.d.ts rename to packages/renderers-rust-cpi/src/types/global.d.ts diff --git a/packages/renderers-pinocchio/src/utils/codecs.ts b/packages/renderers-rust-cpi/src/utils/codecs.ts similarity index 100% rename from packages/renderers-pinocchio/src/utils/codecs.ts rename to packages/renderers-rust-cpi/src/utils/codecs.ts diff --git a/packages/renderers-pinocchio/src/utils/fragment.ts b/packages/renderers-rust-cpi/src/utils/fragment.ts similarity index 100% rename from packages/renderers-pinocchio/src/utils/fragment.ts rename to packages/renderers-rust-cpi/src/utils/fragment.ts diff --git a/packages/renderers-pinocchio/src/utils/importMap.ts b/packages/renderers-rust-cpi/src/utils/importMap.ts similarity index 100% rename from packages/renderers-pinocchio/src/utils/importMap.ts rename to packages/renderers-rust-cpi/src/utils/importMap.ts diff --git a/packages/renderers-pinocchio/src/utils/index.ts b/packages/renderers-rust-cpi/src/utils/index.ts similarity index 100% rename from packages/renderers-pinocchio/src/utils/index.ts rename to packages/renderers-rust-cpi/src/utils/index.ts diff --git a/packages/renderers-pinocchio/src/utils/linkOverrides.ts b/packages/renderers-rust-cpi/src/utils/linkOverrides.ts similarity index 100% rename from packages/renderers-pinocchio/src/utils/linkOverrides.ts rename to packages/renderers-rust-cpi/src/utils/linkOverrides.ts diff --git a/packages/renderers-pinocchio/src/utils/options.ts b/packages/renderers-rust-cpi/src/utils/options.ts similarity index 100% rename from packages/renderers-pinocchio/src/utils/options.ts rename to packages/renderers-rust-cpi/src/utils/options.ts diff --git a/packages/renderers-pinocchio/src/utils/render.ts b/packages/renderers-rust-cpi/src/utils/render.ts similarity index 100% rename from packages/renderers-pinocchio/src/utils/render.ts rename to packages/renderers-rust-cpi/src/utils/render.ts diff --git a/packages/renderers-pinocchio/src/utils/traitOptions.ts b/packages/renderers-rust-cpi/src/utils/traitOptions.ts similarity index 100% rename from packages/renderers-pinocchio/src/utils/traitOptions.ts rename to packages/renderers-rust-cpi/src/utils/traitOptions.ts diff --git a/packages/renderers-pinocchio/src/visitors/getRenderMapVisitor.ts b/packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts similarity index 100% rename from packages/renderers-pinocchio/src/visitors/getRenderMapVisitor.ts rename to packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts diff --git a/packages/renderers-pinocchio/src/visitors/getTypeManifestVisitor.ts b/packages/renderers-rust-cpi/src/visitors/getTypeManifestVisitor.ts similarity index 100% rename from packages/renderers-pinocchio/src/visitors/getTypeManifestVisitor.ts rename to packages/renderers-rust-cpi/src/visitors/getTypeManifestVisitor.ts diff --git a/packages/renderers-pinocchio/src/visitors/index.ts b/packages/renderers-rust-cpi/src/visitors/index.ts similarity index 100% rename from packages/renderers-pinocchio/src/visitors/index.ts rename to packages/renderers-rust-cpi/src/visitors/index.ts diff --git a/packages/renderers-pinocchio/src/visitors/renderValueNodeVisitor.ts b/packages/renderers-rust-cpi/src/visitors/renderValueNodeVisitor.ts similarity index 100% rename from packages/renderers-pinocchio/src/visitors/renderValueNodeVisitor.ts rename to packages/renderers-rust-cpi/src/visitors/renderValueNodeVisitor.ts diff --git a/packages/renderers-pinocchio/src/visitors/renderVisitor.ts b/packages/renderers-rust-cpi/src/visitors/renderVisitor.ts similarity index 100% rename from packages/renderers-pinocchio/src/visitors/renderVisitor.ts rename to packages/renderers-rust-cpi/src/visitors/renderVisitor.ts diff --git a/packages/renderers-pinocchio/test/_setup.ts b/packages/renderers-rust-cpi/test/_setup.ts similarity index 100% rename from packages/renderers-pinocchio/test/_setup.ts rename to packages/renderers-rust-cpi/test/_setup.ts diff --git a/packages/renderers-pinocchio/test/definedTypesPage.test.ts b/packages/renderers-rust-cpi/test/definedTypesPage.test.ts similarity index 100% rename from packages/renderers-pinocchio/test/definedTypesPage.test.ts rename to packages/renderers-rust-cpi/test/definedTypesPage.test.ts diff --git a/packages/renderers-pinocchio/test/exports/commonjs.cjs b/packages/renderers-rust-cpi/test/exports/commonjs.cjs similarity index 100% rename from packages/renderers-pinocchio/test/exports/commonjs.cjs rename to packages/renderers-rust-cpi/test/exports/commonjs.cjs diff --git a/packages/renderers-pinocchio/test/exports/module.mjs b/packages/renderers-rust-cpi/test/exports/module.mjs similarity index 100% rename from packages/renderers-pinocchio/test/exports/module.mjs rename to packages/renderers-rust-cpi/test/exports/module.mjs diff --git a/packages/renderers-pinocchio/test/instructionsPage.test.ts b/packages/renderers-rust-cpi/test/instructionsPage.test.ts similarity index 100% rename from packages/renderers-pinocchio/test/instructionsPage.test.ts rename to packages/renderers-rust-cpi/test/instructionsPage.test.ts diff --git a/packages/renderers-pinocchio/test/types/number.test.ts b/packages/renderers-rust-cpi/test/types/number.test.ts similarity index 100% rename from packages/renderers-pinocchio/test/types/number.test.ts rename to packages/renderers-rust-cpi/test/types/number.test.ts diff --git a/packages/renderers-pinocchio/test/utils/traitOptions.test.ts b/packages/renderers-rust-cpi/test/utils/traitOptions.test.ts similarity index 100% rename from packages/renderers-pinocchio/test/utils/traitOptions.test.ts rename to packages/renderers-rust-cpi/test/utils/traitOptions.test.ts diff --git a/packages/renderers-pinocchio/tsconfig.declarations.json b/packages/renderers-rust-cpi/tsconfig.declarations.json similarity index 100% rename from packages/renderers-pinocchio/tsconfig.declarations.json rename to packages/renderers-rust-cpi/tsconfig.declarations.json diff --git a/packages/renderers-pinocchio/tsconfig.json b/packages/renderers-rust-cpi/tsconfig.json similarity index 100% rename from packages/renderers-pinocchio/tsconfig.json rename to packages/renderers-rust-cpi/tsconfig.json From 8a059e2940e73fd0add9395b84fbb19a744aa7e3 Mon Sep 17 00:00:00 2001 From: febo Date: Tue, 9 Sep 2025 12:32:25 +0100 Subject: [PATCH 14/24] Update code generation --- .../renderers-rust-cpi/e2e/dummy/Cargo.lock | 21 +- .../renderers-rust-cpi/e2e/dummy/Cargo.toml | 4 +- .../generated/instructions/instruction1.rs | 32 ++- .../generated/instructions/instruction2.rs | 32 ++- .../generated/instructions/instruction3.rs | 32 ++- .../generated/instructions/instruction4.rs | 32 ++- .../generated/instructions/instruction5.rs | 36 ++-- .../generated/instructions/instruction6.rs | 43 ++-- .../generated/instructions/instruction7.rs | 43 ++-- .../dummy/src/generated/instructions/mod.rs | 31 ++- .../e2e/dummy/src/generated/mod.rs | 5 +- .../{programs.rs => programs/mod.rs} | 5 +- .../renderers-rust-cpi/e2e/memo/Cargo.lock | 21 +- .../renderers-rust-cpi/e2e/memo/Cargo.toml | 4 +- .../src/generated/instructions/add_memo.rs | 38 ++-- .../memo/src/generated/instructions/mod.rs | 19 +- .../e2e/memo/src/generated/mod.rs | 5 +- .../{programs.rs => programs/mod.rs} | 5 +- .../renderers-rust-cpi/e2e/system/Cargo.lock | 21 +- .../renderers-rust-cpi/e2e/system/Cargo.toml | 4 +- .../instructions/advance_nonce_account.rs | 61 +++--- .../src/generated/instructions/allocate.rs | 49 +++-- .../instructions/allocate_with_seed.rs | 64 ++++-- .../src/generated/instructions/assign.rs | 51 +++-- .../instructions/assign_with_seed.rs | 59 ++++-- .../instructions/authorize_nonce_account.rs | 57 +++-- .../generated/instructions/create_account.rs | 55 +++-- .../instructions/create_account_with_seed.rs | 70 ++++--- .../instructions/initialize_nonce_account.rs | 70 ++++--- .../system/src/generated/instructions/mod.rs | 43 ++-- .../generated/instructions/transfer_sol.rs | 50 +++-- .../instructions/transfer_sol_with_seed.rs | 66 +++--- .../instructions/upgrade_nonce_account.rs | 43 ++-- .../instructions/withdraw_nonce_account.rs | 79 ++++--- .../e2e/system/src/generated/mod.rs | 6 +- .../{programs.rs => programs/mod.rs} | 5 +- .../e2e/system/src/generated/types/mod.rs | 12 -- .../system/src/generated/types/nonce_state.rs | 19 -- .../src/generated/types/nonce_version.rs | 19 -- .../src/fragments/instructionModPage.ts | 37 ++++ .../src/fragments/instructionPage.ts | 195 ++++++++++++++++-- .../src/fragments/modPage.ts | 16 +- ...getInstructionArgumentAssignmentVisitor.ts | 150 ++++++++++++++ .../src/visitors/getRenderMapVisitor.ts | 4 +- .../renderers-rust-cpi/src/visitors/index.ts | 2 + .../test/definedTypesPage.test.ts | 99 --------- .../test/instructionsPage.test.ts | 25 --- .../test/types/number.test.ts | 44 ---- .../test/utils/traitOptions.test.ts | 60 +++--- 49 files changed, 1202 insertions(+), 741 deletions(-) rename packages/renderers-rust-cpi/e2e/dummy/src/generated/{programs.rs => programs/mod.rs} (70%) rename packages/renderers-rust-cpi/e2e/memo/src/generated/{programs.rs => programs/mod.rs} (70%) rename packages/renderers-rust-cpi/e2e/system/src/generated/{programs.rs => programs/mod.rs} (69%) delete mode 100644 packages/renderers-rust-cpi/e2e/system/src/generated/types/mod.rs delete mode 100644 packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_state.rs delete mode 100644 packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_version.rs create mode 100644 packages/renderers-rust-cpi/src/fragments/instructionModPage.ts create mode 100644 packages/renderers-rust-cpi/src/visitors/getInstructionArgumentAssignmentVisitor.ts delete mode 100644 packages/renderers-rust-cpi/test/definedTypesPage.test.ts delete mode 100644 packages/renderers-rust-cpi/test/instructionsPage.test.ts delete mode 100644 packages/renderers-rust-cpi/test/types/number.test.ts diff --git a/packages/renderers-rust-cpi/e2e/dummy/Cargo.lock b/packages/renderers-rust-cpi/e2e/dummy/Cargo.lock index 3b416fa0c..8aab0eeaf 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/Cargo.lock +++ b/packages/renderers-rust-cpi/e2e/dummy/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "assert_matches" @@ -19,9 +19,9 @@ dependencies = [ [[package]] name = "five8_const" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" dependencies = [ "five8_core", ] @@ -34,16 +34,23 @@ checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" [[package]] name = "pinocchio" -version = "0.6.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9f716de2190437efa787dd7414f4bcea88d22c2f81bbeecabb7db6d9cc326bd" +checksum = "0c3410a5d525f024b0aed7f8747e94e918c91ba64274a190e2365903e2c0b2e9" [[package]] name = "pinocchio-pubkey" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4800103b9bea24df2e78f161403fc8f8c2286cb5f874b2e5feebe6c5c4fb35a" +checksum = "cb0225638cadcbebae8932cb7f49cb5da7c15c21beb19f048f05a5ca7d93f065" dependencies = [ "five8_const", "pinocchio", + "sha2-const-stable", ] + +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" diff --git a/packages/renderers-rust-cpi/e2e/dummy/Cargo.toml b/packages/renderers-rust-cpi/e2e/dummy/Cargo.toml index 7666bed19..3ec2755c1 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/Cargo.toml +++ b/packages/renderers-rust-cpi/e2e/dummy/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" test-sbf = [] [dependencies] -pinocchio = "0.6" -pinocchio-pubkey = "0.2" +pinocchio = "0.9" +pinocchio-pubkey = "0.3" [dev-dependencies] assert_matches = "1.5.0" diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs index 82e1b8b2d..632283f20 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs @@ -1,26 +1,36 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `instruction1` CPI helper. pub struct Instruction1 {} impl Instruction1 { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 0] = []; + + let data = &[]; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs index 902c6dd5a..e8564d41b 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs @@ -1,26 +1,36 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `instruction2` CPI helper. pub struct Instruction2 {} impl Instruction2 { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 0] = []; + + let data = &[]; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs index ab90a24b6..bb3d4cdf8 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs @@ -1,26 +1,36 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `instruction3` CPI helper. pub struct Instruction3 {} impl Instruction3 { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 0] = []; + + let data = &42u32.to_le_bytes(); + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs index 52a29cfc1..50d028b64 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs @@ -1,9 +1,14 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `instruction4` CPI helper. pub struct Instruction4 { @@ -12,17 +17,22 @@ pub struct Instruction4 { impl Instruction4 { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 0] = []; + + let data = &self.my_argument.to_le_bytes(); + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs index 6c6f7ec86..a5de40d9a 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs @@ -1,28 +1,36 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `instruction5` CPI helper. -pub struct Instruction5 { - pub my_argument: u64, -} +pub struct Instruction5 {} impl Instruction5 { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 0] = []; + + let data = &42u64.to_le_bytes(); + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs index caccd56f8..ac9472a40 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs @@ -1,33 +1,40 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `instruction6` CPI helper. pub struct Instruction6<'a> { - pub my_account: &'a pinocchio::account_info::AccountInfo, + pub my_account: &'a AccountInfo, } -impl<'a> Instruction6<'a> { +impl Instruction6<'_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 1] = - [pinocchio::instruction::AccountMeta::new( - self.my_account.key(), - true, - false, - )]; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 1] = + [AccountMeta::new(self.my_account.key(), true, false)]; + + let data = &[]; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[&self.my_account], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs index 2fc7fce9a..249dfd46c 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs @@ -1,33 +1,40 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `instruction7` CPI helper. pub struct Instruction7<'a> { - pub my_account: Option<&'a pinocchio::account_info::AccountInfo>, + pub my_account: Option<&'a AccountInfo>, } -impl<'a> Instruction7<'a> { +impl Instruction7<'_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 1] = - [pinocchio::instruction::AccountMeta::new( - self.my_account.key(), - true, - false, - )]; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 1] = + [AccountMeta::new(self.my_account.key(), true, false)]; + + let data = &[]; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[&self.my_account], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/mod.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/mod.rs index a0205b0c4..d539e79a9 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/mod.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/mod.rs @@ -1,17 +1,18 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! -pub(crate) mod r#instruction1; -pub(crate) mod r#instruction2; -pub(crate) mod r#instruction3; -pub(crate) mod r#instruction4; -pub(crate) mod r#instruction5; -pub(crate) mod r#instruction6; -pub(crate) mod r#instruction7; +use core::mem::MaybeUninit; + +pub mod r#instruction1; +pub mod r#instruction2; +pub mod r#instruction3; +pub mod r#instruction4; +pub mod r#instruction5; +pub mod r#instruction6; +pub mod r#instruction7; pub use self::r#instruction1::*; pub use self::r#instruction2::*; @@ -20,3 +21,13 @@ pub use self::r#instruction4::*; pub use self::r#instruction5::*; pub use self::r#instruction6::*; pub use self::r#instruction7::*; + +const UNINIT_BYTE: MaybeUninit = MaybeUninit::::uninit(); + +/// Write bytes from a source slice to a destination slice of `MaybeUninit`. +#[inline(always)] +fn write_bytes(destination: &mut [MaybeUninit], source: &[u8]) { + for (d, s) in destination.iter_mut().zip(source.iter()) { + d.write(*s); + } +} diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/mod.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/mod.rs index 69cb087f7..c1b581407 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/mod.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/mod.rs @@ -1,9 +1,8 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! pub mod instructions; pub mod programs; diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/programs.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/programs/mod.rs similarity index 70% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/programs.rs rename to packages/renderers-rust-cpi/e2e/dummy/src/generated/programs/mod.rs index 4b970e0f4..bada6e398 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/programs.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/programs/mod.rs @@ -1,9 +1,8 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! use pinocchio::pubkey::Pubkey; use pinocchio_pubkey::pubkey; diff --git a/packages/renderers-rust-cpi/e2e/memo/Cargo.lock b/packages/renderers-rust-cpi/e2e/memo/Cargo.lock index a9bceca4d..5a29d8b74 100644 --- a/packages/renderers-rust-cpi/e2e/memo/Cargo.lock +++ b/packages/renderers-rust-cpi/e2e/memo/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "assert_matches" @@ -19,9 +19,9 @@ dependencies = [ [[package]] name = "five8_const" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" dependencies = [ "five8_core", ] @@ -34,16 +34,23 @@ checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" [[package]] name = "pinocchio" -version = "0.6.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9f716de2190437efa787dd7414f4bcea88d22c2f81bbeecabb7db6d9cc326bd" +checksum = "0c3410a5d525f024b0aed7f8747e94e918c91ba64274a190e2365903e2c0b2e9" [[package]] name = "pinocchio-pubkey" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4800103b9bea24df2e78f161403fc8f8c2286cb5f874b2e5feebe6c5c4fb35a" +checksum = "cb0225638cadcbebae8932cb7f49cb5da7c15c21beb19f048f05a5ca7d93f065" dependencies = [ "five8_const", "pinocchio", + "sha2-const-stable", ] + +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" diff --git a/packages/renderers-rust-cpi/e2e/memo/Cargo.toml b/packages/renderers-rust-cpi/e2e/memo/Cargo.toml index e71b5b2d2..ec2143d9f 100644 --- a/packages/renderers-rust-cpi/e2e/memo/Cargo.toml +++ b/packages/renderers-rust-cpi/e2e/memo/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" test-sbf = [] [dependencies] -pinocchio = "0.6" -pinocchio-pubkey = "0.2" +pinocchio = "0.9" +pinocchio-pubkey = "0.3" [dev-dependencies] assert_matches = "1.5.0" diff --git a/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs b/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs index 72bd55334..e0853887e 100644 --- a/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs +++ b/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs @@ -1,28 +1,38 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `add_memo` CPI helper. -pub struct AddMemo { - pub memo: str, +pub struct AddMemo<'a> { + pub memo: &'a str, } -impl AddMemo { +impl AddMemo<'_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 0] = []; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 0] = []; + + let data = self.memo.as_bytes(); + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/mod.rs b/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/mod.rs index c1c3f1794..10fd21284 100644 --- a/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/mod.rs +++ b/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/mod.rs @@ -1,10 +1,21 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! -pub(crate) mod r#add_memo; +use core::mem::MaybeUninit; + +pub mod r#add_memo; pub use self::r#add_memo::*; + +const UNINIT_BYTE: MaybeUninit = MaybeUninit::::uninit(); + +/// Write bytes from a source slice to a destination slice of `MaybeUninit`. +#[inline(always)] +fn write_bytes(destination: &mut [MaybeUninit], source: &[u8]) { + for (d, s) in destination.iter_mut().zip(source.iter()) { + d.write(*s); + } +} diff --git a/packages/renderers-rust-cpi/e2e/memo/src/generated/mod.rs b/packages/renderers-rust-cpi/e2e/memo/src/generated/mod.rs index 69cb087f7..c1b581407 100644 --- a/packages/renderers-rust-cpi/e2e/memo/src/generated/mod.rs +++ b/packages/renderers-rust-cpi/e2e/memo/src/generated/mod.rs @@ -1,9 +1,8 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! pub mod instructions; pub mod programs; diff --git a/packages/renderers-rust-cpi/e2e/memo/src/generated/programs.rs b/packages/renderers-rust-cpi/e2e/memo/src/generated/programs/mod.rs similarity index 70% rename from packages/renderers-rust-cpi/e2e/memo/src/generated/programs.rs rename to packages/renderers-rust-cpi/e2e/memo/src/generated/programs/mod.rs index 2e42a6da9..79694ed81 100644 --- a/packages/renderers-rust-cpi/e2e/memo/src/generated/programs.rs +++ b/packages/renderers-rust-cpi/e2e/memo/src/generated/programs/mod.rs @@ -1,9 +1,8 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! use pinocchio::pubkey::Pubkey; use pinocchio_pubkey::pubkey; diff --git a/packages/renderers-rust-cpi/e2e/system/Cargo.lock b/packages/renderers-rust-cpi/e2e/system/Cargo.lock index 7fe2a7e46..9a8b5d1bf 100644 --- a/packages/renderers-rust-cpi/e2e/system/Cargo.lock +++ b/packages/renderers-rust-cpi/e2e/system/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ahash" @@ -199,9 +199,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "five8_const" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" dependencies = [ "five8_core", ] @@ -363,18 +363,19 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "pinocchio" -version = "0.6.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9f716de2190437efa787dd7414f4bcea88d22c2f81bbeecabb7db6d9cc326bd" +checksum = "0c3410a5d525f024b0aed7f8747e94e918c91ba64274a190e2365903e2c0b2e9" [[package]] name = "pinocchio-pubkey" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4800103b9bea24df2e78f161403fc8f8c2286cb5f874b2e5feebe6c5c4fb35a" +checksum = "cb0225638cadcbebae8932cb7f49cb5da7c15c21beb19f048f05a5ca7d93f065" dependencies = [ "five8_const", "pinocchio", + "sha2-const-stable", ] [[package]] @@ -478,6 +479,12 @@ dependencies = [ "syn 2.0.85", ] +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + [[package]] name = "shlex" version = "1.3.0" diff --git a/packages/renderers-rust-cpi/e2e/system/Cargo.toml b/packages/renderers-rust-cpi/e2e/system/Cargo.toml index 328022e7b..71ad5bfbd 100644 --- a/packages/renderers-rust-cpi/e2e/system/Cargo.toml +++ b/packages/renderers-rust-cpi/e2e/system/Cargo.toml @@ -12,8 +12,8 @@ test-sbf = [] borsh = { version = "^0.10", optional = true } num-derive = "^0.3" num-traits = "^0.2" -pinocchio = "0.6" -pinocchio-pubkey = "0.2" +pinocchio = "0.9" +pinocchio-pubkey = "0.3" serde = { version = "^1.0", features = ["derive"], optional = true } serde_with = { version = "^3.0", optional = true } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs index 5d4e0c415..cb8e7a39b 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs @@ -1,40 +1,53 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `advance_nonce_account` CPI helper. pub struct AdvanceNonceAccount<'a> { - pub nonce_account: &'a pinocchio::account_info::AccountInfo, - - pub recent_blockhashes_sysvar: &'a pinocchio::account_info::AccountInfo, - - pub nonce_authority: &'a pinocchio::account_info::AccountInfo, + pub nonce_account: &'a AccountInfo, + pub recent_blockhashes_sysvar: &'a AccountInfo, + pub nonce_authority: &'a AccountInfo, } -impl<'a> AdvanceNonceAccount<'a> { +impl AdvanceNonceAccount<'_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 3] = [ - pinocchio::instruction::AccountMeta::new(self.nonce_account.key(), true, false), - pinocchio::instruction::AccountMeta::new( - self.recent_blockhashes_sysvar.key(), - false, - false, - ), - pinocchio::instruction::AccountMeta::new(self.nonce_authority.key(), false, true), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 3] = [ + AccountMeta::new(self.nonce_account.key(), true, false), + AccountMeta::new(self.recent_blockhashes_sysvar.key(), false, false), + AccountMeta::new(self.nonce_authority.key(), false, true), ]; - Ok(()) + let data = &4u32.to_le_bytes(); + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed( + &instruction, + &[ + &self.nonce_account, + &self.recent_blockhashes_sysvar, + &self.nonce_authority, + ], + signers, + ) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs index a8f9d33d8..450173c6a 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs @@ -1,34 +1,47 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `allocate` CPI helper. pub struct Allocate<'a> { - pub new_account: &'a pinocchio::account_info::AccountInfo, + pub new_account: &'a AccountInfo, pub space: u64, } -impl<'a> Allocate<'a> { +impl Allocate<'_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 1] = - [pinocchio::instruction::AccountMeta::new( - self.new_account.key(), - true, - true, - )]; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 1] = + [AccountMeta::new(self.new_account.key(), true, true)]; + + let mut uninit_data = [UNINIT_BYTE; 12]; + write_bytes(&mut uninit_data[0..4], &8u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..12], &self.space.to_le_bytes()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 12) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[&self.new_account], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs index 25449e713..e0a867347 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs @@ -1,39 +1,61 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; +use pinocchio::ProgramResult; /// `allocate_with_seed` CPI helper. -pub struct AllocateWithSeed<'a> { - pub new_account: &'a pinocchio::account_info::AccountInfo, - - pub base_account: &'a pinocchio::account_info::AccountInfo, - pub base: Pubkey, - pub seed: String, +pub struct AllocateWithSeed<'a, 'b, 'c, 'd> { + pub new_account: &'a AccountInfo, + pub base_account: &'a AccountInfo, + pub base: &'b Pubkey, + pub seed: &'c String, pub space: u64, - pub program_address: Pubkey, + pub program_address: &'d Pubkey, } -impl<'a> AllocateWithSeed<'a> { +impl AllocateWithSeed<'_, '_, '_, '_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ - pinocchio::instruction::AccountMeta::new(self.new_account.key(), true, false), - pinocchio::instruction::AccountMeta::new(self.base_account.key(), false, true), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 2] = [ + AccountMeta::new(self.new_account.key(), true, false), + AccountMeta::new(self.base_account.key(), false, true), ]; - Ok(()) + let mut uninit_data = [UNINIT_BYTE; 0]; + write_bytes(&mut uninit_data[0..4], &9u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..36], self.base.as_ref()); + + write_bytes(&mut uninit_data[0..8], &self.space.to_le_bytes()); + write_bytes(&mut uninit_data[8..40], self.program_address.as_ref()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 40) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed( + &instruction, + &[&self.new_account, &self.base_account], + signers, + ) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs index cde5299ee..0d30d0f42 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs @@ -1,36 +1,47 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; +use pinocchio::ProgramResult; /// `assign` CPI helper. -pub struct Assign<'a> { - pub account: &'a pinocchio::account_info::AccountInfo, - pub program_address: Pubkey, +pub struct Assign<'a, 'b> { + pub account: &'a AccountInfo, + pub program_address: &'b Pubkey, } -impl<'a> Assign<'a> { +impl Assign<'_, '_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 1] = - [pinocchio::instruction::AccountMeta::new( - self.account.key(), - true, - true, - )]; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 1] = [AccountMeta::new(self.account.key(), true, true)]; + + let mut uninit_data = [UNINIT_BYTE; 36]; + write_bytes(&mut uninit_data[0..4], &1u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..36], self.program_address.as_ref()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 36) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[&self.account], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs index f6c2b1cdf..161ebd9f7 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs @@ -1,38 +1,55 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; +use pinocchio::ProgramResult; /// `assign_with_seed` CPI helper. -pub struct AssignWithSeed<'a> { - pub account: &'a pinocchio::account_info::AccountInfo, - - pub base_account: &'a pinocchio::account_info::AccountInfo, - pub base: Pubkey, - pub seed: String, - pub program_address: Pubkey, +pub struct AssignWithSeed<'a, 'b, 'c, 'd> { + pub account: &'a AccountInfo, + pub base_account: &'a AccountInfo, + pub base: &'b Pubkey, + pub seed: &'c String, + pub program_address: &'d Pubkey, } -impl<'a> AssignWithSeed<'a> { +impl AssignWithSeed<'_, '_, '_, '_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ - pinocchio::instruction::AccountMeta::new(self.account.key(), true, false), - pinocchio::instruction::AccountMeta::new(self.base_account.key(), false, true), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 2] = [ + AccountMeta::new(self.account.key(), true, false), + AccountMeta::new(self.base_account.key(), false, true), ]; - Ok(()) + let mut uninit_data = [UNINIT_BYTE; 0]; + write_bytes(&mut uninit_data[0..4], &10u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..36], self.base.as_ref()); + + write_bytes(&mut uninit_data[0..32], self.program_address.as_ref()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 32) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed(&instruction, &[&self.account, &self.base_account], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs index 6830d221f..baa5a95ff 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs @@ -1,36 +1,55 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; +use pinocchio::ProgramResult; /// `authorize_nonce_account` CPI helper. -pub struct AuthorizeNonceAccount<'a> { - pub nonce_account: &'a pinocchio::account_info::AccountInfo, - - pub nonce_authority: &'a pinocchio::account_info::AccountInfo, - pub new_nonce_authority: Pubkey, +pub struct AuthorizeNonceAccount<'a, 'b> { + pub nonce_account: &'a AccountInfo, + pub nonce_authority: &'a AccountInfo, + pub new_nonce_authority: &'b Pubkey, } -impl<'a> AuthorizeNonceAccount<'a> { +impl AuthorizeNonceAccount<'_, '_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ - pinocchio::instruction::AccountMeta::new(self.nonce_account.key(), true, false), - pinocchio::instruction::AccountMeta::new(self.nonce_authority.key(), false, true), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 2] = [ + AccountMeta::new(self.nonce_account.key(), true, false), + AccountMeta::new(self.nonce_authority.key(), false, true), ]; - Ok(()) + let mut uninit_data = [UNINIT_BYTE; 36]; + write_bytes(&mut uninit_data[0..4], &7u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..36], self.new_nonce_authority.as_ref()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 36) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed( + &instruction, + &[&self.nonce_account, &self.nonce_authority], + signers, + ) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs index 9f8f91284..da5774a53 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs @@ -1,38 +1,55 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; +use pinocchio::ProgramResult; /// `create_account` CPI helper. -pub struct CreateAccount<'a> { - pub payer: &'a pinocchio::account_info::AccountInfo, - - pub new_account: &'a pinocchio::account_info::AccountInfo, +pub struct CreateAccount<'a, 'b> { + pub payer: &'a AccountInfo, + pub new_account: &'a AccountInfo, pub lamports: u64, pub space: u64, - pub program_address: Pubkey, + pub program_address: &'b Pubkey, } -impl<'a> CreateAccount<'a> { +impl CreateAccount<'_, '_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ - pinocchio::instruction::AccountMeta::new(self.payer.key(), true, true), - pinocchio::instruction::AccountMeta::new(self.new_account.key(), true, true), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 2] = [ + AccountMeta::new(self.payer.key(), true, true), + AccountMeta::new(self.new_account.key(), true, true), ]; - Ok(()) + let mut uninit_data = [UNINIT_BYTE; 52]; + write_bytes(&mut uninit_data[0..4], &0u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..12], &self.lamports.to_le_bytes()); + write_bytes(&mut uninit_data[12..20], &self.space.to_le_bytes()); + write_bytes(&mut uninit_data[20..52], self.program_address.as_ref()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 52) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed(&instruction, &[&self.payer, &self.new_account], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs index 76c42441f..d31b88cab 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs @@ -1,43 +1,65 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; +use pinocchio::ProgramResult; /// `create_account_with_seed` CPI helper. -pub struct CreateAccountWithSeed<'a> { - pub payer: &'a pinocchio::account_info::AccountInfo, - - pub new_account: &'a pinocchio::account_info::AccountInfo, - - pub base_account: &'a pinocchio::account_info::AccountInfo, - pub base: Pubkey, - pub seed: String, +pub struct CreateAccountWithSeed<'a, 'b, 'c, 'd> { + pub payer: &'a AccountInfo, + pub new_account: &'a AccountInfo, + pub base_account: &'a AccountInfo, + pub base: &'b Pubkey, + pub seed: &'c String, pub amount: u64, pub space: u64, - pub program_address: Pubkey, + pub program_address: &'d Pubkey, } -impl<'a> CreateAccountWithSeed<'a> { +impl CreateAccountWithSeed<'_, '_, '_, '_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 3] = [ - pinocchio::instruction::AccountMeta::new(self.payer.key(), true, true), - pinocchio::instruction::AccountMeta::new(self.new_account.key(), true, false), - pinocchio::instruction::AccountMeta::new(self.base_account.key(), false, true), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 3] = [ + AccountMeta::new(self.payer.key(), true, true), + AccountMeta::new(self.new_account.key(), true, false), + AccountMeta::new(self.base_account.key(), false, true), ]; - Ok(()) + let mut uninit_data = [UNINIT_BYTE; 0]; + write_bytes(&mut uninit_data[0..4], &3u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..36], self.base.as_ref()); + + write_bytes(&mut uninit_data[0..8], &self.amount.to_le_bytes()); + write_bytes(&mut uninit_data[8..16], &self.space.to_le_bytes()); + write_bytes(&mut uninit_data[16..48], self.program_address.as_ref()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 48) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed( + &instruction, + &[&self.payer, &self.new_account, &self.base_account], + signers, + ) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs index 9e872d601..190da914a 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs @@ -1,43 +1,61 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; +use pinocchio::ProgramResult; /// `initialize_nonce_account` CPI helper. -pub struct InitializeNonceAccount<'a> { - pub nonce_account: &'a pinocchio::account_info::AccountInfo, - - pub recent_blockhashes_sysvar: &'a pinocchio::account_info::AccountInfo, - - pub rent_sysvar: &'a pinocchio::account_info::AccountInfo, - pub nonce_authority: Pubkey, +pub struct InitializeNonceAccount<'a, 'b> { + pub nonce_account: &'a AccountInfo, + pub recent_blockhashes_sysvar: &'a AccountInfo, + pub rent_sysvar: &'a AccountInfo, + pub nonce_authority: &'b Pubkey, } -impl<'a> InitializeNonceAccount<'a> { +impl InitializeNonceAccount<'_, '_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 3] = [ - pinocchio::instruction::AccountMeta::new(self.nonce_account.key(), true, false), - pinocchio::instruction::AccountMeta::new( - self.recent_blockhashes_sysvar.key(), - false, - false, - ), - pinocchio::instruction::AccountMeta::new(self.rent_sysvar.key(), false, false), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 3] = [ + AccountMeta::new(self.nonce_account.key(), true, false), + AccountMeta::new(self.recent_blockhashes_sysvar.key(), false, false), + AccountMeta::new(self.rent_sysvar.key(), false, false), ]; - Ok(()) + let mut uninit_data = [UNINIT_BYTE; 36]; + write_bytes(&mut uninit_data[0..4], &6u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..36], self.nonce_authority.as_ref()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 36) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed( + &instruction, + &[ + &self.nonce_account, + &self.recent_blockhashes_sysvar, + &self.rent_sysvar, + ], + signers, + ) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/mod.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/mod.rs index 85422fddb..77c98d0b5 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/mod.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/mod.rs @@ -1,23 +1,24 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! -pub(crate) mod r#advance_nonce_account; -pub(crate) mod r#allocate; -pub(crate) mod r#allocate_with_seed; -pub(crate) mod r#assign; -pub(crate) mod r#assign_with_seed; -pub(crate) mod r#authorize_nonce_account; -pub(crate) mod r#create_account; -pub(crate) mod r#create_account_with_seed; -pub(crate) mod r#initialize_nonce_account; -pub(crate) mod r#transfer_sol; -pub(crate) mod r#transfer_sol_with_seed; -pub(crate) mod r#upgrade_nonce_account; -pub(crate) mod r#withdraw_nonce_account; +use core::mem::MaybeUninit; + +pub mod r#advance_nonce_account; +pub mod r#allocate; +pub mod r#allocate_with_seed; +pub mod r#assign; +pub mod r#assign_with_seed; +pub mod r#authorize_nonce_account; +pub mod r#create_account; +pub mod r#create_account_with_seed; +pub mod r#initialize_nonce_account; +pub mod r#transfer_sol; +pub mod r#transfer_sol_with_seed; +pub mod r#upgrade_nonce_account; +pub mod r#withdraw_nonce_account; pub use self::r#advance_nonce_account::*; pub use self::r#allocate::*; @@ -32,3 +33,13 @@ pub use self::r#transfer_sol::*; pub use self::r#transfer_sol_with_seed::*; pub use self::r#upgrade_nonce_account::*; pub use self::r#withdraw_nonce_account::*; + +const UNINIT_BYTE: MaybeUninit = MaybeUninit::::uninit(); + +/// Write bytes from a source slice to a destination slice of `MaybeUninit`. +#[inline(always)] +fn write_bytes(destination: &mut [MaybeUninit], source: &[u8]) { + for (d, s) in destination.iter_mut().zip(source.iter()) { + d.write(*s); + } +} diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs index 3a844be79..b68174da6 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs @@ -1,34 +1,50 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `transfer_sol` CPI helper. pub struct TransferSol<'a> { - pub source: &'a pinocchio::account_info::AccountInfo, - - pub destination: &'a pinocchio::account_info::AccountInfo, + pub source: &'a AccountInfo, + pub destination: &'a AccountInfo, pub amount: u64, } -impl<'a> TransferSol<'a> { +impl TransferSol<'_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 2] = [ - pinocchio::instruction::AccountMeta::new(self.source.key(), true, true), - pinocchio::instruction::AccountMeta::new(self.destination.key(), true, false), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 2] = [ + AccountMeta::new(self.source.key(), true, true), + AccountMeta::new(self.destination.key(), true, false), ]; - Ok(()) + let mut uninit_data = [UNINIT_BYTE; 12]; + write_bytes(&mut uninit_data[0..4], &2u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..12], &self.amount.to_le_bytes()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 12) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed(&instruction, &[&self.source, &self.destination], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs index aedb0c8bc..09fb23417 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs @@ -1,41 +1,61 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; +use pinocchio::ProgramResult; /// `transfer_sol_with_seed` CPI helper. -pub struct TransferSolWithSeed<'a> { - pub source: &'a pinocchio::account_info::AccountInfo, - - pub base_account: &'a pinocchio::account_info::AccountInfo, - - pub destination: &'a pinocchio::account_info::AccountInfo, +pub struct TransferSolWithSeed<'a, 'b, 'c> { + pub source: &'a AccountInfo, + pub base_account: &'a AccountInfo, + pub destination: &'a AccountInfo, pub amount: u64, - pub from_seed: String, - pub from_owner: Pubkey, + pub from_seed: &'b String, + pub from_owner: &'c Pubkey, } -impl<'a> TransferSolWithSeed<'a> { +impl TransferSolWithSeed<'_, '_, '_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 3] = [ - pinocchio::instruction::AccountMeta::new(self.source.key(), true, false), - pinocchio::instruction::AccountMeta::new(self.base_account.key(), false, true), - pinocchio::instruction::AccountMeta::new(self.destination.key(), true, false), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 3] = [ + AccountMeta::new(self.source.key(), true, false), + AccountMeta::new(self.base_account.key(), false, true), + AccountMeta::new(self.destination.key(), true, false), ]; - Ok(()) + let mut uninit_data = [UNINIT_BYTE; 0]; + write_bytes(&mut uninit_data[0..4], &11u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..12], &self.amount.to_le_bytes()); + + write_bytes(&mut uninit_data[0..32], self.from_owner.as_ref()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 32) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed( + &instruction, + &[&self.source, &self.base_account, &self.destination], + signers, + ) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs index 443d4a6fa..46fd466df 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs @@ -1,33 +1,40 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `upgrade_nonce_account` CPI helper. pub struct UpgradeNonceAccount<'a> { - pub nonce_account: &'a pinocchio::account_info::AccountInfo, + pub nonce_account: &'a AccountInfo, } -impl<'a> UpgradeNonceAccount<'a> { +impl UpgradeNonceAccount<'_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 1] = - [pinocchio::instruction::AccountMeta::new( - self.nonce_account.key(), - true, - false, - )]; + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 1] = + [AccountMeta::new(self.nonce_account.key(), true, false)]; + + let data = &12u32.to_le_bytes(); + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; - Ok(()) + invoke_signed(&instruction, &[&self.nonce_account], signers) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs index 4b2d03dbe..21fe51f0c 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs @@ -1,47 +1,66 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! + +use super::write_bytes; +use super::UNINIT_BYTE; +use core::slice::from_raw_parts; +use pinocchio::account_info::AccountInfo; +use pinocchio::cpi::invoke_signed; +use pinocchio::instruction::AccountMeta; +use pinocchio::instruction::Instruction; +use pinocchio::instruction::Signer; +use pinocchio::ProgramResult; /// `withdraw_nonce_account` CPI helper. pub struct WithdrawNonceAccount<'a> { - pub nonce_account: &'a pinocchio::account_info::AccountInfo, - - pub recipient_account: &'a pinocchio::account_info::AccountInfo, - - pub recent_blockhashes_sysvar: &'a pinocchio::account_info::AccountInfo, - - pub rent_sysvar: &'a pinocchio::account_info::AccountInfo, - - pub nonce_authority: &'a pinocchio::account_info::AccountInfo, + pub nonce_account: &'a AccountInfo, + pub recipient_account: &'a AccountInfo, + pub recent_blockhashes_sysvar: &'a AccountInfo, + pub rent_sysvar: &'a AccountInfo, + pub nonce_authority: &'a AccountInfo, pub withdraw_amount: u64, } -impl<'a> WithdrawNonceAccount<'a> { +impl WithdrawNonceAccount<'_> { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed( - &self, - _signers: &[pinocchio::instruction::Signer], - ) -> pinocchio::ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; 5] = [ - pinocchio::instruction::AccountMeta::new(self.nonce_account.key(), true, false), - pinocchio::instruction::AccountMeta::new(self.recipient_account.key(), true, false), - pinocchio::instruction::AccountMeta::new( - self.recent_blockhashes_sysvar.key(), - false, - false, - ), - pinocchio::instruction::AccountMeta::new(self.rent_sysvar.key(), false, false), - pinocchio::instruction::AccountMeta::new(self.nonce_authority.key(), false, true), + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { + // account metas + let account_metas: [AccountMeta; 5] = [ + AccountMeta::new(self.nonce_account.key(), true, false), + AccountMeta::new(self.recipient_account.key(), true, false), + AccountMeta::new(self.recent_blockhashes_sysvar.key(), false, false), + AccountMeta::new(self.rent_sysvar.key(), false, false), + AccountMeta::new(self.nonce_authority.key(), false, true), ]; - Ok(()) + let mut uninit_data = [UNINIT_BYTE; 12]; + write_bytes(&mut uninit_data[0..4], &5u32.to_le_bytes()); + write_bytes(&mut uninit_data[4..12], &self.withdraw_amount.to_le_bytes()); + let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, 12) }; + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed( + &instruction, + &[ + &self.nonce_account, + &self.recipient_account, + &self.recent_blockhashes_sysvar, + &self.rent_sysvar, + &self.nonce_authority, + ], + signers, + ) } } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/mod.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/mod.rs index b04b2e846..c1b581407 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/mod.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/mod.rs @@ -1,10 +1,8 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! pub mod instructions; pub mod programs; -pub mod types; diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/programs.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/programs/mod.rs similarity index 69% rename from packages/renderers-rust-cpi/e2e/system/src/generated/programs.rs rename to packages/renderers-rust-cpi/e2e/system/src/generated/programs/mod.rs index 31c24093f..5470e7884 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/programs.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/programs/mod.rs @@ -1,9 +1,8 @@ -//! This code was AUTOGENERATED using the codama library. +//! This code was AUTOGENERATED using the Codama library. //! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. +//! to add features, then rerun Codama to update it. //! //! -//! use pinocchio::pubkey::Pubkey; use pinocchio_pubkey::pubkey; diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/types/mod.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/types/mod.rs deleted file mode 100644 index 396fe1865..000000000 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/types/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! This code was AUTOGENERATED using the codama library. -//! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. -//! -//! -//! - -pub(crate) mod r#nonce_state; -pub(crate) mod r#nonce_version; - -pub use self::r#nonce_state::*; -pub use self::r#nonce_version::*; diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_state.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_state.rs deleted file mode 100644 index b504b41a0..000000000 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_state.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! This code was AUTOGENERATED using the codama library. -//! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. -//! -//! -//! - -use num_derive::FromPrimitive; - -#[derive(Clone, Debug, Eq, PartialEq, Copy, PartialOrd, Hash, FromPrimitive)] -#[cfg_attr( - feature = "borsh", - derive(borsh::BorshSerialize, borsh::BorshDeserialize) -)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum NonceState { - Uninitialized, - Initialized, -} diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_version.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_version.rs deleted file mode 100644 index 5f85b93a5..000000000 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/types/nonce_version.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! This code was AUTOGENERATED using the codama library. -//! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun codama to update it. -//! -//! -//! - -use num_derive::FromPrimitive; - -#[derive(Clone, Debug, Eq, PartialEq, Copy, PartialOrd, Hash, FromPrimitive)] -#[cfg_attr( - feature = "borsh", - derive(borsh::BorshSerialize, borsh::BorshDeserialize) -)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum NonceVersion { - Legacy, - Current, -} diff --git a/packages/renderers-rust-cpi/src/fragments/instructionModPage.ts b/packages/renderers-rust-cpi/src/fragments/instructionModPage.ts new file mode 100644 index 000000000..309bedd38 --- /dev/null +++ b/packages/renderers-rust-cpi/src/fragments/instructionModPage.ts @@ -0,0 +1,37 @@ +import { InstructionNode } from '@codama/nodes'; +import { addFragmentImports, fragment, Fragment, getPageFragment, mergeFragments, RenderScope } from '../utils'; +import { getModImportsFragment } from './modPage'; + +/** + * Get the mod page fragment for instructions. + */ +export function getInstructionModPageFragment( + scope: Pick & { instructions: InstructionNode[] }, +): Fragment | undefined { + const imports = getModImportsFragment(scope.instructions); + if (!imports) return; + + return getPageFragment( + mergeFragments([imports, getInstructionHelpersFragment()], cs => cs.join('\n\n')), + scope, + ); +} + +/** + * Helpers for handling `MaybeUninit` buffers. + */ +function getInstructionHelpersFragment(): Fragment { + return addFragmentImports( + fragment` + const UNINIT_BYTE: MaybeUninit = MaybeUninit::::uninit(); + + /// Write bytes from a source slice to a destination slice of \`MaybeUninit\`. + #[inline(always)] + fn write_bytes(destination: &mut [MaybeUninit], source: &[u8]) { + for (d, s) in destination.iter_mut().zip(source.iter()) { + d.write(*s); + } + }`, + ['core::mem::MaybeUninit'], + ); +} diff --git a/packages/renderers-rust-cpi/src/fragments/instructionPage.ts b/packages/renderers-rust-cpi/src/fragments/instructionPage.ts index 28c451027..531b4f1ae 100644 --- a/packages/renderers-rust-cpi/src/fragments/instructionPage.ts +++ b/packages/renderers-rust-cpi/src/fragments/instructionPage.ts @@ -21,7 +21,11 @@ import { } from '../utils'; import { getTypeManifestVisitor, TypeManifest } from '../visitors/getTypeManifestVisitor'; import { renderValueNode } from '../visitors/renderValueNodeVisitor'; +import { getInstructionArgumentAssignmentVisitor } from '../visitors'; +/** + * Get the instruction page fragment. + */ export function getInstructionPageFragment( scope: Pick & { instructionPath: NodePath; @@ -42,20 +46,23 @@ export function getInstructionPageFragment( // Instruction arguments. const instructionArguments = getParsedInstructionArguments(instructionNode, accountsAndArgsConflicts, scope); + + /* const hasArgs = instructionArguments.some(arg => arg.defaultValueStrategy !== 'omitted'); const hasOptional = instructionArguments.some( arg => !arg.resolvedDefaultValue && arg.defaultValueStrategy !== 'omitted', ); + */ - // Helpers. + // Determines the size of the instruction data. The size is `null` if any of the arguments is + // variable-sized. const instructionFixedSize = visit(instructionNode, scope.byteSizeVisitor); - const lifetime = instructionNode.accounts.length > 0 ? "<'a>" : ''; return getPageFragment( mergeFragments( [ - getInstructionStructFragment(instructionNode, instructionArguments, lifetime), - getInstructionImplFragment(instructionNode, instructionArguments, lifetime), + getInstructionStructFragment(instructionNode, instructionArguments), + getInstructionImplFragment(instructionNode, instructionArguments, instructionFixedSize), getInstructionNestedStructsFragment(instructionArguments), ], cs => cs.join('\n\n'), @@ -64,10 +71,13 @@ export function getInstructionPageFragment( ); } +/** + * Get the instruction `struct` fragment. The fragment includes the accounts and arguments + * as fields. + */ function getInstructionStructFragment( instructionNode: InstructionNode, instructionArguments: ParsedInstructionArgument[], - lifetime: string, ) { const accountsFragment = mergeFragments( instructionNode.accounts.map(account => { @@ -84,29 +94,34 @@ function getInstructionStructFragment( cs => cs.join('\n'), ); + const structLifetimes = getLifetimeDeclarations(instructionNode, instructionArguments); const argumentsFragment = mergeFragments( instructionArguments .filter(arg => !arg.resolvedDefaultValue) .map(arg => { const docs = getDocblockFragment(arg.docs ?? [], true); - return fragment`${docs}pub ${arg.displayName}: ${arg.manifest.type},`; + const lifetime = arg.lifetime ? `&'${arg.lifetime} ` : ''; + return fragment`${docs}pub ${arg.displayName}: ${lifetime}${arg.manifest.type},`; }), cs => cs.join('\n'), ); - return fragment`/// \`${snakeCase(instructionNode.name)}\` CPI helper. -pub struct ${pascalCase(instructionNode.name)}${lifetime} { + return fragment`/// Helper for cross-program invocations of \`${snakeCase(instructionNode.name)}\` instruction. +pub struct ${pascalCase(instructionNode.name)}${structLifetimes} { ${accountsFragment} ${argumentsFragment} }`; } +/** + * Get the instruction `impl` fragment. The fragment includes the `invoke` and `invoke_signed` methods. + */ function getInstructionImplFragment( instructionNode: InstructionNode, - _instructionArguments: ParsedInstructionArgument[], - lifetime: string, + instructionArguments: ParsedInstructionArgument[], + instructionFixedSize: number | null, ) { - const accountsFragment = mergeFragments( + const accountMetasFragment = mergeFragments( instructionNode.accounts.map(account => { const name = snakeCase(account.name); const isWritable = account.isWritable ? 'true' : 'false'; @@ -114,29 +129,64 @@ function getInstructionImplFragment( account.isSigner === 'either' ? fragment`self.${name}.0.key(), ${isWritable}, self.${name}.1` : fragment`self.${name}.key(), ${isWritable}, ${account.isSigner}`; - return fragment`pinocchio::instruction::AccountMeta::new(${accountMetaArguments}),`; + return fragment`AccountMeta::new(${accountMetaArguments}),`; + }), + cs => cs.join('\n'), + ); + + const accountsFragment = mergeFragments( + instructionNode.accounts.map(account => { + const name = snakeCase(account.name); + return fragment`&self.${name},`; }), cs => cs.join('\n'), ); - return fragment`impl${lifetime} ${pascalCase(instructionNode.name)}${lifetime} { + const instructionDataFragment = + instructionArguments.length > 0 + ? getInstructionDataFragment(instructionArguments, instructionFixedSize) + : fragment`let data = &[];`; + + const structLifetimes = getLifetimeDeclarations(instructionNode, instructionArguments, true); + + return addFragmentImports( + fragment`impl ${pascalCase(instructionNode.name)}${structLifetimes} { #[inline(always)] - pub fn invoke(&self) -> pinocchio::ProgramResult { + pub fn invoke(&self) -> ProgramResult { self.invoke_signed(&[]) } - pub fn invoke_signed(&self, _signers: &[pinocchio::instruction::Signer]) -> pinocchio::ProgramResult { + pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult { - // account metadata - let account_metas: [pinocchio::instruction::AccountMeta; {{ instruction.accounts.length }}] = [ - ${accountsFragment} + // account metas + let account_metas: [AccountMeta; ${instructionNode.accounts.length}] = [ + ${accountMetasFragment} ]; - Ok(()) + ${instructionDataFragment} + + let instruction = Instruction { + program_id: &crate::ID, + accounts: &account_metas, + data, + }; + + invoke_signed(&instruction, &[${accountsFragment}], signers) } -}`; +}`, + [ + 'pinocchio::cpi::invoke_signed', + 'pinocchio::instruction::Instruction', + 'pinocchio::instruction::AccountMeta', + 'pinocchio::ProgramResult', + 'pinocchio::instruction::Signer', + ], + ); } +/** + * Get the fragment for any nested `struct`s used in the instruction arguments. + */ function getInstructionNestedStructsFragment(instructionArguments: ParsedInstructionArgument[]): Fragment { return mergeFragments( instructionArguments.flatMap(arg => arg.manifest.nestedStructs), @@ -144,9 +194,80 @@ function getInstructionNestedStructsFragment(instructionArguments: ParsedInstruc ); } -type ParsedInstructionArgument = InstructionArgumentNode & { +/** + * Get the fragment that constructs the instruction data. There are several special cases + * to handle single argument instructions. + */ +function getInstructionDataFragment( + instructionArguments: ParsedInstructionArgument[], + instructionFixedSize: number | null, +): Fragment { + // When there is a single byte array or string (e.g., `&[u8]`, `&str`) argument, there is + // no need to copy the data into a fixed-size array. + if ( + instructionArguments.length === 1 && + (instructionArguments[0].type.kind === 'bytesTypeNode' || + instructionArguments[0].type.kind === 'stringTypeNode') + ) { + if (instructionArguments[0].defaultValue) { + return fragment`let data = ${ + instructionArguments[0].type.kind === 'stringTypeNode' + ? `${instructionArguments[0].defaultValue}.as_bytes()` + : `&${instructionArguments[0].defaultValue}` + };`; + } else { + return fragment`let data = self.${instructionArguments[0].displayName}${instructionArguments[0].type.kind === 'stringTypeNode' ? '.as_bytes()' : ''};`; + } + } + // When there is a single byte argument, the instruction data is a single-element byte array. + else if ( + instructionArguments.length === 1 && + instructionArguments[0].type.kind === 'numberTypeNode' && + instructionArguments[0].type.format === 'u8' + ) { + if (instructionArguments[0].defaultValue) { + return fragment`let data = &[${instructionArguments[0].defaultValue}${instructionArguments[0].type.format}];`; + } else { + return fragment`let data = &[self.${instructionArguments[0].displayName}];`; + } + } + // When there is a single number (e.g., `u16`, `u32`, `u64`) argument, the instruction data is the + // little-endian representation of the number. + else if (instructionArguments.length === 1 && instructionArguments[0].type.kind === 'numberTypeNode') { + if (instructionArguments[0].defaultValue) { + return fragment`let data = &${instructionArguments[0].resolvedDefaultValue}${instructionArguments[0].type.format}.to_le_bytes();`; + } else { + return fragment`let data = &self.${instructionArguments[0].displayName}.to_le_bytes();`; + } + } + // Handles any other case, which requires copying the data into a fixed-size array. + else { + const declareDataFragment = addFragmentImports( + fragment`let mut uninit_data = [UNINIT_BYTE; ${instructionFixedSize !== null ? instructionFixedSize : 0}];`, + ['super::UNINIT_BYTE', 'core::slice::from_raw_parts'], + ); + let offset = 0; + const assignDataContentFragment = mergeFragments( + instructionArguments.map(argument => { + const [fragment, updated] = visit( + argument.type, + getInstructionArgumentAssignmentVisitor(argument, offset), + ); + offset = updated; + return fragment; + }), + cs => cs.join('\n'), + ); + const transmuteData = fragment`let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, ${offset}) };`; + + return mergeFragments([declareDataFragment, assignDataContentFragment, transmuteData], cs => cs.join('\n')); + } +} + +export type ParsedInstructionArgument = InstructionArgumentNode & { displayName: SnakeCaseString; fixedSize: number | null; + lifetime: string | null; manifest: TypeManifest; resolvedDefaultValue: Fragment | null; resolvedInnerOptionType: Fragment | null; @@ -157,6 +278,7 @@ function getParsedInstructionArguments( accountsAndArgsConflicts: string[], scope: Pick, ): ParsedInstructionArgument[] { + const lifetimeIterator = getLifetimeIterator(instructionNode); const argumentVisitor = getTypeManifestVisitor({ ...scope, nestedStruct: true, @@ -164,12 +286,16 @@ function getParsedInstructionArguments( }); return instructionNode.arguments.map(argument => { + const fixedSize = visit(argument.type, scope.byteSizeVisitor); + const shouldUseLifetime = fixedSize === null || fixedSize > 8; + return { ...argument, displayName: accountsAndArgsConflicts.includes(argument.name) ? (`${snakeCase(argument.name)}_arg` as SnakeCaseString) : snakeCase(argument.name), - fixedSize: visit(argument.type, scope.byteSizeVisitor), + fixedSize, + lifetime: shouldUseLifetime ? lifetimeIterator.next().value : null, manifest: visit(argument.type, argumentVisitor), resolvedDefaultValue: !!argument.defaultValue && isNode(argument.defaultValue, VALUE_NODES) @@ -182,6 +308,31 @@ function getParsedInstructionArguments( }); } +function getLifetimeIterator(instructionNode: InstructionNode): Iterator { + // Start from 'b instead of 'a if we have accounts. + let lifetime = instructionNode.accounts.length > 0 ? 1 : 0; + return { + next: () => { + if (lifetime >= 26) { + throw new Error('Exceeded maximum number of lifetimes (26)'); + } + return { value: String.fromCharCode(97 + lifetime++), done: false }; + }, + }; +} + +function getLifetimeDeclarations( + instructionNode: InstructionNode, + instructionArguments: ParsedInstructionArgument[], + useUnderscore = false, +): string { + const lifetimes = [ + ...(instructionNode.accounts.length > 0 ? [useUnderscore ? `'_` : `'a`] : []), + ...instructionArguments.flatMap(arg => (arg.lifetime ? [useUnderscore ? `'_` : `'${arg.lifetime}`] : [])), + ]; + return lifetimes.length > 0 ? `<${lifetimes.join(', ')}>` : ''; +} + function getConflictsBetweenAccountsAndArguments(instructionNode: InstructionNode): string[] { const allNames = [ ...instructionNode.accounts.map(account => account.name), diff --git a/packages/renderers-rust-cpi/src/fragments/modPage.ts b/packages/renderers-rust-cpi/src/fragments/modPage.ts index 638a3a289..7d8a9b9b0 100644 --- a/packages/renderers-rust-cpi/src/fragments/modPage.ts +++ b/packages/renderers-rust-cpi/src/fragments/modPage.ts @@ -5,7 +5,15 @@ import { Fragment, fragment, getPageFragment, mergeFragments, RenderScope } from export function getModPageFragment( scope: Pick & { items: { name: CamelCaseString }[] }, ): Fragment | undefined { - const { items } = scope; + const imports = getModImportsFragment(scope.items); + if (!imports) return; + + return getPageFragment(imports, scope); +} + +export function getModImportsFragment( + items: { name: CamelCaseString }[], +): Fragment | undefined { if (items.length === 0) return; const sortedItems = items.slice().sort((a, b) => a.name.localeCompare(b.name)); @@ -18,8 +26,6 @@ export function getModPageFragment( cs => cs.join('\n'), ); - return getPageFragment( - mergeFragments([modStatements, useStatements], cs => cs.join('\n\n')), - scope, - ); + return mergeFragments([modStatements, useStatements], cs => cs.join('\n\n')) + } diff --git a/packages/renderers-rust-cpi/src/visitors/getInstructionArgumentAssignmentVisitor.ts b/packages/renderers-rust-cpi/src/visitors/getInstructionArgumentAssignmentVisitor.ts new file mode 100644 index 000000000..485698598 --- /dev/null +++ b/packages/renderers-rust-cpi/src/visitors/getInstructionArgumentAssignmentVisitor.ts @@ -0,0 +1,150 @@ +import { CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, CodamaError } from '@codama/errors'; +import { REGISTERED_TYPE_NODE_KINDS } from '@codama/nodes'; +import { extendVisitor, pipe, staticVisitor, visit } from '@codama/visitors-core'; + +import { addFragmentImports, Fragment, fragment } from '../utils'; +import type { ParsedInstructionArgument } from '../fragments'; + +export function getInstructionArgumentAssignmentVisitor(argument: ParsedInstructionArgument, offset: number) { + return pipe( + staticVisitor((): [Fragment, number] => [fragment``, 0], { + keys: [...REGISTERED_TYPE_NODE_KINDS, 'definedTypeLinkNode'], + }), + v => + extendVisitor(v, { + visitDefinedTypeLink() { + return [fragment``, 0]; + }, + + visitArrayType() { + return [fragment``, 0]; + }, + + visitBooleanType() { + return [fragment``, 0]; + }, + + visitBytesType() { + return [fragment``, 0]; + }, + + visitEnumEmptyVariantType() { + return [fragment``, 0]; + }, + + visitEnumStructVariantType() { + return [fragment``, 0]; + }, + + visitEnumTupleVariantType() { + return [fragment``, 0]; + }, + + visitEnumType() { + return [fragment``, 0]; + }, + + visitFixedSizeType(fixedSizeType, { self }) { + if (fixedSizeType.type.kind === 'bytesTypeNode') { + let value: Fragment; + if (argument.defaultValue) { + value = fragment`&${argument.resolvedDefaultValue}`; + } else { + value = fragment`self.${argument.displayName}.as_ref()`; + } + return [ + addFragmentImports( + fragment`write_bytes(&mut uninit_data[${offset}..${offset + argument.fixedSize!}], ${value});`, + ['super::write_bytes'], + ), + offset + argument.fixedSize!, + ]; + } + + return visit(fixedSizeType.type, self); + }, + + visitMapType() { + return [fragment``, 0]; + }, + + visitNumberType(numberType) { + if (numberType.format === 'u8') { + let value: Fragment; + if (argument.defaultValue) { + value = fragment`${argument.resolvedDefaultValue}`; + } else { + value = fragment`self.${argument.displayName}`; + } + return [fragment`uninit_data[${offset}] = ${value};`, offset + 1]; + } else { + let value: Fragment; + if (argument.defaultValue) { + value = fragment`${argument.resolvedDefaultValue}${numberType.format}`; + } else { + value = fragment`self.${argument.displayName}`; + } + return [ + addFragmentImports( + fragment`write_bytes(&mut uninit_data[${offset}..${offset + argument.fixedSize!}], &${value}.to_le_bytes());`, + ['super::write_bytes'], + ), + offset + argument.fixedSize!, + ]; + } + }, + + visitOptionType() { + return [fragment``, 0]; + }, + + visitPublicKeyType() { + let value: Fragment; + if (argument.defaultValue) { + value = fragment`${argument.resolvedDefaultValue}`; + } else { + value = fragment`self.${argument.displayName}`; + } + return [ + addFragmentImports( + fragment`write_bytes(&mut uninit_data[${offset}..${offset + argument.fixedSize!}], ${value}.as_ref());`, + ['super::write_bytes'], + ), + offset + argument.fixedSize!, + ]; + }, + + visitRemainderOptionType(node) { + throw new CodamaError(CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, { kind: node.kind, node }); + }, + + visitSetType() { + return [fragment``, 0]; + }, + + visitSizePrefixType() { + return [fragment``, 0]; + }, + + visitStringType() { + return [fragment``, 0]; + }, + + visitStructFieldType() { + return [fragment``, 0]; + }, + + visitStructType() { + return [fragment``, 0]; + }, + + visitTupleType() { + return [fragment``, 0]; + }, + + visitZeroableOptionType(node) { + throw new CodamaError(CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, { kind: node.kind, node }); + }, + }), + ); +} diff --git a/packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts b/packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts index 386594e73..83d921b05 100644 --- a/packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts +++ b/packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts @@ -14,12 +14,12 @@ import { import { getInstructionPageFragment, - getModPageFragment, getProgramModPageFragment, getRootModPageFragment, } from '../fragments'; import { getImportFromFactory, GetRenderMapOptions, getTraitsFromNodeFactory, RenderScope } from '../utils'; import { getTypeManifestVisitor } from './getTypeManifestVisitor'; +import { getInstructionModPageFragment } from '../fragments/instructionModPage'; export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const linkables = new LinkableDictionary(); @@ -73,7 +73,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const rootMod = getRootModPageFragment(scope); const programsMod = getProgramModPageFragment(scope); - const instructionsMod = getModPageFragment({ ...renderScope, items: instructionsToExport }); + const instructionsMod = getInstructionModPageFragment({ ...renderScope, instructions: instructionsToExport }); return mergeRenderMaps([ // mod.rs diff --git a/packages/renderers-rust-cpi/src/visitors/index.ts b/packages/renderers-rust-cpi/src/visitors/index.ts index 4f77dda46..b94ed0bd1 100644 --- a/packages/renderers-rust-cpi/src/visitors/index.ts +++ b/packages/renderers-rust-cpi/src/visitors/index.ts @@ -1,4 +1,6 @@ +export * from './getInstructionArgumentAssignmentVisitor'; export * from './getRenderMapVisitor'; export * from './getTypeManifestVisitor'; export * from './renderValueNodeVisitor'; export * from './renderVisitor'; + diff --git a/packages/renderers-rust-cpi/test/definedTypesPage.test.ts b/packages/renderers-rust-cpi/test/definedTypesPage.test.ts deleted file mode 100644 index e34e51339..000000000 --- a/packages/renderers-rust-cpi/test/definedTypesPage.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { - definedTypeNode, - enumEmptyVariantTypeNode, - enumStructVariantTypeNode, - enumTypeNode, - numberTypeNode, - programNode, - sizePrefixTypeNode, - stringTypeNode, - structFieldTypeNode, - structTypeNode, -} from '@codama/nodes'; -import { visit } from '@codama/visitors-core'; -import { test } from 'vitest'; - -import { getRenderMapVisitor } from '../src'; -import { codeContains, codeDoesNotContains } from './_setup'; -import { getFromRenderMap } from '@codama/renderers-core'; - -test('it renders a prefix string on a defined type', () => { - // Given the following program with 1 defined type using a prefixed size string. - const node = programNode({ - definedTypes: [ - definedTypeNode({ - name: 'blob', - type: structTypeNode([ - structFieldTypeNode({ - name: 'contentType', - type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u8')), - }), - ]), - }), - ], - name: 'splToken', - publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', - }); - - // When we render it. - const renderMap = visit(node, getRenderMapVisitor()); - - // Then we expect the following use and identifier to be rendered. - codeContains(getFromRenderMap(renderMap, 'types/blob.rs'), [ - `use kaigan::types::U8PrefixString;`, - `content_type: U8PrefixString,`, - ]); -}); - -test('it renders a scalar enum with Copy derive', () => { - // Given the following program with 1 defined type using a prefixed size string. - const node = programNode({ - definedTypes: [ - definedTypeNode({ - name: 'tag', - type: enumTypeNode([enumEmptyVariantTypeNode('Uninitialized'), enumEmptyVariantTypeNode('Account')]), - }), - ], - name: 'splToken', - publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', - }); - - // When we render it. - const renderMap = visit(node, getRenderMapVisitor()); - - // Then we expect the following use and identifier to be rendered. - codeContains(getFromRenderMap(renderMap, 'types/tag.rs'), [`#[derive(`, `Copy`, `pub enum Tag`]); -}); - -test('it renders a non-scalar enum without Copy derive', () => { - // Given the following program with 1 defined type using a prefixed size string. - const node = programNode({ - definedTypes: [ - definedTypeNode({ - name: 'tagWithStruct', - type: enumTypeNode([ - enumEmptyVariantTypeNode('Uninitialized'), - enumStructVariantTypeNode( - 'Account', - structTypeNode([ - structFieldTypeNode({ - name: 'contentType', - type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u8')), - }), - ]), - ), - ]), - }), - ], - name: 'splToken', - publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', - }); - - // When we render it. - const renderMap = visit(node, getRenderMapVisitor()); - - // Then we expect the following use and identifier to be rendered. - codeContains(getFromRenderMap(renderMap, 'types/tag_with_struct.rs'), [`#[derive(`, `pub enum TagWithStruct`]); - // And we expect the Copy derive to be missing. - codeDoesNotContains(getFromRenderMap(renderMap, 'types/tag_with_struct.rs'), `Copy`); -}); diff --git a/packages/renderers-rust-cpi/test/instructionsPage.test.ts b/packages/renderers-rust-cpi/test/instructionsPage.test.ts deleted file mode 100644 index e27658103..000000000 --- a/packages/renderers-rust-cpi/test/instructionsPage.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { instructionNode, programNode } from '@codama/nodes'; -import { visit } from '@codama/visitors-core'; -import { test } from 'vitest'; - -import { getRenderMapVisitor } from '../src'; -import { codeContains } from './_setup'; -import { getFromRenderMap } from '@codama/renderers-core'; - -test('it renders a public instruction data struct', () => { - // Given the following program with 1 instruction. - const node = programNode({ - instructions: [instructionNode({ name: 'mintTokens' })], - name: 'splToken', - publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', - }); - - // When we render it. - const renderMap = visit(node, getRenderMapVisitor()); - - // Then we expect the following pub struct. - codeContains(getFromRenderMap(renderMap, 'instructions/mint_tokens.rs'), [ - `pub struct MintTokensInstructionData`, - `pub fn new(`, - ]); -}); diff --git a/packages/renderers-rust-cpi/test/types/number.test.ts b/packages/renderers-rust-cpi/test/types/number.test.ts deleted file mode 100644 index e53c1136b..000000000 --- a/packages/renderers-rust-cpi/test/types/number.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { definedTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode } from '@codama/nodes'; -import { visit } from '@codama/visitors-core'; -import { test } from 'vitest'; - -import { getRenderMapVisitor } from '../../src'; -import { codeContains, codeDoesNotContains } from '../_setup'; - -test('it exports short u16 numbers', () => { - // Given a shortU16 number. - const node = definedTypeNode({ - name: 'myShortU16', - type: numberTypeNode('shortU16'), - }); - - // When we render the number. - const renderMap = visit(node, getRenderMapVisitor()); - - // Then we expect a short u16 to be exported. - codeContains(renderMap.get('types/my_short_u16.rs'), [ - /pub type MyShortU16 = ShortU16/, - /use solana_program::short_vec::ShortU16/, - ]); - codeDoesNotContains(renderMap.get('types/my_short_u16.rs'), [ - /use borsh::BorshSerialize/, - /use borsh::BorshDeserialize/, - ]); -}); - -test('it exports short u16 numbers as struct fields', () => { - // Given a shortU16 number. - const node = definedTypeNode({ - name: 'myShortU16', - type: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('shortU16') })]), - }); - - // When we render the number. - const renderMap = visit(node, getRenderMapVisitor()); - - // Then we expect a short u16 to be exported as a struct field. - codeContains(renderMap.get('types/my_short_u16.rs'), [ - /pub value: ShortU16/, - /use solana_program::short_vec::ShortU16/, - ]); -}); diff --git a/packages/renderers-rust-cpi/test/utils/traitOptions.test.ts b/packages/renderers-rust-cpi/test/utils/traitOptions.test.ts index 82bc8d792..2ae52154b 100644 --- a/packages/renderers-rust-cpi/test/utils/traitOptions.test.ts +++ b/packages/renderers-rust-cpi/test/utils/traitOptions.test.ts @@ -27,10 +27,10 @@ describe('default values', () => { }); // When we get the traits from the node using the default options. - const { render, imports } = getTraitsFromNode(node); + const { content, imports } = getTraitsFromNode(node); // Then we expect the following traits to be rendered. - expect(render).toBe( + expect(content).toBe( `#[derive(Clone, Debug, Eq, PartialEq)]\n` + `#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]\n` + `#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]\n`, @@ -48,10 +48,10 @@ describe('default values', () => { }); // When we get the traits from the node using the default options. - const { render, imports } = getTraitsFromNode(node); + const { content, imports } = getTraitsFromNode(node); // Then we expect the following traits to be rendered. - expect(render).toBe( + expect(content).toBe( `#[derive(Clone, Debug, Eq, PartialEq, Copy, PartialOrd, Hash, FromPrimitive)]\n` + `#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]\n` + `#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]\n`, @@ -72,10 +72,10 @@ describe('default values', () => { }); // When we get the traits from the node using the default options. - const { render, imports } = getTraitsFromNode(node); + const { content, imports } = getTraitsFromNode(node); // Then we expect the following traits to be rendered. - expect(render).toBe( + expect(content).toBe( `#[derive(Clone, Debug, Eq, PartialEq)]\n` + `#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]\n` + `#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]\n`, @@ -97,12 +97,12 @@ describe('default values', () => { // When we get the traits from the node using the // default options with the overrides attribute. - const { render, imports } = getTraitsFromNode(node, { + const { content, imports } = getTraitsFromNode(node, { overrides: { coordinates: ['My', 'special::Traits'] }, }); // Then we expect the following traits to be rendered. - expect(render).toBe(`#[derive(My, Traits)]\n`); + expect(content).toBe(`#[derive(My, Traits)]\n`); // And the following imports to be used. expect([...imports.imports]).toStrictEqual(['special::Traits']); @@ -120,12 +120,12 @@ describe('default values', () => { // When we get the traits from the node using custom traits // such that some are part of the feature flag defaults. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { overrides: { coordinates: ['My', 'special::Traits', 'serde::Serialize'] }, }); // Then we expect the following traits to be rendered. - expect(render).toBe(`#[derive(My, Traits)]\n#[cfg_attr(feature = "serde", derive(serde::Serialize))]\n`); + expect(content).toBe(`#[derive(My, Traits)]\n#[cfg_attr(feature = "serde", derive(serde::Serialize))]\n`); }); }); @@ -154,14 +154,14 @@ describe('base traits', () => { }); // When we get the traits from the node using custom base and data enum defaults. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { ...RESET_OPTIONS, baseDefaults: ['MyBaseTrait'], dataEnumDefaults: ['MyDataEnumTrait'], }); // Then we expect both the base and data enum traits to be rendered. - expect(render).toBe(`#[derive(MyBaseTrait, MyDataEnumTrait)]\n`); + expect(content).toBe(`#[derive(MyBaseTrait, MyDataEnumTrait)]\n`); }); test('it uses both the base and scalar enum traits', () => { @@ -172,14 +172,14 @@ describe('base traits', () => { }); // When we get the traits from the node using custom base and scalar enum defaults. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { ...RESET_OPTIONS, baseDefaults: ['MyBaseTrait'], scalarEnumDefaults: ['MyScalarEnumTrait'], }); // Then we expect both the base and scalar enum traits to be rendered. - expect(render).toBe(`#[derive(MyBaseTrait, MyScalarEnumTrait)]\n`); + expect(content).toBe(`#[derive(MyBaseTrait, MyScalarEnumTrait)]\n`); }); test('it uses both the base and struct traits', () => { @@ -193,14 +193,14 @@ describe('base traits', () => { }); // When we get the traits from the node using custom base and struct defaults. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { ...RESET_OPTIONS, baseDefaults: ['MyBaseTrait'], structDefaults: ['MyStructTrait'], }); // Then we expect both the base and struct traits to be rendered. - expect(render).toBe(`#[derive(MyBaseTrait, MyStructTrait)]\n`); + expect(content).toBe(`#[derive(MyBaseTrait, MyStructTrait)]\n`); }); test('it never uses traits for type aliases', () => { @@ -211,13 +211,13 @@ describe('base traits', () => { }); // When we get the traits from the node such that we have base defaults. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { ...RESET_OPTIONS, baseDefaults: ['MyBaseTrait'], }); // Then we expect no traits to be rendered. - expect(render).toBe(''); + expect(content).toBe(''); }); test('it identifies feature flags under all default traits', () => { @@ -230,7 +230,7 @@ describe('base traits', () => { // When we get the traits from the node such that: // - We provide custom base and scalar enum defaults. // - We provide custom feature flags for traits in both categories. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { ...RESET_OPTIONS, baseDefaults: ['MyBaseTrait', 'MyNonFeatureTrait'], featureFlags: { @@ -241,7 +241,7 @@ describe('base traits', () => { }); // Then we expect both the base and enum traits to be rendered as separate feature flags. - expect(render).toBe( + expect(content).toBe( `#[derive(MyNonFeatureTrait)]\n` + `#[cfg_attr(feature = "base", derive(MyBaseTrait))]\n` + `#[cfg_attr(feature = "enum", derive(MyScalarEnumTrait))]\n`, @@ -257,7 +257,7 @@ describe('base traits', () => { // When we get the traits from the node such that // all traits are under feature flags. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { ...RESET_OPTIONS, baseDefaults: ['MyBaseTrait'], featureFlags: { @@ -268,7 +268,7 @@ describe('base traits', () => { }); // Then we expect the following traits to be rendered. - expect(render).toBe( + expect(content).toBe( `#[cfg_attr(feature = "base", derive(MyBaseTrait))]\n#[cfg_attr(feature = "enum", derive(MyScalarEnumTrait))]\n`, ); }); @@ -285,7 +285,7 @@ describe('overridden traits', () => { // When we get the traits from the node such that: // - We provide custom base and enum defaults. // - We override the feedback type with custom traits. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { ...RESET_OPTIONS, baseDefaults: ['MyBaseTrait'], overrides: { feedback: ['MyFeedbackTrait'] }, @@ -293,7 +293,7 @@ describe('overridden traits', () => { }); // Then we expect only the feedback traits to be rendered. - expect(render).toBe(`#[derive(MyFeedbackTrait)]\n`); + expect(content).toBe(`#[derive(MyFeedbackTrait)]\n`); }); test('it finds traits to override when using pascal case', () => { @@ -305,13 +305,13 @@ describe('overridden traits', () => { // When we get the traits from the node such that // we use PascalCase for the type name. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { ...RESET_OPTIONS, overrides: { Feedback: ['MyFeedbackTrait'] }, }); // Then we still expect the custom feedback traits to be rendered. - expect(render).toBe(`#[derive(MyFeedbackTrait)]\n`); + expect(content).toBe(`#[derive(MyFeedbackTrait)]\n`); }); test('it identifies feature flags under all overridden traits', () => { @@ -324,14 +324,14 @@ describe('overridden traits', () => { // When we get the traits from the node such that: // - We override the feedback type with custom traits. // - We provide custom feature flags for these some of these custom traits. - const { render } = getTraitsFromNode(node, { + const { content } = getTraitsFromNode(node, { ...RESET_OPTIONS, featureFlags: { custom: ['MyFeedbackTrait'] }, overrides: { feedback: ['MyFeedbackTrait', 'MyNonFeatureTrait'] }, }); // Then we expect some of the overridden traits to be rendered under feature flags. - expect(render).toBe(`#[derive(MyNonFeatureTrait)]\n#[cfg_attr(feature = "custom", derive(MyFeedbackTrait))]\n`); + expect(content).toBe(`#[derive(MyNonFeatureTrait)]\n#[cfg_attr(feature = "custom", derive(MyFeedbackTrait))]\n`); }); }); @@ -344,14 +344,14 @@ describe('fully qualified name traits', () => { }); // When we get the traits from the node such that we use fully qualified names. - const { render, imports } = getTraitsFromNode(node, { + const { content, imports } = getTraitsFromNode(node, { ...RESET_OPTIONS, baseDefaults: ['fruits::Apple', 'fruits::Banana', 'vegetables::Carrot'], useFullyQualifiedName: true, }); // Then we expect the fully qualified names to be used for the traits. - expect(render).toBe(`#[derive(fruits::Apple, fruits::Banana, vegetables::Carrot)]\n`); + expect(content).toBe(`#[derive(fruits::Apple, fruits::Banana, vegetables::Carrot)]\n`); // And no imports should be used. expect([...imports.imports]).toStrictEqual([]); From ce117fc5486c46fcc6beda781af9ee705f42b5fb Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 9 Sep 2025 15:36:44 +0100 Subject: [PATCH 15/24] Update code to match main branch --- .../src/fragments/instructionModPage.ts | 3 +- .../src/fragments/instructionPage.ts | 22 ++++++------ .../renderers-rust-cpi/src/utils/fragment.ts | 19 +--------- ...getInstructionArgumentAssignmentVisitor.ts | 14 ++++---- .../src/visitors/getRenderMapVisitor.ts | 35 ++++++++----------- 5 files changed, 35 insertions(+), 58 deletions(-) diff --git a/packages/renderers-rust-cpi/src/fragments/instructionModPage.ts b/packages/renderers-rust-cpi/src/fragments/instructionModPage.ts index 309bedd38..be933ef55 100644 --- a/packages/renderers-rust-cpi/src/fragments/instructionModPage.ts +++ b/packages/renderers-rust-cpi/src/fragments/instructionModPage.ts @@ -1,5 +1,6 @@ import { InstructionNode } from '@codama/nodes'; -import { addFragmentImports, fragment, Fragment, getPageFragment, mergeFragments, RenderScope } from '../utils'; + +import { addFragmentImports, Fragment, fragment, getPageFragment, mergeFragments, RenderScope } from '../utils'; import { getModImportsFragment } from './modPage'; /** diff --git a/packages/renderers-rust-cpi/src/fragments/instructionPage.ts b/packages/renderers-rust-cpi/src/fragments/instructionPage.ts index 531b4f1ae..eee538664 100644 --- a/packages/renderers-rust-cpi/src/fragments/instructionPage.ts +++ b/packages/renderers-rust-cpi/src/fragments/instructionPage.ts @@ -19,9 +19,9 @@ import { mergeFragments, RenderScope, } from '../utils'; +import { getInstructionArgumentAssignmentVisitor } from '../visitors'; import { getTypeManifestVisitor, TypeManifest } from '../visitors/getTypeManifestVisitor'; import { renderValueNode } from '../visitors/renderValueNodeVisitor'; -import { getInstructionArgumentAssignmentVisitor } from '../visitors'; /** * Get the instruction page fragment. @@ -206,23 +206,23 @@ function getInstructionDataFragment( // no need to copy the data into a fixed-size array. if ( instructionArguments.length === 1 && - (instructionArguments[0].type.kind === 'bytesTypeNode' || - instructionArguments[0].type.kind === 'stringTypeNode') + isNode(instructionArguments[0].type, ['bytesTypeNode', 'stringTypeNode']) ) { if (instructionArguments[0].defaultValue) { return fragment`let data = ${ - instructionArguments[0].type.kind === 'stringTypeNode' - ? `${instructionArguments[0].defaultValue}.as_bytes()` - : `&${instructionArguments[0].defaultValue}` + isNode(instructionArguments[0].type, 'stringTypeNode') + ? fragment`${instructionArguments[0].resolvedDefaultValue}.as_bytes()` + : fragment`&${instructionArguments[0].resolvedDefaultValue}` };`; } else { - return fragment`let data = self.${instructionArguments[0].displayName}${instructionArguments[0].type.kind === 'stringTypeNode' ? '.as_bytes()' : ''};`; + const asBytes = isNode(instructionArguments[0].type, 'stringTypeNode') ? '.as_bytes()' : ''; + return fragment`let data = self.${instructionArguments[0].displayName}${asBytes};`; } } // When there is a single byte argument, the instruction data is a single-element byte array. else if ( instructionArguments.length === 1 && - instructionArguments[0].type.kind === 'numberTypeNode' && + isNode(instructionArguments[0].type, 'numberTypeNode') && instructionArguments[0].type.format === 'u8' ) { if (instructionArguments[0].defaultValue) { @@ -233,7 +233,7 @@ function getInstructionDataFragment( } // When there is a single number (e.g., `u16`, `u32`, `u64`) argument, the instruction data is the // little-endian representation of the number. - else if (instructionArguments.length === 1 && instructionArguments[0].type.kind === 'numberTypeNode') { + else if (instructionArguments.length === 1 && isNode(instructionArguments[0].type, 'numberTypeNode')) { if (instructionArguments[0].defaultValue) { return fragment`let data = &${instructionArguments[0].resolvedDefaultValue}${instructionArguments[0].type.format}.to_le_bytes();`; } else { @@ -308,7 +308,7 @@ function getParsedInstructionArguments( }); } -function getLifetimeIterator(instructionNode: InstructionNode): Iterator { +function getLifetimeIterator(instructionNode: InstructionNode): Iterator { // Start from 'b instead of 'a if we have accounts. let lifetime = instructionNode.accounts.length > 0 ? 1 : 0; return { @@ -316,7 +316,7 @@ function getLifetimeIterator(instructionNode: InstructionNode): Iterator if (lifetime >= 26) { throw new Error('Exceeded maximum number of lifetimes (26)'); } - return { value: String.fromCharCode(97 + lifetime++), done: false }; + return { done: false, value: String.fromCharCode(97 + lifetime++) }; }, }; } diff --git a/packages/renderers-rust-cpi/src/utils/fragment.ts b/packages/renderers-rust-cpi/src/utils/fragment.ts index 6034e5889..acc7b0f43 100644 --- a/packages/renderers-rust-cpi/src/utils/fragment.ts +++ b/packages/renderers-rust-cpi/src/utils/fragment.ts @@ -1,5 +1,5 @@ import { Docs } from '@codama/nodes'; -import { BaseFragment } from '@codama/renderers-core'; +import { BaseFragment, createFragmentTemplate } from '@codama/renderers-core'; import { ImportMap } from './importMap'; import { RenderScope } from './options'; @@ -63,20 +63,3 @@ export function getPageFragment(page: Fragment, scope: Pick cs.join('\n\n')); } - -// TODO: Will be part of renderers-core soon. -function createFragmentTemplate( - template: TemplateStringsArray, - items: unknown[], - isFragment: (value: unknown) => value is TFragment, - mergeFragments: (fragments: TFragment[], mergeContent: (contents: string[]) => string) => TFragment, -): TFragment { - const fragments = items.filter(isFragment); - const zippedItems = items.map((item, i) => { - const itemPrefix = template[i]; - if (typeof item === 'undefined') return itemPrefix; - if (isFragment(item)) return itemPrefix + item.content; - return itemPrefix + String(item); - }); - return mergeFragments(fragments, () => zippedItems.join('') + template[template.length - 1]); -} diff --git a/packages/renderers-rust-cpi/src/visitors/getInstructionArgumentAssignmentVisitor.ts b/packages/renderers-rust-cpi/src/visitors/getInstructionArgumentAssignmentVisitor.ts index 485698598..7de8cfd16 100644 --- a/packages/renderers-rust-cpi/src/visitors/getInstructionArgumentAssignmentVisitor.ts +++ b/packages/renderers-rust-cpi/src/visitors/getInstructionArgumentAssignmentVisitor.ts @@ -1,9 +1,9 @@ import { CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, CodamaError } from '@codama/errors'; -import { REGISTERED_TYPE_NODE_KINDS } from '@codama/nodes'; +import { isNode, REGISTERED_TYPE_NODE_KINDS } from '@codama/nodes'; import { extendVisitor, pipe, staticVisitor, visit } from '@codama/visitors-core'; -import { addFragmentImports, Fragment, fragment } from '../utils'; import type { ParsedInstructionArgument } from '../fragments'; +import { addFragmentImports, Fragment, fragment } from '../utils'; export function getInstructionArgumentAssignmentVisitor(argument: ParsedInstructionArgument, offset: number) { return pipe( @@ -12,10 +12,6 @@ export function getInstructionArgumentAssignmentVisitor(argument: ParsedInstruct }), v => extendVisitor(v, { - visitDefinedTypeLink() { - return [fragment``, 0]; - }, - visitArrayType() { return [fragment``, 0]; }, @@ -28,6 +24,10 @@ export function getInstructionArgumentAssignmentVisitor(argument: ParsedInstruct return [fragment``, 0]; }, + visitDefinedTypeLink() { + return [fragment``, 0]; + }, + visitEnumEmptyVariantType() { return [fragment``, 0]; }, @@ -45,7 +45,7 @@ export function getInstructionArgumentAssignmentVisitor(argument: ParsedInstruct }, visitFixedSizeType(fixedSizeType, { self }) { - if (fixedSizeType.type.kind === 'bytesTypeNode') { + if (isNode(fixedSizeType.type, 'stringTypeNode')) { let value: Fragment; if (argument.defaultValue) { value = fragment`&${argument.resolvedDefaultValue}`; diff --git a/packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts b/packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts index 83d921b05..1582c8505 100644 --- a/packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts +++ b/packages/renderers-rust-cpi/src/visitors/getRenderMapVisitor.ts @@ -1,5 +1,5 @@ import { getAllInstructionsWithSubs, getAllPrograms, snakeCase } from '@codama/nodes'; -import { fragmentToRenderMap, mergeRenderMaps, renderMap } from '@codama/renderers-core'; +import { createRenderMap, mergeRenderMaps } from '@codama/renderers-core'; import { extendVisitor, getByteSizeVisitor, @@ -12,14 +12,10 @@ import { visit, } from '@codama/visitors-core'; -import { - getInstructionPageFragment, - getProgramModPageFragment, - getRootModPageFragment, -} from '../fragments'; +import { getInstructionPageFragment, getProgramModPageFragment, getRootModPageFragment } from '../fragments'; +import { getInstructionModPageFragment } from '../fragments/instructionModPage'; import { getImportFromFactory, GetRenderMapOptions, getTraitsFromNodeFactory, RenderScope } from '../utils'; import { getTypeManifestVisitor } from './getTypeManifestVisitor'; -import { getInstructionModPageFragment } from '../fragments/instructionModPage'; export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const linkables = new LinkableDictionary(); @@ -43,16 +39,16 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { }; return pipe( - staticVisitor(() => renderMap(), { + staticVisitor(() => createRenderMap(), { keys: ['rootNode', 'programNode', 'instructionNode', 'accountNode', 'definedTypeNode'], }), v => extendVisitor(v, { visitInstruction(node) { const instructionPath = stack.getPath('instructionNode'); - return fragmentToRenderMap( - getInstructionPageFragment({ ...renderScope, instructionPath }), + return createRenderMap( `instructions/${snakeCase(node.name)}.rs`, + getInstructionPageFragment({ ...renderScope, instructionPath }), ); }, @@ -71,18 +67,15 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { }); const scope = { ...renderScope, instructionsToExport, programsToExport }; - const rootMod = getRootModPageFragment(scope); - const programsMod = getProgramModPageFragment(scope); - const instructionsMod = getInstructionModPageFragment({ ...renderScope, instructions: instructionsToExport }); - return mergeRenderMaps([ - // mod.rs - ...(rootMod ? [fragmentToRenderMap(rootMod, 'mod.rs')] : []), - // programs/mod.rs - ...(programsMod ? [fragmentToRenderMap(programsMod, 'programs/mod.rs')] : []), - // instructions/mod.rs - ...(instructionsMod ? [fragmentToRenderMap(instructionsMod, 'instructions/mod.rs')] : []), - // Rest of the generated content. + createRenderMap({ + ['instructions/mod.rs']: getInstructionModPageFragment({ + ...renderScope, + instructions: instructionsToExport, + }), + ['mod.rs']: getRootModPageFragment(scope), + ['programs/mod.rs']: getProgramModPageFragment(scope), + }), ...programsToExport.map(p => visit(p, self)), ]); }, From 5275bb77b20d1c9c26981e7a090715bd1bdca179 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 9 Sep 2025 15:36:58 +0100 Subject: [PATCH 16/24] Regenerate code from previous changes --- .../e2e/dummy/src/generated/instructions/instruction1.rs | 2 +- .../e2e/dummy/src/generated/instructions/instruction2.rs | 2 +- .../e2e/dummy/src/generated/instructions/instruction3.rs | 2 +- .../e2e/dummy/src/generated/instructions/instruction4.rs | 2 +- .../e2e/dummy/src/generated/instructions/instruction5.rs | 2 +- .../e2e/dummy/src/generated/instructions/instruction6.rs | 2 +- .../e2e/dummy/src/generated/instructions/instruction7.rs | 2 +- .../e2e/memo/src/generated/instructions/add_memo.rs | 2 +- .../system/src/generated/instructions/advance_nonce_account.rs | 2 +- .../e2e/system/src/generated/instructions/allocate.rs | 2 +- .../e2e/system/src/generated/instructions/allocate_with_seed.rs | 2 +- .../e2e/system/src/generated/instructions/assign.rs | 2 +- .../e2e/system/src/generated/instructions/assign_with_seed.rs | 2 +- .../src/generated/instructions/authorize_nonce_account.rs | 2 +- .../e2e/system/src/generated/instructions/create_account.rs | 2 +- .../src/generated/instructions/create_account_with_seed.rs | 2 +- .../src/generated/instructions/initialize_nonce_account.rs | 2 +- .../e2e/system/src/generated/instructions/transfer_sol.rs | 2 +- .../system/src/generated/instructions/transfer_sol_with_seed.rs | 2 +- .../system/src/generated/instructions/upgrade_nonce_account.rs | 2 +- .../system/src/generated/instructions/withdraw_nonce_account.rs | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs index 632283f20..1afb94408 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs @@ -10,7 +10,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `instruction1` CPI helper. +/// Helper for cross-program invocations of `instruction1` instruction. pub struct Instruction1 {} impl Instruction1 { diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs index e8564d41b..3d69c5ab4 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs @@ -10,7 +10,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `instruction2` CPI helper. +/// Helper for cross-program invocations of `instruction2` instruction. pub struct Instruction2 {} impl Instruction2 { diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs index bb3d4cdf8..934d0e302 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs @@ -10,7 +10,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `instruction3` CPI helper. +/// Helper for cross-program invocations of `instruction3` instruction. pub struct Instruction3 {} impl Instruction3 { diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs index 50d028b64..445781343 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs @@ -10,7 +10,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `instruction4` CPI helper. +/// Helper for cross-program invocations of `instruction4` instruction. pub struct Instruction4 { pub my_argument: u64, } diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs index a5de40d9a..1bba2e820 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs @@ -10,7 +10,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `instruction5` CPI helper. +/// Helper for cross-program invocations of `instruction5` instruction. pub struct Instruction5 {} impl Instruction5 { diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs index ac9472a40..5c030f402 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs @@ -11,7 +11,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `instruction6` CPI helper. +/// Helper for cross-program invocations of `instruction6` instruction. pub struct Instruction6<'a> { pub my_account: &'a AccountInfo, } diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs index 249dfd46c..244697f7b 100644 --- a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs +++ b/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs @@ -11,7 +11,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `instruction7` CPI helper. +/// Helper for cross-program invocations of `instruction7` instruction. pub struct Instruction7<'a> { pub my_account: Option<&'a AccountInfo>, } diff --git a/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs b/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs index e0853887e..edb7c16dc 100644 --- a/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs +++ b/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs @@ -10,7 +10,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `add_memo` CPI helper. +/// Helper for cross-program invocations of `add_memo` instruction. pub struct AddMemo<'a> { pub memo: &'a str, } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs index cb8e7a39b..448d2a03d 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs @@ -11,7 +11,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `advance_nonce_account` CPI helper. +/// Helper for cross-program invocations of `advance_nonce_account` instruction. pub struct AdvanceNonceAccount<'a> { pub nonce_account: &'a AccountInfo, pub recent_blockhashes_sysvar: &'a AccountInfo, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs index 450173c6a..7b7da8c88 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs @@ -14,7 +14,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `allocate` CPI helper. +/// Helper for cross-program invocations of `allocate` instruction. pub struct Allocate<'a> { pub new_account: &'a AccountInfo, pub space: u64, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs index e0a867347..bb0e1cd80 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs @@ -15,7 +15,7 @@ use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; use pinocchio::ProgramResult; -/// `allocate_with_seed` CPI helper. +/// Helper for cross-program invocations of `allocate_with_seed` instruction. pub struct AllocateWithSeed<'a, 'b, 'c, 'd> { pub new_account: &'a AccountInfo, pub base_account: &'a AccountInfo, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs index 0d30d0f42..6270e9c15 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs @@ -15,7 +15,7 @@ use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; use pinocchio::ProgramResult; -/// `assign` CPI helper. +/// Helper for cross-program invocations of `assign` instruction. pub struct Assign<'a, 'b> { pub account: &'a AccountInfo, pub program_address: &'b Pubkey, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs index 161ebd9f7..aff297080 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs @@ -15,7 +15,7 @@ use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; use pinocchio::ProgramResult; -/// `assign_with_seed` CPI helper. +/// Helper for cross-program invocations of `assign_with_seed` instruction. pub struct AssignWithSeed<'a, 'b, 'c, 'd> { pub account: &'a AccountInfo, pub base_account: &'a AccountInfo, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs index baa5a95ff..5e3b7a0f7 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs @@ -15,7 +15,7 @@ use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; use pinocchio::ProgramResult; -/// `authorize_nonce_account` CPI helper. +/// Helper for cross-program invocations of `authorize_nonce_account` instruction. pub struct AuthorizeNonceAccount<'a, 'b> { pub nonce_account: &'a AccountInfo, pub nonce_authority: &'a AccountInfo, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs index da5774a53..138aa03de 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs @@ -15,7 +15,7 @@ use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; use pinocchio::ProgramResult; -/// `create_account` CPI helper. +/// Helper for cross-program invocations of `create_account` instruction. pub struct CreateAccount<'a, 'b> { pub payer: &'a AccountInfo, pub new_account: &'a AccountInfo, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs index d31b88cab..62adc0a3f 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs @@ -15,7 +15,7 @@ use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; use pinocchio::ProgramResult; -/// `create_account_with_seed` CPI helper. +/// Helper for cross-program invocations of `create_account_with_seed` instruction. pub struct CreateAccountWithSeed<'a, 'b, 'c, 'd> { pub payer: &'a AccountInfo, pub new_account: &'a AccountInfo, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs index 190da914a..6dd0fec5f 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs @@ -15,7 +15,7 @@ use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; use pinocchio::ProgramResult; -/// `initialize_nonce_account` CPI helper. +/// Helper for cross-program invocations of `initialize_nonce_account` instruction. pub struct InitializeNonceAccount<'a, 'b> { pub nonce_account: &'a AccountInfo, pub recent_blockhashes_sysvar: &'a AccountInfo, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs index b68174da6..644e8430f 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs @@ -14,7 +14,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `transfer_sol` CPI helper. +/// Helper for cross-program invocations of `transfer_sol` instruction. pub struct TransferSol<'a> { pub source: &'a AccountInfo, pub destination: &'a AccountInfo, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs index 09fb23417..85b1cf0c2 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs @@ -15,7 +15,7 @@ use pinocchio::instruction::Signer; use pinocchio::pubkey::Pubkey; use pinocchio::ProgramResult; -/// `transfer_sol_with_seed` CPI helper. +/// Helper for cross-program invocations of `transfer_sol_with_seed` instruction. pub struct TransferSolWithSeed<'a, 'b, 'c> { pub source: &'a AccountInfo, pub base_account: &'a AccountInfo, diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs index 46fd466df..9dd6d6e2c 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs @@ -11,7 +11,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `upgrade_nonce_account` CPI helper. +/// Helper for cross-program invocations of `upgrade_nonce_account` instruction. pub struct UpgradeNonceAccount<'a> { pub nonce_account: &'a AccountInfo, } diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs index 21fe51f0c..074f7abc6 100644 --- a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs +++ b/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs @@ -14,7 +14,7 @@ use pinocchio::instruction::Instruction; use pinocchio::instruction::Signer; use pinocchio::ProgramResult; -/// `withdraw_nonce_account` CPI helper. +/// Helper for cross-program invocations of `withdraw_nonce_account` instruction. pub struct WithdrawNonceAccount<'a> { pub nonce_account: &'a AccountInfo, pub recipient_account: &'a AccountInfo, From 27a40f0380bdb197c512cac1de647b2d54c6756a Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 9 Sep 2025 15:39:27 +0100 Subject: [PATCH 17/24] Resolved default value should be used in fragments `defaultValue` will be a node whereas `resolvedDefaultValue` is the result of the `defaultValue` node going through the value visitor (returning a `Fragment`). --- .../renderers-rust-cpi/src/fragments/instructionPage.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/renderers-rust-cpi/src/fragments/instructionPage.ts b/packages/renderers-rust-cpi/src/fragments/instructionPage.ts index eee538664..b5a9dff96 100644 --- a/packages/renderers-rust-cpi/src/fragments/instructionPage.ts +++ b/packages/renderers-rust-cpi/src/fragments/instructionPage.ts @@ -208,7 +208,7 @@ function getInstructionDataFragment( instructionArguments.length === 1 && isNode(instructionArguments[0].type, ['bytesTypeNode', 'stringTypeNode']) ) { - if (instructionArguments[0].defaultValue) { + if (instructionArguments[0].resolvedDefaultValue) { return fragment`let data = ${ isNode(instructionArguments[0].type, 'stringTypeNode') ? fragment`${instructionArguments[0].resolvedDefaultValue}.as_bytes()` @@ -225,8 +225,8 @@ function getInstructionDataFragment( isNode(instructionArguments[0].type, 'numberTypeNode') && instructionArguments[0].type.format === 'u8' ) { - if (instructionArguments[0].defaultValue) { - return fragment`let data = &[${instructionArguments[0].defaultValue}${instructionArguments[0].type.format}];`; + if (instructionArguments[0].resolvedDefaultValue) { + return fragment`let data = &[${instructionArguments[0].resolvedDefaultValue}${instructionArguments[0].type.format}];`; } else { return fragment`let data = &[self.${instructionArguments[0].displayName}];`; } @@ -234,7 +234,7 @@ function getInstructionDataFragment( // When there is a single number (e.g., `u16`, `u32`, `u64`) argument, the instruction data is the // little-endian representation of the number. else if (instructionArguments.length === 1 && isNode(instructionArguments[0].type, 'numberTypeNode')) { - if (instructionArguments[0].defaultValue) { + if (instructionArguments[0].resolvedDefaultValue) { return fragment`let data = &${instructionArguments[0].resolvedDefaultValue}${instructionArguments[0].type.format}.to_le_bytes();`; } else { return fragment`let data = &self.${instructionArguments[0].displayName}.to_le_bytes();`; From a215ba00ded177acec262b3f2e936166c6bbba1c Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 9 Sep 2025 15:41:18 +0100 Subject: [PATCH 18/24] Remove nunjucks dependency --- packages/renderers-rust-cpi/package.json | 6 +---- .../renderers-rust-cpi/src/utils/index.ts | 1 - .../renderers-rust-cpi/src/utils/render.ts | 25 ------------------- .../src/visitors/getTypeManifestVisitor.ts | 9 +++---- pnpm-lock.yaml | 7 ------ 5 files changed, 5 insertions(+), 43 deletions(-) delete mode 100644 packages/renderers-rust-cpi/src/utils/render.ts diff --git a/packages/renderers-rust-cpi/package.json b/packages/renderers-rust-cpi/package.json index 5cbd4ecde..513a18f97 100644 --- a/packages/renderers-rust-cpi/package.json +++ b/packages/renderers-rust-cpi/package.json @@ -46,11 +46,7 @@ "@codama/nodes": "workspace:*", "@codama/renderers-core": "workspace:*", "@codama/visitors-core": "workspace:*", - "@solana/codecs-strings": "^3.0.2", - "nunjucks": "^3.2.4" - }, - "devDependencies": { - "@types/nunjucks": "^3.2.6" + "@solana/codecs-strings": "^3.0.2" }, "license": "MIT", "repository": { diff --git a/packages/renderers-rust-cpi/src/utils/index.ts b/packages/renderers-rust-cpi/src/utils/index.ts index b6381ccc0..3e7527dad 100644 --- a/packages/renderers-rust-cpi/src/utils/index.ts +++ b/packages/renderers-rust-cpi/src/utils/index.ts @@ -3,5 +3,4 @@ export * from './fragment'; export * from './linkOverrides'; export * from './options'; export * from './importMap'; -export * from './render'; export * from './traitOptions'; diff --git a/packages/renderers-rust-cpi/src/utils/render.ts b/packages/renderers-rust-cpi/src/utils/render.ts deleted file mode 100644 index fa14c0d62..000000000 --- a/packages/renderers-rust-cpi/src/utils/render.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { dirname as pathDirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { camelCase, kebabCase, pascalCase, snakeCase, titleCase } from '@codama/nodes'; -import nunjucks, { ConfigureOptions as NunJucksOptions } from 'nunjucks'; - -export function rustDocblock(docs: string[]): string { - if (docs.length <= 0) return ''; - const lines = docs.map(doc => `/// ${doc}`); - return `${lines.join('\n')}\n`; -} - -export const render = (template: string, context?: object, options?: NunJucksOptions): string => { - // @ts-expect-error import.meta will be used in the right environment. - const dirname = __ESM__ ? pathDirname(fileURLToPath(import.meta.url)) : __dirname; - const templates = __TEST__ ? join(dirname, '..', '..', 'public', 'templates') : join(dirname, 'templates'); // Path to templates from bundled output file. - const env = nunjucks.configure(templates, { autoescape: false, trimBlocks: true, ...options }); - env.addFilter('pascalCase', pascalCase); - env.addFilter('camelCase', camelCase); - env.addFilter('snakeCase', snakeCase); - env.addFilter('kebabCase', kebabCase); - env.addFilter('titleCase', titleCase); - env.addFilter('rustDocblock', rustDocblock); - return env.render(template, context); -}; diff --git a/packages/renderers-rust-cpi/src/visitors/getTypeManifestVisitor.ts b/packages/renderers-rust-cpi/src/visitors/getTypeManifestVisitor.ts index fef0a7f36..c4f25628f 100644 --- a/packages/renderers-rust-cpi/src/visitors/getTypeManifestVisitor.ts +++ b/packages/renderers-rust-cpi/src/visitors/getTypeManifestVisitor.ts @@ -7,7 +7,6 @@ import { isNode, NumberTypeNode, numberTypeNode, - parseDocs, pascalCase, prefixedCountNode, REGISTERED_TYPE_NODE_KINDS, @@ -21,10 +20,10 @@ import { addFragmentImports, Fragment, fragment, + getDocblockFragment, GetImportFromFunction, GetTraitsFromNodeFunction, mergeFragments, - rustDocblock, } from '../utils'; export type TypeManifest = { @@ -320,7 +319,7 @@ export function getTypeManifestVisitor(options: { nestedStruct = originalNestedStruct; const fieldName = snakeCase(structFieldType.name); - const docblock = rustDocblock(parseDocs(structFieldType.docs)); + const docs = getDocblockFragment(structFieldType.docs ?? [], true); const resolvedNestedType = resolveNestedTypeNode(structFieldType.type); let derive = ''; @@ -345,8 +344,8 @@ export function getTypeManifestVisitor(options: { return { ...fieldManifest, type: inlineStruct - ? fragment`${docblock}${derive}${fieldName}: ${fieldManifest.type},` - : fragment`${docblock}${derive}pub ${fieldName}: ${fieldManifest.type},`, + ? fragment`${docs}${derive}${fieldName}: ${fieldManifest.type},` + : fragment`${docs}${derive}pub ${fieldName}: ${fieldManifest.type},`, }; }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 97dc9d411..b1dfb94df 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -352,13 +352,6 @@ importers: '@solana/codecs-strings': specifier: ^3.0.2 version: 3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - nunjucks: - specifier: ^3.2.4 - version: 3.2.4(chokidar@3.6.0) - devDependencies: - '@types/nunjucks': - specifier: ^3.2.6 - version: 3.2.6 packages/renderers-vixen-parser: dependencies: From 68d372765f331f7e951b25acc03de655fdc5e90f Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 9 Sep 2025 15:49:21 +0100 Subject: [PATCH 19/24] Move e2e folder under test --- packages/renderers-rust-cpi/{ => test}/e2e/dummy/Cargo.lock | 0 packages/renderers-rust-cpi/{ => test}/e2e/dummy/Cargo.toml | 0 packages/renderers-rust-cpi/{ => test}/e2e/dummy/idl.json | 0 .../e2e/dummy/src/generated/instructions/instruction1.rs | 0 .../e2e/dummy/src/generated/instructions/instruction2.rs | 0 .../e2e/dummy/src/generated/instructions/instruction3.rs | 0 .../e2e/dummy/src/generated/instructions/instruction4.rs | 0 .../e2e/dummy/src/generated/instructions/instruction5.rs | 0 .../e2e/dummy/src/generated/instructions/instruction6.rs | 0 .../e2e/dummy/src/generated/instructions/instruction7.rs | 0 .../{ => test}/e2e/dummy/src/generated/instructions/mod.rs | 0 .../{ => test}/e2e/dummy/src/generated/mod.rs | 0 .../{ => test}/e2e/dummy/src/generated/programs/mod.rs | 0 packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/lib.rs | 0 packages/renderers-rust-cpi/{ => test}/e2e/generate.cjs | 2 +- packages/renderers-rust-cpi/{ => test}/e2e/memo/Cargo.lock | 0 packages/renderers-rust-cpi/{ => test}/e2e/memo/Cargo.toml | 0 packages/renderers-rust-cpi/{ => test}/e2e/memo/idl.json | 0 .../e2e/memo/src/generated/instructions/add_memo.rs | 0 .../{ => test}/e2e/memo/src/generated/instructions/mod.rs | 0 .../{ => test}/e2e/memo/src/generated/mod.rs | 0 .../{ => test}/e2e/memo/src/generated/programs/mod.rs | 0 packages/renderers-rust-cpi/{ => test}/e2e/memo/src/lib.rs | 0 .../renderers-rust-cpi/{ => test}/e2e/system/Cargo.lock | 0 .../renderers-rust-cpi/{ => test}/e2e/system/Cargo.toml | 0 packages/renderers-rust-cpi/{ => test}/e2e/system/idl.json | 0 .../src/generated/instructions/advance_nonce_account.rs | 0 .../e2e/system/src/generated/instructions/allocate.rs | 0 .../system/src/generated/instructions/allocate_with_seed.rs | 0 .../e2e/system/src/generated/instructions/assign.rs | 0 .../system/src/generated/instructions/assign_with_seed.rs | 0 .../src/generated/instructions/authorize_nonce_account.rs | 0 .../e2e/system/src/generated/instructions/create_account.rs | 0 .../src/generated/instructions/create_account_with_seed.rs | 0 .../src/generated/instructions/initialize_nonce_account.rs | 0 .../{ => test}/e2e/system/src/generated/instructions/mod.rs | 0 .../e2e/system/src/generated/instructions/transfer_sol.rs | 0 .../src/generated/instructions/transfer_sol_with_seed.rs | 0 .../src/generated/instructions/upgrade_nonce_account.rs | 0 .../src/generated/instructions/withdraw_nonce_account.rs | 0 .../{ => test}/e2e/system/src/generated/mod.rs | 0 .../{ => test}/e2e/system/src/generated/programs/mod.rs | 0 .../renderers-rust-cpi/{ => test}/e2e/system/src/lib.rs | 0 packages/renderers-rust-cpi/{ => test}/e2e/test.sh | 6 +++--- 44 files changed, 4 insertions(+), 4 deletions(-) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/Cargo.lock (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/Cargo.toml (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/idl.json (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/instructions/instruction1.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/instructions/instruction2.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/instructions/instruction3.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/instructions/instruction4.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/instructions/instruction5.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/instructions/instruction6.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/instructions/instruction7.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/instructions/mod.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/mod.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/generated/programs/mod.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/dummy/src/lib.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/generate.cjs (93%) rename packages/renderers-rust-cpi/{ => test}/e2e/memo/Cargo.lock (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/memo/Cargo.toml (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/memo/idl.json (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/memo/src/generated/instructions/add_memo.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/memo/src/generated/instructions/mod.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/memo/src/generated/mod.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/memo/src/generated/programs/mod.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/memo/src/lib.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/Cargo.lock (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/Cargo.toml (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/idl.json (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/advance_nonce_account.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/allocate.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/allocate_with_seed.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/assign.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/assign_with_seed.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/authorize_nonce_account.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/create_account.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/create_account_with_seed.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/initialize_nonce_account.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/mod.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/transfer_sol.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/upgrade_nonce_account.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/instructions/withdraw_nonce_account.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/mod.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/generated/programs/mod.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/system/src/lib.rs (100%) rename packages/renderers-rust-cpi/{ => test}/e2e/test.sh (65%) diff --git a/packages/renderers-rust-cpi/e2e/dummy/Cargo.lock b/packages/renderers-rust-cpi/test/e2e/dummy/Cargo.lock similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/Cargo.lock rename to packages/renderers-rust-cpi/test/e2e/dummy/Cargo.lock diff --git a/packages/renderers-rust-cpi/e2e/dummy/Cargo.toml b/packages/renderers-rust-cpi/test/e2e/dummy/Cargo.toml similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/Cargo.toml rename to packages/renderers-rust-cpi/test/e2e/dummy/Cargo.toml diff --git a/packages/renderers-rust-cpi/e2e/dummy/idl.json b/packages/renderers-rust-cpi/test/e2e/dummy/idl.json similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/idl.json rename to packages/renderers-rust-cpi/test/e2e/dummy/idl.json diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction1.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction1.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction1.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction2.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction2.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction2.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction3.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction3.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction3.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction4.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction4.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction4.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction5.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction5.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction5.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction6.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction6.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction6.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction7.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/instruction7.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/instruction7.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/mod.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/mod.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/instructions/mod.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/instructions/mod.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/mod.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/mod.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/mod.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/mod.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/generated/programs/mod.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/generated/programs/mod.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/generated/programs/mod.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/generated/programs/mod.rs diff --git a/packages/renderers-rust-cpi/e2e/dummy/src/lib.rs b/packages/renderers-rust-cpi/test/e2e/dummy/src/lib.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/dummy/src/lib.rs rename to packages/renderers-rust-cpi/test/e2e/dummy/src/lib.rs diff --git a/packages/renderers-rust-cpi/e2e/generate.cjs b/packages/renderers-rust-cpi/test/e2e/generate.cjs similarity index 93% rename from packages/renderers-rust-cpi/e2e/generate.cjs rename to packages/renderers-rust-cpi/test/e2e/generate.cjs index f30672c7f..e18a45786 100755 --- a/packages/renderers-rust-cpi/e2e/generate.cjs +++ b/packages/renderers-rust-cpi/test/e2e/generate.cjs @@ -7,7 +7,7 @@ const { rootNode } = require('@codama/nodes'); const { readJson } = require('@codama/renderers-core'); const { visit } = require('@codama/visitors-core'); -const { renderVisitor } = require('../dist/index.node.cjs'); +const { renderVisitor } = require('../../dist/index.node.cjs'); async function main() { const project = process.argv.slice(2)[0] ?? undefined; diff --git a/packages/renderers-rust-cpi/e2e/memo/Cargo.lock b/packages/renderers-rust-cpi/test/e2e/memo/Cargo.lock similarity index 100% rename from packages/renderers-rust-cpi/e2e/memo/Cargo.lock rename to packages/renderers-rust-cpi/test/e2e/memo/Cargo.lock diff --git a/packages/renderers-rust-cpi/e2e/memo/Cargo.toml b/packages/renderers-rust-cpi/test/e2e/memo/Cargo.toml similarity index 100% rename from packages/renderers-rust-cpi/e2e/memo/Cargo.toml rename to packages/renderers-rust-cpi/test/e2e/memo/Cargo.toml diff --git a/packages/renderers-rust-cpi/e2e/memo/idl.json b/packages/renderers-rust-cpi/test/e2e/memo/idl.json similarity index 100% rename from packages/renderers-rust-cpi/e2e/memo/idl.json rename to packages/renderers-rust-cpi/test/e2e/memo/idl.json diff --git a/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs b/packages/renderers-rust-cpi/test/e2e/memo/src/generated/instructions/add_memo.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/add_memo.rs rename to packages/renderers-rust-cpi/test/e2e/memo/src/generated/instructions/add_memo.rs diff --git a/packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/mod.rs b/packages/renderers-rust-cpi/test/e2e/memo/src/generated/instructions/mod.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/memo/src/generated/instructions/mod.rs rename to packages/renderers-rust-cpi/test/e2e/memo/src/generated/instructions/mod.rs diff --git a/packages/renderers-rust-cpi/e2e/memo/src/generated/mod.rs b/packages/renderers-rust-cpi/test/e2e/memo/src/generated/mod.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/memo/src/generated/mod.rs rename to packages/renderers-rust-cpi/test/e2e/memo/src/generated/mod.rs diff --git a/packages/renderers-rust-cpi/e2e/memo/src/generated/programs/mod.rs b/packages/renderers-rust-cpi/test/e2e/memo/src/generated/programs/mod.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/memo/src/generated/programs/mod.rs rename to packages/renderers-rust-cpi/test/e2e/memo/src/generated/programs/mod.rs diff --git a/packages/renderers-rust-cpi/e2e/memo/src/lib.rs b/packages/renderers-rust-cpi/test/e2e/memo/src/lib.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/memo/src/lib.rs rename to packages/renderers-rust-cpi/test/e2e/memo/src/lib.rs diff --git a/packages/renderers-rust-cpi/e2e/system/Cargo.lock b/packages/renderers-rust-cpi/test/e2e/system/Cargo.lock similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/Cargo.lock rename to packages/renderers-rust-cpi/test/e2e/system/Cargo.lock diff --git a/packages/renderers-rust-cpi/e2e/system/Cargo.toml b/packages/renderers-rust-cpi/test/e2e/system/Cargo.toml similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/Cargo.toml rename to packages/renderers-rust-cpi/test/e2e/system/Cargo.toml diff --git a/packages/renderers-rust-cpi/e2e/system/idl.json b/packages/renderers-rust-cpi/test/e2e/system/idl.json similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/idl.json rename to packages/renderers-rust-cpi/test/e2e/system/idl.json diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/advance_nonce_account.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/advance_nonce_account.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/advance_nonce_account.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/allocate.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/allocate.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/allocate_with_seed.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/allocate_with_seed.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/allocate_with_seed.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/assign.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/assign.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/assign_with_seed.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/assign_with_seed.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/assign_with_seed.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/authorize_nonce_account.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/authorize_nonce_account.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/authorize_nonce_account.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/create_account.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/create_account.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/create_account_with_seed.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/create_account_with_seed.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/create_account_with_seed.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/initialize_nonce_account.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/initialize_nonce_account.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/initialize_nonce_account.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/mod.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/mod.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/mod.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/mod.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/transfer_sol.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/transfer_sol.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/upgrade_nonce_account.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/upgrade_nonce_account.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/upgrade_nonce_account.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/withdraw_nonce_account.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/instructions/withdraw_nonce_account.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/instructions/withdraw_nonce_account.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/mod.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/mod.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/mod.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/mod.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/generated/programs/mod.rs b/packages/renderers-rust-cpi/test/e2e/system/src/generated/programs/mod.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/generated/programs/mod.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/generated/programs/mod.rs diff --git a/packages/renderers-rust-cpi/e2e/system/src/lib.rs b/packages/renderers-rust-cpi/test/e2e/system/src/lib.rs similarity index 100% rename from packages/renderers-rust-cpi/e2e/system/src/lib.rs rename to packages/renderers-rust-cpi/test/e2e/system/src/lib.rs diff --git a/packages/renderers-rust-cpi/e2e/test.sh b/packages/renderers-rust-cpi/test/e2e/test.sh similarity index 65% rename from packages/renderers-rust-cpi/e2e/test.sh rename to packages/renderers-rust-cpi/test/e2e/test.sh index e524b8c50..0f88ff654 100755 --- a/packages/renderers-rust-cpi/e2e/test.sh +++ b/packages/renderers-rust-cpi/test/e2e/test.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash function test_project() { - ./e2e/generate.cjs $1 - cd e2e/$1 + ./test/e2e/generate.cjs $1 + cd test/e2e/$1 cargo check - cd ../.. + cd ../../.. } test_project dummy From 08fd301739d5023f3c34785978d51a6eb242f7d6 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 9 Sep 2025 15:49:33 +0100 Subject: [PATCH 20/24] Add browser support --- packages/internals/tsup.config.base.ts | 2 +- packages/renderers-rust-cpi/package.json | 19 +++++++++--- .../src/visitors/renderVisitor.ts | 31 +++++++++++-------- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/packages/internals/tsup.config.base.ts b/packages/internals/tsup.config.base.ts index 95f0a7d8b..b234bb7f2 100644 --- a/packages/internals/tsup.config.base.ts +++ b/packages/internals/tsup.config.base.ts @@ -35,7 +35,7 @@ export function getBuildConfig(options: BuildOptions): TsupConfig { }; } }, - external: ['node:fs', 'node:path', 'node:url'], + external: ['node:child_process', 'node:fs', 'node:path', 'node:url'], format, globalName: 'globalThis.codama', name: platform, diff --git a/packages/renderers-rust-cpi/package.json b/packages/renderers-rust-cpi/package.json index 513a18f97..a9b0be92b 100644 --- a/packages/renderers-rust-cpi/package.json +++ b/packages/renderers-rust-cpi/package.json @@ -4,17 +4,26 @@ "description": "Renders CPI clients for your programs", "exports": { "types": "./dist/types/index.d.ts", + "react-native": "./dist/index.react-native.mjs", + "browser": { + "import": "./dist/index.browser.mjs", + "require": "./dist/index.browser.cjs" + }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, + "browser": { + "./dist/index.node.cjs": "./dist/index.browser.cjs", + "./dist/index.node.mjs": "./dist/index.browser.mjs" + }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", + "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ - "./dist/templates", "./dist/types", "./dist/index.*" ], @@ -29,15 +38,17 @@ ], "scripts": { "build": "rimraf dist && pnpm build:src && pnpm build:types", - "build:src": "zx ../../node_modules/@codama/internals/scripts/build-src.mjs node", + "build:src": "zx ../../node_modules/@codama/internals/scripts/build-src.mjs package", "build:types": "zx ../../node_modules/@codama/internals/scripts/build-types.mjs", "dev": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs node --watch", "lint": "zx ../../node_modules/@codama/internals/scripts/lint.mjs", "lint:fix": "zx ../../node_modules/@codama/internals/scripts/lint.mjs --fix", - "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:node && pnpm test:e2e && pnpm test:exports", - "test:e2e": "./e2e/test.sh", + "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:browser && pnpm test:node && pnpm test:react-native && pnpm test:e2e && pnpm test:exports", + "test:browser": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs browser", + "test:e2e": "./test/e2e/test.sh", "test:exports": "node ./test/exports/module.mjs && node ./test/exports/commonjs.cjs", "test:node": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs node", + "test:react-native": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs react-native", "test:treeshakability": "zx ../../node_modules/@codama/internals/scripts/test-treeshakability.mjs", "test:types": "zx ../../node_modules/@codama/internals/scripts/test-types.mjs" }, diff --git a/packages/renderers-rust-cpi/src/visitors/renderVisitor.ts b/packages/renderers-rust-cpi/src/visitors/renderVisitor.ts index bc9fa1d0b..34a29762f 100644 --- a/packages/renderers-rust-cpi/src/visitors/renderVisitor.ts +++ b/packages/renderers-rust-cpi/src/visitors/renderVisitor.ts @@ -1,7 +1,8 @@ +import { spawnSync } from 'node:child_process'; + import { logError, logWarn } from '@codama/errors'; import { deleteDirectory, writeRenderMapVisitor } from '@codama/renderers-core'; import { rootNodeVisitor, visit } from '@codama/visitors-core'; -import { spawnSync } from 'child_process'; import { RenderOptions } from '../utils'; import { getRenderMapVisitor } from './getRenderMapVisitor'; @@ -29,17 +30,21 @@ export function renderVisitor(path: string, options: RenderOptions = {}) { } function runFormatter(cmd: string, args: string[]) { - const { stdout, stderr, error } = spawnSync(cmd, args); - if (error?.message?.includes('ENOENT')) { - logWarn(`Could not find ${cmd}, skipping formatting.`); - return; - } - if (stdout.length > 0) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - logWarn(`(cargo-fmt) ${stdout || error}`); - } - if (stderr.length > 0) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - logError(`(cargo-fmt) ${stderr || error}`); + if (__NODEJS__) { + const { stdout, stderr, error } = spawnSync(cmd, args); + if (error?.message?.includes('ENOENT')) { + logWarn(`Could not find ${cmd}, skipping formatting.`); + return; + } + if (stdout.length > 0) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + logWarn(`(cargo-fmt) ${stdout || error}`); + } + if (stderr.length > 0) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + logError(`(cargo-fmt) ${stderr || error}`); + } + } else { + logWarn('Can only use cargo-fmt in Node environments, skipping formatting.'); } } From 28e55e272b389585805c35428300a6a8e6a9a7b8 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 9 Sep 2025 16:01:02 +0100 Subject: [PATCH 21/24] Add getInstructionDataFromSingleArgumentFragment helper --- .../src/fragments/instructionPage.ts | 107 +++++++++--------- 1 file changed, 53 insertions(+), 54 deletions(-) diff --git a/packages/renderers-rust-cpi/src/fragments/instructionPage.ts b/packages/renderers-rust-cpi/src/fragments/instructionPage.ts index b5a9dff96..ccfd36465 100644 --- a/packages/renderers-rust-cpi/src/fragments/instructionPage.ts +++ b/packages/renderers-rust-cpi/src/fragments/instructionPage.ts @@ -202,65 +202,64 @@ function getInstructionDataFragment( instructionArguments: ParsedInstructionArgument[], instructionFixedSize: number | null, ): Fragment { - // When there is a single byte array or string (e.g., `&[u8]`, `&str`) argument, there is - // no need to copy the data into a fixed-size array. - if ( - instructionArguments.length === 1 && - isNode(instructionArguments[0].type, ['bytesTypeNode', 'stringTypeNode']) - ) { - if (instructionArguments[0].resolvedDefaultValue) { - return fragment`let data = ${ - isNode(instructionArguments[0].type, 'stringTypeNode') - ? fragment`${instructionArguments[0].resolvedDefaultValue}.as_bytes()` - : fragment`&${instructionArguments[0].resolvedDefaultValue}` - };`; - } else { - const asBytes = isNode(instructionArguments[0].type, 'stringTypeNode') ? '.as_bytes()' : ''; - return fragment`let data = self.${instructionArguments[0].displayName}${asBytes};`; - } + const singleArgumentFragment = getInstructionDataFromSingleArgumentFragment(instructionArguments); + if (singleArgumentFragment) return singleArgumentFragment; + + const declareDataFragment = addFragmentImports( + fragment`let mut uninit_data = [UNINIT_BYTE; ${instructionFixedSize !== null ? instructionFixedSize : 0}];`, + ['super::UNINIT_BYTE', 'core::slice::from_raw_parts'], + ); + let offset = 0; + const assignDataContentFragment = mergeFragments( + instructionArguments.map(argument => { + const [fragment, updated] = visit(argument.type, getInstructionArgumentAssignmentVisitor(argument, offset)); + offset = updated; + return fragment; + }), + cs => cs.join('\n'), + ); + const transmuteData = fragment`let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, ${offset}) };`; + + return mergeFragments([declareDataFragment, assignDataContentFragment, transmuteData], cs => cs.join('\n')); +} + +// When there is a single byte array or string (e.g., `&[u8]`, `&str`) argument, there is +// no need to copy the data into a fixed-size array. +function getInstructionDataFromSingleArgumentFragment( + instructionArguments: ParsedInstructionArgument[], +): Fragment | undefined { + if (instructionArguments.length !== 1) return; + const argument = instructionArguments[0]; + + if (isNode(argument.type, 'bytesTypeNode')) { + return argument.resolvedDefaultValue + ? fragment`let data = &${argument.resolvedDefaultValue};` + : fragment`let data = self.${argument.displayName};`; } + + if (isNode(argument.type, 'stringTypeNode')) { + return argument.resolvedDefaultValue + ? fragment`let data = ${argument.resolvedDefaultValue}.as_bytes();` + : fragment`let data = self.${argument.displayName}.as_bytes();`; + } + // When there is a single byte argument, the instruction data is a single-element byte array. - else if ( - instructionArguments.length === 1 && - isNode(instructionArguments[0].type, 'numberTypeNode') && - instructionArguments[0].type.format === 'u8' - ) { - if (instructionArguments[0].resolvedDefaultValue) { - return fragment`let data = &[${instructionArguments[0].resolvedDefaultValue}${instructionArguments[0].type.format}];`; - } else { - return fragment`let data = &[self.${instructionArguments[0].displayName}];`; - } + if (isNode(argument.type, 'numberTypeNode') && argument.type.format === 'u8') { + return argument.resolvedDefaultValue + ? fragment`let data = &[${argument.resolvedDefaultValue}${argument.type.format}];` + : fragment`let data = &[self.${argument.displayName}];`; } + // When there is a single number (e.g., `u16`, `u32`, `u64`) argument, the instruction data is the // little-endian representation of the number. - else if (instructionArguments.length === 1 && isNode(instructionArguments[0].type, 'numberTypeNode')) { - if (instructionArguments[0].resolvedDefaultValue) { - return fragment`let data = &${instructionArguments[0].resolvedDefaultValue}${instructionArguments[0].type.format}.to_le_bytes();`; - } else { - return fragment`let data = &self.${instructionArguments[0].displayName}.to_le_bytes();`; - } - } - // Handles any other case, which requires copying the data into a fixed-size array. - else { - const declareDataFragment = addFragmentImports( - fragment`let mut uninit_data = [UNINIT_BYTE; ${instructionFixedSize !== null ? instructionFixedSize : 0}];`, - ['super::UNINIT_BYTE', 'core::slice::from_raw_parts'], - ); - let offset = 0; - const assignDataContentFragment = mergeFragments( - instructionArguments.map(argument => { - const [fragment, updated] = visit( - argument.type, - getInstructionArgumentAssignmentVisitor(argument, offset), - ); - offset = updated; - return fragment; - }), - cs => cs.join('\n'), - ); - const transmuteData = fragment`let data = unsafe { from_raw_parts(uninit_data.as_ptr() as _, ${offset}) };`; - - return mergeFragments([declareDataFragment, assignDataContentFragment, transmuteData], cs => cs.join('\n')); + if ( + isNode(argument.type, 'numberTypeNode') && + argument.type.format !== 'shortU16' && + argument.type.endian === 'le' + ) { + return argument.resolvedDefaultValue + ? fragment`let data = &${argument.resolvedDefaultValue}${argument.type.format}.to_le_bytes();` + : fragment`let data = &self.${argument.displayName}.to_le_bytes();`; } } From 7277c2058a5413179f2c3d8382f963a64fadc27f Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 9 Sep 2025 16:01:44 +0100 Subject: [PATCH 22/24] Update LICENSE --- packages/renderers-rust-cpi/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderers-rust-cpi/LICENSE b/packages/renderers-rust-cpi/LICENSE index 22fd7b02c..2db0266e0 100644 --- a/packages/renderers-rust-cpi/LICENSE +++ b/packages/renderers-rust-cpi/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Codama +Copyright (c) 2025 Codama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the From 591be15e1ab241bd725304b0340295a7e7fe5ea8 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Thu, 11 Sep 2025 13:20:30 +0100 Subject: [PATCH 23/24] Use inlined scripts --- packages/renderers-rust-cpi/.prettierignore | 2 +- packages/renderers-rust-cpi/package.json | 20 ++++++-------- packages/renderers-rust-cpi/tsconfig.json | 5 ++-- packages/renderers-rust-cpi/tsup.config.ts | 5 ++++ packages/renderers-rust-cpi/vitest.config.mts | 8 ++++++ pnpm-lock.yaml | 26 +------------------ 6 files changed, 26 insertions(+), 40 deletions(-) create mode 100644 packages/renderers-rust-cpi/tsup.config.ts create mode 100644 packages/renderers-rust-cpi/vitest.config.mts diff --git a/packages/renderers-rust-cpi/.prettierignore b/packages/renderers-rust-cpi/.prettierignore index 3d73fdedb..ebf37de71 100644 --- a/packages/renderers-rust-cpi/.prettierignore +++ b/packages/renderers-rust-cpi/.prettierignore @@ -1,5 +1,5 @@ dist/ -e2e/ +test/e2e/ test-ledger/ target/ CHANGELOG.md diff --git a/packages/renderers-rust-cpi/package.json b/packages/renderers-rust-cpi/package.json index a9b0be92b..83af61a50 100644 --- a/packages/renderers-rust-cpi/package.json +++ b/packages/renderers-rust-cpi/package.json @@ -37,20 +37,16 @@ "client" ], "scripts": { - "build": "rimraf dist && pnpm build:src && pnpm build:types", - "build:src": "zx ../../node_modules/@codama/internals/scripts/build-src.mjs package", - "build:types": "zx ../../node_modules/@codama/internals/scripts/build-types.mjs", - "dev": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs node --watch", - "lint": "zx ../../node_modules/@codama/internals/scripts/lint.mjs", - "lint:fix": "zx ../../node_modules/@codama/internals/scripts/lint.mjs --fix", - "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:browser && pnpm test:node && pnpm test:react-native && pnpm test:e2e && pnpm test:exports", - "test:browser": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs browser", + "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", + "dev": "vitest --project node", + "lint": "eslint . && prettier --check .", + "lint:fix": "eslint --fix . && prettier --write .", + "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit && pnpm test:e2e && pnpm test:exports", "test:e2e": "./test/e2e/test.sh", "test:exports": "node ./test/exports/module.mjs && node ./test/exports/commonjs.cjs", - "test:node": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs node", - "test:react-native": "zx ../../node_modules/@codama/internals/scripts/test-unit.mjs react-native", - "test:treeshakability": "zx ../../node_modules/@codama/internals/scripts/test-treeshakability.mjs", - "test:types": "zx ../../node_modules/@codama/internals/scripts/test-types.mjs" + "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", + "test:types": "tsc --noEmit", + "test:unit": "vitest run" }, "dependencies": { "@codama/errors": "workspace:*", diff --git a/packages/renderers-rust-cpi/tsconfig.json b/packages/renderers-rust-cpi/tsconfig.json index e3e899910..f84dde13d 100644 --- a/packages/renderers-rust-cpi/tsconfig.json +++ b/packages/renderers-rust-cpi/tsconfig.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/renderers-rust", - "extends": "../internals/tsconfig.base.json", - "include": ["src", "test"] + "extends": "../../tsconfig.json", + "include": ["src", "test"], + "exclude": ["test/e2e"] } diff --git a/packages/renderers-rust-cpi/tsup.config.ts b/packages/renderers-rust-cpi/tsup.config.ts new file mode 100644 index 000000000..55e99457f --- /dev/null +++ b/packages/renderers-rust-cpi/tsup.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from 'tsup'; + +import { getPackageBuildConfigs } from '../../tsup.config.base'; + +export default defineConfig(getPackageBuildConfigs()); diff --git a/packages/renderers-rust-cpi/vitest.config.mts b/packages/renderers-rust-cpi/vitest.config.mts new file mode 100644 index 000000000..8fd0137cc --- /dev/null +++ b/packages/renderers-rust-cpi/vitest.config.mts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; +import { getVitestConfig } from '../../vitest.config.base.mjs'; + +export default defineConfig({ + test: { + projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a32bc552b..b83953aa0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -342,7 +342,7 @@ importers: version: link:../visitors-core '@solana/codecs-strings': specifier: ^3.0.2 - version: 3.0.2(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) + version: 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) packages/renderers-vixen-parser: dependencies: @@ -1385,12 +1385,6 @@ packages: '@sinonjs/fake-timers@11.3.1': resolution: {integrity: sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==} - '@solana/codecs-core@3.0.2': - resolution: {integrity: sha512-vpy8ySWgPF8+APwpeEr4dQbU/EyHjisd/TywIw3rymguWeZ9/wcThS0WDRi08Z44W6InCIbtI08RdtuHQZoSag==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - '@solana/codecs-core@3.0.3': resolution: {integrity: sha512-emKykJ3h1DmnDOY29Uv9eJXP8E/FHzvlUBJ6te+5EbKdFjj7vdlKYPfDxOI6iGdXTY+YC/ELtbNBh6QwF2uEDQ==} engines: {node: '>=20.18.0'} @@ -1422,13 +1416,6 @@ packages: peerDependencies: typescript: '>=5.3.3' - '@solana/errors@3.0.2': - resolution: {integrity: sha512-0B4y9JUsX8/DzflhdSXSAF+UPUKyo1R1rrQ/ShS/8ApCOIWIFqZlve0TPatuTOGGNBememoukPOvDVtFy0ZYpg==} - engines: {node: '>=20.18.0'} - hasBin: true - peerDependencies: - typescript: '>=5.3.3' - '@solana/errors@3.0.3': resolution: {integrity: sha512-1l84xJlHNva6io62PcYfUamwWlc0eM95nHgCrKX0g0cLoC6D6QHYPCEbEVkR+C5UtP9JDgyQM8MFiv+Ei5tO9Q==} engines: {node: '>=20.18.0'} @@ -4604,11 +4591,6 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@solana/codecs-core@3.0.2(typescript@5.9.2)': - dependencies: - '@solana/errors': 3.0.2(typescript@5.9.2) - typescript: 5.9.2 - '@solana/codecs-core@3.0.3(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) @@ -4646,12 +4628,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/errors@3.0.2(typescript@5.9.2)': - dependencies: - chalk: 5.6.2 - commander: 14.0.0 - typescript: 5.9.2 - '@solana/errors@3.0.3(typescript@5.9.2)': dependencies: chalk: 5.6.2 From 739ff24efba880e49983497a1db797fdd2e488ee Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Thu, 11 Sep 2025 13:21:41 +0100 Subject: [PATCH 24/24] Lint fix --- packages/renderers-rust-cpi/README.md | 15 +++++---------- .../renderers-rust-cpi/src/fragments/modPage.ts | 7 ++----- packages/renderers-rust-cpi/src/visitors/index.ts | 1 - .../test/utils/traitOptions.test.ts | 6 ++++-- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/packages/renderers-rust-cpi/README.md b/packages/renderers-rust-cpi/README.md index c37e38437..5d2479c5c 100644 --- a/packages/renderers-rust-cpi/README.md +++ b/packages/renderers-rust-cpi/README.md @@ -57,21 +57,16 @@ The Rust renderer provides sensible default traits when generating the various R 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: -- `baseDefaults`: The default traits to implement for all types. -- `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 }`. -- `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 }`. -- `structDefaults`: The default traits to implement for all struct types, in addition to the `baseDefaults` traits. +- `baseDefaults`: The default traits to implement for all types. +- `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 }`. +- `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 }`. +- `structDefaults`: The default traits to implement for all struct types, in addition to the `baseDefaults` traits. 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: ```ts const traitOptions = { - baseDefaults: [ - 'Clone', - 'Debug', - 'Eq', - 'PartialEq', - ], + baseDefaults: ['Clone', 'Debug', 'Eq', 'PartialEq'], dataEnumDefaults: [], scalarEnumDefaults: ['Copy', 'PartialOrd', 'Hash', 'num_derive::FromPrimitive'], structDefaults: [], diff --git a/packages/renderers-rust-cpi/src/fragments/modPage.ts b/packages/renderers-rust-cpi/src/fragments/modPage.ts index 7d8a9b9b0..431fcbe1a 100644 --- a/packages/renderers-rust-cpi/src/fragments/modPage.ts +++ b/packages/renderers-rust-cpi/src/fragments/modPage.ts @@ -11,9 +11,7 @@ export function getModPageFragment( return getPageFragment(imports, scope); } -export function getModImportsFragment( - items: { name: CamelCaseString }[], -): Fragment | undefined { +export function getModImportsFragment(items: { name: CamelCaseString }[]): Fragment | undefined { if (items.length === 0) return; const sortedItems = items.slice().sort((a, b) => a.name.localeCompare(b.name)); @@ -26,6 +24,5 @@ export function getModImportsFragment( cs => cs.join('\n'), ); - return mergeFragments([modStatements, useStatements], cs => cs.join('\n\n')) - + return mergeFragments([modStatements, useStatements], cs => cs.join('\n\n')); } diff --git a/packages/renderers-rust-cpi/src/visitors/index.ts b/packages/renderers-rust-cpi/src/visitors/index.ts index b94ed0bd1..dc39bc10a 100644 --- a/packages/renderers-rust-cpi/src/visitors/index.ts +++ b/packages/renderers-rust-cpi/src/visitors/index.ts @@ -3,4 +3,3 @@ export * from './getRenderMapVisitor'; export * from './getTypeManifestVisitor'; export * from './renderValueNodeVisitor'; export * from './renderVisitor'; - diff --git a/packages/renderers-rust-cpi/test/utils/traitOptions.test.ts b/packages/renderers-rust-cpi/test/utils/traitOptions.test.ts index 2ae52154b..e7007fcb4 100644 --- a/packages/renderers-rust-cpi/test/utils/traitOptions.test.ts +++ b/packages/renderers-rust-cpi/test/utils/traitOptions.test.ts @@ -32,7 +32,7 @@ describe('default values', () => { // Then we expect the following traits to be rendered. expect(content).toBe( `#[derive(Clone, Debug, Eq, PartialEq)]\n` + - `#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]\n` + + `#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]\n` + `#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]\n`, ); @@ -331,7 +331,9 @@ describe('overridden traits', () => { }); // Then we expect some of the overridden traits to be rendered under feature flags. - expect(content).toBe(`#[derive(MyNonFeatureTrait)]\n#[cfg_attr(feature = "custom", derive(MyFeedbackTrait))]\n`); + expect(content).toBe( + `#[derive(MyNonFeatureTrait)]\n#[cfg_attr(feature = "custom", derive(MyFeedbackTrait))]\n`, + ); }); });