Skip to content

Latest commit

 

History

History
37 lines (24 loc) · 5.23 KB

File metadata and controls

37 lines (24 loc) · 5.23 KB

Contributing to Codama

Getting started

The repository is a pnpm workspace orchestrated by turbo. The following commands cover the full development loop:

pnpm install
pnpm generate    # regenerate all generated code (must leave a clean tree)
pnpm build       # build all packages
pnpm test        # type checks, treeshakability checks and unit tests
pnpm lint        # oxlint && oxfmt --check
pnpm lint:fix

Most generated/ directories — those under @codama/node-types, @codama/nodes and @codama/visitors-core — are produced by the private @codama-internal/spec-generators package from the @codama/spec meta-model, and must never be edited by hand. CI regenerates them and fails on any diff, so committed generated code always matches the single living spec pin in packages/spec-generators/package.json:

  • @codama/spec is the living pin: the spec version the current major is generated from. It is exact rather than a range, so generated output only changes through a deliberate, reviewable pin (or generator) change.

The generator is single-major: it only renders the spec on its own branch. Node types for older majors live as frozen static snapshots under packages/upgrade/src/vN/generated (e.g. src/v1/generated); these are hand-maintained source, are not regenerated by pnpm generate, and are excluded from the CI freshness check. See packages/upgrade/src/v1/README.md.

Changesets

Any user-facing change needs a changeset: run npx changeset add --empty and edit the created file. One changeset file per concern; entries start with a verb. Never edit CHANGELOG.md files — they are generated by the release workflow. Note that the core packages (codama, @codama/errors, @codama/node-types, @codama/nodes, @codama/validators and the @codama/visitors* packages) version in lockstep as a fixed group, while the remaining packages version independently — below a shared ceiling: all public packages carry the same major version (the era, matching the branch name), so no package ever bumps its major on its own; breaking changes to individual packages wait for the next major cut. The era currently coincides with the spec major it supports — a convenience, not a rule: an ecosystem-impacting codama-only major (no spec change) is legitimate and runs the full candidacy per RELEASING.md.

Releasing a new major of the Codama standard

Branch, dist-tag and lifecycle mechanics (cut / bake / promote) are defined once for the whole ecosystem in the spec repository's RELEASING.md. Releasing major N+1 of the Codama spec additionally requires the following steps specific to this repository. The design intent is that this list never grows: one new upgrade function per major, everything else mechanical.

  1. Freeze the vN node types. Before moving the living @codama/spec pin to the (N+1).x release, snapshot the current vN node types into @codama/upgrade: copy @codama/node-types/src/generated into packages/upgrade/src/vN/generated, keeping the layout identical so a later backported vN change can be ported forward by applying the same patch. Also copy the hand-written siblings (brands.ts, Docs.ts, Version.ts) next to it as vN-shaped frozen copies, so the snapshot is self-contained, and export the vN types as a type-only namespace (export type * as vN) from the package index. The snapshot is static source — it is never regenerated. Then move the living @codama/spec pin to the (N+1).x release and run pnpm generate, which rewrites the living generated/ dirs and restamps CODAMA_VERSION.
  2. Write the upgrade step. Add a single hand-written, pure upgradeVNToVN+1 function to @codama/upgrade — a JSON-tree-in, JSON-tree-out converter in the nodes-from-anchor top-down style — and wire it into upgrade() as its if (major <= N) block.
  3. Run the ecosystem lifecycle. Cut this repository's N.x maintenance branch per RELEASING.md, after which main hosts the vN+1 work, with one codama-specific detail: the seeded major changeset covers all public packages, upholding the same-major invariant. main then versions as (N+1).0.0-rc.n under the rc dist-tag through the candidacy, and is promoted to latest while N.x switches to release-N.x. Old majors receive clarifications and documentation fixes only, never semantic changes.

Two invariants protect consumers and must never be broken:

  • The upgrade chain is append-only. The upgrade functions and frozen node types in @codama/upgrade are committed source with zero runtime dependencies; they are never removed or rewritten, so every major back to 1.0.0 stays upgradable forever.
  • The generator is single-major; snapshots are static. The generator on main only ever renders the living spec of the current major — it is never forked or taught to speak an older spec dialect. Older majors' node types are frozen static snapshots under packages/upgrade/src/vN/generated, whose layout mirrors that major's @codama/node-types/src/generated so a rare backported change is ported forward as a patch. Slightly stale docblocks in a snapshot are acceptable, since old majors never change shape.