Skip to content

feat(nodes): add ConstantNode support with Anchor parsing#958

Open
tanmay4l wants to merge 1 commit intocodama-idl:mainfrom
tanmay4l:t1
Open

feat(nodes): add ConstantNode support with Anchor parsing#958
tanmay4l wants to merge 1 commit intocodama-idl:mainfrom
tanmay4l:t1

Conversation

@tanmay4l
Copy link
Copy Markdown
Contributor

@tanmay4l tanmay4l commented Dec 12, 2025

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Dec 12, 2025

🦋 Changeset detected

Latest commit: caa2700

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@codama/visitors-core Minor
@codama/nodes-from-anchor Minor
@codama/node-types Minor
@codama/nodes Minor
@codama/cli Patch
@codama/dynamic-codecs Patch
@codama/dynamic-parsers Patch
@codama/renderers-core Patch
@codama/validators Minor
@codama/visitors Minor
@codama/errors Minor
codama Minor

Not sure what this means? Click here to learn what changesets are.

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

@tanmay4l tanmay4l marked this pull request as ready for review December 12, 2025 13:40
@lorisleiva
Copy link
Copy Markdown
Member

Hi, thanks for the PR!

This is looking pretty good. The only thing I'm unsure of is whether on not the ConstantNode should wrap the existing ConstantValueNode which is the existing way for us to describe a type + value combo.

On one hand, this would make the ConstantValueNode the single source of truth for handling constants (visitors just need to add an implementation for this Node and it'll work everywhere in the tree).

On the other hand, this make the ConstantNode a bit awkward because it'll access data by doing something like program.constants[0].constant.value. Maybe something that can be fixed with a better naming convention?

What do you think?

@tanmay4l
Copy link
Copy Markdown
Contributor Author

tanmay4l commented Jan 5, 2026

Hi, thanks for the PR!

This is looking pretty good. The only thing I'm unsure of is whether on not the ConstantNode should wrap the existing ConstantValueNode which is the existing way for us to describe a type + value combo.

On one hand, this would make the ConstantValueNode the single source of truth for handling constants (visitors just need to add an implementation for this Node and it'll work everywhere in the tree).

On the other hand, this make the ConstantNode a bit awkward because it'll access data by doing something like program.constants[0].constant.value. Maybe something that can be fixed with a better naming convention?

What do you think?

hmm interesting point about ConstantValueNode. I kept them separate because program constants need name field, which ConstantValueNode doesn't have. also constants[0].constant.value feels awkward. But I see your point about reuse.
would you prefer I refactor it to wrap ConstantValueNode? happy to change if that's the direction you want

@tanmay4l tanmay4l closed this Mar 30, 2026
@lorisleiva
Copy link
Copy Markdown
Member

Hey sorry for the late reply, I was actually gonna review this properly this week. Are you still okay keeping this PR open? ☺️

@tanmay4l
Copy link
Copy Markdown
Contributor Author

tanmay4l commented Mar 30, 2026

Hey sorry for the late reply, I was actually gonna review this properly this week. Are you still okay keeping this PR open? ☺️

sure haha ( ill resolve conflict )

@tanmay4l tanmay4l reopened this Mar 30, 2026
Copy link
Copy Markdown
Member

@lorisleiva lorisleiva left a comment

Choose a reason for hiding this comment

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

Thanks for this PR and again sorry for the super later review.

I've made a few comments, lmk what you think.

I also think you're missing an important test file in the packages/visitors-core/test/nodes folder (e.g. look at the packages/visitors-core/test/nodes/DefinedTypeNode.test.ts file for reference).

P.S.: Don't forget to rebase. ☺️

Comment on lines +13 to +14
readonly type: TType;
readonly value: TValue;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Btw I've decided, I think it's better to keep the design as-is. 🙌

Wrapping a ConstantValueNode inside feels a bit dirty just for the sake of removing a little duplication.

// so we use u8 to represent the type of each element
const type =
idl.type === 'bytes'
? numberTypeNode('u8')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are you sure this is correct? This represents a single u8 number. Should this not just be bytesTypeNode() since the parseConstantValue returns a bytesValueNode('base16', ...) anyway?

I also wonder if we should check the parsed value against the unparsed type to make sure they match together. Wdyt?

// so we use u8 to represent the type of each element
const type =
idl.type === 'bytes'
? numberTypeNode('u8')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same question here.

value: '[116, 101, 115, 116]', // "test" in bytes
});

expect(node).toEqual(constantNode('seedPrefix', numberTypeNode('u8'), bytesValueNode('base16', '74657374')));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah see this should actually just use the bytesTypeNode() type here to match bytesValueNode(...).

The BytesTypeNode basically just means, it's a type representing raw-bytes without any size constraints. BytesValueNode helps describing the value for these bytes.

Comment on lines +33 to +35
// Type should be parsed, value should be string
expect(node.name).toBe('appName');
expect(node.value).toEqual(stringValueNode('MyApp'));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What's the type here?

### Numeric Constant

```ts
const maxSize = constantNode('MAX_SIZE', numberTypeNode('u32'), numberValueNode(100));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's stay consistent here with the casing so MAX_SIZE should be maxSize. Let's also use const node = to be consistent with the rest of the documentation.

Comment on lines +48 to +51
```ts
const maxItems = constantNode('MAX_ITEMS', numberTypeNode('u64'), numberValueNode(1000));
// Note: Add docs via the ConstantNode interface if needed
```
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This example needs to use the 4th parameter to show how to document a constant.

// Note: Add docs via the ConstantNode interface if needed
```

## Parsing from Anchor IDL
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's remove that section. We don't do that for any other node. Anchor parsing is bounded in its own package.

Comment thread tsup.config.base.ts
outExtension() {
return { js: `.cjs` };
},
treeshake: false,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's remove this change unless this is a blocker for this PR.

Comment on lines +75 to +80
test('it preserves docs on constantNode', () => {
const node = constantNode('myConstant', numberTypeNode('u32'), numberValueNode(42), ['My docs']);
const result = visit(node, identityVisitor());
assertIsNode(result, 'constantNode');
expect(result.docs).toEqual(['My docs']);
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a bit too specific of a test for that file. I'd remove it altogether.

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