Skip to content

feat(cli): add additionalIdls config option#1018

Open
plutohan wants to merge 4 commits into
codama-idl:mainfrom
plutohan:plutohan/issue-983-additional-idls
Open

feat(cli): add additionalIdls config option#1018
plutohan wants to merge 4 commits into
codama-idl:mainfrom
plutohan:plutohan/issue-983-additional-idls

Conversation

@plutohan

@plutohan plutohan commented Jul 2, 2026

Copy link
Copy Markdown

Closes #983.

Implements the additionalIdls approach from your comment @lorisleiva: the config can list additional Anchor IDLs, and their programs get merged into the root node's additionalPrograms, so one codama.json generates clients for every program in an Anchor workspace.

Includes a README entry, a test, and a changeset.

@changeset-bot

changeset-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6e12844

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

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

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

Comment thread packages/cli/src/parsedConfig.ts Outdated
additionalPrograms.push(...getAllPrograms(additionalRootNode));
}

return rootNode(mainRootNode.program, additionalPrograms);

@mikhd mikhd Jul 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the version could be lost here. (worth checking other fields as well)

getRootNodeFromIdl returns a RootNode one of two ways:

  • If the IDL already is a Codama root node, it returns it as-is, preserving the whatever specified version.
  • Otherwise it's an Anchor IDL, and rootNodeFromAnchor(idl) builds a root node via the rootNode().

const parsed = await getParsedConfig({});

expect(parsed.rootNode.program.name).toBe('main');
expect(parsed.rootNode.additionalPrograms.map(p => p.name)).toEqual(['a', 'b']);

@mikhd mikhd Jul 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would double check that version and other fields are preserved after additionalPrograms merge.
Thank you!

@plutohan

plutohan commented Jul 6, 2026

Copy link
Copy Markdown
Author

Good catch, the merge rebuilt the root node and reset version and standard. It now spreads the main root node instead, with test assertions for both.

@lorisleiva lorisleiva left a comment

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.

Thanks, I like the idea! I've just made a comment on the execution of this idea to make it more async.

Comment thread packages/cli/src/parsedConfig.ts Outdated
Comment on lines +49 to +50
const mainRootNode = await getRootNodeFromIdl(idlContent);
const rootNode = await mergeAdditionalIdls(mainRootNode, config.additionalIdls ?? [], configPath);

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.

I would rather we implemented this as:

  1. Promise.all await all conversions from IDL string to RootNode such that you end up with an array of RootNodes where the first one is the main one. That way all async operations are parallel.
  2. Then have a mergeRootNodes helper function that destructs [head, ...tail] and adds all programs inside tail to the additional programs of head.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done — conversions now run in parallel via Promise.all and a mergeRootNodes helper merges [head, ...tail]. Thanks!

Comment thread packages/cli/src/parsedConfig.ts Outdated
Comment on lines +48 to +49
const idlContent = await importModuleItem({ identifier: 'IDL', from: idlPath });
const rootNode = await getRootNodeFromIdl(idlContent);
const rootNode = await mergeAdditionalIdls(idlContent, config.additionalIdls ?? [], configPath);

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.

Thanks, much better. I still think it would be nice if all RootNodes were recovered in the same way. Here the main RootNode has its own importModuleItem whereas the others at in the parallel execution. Do you know what I mean?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good point — the main IDL now goes through the same loadIdl helper as the others, so all root nodes are recovered identically inside the same Promise.all.

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.

[cli] Add additionalIdls to codama.json config file

4 participants