Skip to content

fix(cli): allow convert to work without a package.json#1009

Merged
lorisleiva merged 6 commits into
codama-idl:mainfrom
senzenn:fix/convert-without-package-json
Jun 22, 2026
Merged

fix(cli): allow convert to work without a package.json#1009
lorisleiva merged 6 commits into
codama-idl:mainfrom
senzenn:fix/convert-without-package-json

Conversation

@senzenn

@senzenn senzenn commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #1008 (closed), trimmed down to just the decoupled fix we talked about there.

Running codama convert outside a Node project failed with Cannot read package.json. The install prompt never got a chance to run because installMissingDependencies reads the package.json first and throws when it's missing.

Changes:

  • tryGetPackageJson no longer throws when there's no package.json. A missing file just means "no deps" and "no package manager set".
  • If @codama/nodes-from-anchor is already installed, use it directly instead of going through the install prompt. So convert works without a package.json when the adapter is there.

Left out on purpose:

The adapter-side CLI (option 1 from the thread) isn't here, can do that once we agree on the direction.

tsc --noEmit, eslint, prettier --check and vitest all pass.

@changeset-bot

changeset-bot Bot commented Jun 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1b8667c

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 Patch
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/utils/packageJson.ts
Comment thread packages/cli/src/utils/nodes.ts Outdated

@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.

Trimmed-down follow-up to #1008 — much nicer scope. The fix is two clean parts:

  1. tryGetPackageJson() returns undefined instead of throwing, and getPackageJsonDependencies / detectPackageManagerFromPackageJson now degrade to "no deps" / "unknown PM" rather than blowing up. getPackageJson() is preserved as the throwing variant for callers that genuinely require it.
  2. getRootNodeFromIdl tries to import @codama/nodes-from-anchor directly before falling back to the install prompt, so a globally/npx-resolvable adapter works without a package.json in cwd.

The behavior change is small and well-scoped to fixing the codama convert UX outside a Node project. Two things worth a look before merging — both around the nodes.ts try/catch — plus one note on a subtle behavior shift in getPackageJsonDependencies. Nothing blocking from my side.

Things to verify:

  • Manual smoke test: codama convert in a tmp dir with no package.json, with @codama/nodes-from-anchor reachable both (a) via a globally-linked install and (b) via npx codama convert. Both should resolve the adapter without hitting the install prompt.
  • Same command in a tmp dir with no package.json and no adapter reachable — should still fall through to the install prompt and not crash with the old Cannot read package.json error.
  • getPackageManager() in a no-package.json dir should now fall through to lockfile / installed-CLI detection / npm fallback without throwing.

Notes for subsequent reviewers:

  • No tests added; the utils don't seem to have a great harness for fs-touching code today, so probably fine — but a unit test for tryGetPackageJson returning undefined would be cheap insurance if you have a fixture pattern in mind.
  • Option 1 from the #1008 thread (adapter-side CLI) is deliberately not in scope here, as called out in the description.

Comment thread packages/cli/src/utils/nodes.ts Outdated
Comment thread packages/cli/src/utils/nodes.ts Outdated
Comment thread packages/cli/src/utils/packageJson.ts
Comment thread packages/cli/src/utils/packageJson.ts
@senzenn

senzenn commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

hey @trevor-cortex Scope's exactly the intent. Ran the smoke tests:

  • no package.json + adapter resolvable → converts directly, no prompt. Tested via the adapter resolvable next to the CLI, same branch a global link / npx
    adapter hits.
  • no package.json + no adapter → packed the CLI and installed it outside the monorepo so nodes-from-anchor is genuinely unresolvable. Falls through to
    Install dependencies? (Y/n), no Cannot read package.json crash. Under CI=1 prints the manual command and exits clean.
  • getPackageManager() with no package.json → confirmed by the above, didn't throw, resolved a PM via the fallback path.

Unit test for tryGetPackageJson → undefined is fair; can add one in this PR before merge if you want, else follow-up. Adapter-side CLI stays out of scope.

@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.

Looks good, thanks!

EDIT: One weird test failing in CI haha. If you wouldn't mind taking care of that? 🙏

Comment thread packages/cli/src/utils/nodes.ts Outdated
@lorisleiva

Copy link
Copy Markdown
Member

@trevor-cortex

@trevor-cortex

Copy link
Copy Markdown

Found it — it's nodes.test.ts › suggests npx without installing when package.json and the adapter are missing. The test asserts plain strings:

'Missing dependency: @codama/nodes-from-anchor',
...
'Re-run with: npx -p codama -p @codama/nodes-from-anchor codama convert anchor.json codama.json',

but the production code wraps those labels with pico.bold(...) / pico.yellow(...). Picocolors' isColorSupported is true whenever process.env.CI is set (even without a TTY), so in GitHub Actions those calls actually emit ANSI escapes — \x1b[1mMissing dependency\x1b[22m: … — and the toEqual([...]) comparison fails. Locally there's no CI env var and no TTY, so the same calls return plain strings and the test passes. Classic env-dependent flake.

Cleanest fix is to mock picocolors in that test file so the assertions are deterministic regardless of where they run:

vi.mock('picocolors', () => ({
    default: { bold: (s: string) => s, yellow: (s: string) => s },
}));

(pico is imported as the default export in nodes.ts, so mocking default is what matters.) Alternatively, strip ANSI from the actual values before comparing, but the mock is less code and keeps the expected strings readable.

No other tests look affected — packageJson.test.ts doesn't touch picocolors output, and the other nodes.test.ts cases only assert on error.message (no pico calls on that path).

Drop the message-based assertion that the error names the requested
module; any ERR_MODULE_NOT_FOUND/MODULE_NOT_FOUND now means the adapter
is not resolvable and we fall back accordingly.
@senzenn senzenn requested a review from lorisleiva June 20, 2026 01:28

@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! Just one last nit and LGTM. 👌

Comment thread packages/cli/src/utils/nodes.ts Outdated
@lorisleiva lorisleiva merged commit f6deb59 into codama-idl:main Jun 22, 2026
4 checks passed
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.

3 participants