Skip to content

[nodes-from-anchor] Issue with renderers-js and nested account names #754

@macalinao

Description

@macalinao

If one has an Anchor program with two separate nested accounts with the same account name, Codama generates TypeScript code with duplicate property names.

Below is my fix for this issue-- is there a recommended place for this to go in the codebase?

import type {
  AnchorIdl,
  IdlV01InstructionAccountItem,
} from "@codama/nodes-from-anchor";
import { instructionAccountNodeFromAnchorV01 } from "@codama/nodes-from-anchor";
import type {
  AccountNode,
  InstructionAccountNode,
  InstructionArgumentNode,
} from "codama";
import {
  assertIsNode,
  bottomUpTransformerVisitor,
  camelCase,
  rootNodeVisitor,
  visit,
} from "codama";

function instructionAccountNodesFromAnchorV01(
  allAccounts: AccountNode[],
  instructionArguments: InstructionArgumentNode[],
  idl: IdlV01InstructionAccountItem[],
  parent: string | null = null,
): InstructionAccountNode[] {
  return idl.flatMap((account) =>
    "accounts" in account
      ? instructionAccountNodesFromAnchorV01(
          allAccounts,
          instructionArguments,
          account.accounts,
          // null,
          parent ? `${parent}_${account.name}` : account.name,
        )
      : [
          instructionAccountNodeFromAnchorV01(
            allAccounts,
            instructionArguments,
            {
              ...account,
              name: parent ? `${parent}_${account.name}` : account.name,
              pda:
                account.pda && parent
                  ? {
                      ...account.pda,
                      seeds: account.pda.seeds.map((seed) => {
                        if (seed.kind === "account") {
                          return {
                            ...seed,
                            path: `${parent}_${seed.path}`,
                          };
                        }
                        return seed;
                      }),
                    }
                  : undefined,
            },
            idl,
          ),
        ],
  );
}

export function instructionAccountsDedupeVisitor(idl: AnchorIdl) {
  return rootNodeVisitor((node) => {
    const accountNodes = node.program.accounts;
    const instructionVisitor = bottomUpTransformerVisitor([
      {
        select: "[instructionNode]",
        transform: (node, _stack) => {
          assertIsNode(node, "instructionNode");
          const idlIx = idl.instructions.find(
            (ix) => camelCase(ix.name) === node.name,
          );
          if (!idlIx) {
            throw new Error(`Instruction ${node.name} not found in Idl`);
          }
          return {
            ...node,
            accounts: instructionAccountNodesFromAnchorV01(
              accountNodes,
              node.arguments,
              idlIx.accounts,
            ),
          };
        },
      },
    ]);
    return visit(node, instructionVisitor);
  });
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    anchorImproves conversion from Anchor IDL

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions