Skip to content

[2.x] Return decoded nodes from dynamic parsers - #1216

Draft
lorisleiva wants to merge 1 commit into
10-07-add_formatters_for_decoded_nodesfrom
10-07-return_decoded_nodes_from_dynamic_parsers
Draft

lorisleiva wants to merge 1 commit into
10-07-add_formatters_for_decoded_nodesfrom
10-07-return_decoded_nodes_from_dynamic_parsers

Conversation

@lorisleiva

@lorisleiva lorisleiva commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

This PR makes the parsers of @codama/dynamic-parsers return the decoded nodes of @codama/dynamic-codecs, so parsed accounts, events and instructions keep the node of every decoded value, e.g. to format it.

// Before
const parsed = parseAccountData(root, bytes);
parsed.data; // { amount: 42n }
parsed.path; // [root, program, account]

// After
const parsed = parseAccountData(root, bytes); // DecodedAccountNode
parsed.value; // { amount: 42n }
parsed.data; // the decoded struct, with its `fields`
parsed.path; // [root, program, account]
parsed.preOffset; // 0
parsed.postOffset; // 9
  • Decoded nodes: parseAccountData, parseEventData, parseInstructionData and parseData return DecodedAccountNode, DecodedEventNode and DecodedInstructionNode. ParsedData is removed, and the plain value moves from data to value.
  • ParsedInstruction: a DecodedInstructionNode with its named accounts and its remainingAccounts, which is now always present. Named accounts carry their identifier instead of a name.
  • Options: the new ParseDataOptions adds bytesEncoding to programAddress, and parseInstruction accepts bytesEncoding too.
  • Unparsable bytes: unchanged, parsers return undefined when nothing is identified or when the identified node cannot decode the bytes.

@changeset-bot

changeset-bot Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: dbc49ce

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@lorisleiva

Copy link
Copy Markdown
Member Author

@trevor-cortex

@trevor-cortex trevor-cortex left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Swaps getNodeValueCodec for getNodeCodec in parseData, so every parser now returns the DecodedAccountNode / DecodedEventNode / DecodedInstructionNode of @codama/dynamic-codecs instead of the local ParsedData<TNode> wrapper. ParsedInstruction becomes DecodedInstructionNode & { accounts, remainingAccounts }, with remainingAccounts now required and named accounts carrying identifier rather than name. A new ParseDataOptions = CodecVisitorOptions & IdentifyDataOptions threads bytesEncoding through, and parseInstruction takes CodecVisitorOptions directly (its programAddress still comes from the instruction). README and tests are updated accordingly.

The implementation is a thin, correct delegation. Things I checked:

  • Option splitting in parseData is explicit ({ programAddress } → identifyData, { bytesEncoding } → getNodeCodec) rather than forwarding the merged object, so neither side sees keys it doesn't own. Identification only encodes discriminator constants, so it genuinely doesn't need bytesEncoding — nothing is lost there.
  • The as GetDecodedNodeFromKind<TKind> cast is the same shape of erasure as the previous path as NodePath<ParsableNode> and is sound: getNodeCodec on a ParsableNode path yields the union of the three decoded node types, and the kind filter already narrowed the path.
  • Unparsable bytes keep the same try/catch → undefined contract; the "truncated data" and "unknown program" tests still cover it.
  • parseInstruction options type is CodecVisitorOptions, not ParseDataOptions — correct, since passing a programAddress there would silently conflict with instruction.programAddress.
  • README anchors (#decoded-nodes, #value-format, #formatting) all exist in packages/dynamic-codecs/README.md.
  • No other in-repo consumers of ParsedData, .data from the parsers, or name on parsed accounts that this would break (@codama/dynamic-client doesn't depend on dynamic-parsers on this branch).

Things to watch out for

  • ParsedInstruction inherits data?: DecodedTypeNode from DecodedInstructionNode, so for data-less instructions (e.g. the close test) parsed.data is undefined while parsed.value is also undefined. That's consistent with dynamic-codecs, but the "Decoded nodes" intro in this README says every parser returns "the decoded nodes of its data" without that caveat — see inline.
  • The first parseAccountData test asserts toStrictEqual(getNodeCodec(...).decode(...)), which is mostly tautological on its own; it's fine because the two tests right after it pin down the actual shape (path/value/preOffset/postOffset and isDecodedNode(result.data, 'structTypeNode')).

Notes for subsequent reviewers

  • Changeset: none in the PR, which matches the convention on the other [2.x] PRs (seeded major changeset at the end of the migration). When that changeset is written, this PR contributes: ParsedData removed; data → value on all parser results; accounts[].name → identifier and remainingAccounts now required on ParsedInstruction; new ParseDataOptions / bytesEncoding option on all parsers and parseInstruction.
  • Behaviour of identification, the single-candidate fallback, and program selection is untouched — only the decode step and the return shape changed.

Comment thread packages/dynamic-parsers/README.md Outdated
Comment thread packages/dynamic-parsers/README.md Outdated
@lorisleiva
lorisleiva force-pushed the 10-07-return_decoded_nodes_from_dynamic_parsers branch from 95df4cd to dbc49ce Compare October 7, 2026 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants