Skip to content

[2.x] Add v1 to v2 upgrade converters for types and values - #1200

Merged
lorisleiva merged 1 commit into
mainfrom
10-02-add_v1_to_v2_upgrade_converters_for_types_and_values
Oct 9, 2026
Merged

lorisleiva merged 1 commit into
mainfrom
10-02-add_v1_to_v2_upgrade_converters_for_types_and_values

Conversation

@lorisleiva

@lorisleiva lorisleiva commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

This PR adds the converters that turn v1 type and value nodes into v2 ones, in packages/upgrade/src/v1ToV2/. It doesn't wire them into upgrade() yet: that comes with instructions, programs and the root.

What they do:

  • Renames name to identifier, joins docs with \n, and turns wrapper types into transforms.
  • Splits numbers into integer and float types, and moves date-times, durations and amounts into their v2 types or displays.
  • Unifies enum variants into enumVariantTypeNode. One-item tuple variants keep their tuple, along with the payloads of their values, so the upgrade is a faithful translation and generated APIs stay unchanged.
  • Types v1 numbers from their expected type, following links across programs, so 3 on an f64 becomes floatValueNode('3'). Without a type, whole numbers become integers.
  • Converts discriminators, PDAs, links and definitions. programNode.origin is dropped.

Nodes are built as plain objects with compactAndFreeze rather than with the @codama/nodes constructors. That way this step keeps producing v2 nodes once the constructors move on to later majors. Each node is frozen along with its array attributes, and its attributes mirror the v1 node rather than the v2 constructor defaults.

Some v1 information can't be expressed in v2 and is dropped. None of it affects encoding:

v1 v2
Date-time or duration display on a size prefix Plain integer
Date-time on a float Plain float
Amount display or amountTypeNode on a float Unit display only
Amount display without decimals Unit display, or nothing without a unit
amountTypeNode on shortU16 Integer with an amount display
Amount or duration display on the number of a dateTimeTypeNode Date-time without the display

A float where only integers are accepted, such as a size prefix, throws. A non-integral value on an integer type, such as 1.5 on a u64, becomes a floatValueNode rather than throwing: the v1 input was already invalid, and this is the one case where the output isn't valid v2, so validators will report it.

This PR also fixes the existing upgrade tests, which assumed v1 was the latest major, and corrects the README, which claimed the v1 types were generated.

@changeset-bot

changeset-bot Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: cd53890

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 lorisleiva changed the title Add v1 to v2 upgrade converters for types and values [2.x] Add v1 to v2 upgrade converters for types and values Oct 2, 2026
@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

Adds the v1 → v2 converters for types, values, displays, links, PDAs, discriminators and definitions under packages/upgrade/src/v1ToV2/, without wiring them into upgrade() yet. Nodes are built as plain frozen objects via compactAndFreeze (so the step keeps emitting v2 once @codama/nodes moves on), v1 numbers are typed from their expected type by following links across programs through a V1NodePath abstraction, wrappers become transforms, and the quantity/date-time/duration display → type migrations are handled with explicit lossy rules. Also fixes the existing upgrade tests that assumed v1 was the latest major, and adds a type-only src/v2 namespace that re-exports @codama/node-types for now.

This is a careful, well-tested PR. The path-based link resolution in paths.ts is clean, the lossy cases are explicitly enumerated and tested, and the freeze-everything test in shared.test.ts is a nice guard. Comments below are small; the only one I'd want addressed before merge is the first.

Things to watch out for

  1. dateTimeTypeNodeFromV1 can leak a display into the date-time's number slot. numberTypeNodeFromV1 keeps amountNumberDisplayNodes on integers, so a v1 dateTimeTypeNode whose inner number carries one yields a v2 dateTimeTypeNode whose number has a display — which the v2 DateTimeTypeNode.number docblock forbids ("a pure encoding slot… must not carry a unit or display of its own"). quantityTypeNodeFromV1 already strips displays for exactly this reason; this path should too. Inline comment with details.

  2. Duration display inside a v1 dateTimeTypeNode drops the date-time entirely. The default branch returns converted.number for the durationTypeNode case, so the result is a bare integer. I'd have expected the outer, type-level dateTimeTypeNode to win over a presentational display. Question inline; either way it's untested and missing from the lossy table in the description.

  3. Non-integral numbers on integer types become floatValueNodes (numberValueNodeFromV1). That's lossless and tested, but it produces a v2 tree the validators will reject rather than throwing at upgrade time like integerTypeNodeFromV1 does for float formats. I think not throwing is the right call for value nodes (the v1 tree was already invalid), just flagging the asymmetry so it's a conscious choice — worth a line in the description.

  4. CONTRIBUTING playbook. Step 1 of "Releasing a new major" says to snapshot @codama/node-types/src/generated into packages/upgrade/src/vN/generated. Now that src/v2/index.ts exists as a living re-export of @codama/node-types, cutting v3 means replacing that file with the frozen snapshot's index and creating src/v3/index.ts as the new re-export. The docblock in src/v2/index.ts says this, but the playbook is meant to be the single source of truth — a sentence there (and maybe a note that @codama/node-types in dependencies is type-only, to reconcile with the "zero runtime dependencies" invariant) would keep it that way. Could be a follow-up when upgrade() gets wired.

Notes for subsequent reviewers

  • Enum value link resolution is positional. enumValueNodeFromV1 resolves value.enum from the value's path (the program the value is written in), not from the path of the type the value belongs to. The test "it resolves enum links without a program in the program of the value" pins this. It matches v1 LinkableDictionary semantics, so it looks right to me, but it's the subtlest decision in valueNodes.ts.
  • 1-tuple variants are deliberately kept as tuples, even though v2 says a single-type variant needs no tuple. The description explains why (faithful translation, generated APIs unchanged). Valid v2, just non-idiomatic.
  • unit vs unitNumberDisplayNode on floats: amountTypeNode over a float → unit (static string, semantic), while an amountNumberDisplayNode over a float → display: unitNumberDisplayNode (injectable, presentational). That asymmetry is correct given v1's two different unit fields, not an inconsistency.
  • displayNodeFromV1 shallow-spreads v1 display nodes; I verified all five "unchanged" kinds are flat (strings/enums only) in v1 and that v2 accepts string where it now also allows TextNode, so this is safe.
  • decimalStringFromV1 / integerStringFromV1 outputs match the DecimalString / IntegerString grammars in brands.ts, including -0, NaN and ±Infinity.

Comment thread packages/upgrade/src/v1ToV2/typeNodes.ts Outdated
Comment thread packages/upgrade/src/v1ToV2/typeNodes.ts Outdated
Comment thread packages/upgrade/src/v1ToV2/valueNodes.ts
@lorisleiva
lorisleiva force-pushed the 10-02-add_v1_to_v2_upgrade_converters_for_types_and_values branch from 74545e7 to cd53890 Compare October 2, 2026 14:44

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

Re-review

All three code-level points from my first pass are addressed, and the description now documents both lossy behaviours I asked about. Approving.

What changed since last time (typeNodes.ts, typeNodes.test.ts, description):

  • dateTimeTypeNodeFromV1 now rebuilds the number slot with display: undefined for both the integerTypeNode and durationTypeNode cases, so an amount display can no longer leak into the v2 date-time's pure encoding slot. The two branches share one arm, which keeps it tidy. The dateTimeTypeNode branch is safe without stripping because numberTypeNodeFromV1 only attaches a display when the v1 display is an amountNumberDisplayNode, which is mutually exclusive with the date-time display that produces that branch.
  • A duration display inside a v1 dateTimeTypeNode now yields a dateTimeTypeNode (type wins over presentational display) rather than a bare integer. The new test covers both the amount and duration cases, and the duration case also exercises a wrapper so the transforms-on-the-date-time path is pinned.
  • The docblock on dateTimeTypeNodeFromV1 spells out the rules, and the description's lossy table gained the corresponding row plus the note on non-integral values becoming floatValueNodes.

Still open, non-blocking: the CONTRIBUTING "Releasing a new major" step 1 doesn't yet mention that src/v2/index.ts is a living re-export that gets replaced (and src/v3/index.ts created) at the next major. Fine as a follow-up when upgrade() is wired, as noted before.

No new issues found in the re-fetched diff.

@lorisleiva
lorisleiva force-pushed the 10-02-add_v1_to_v2_upgrade_converters_for_types_and_values branch from cd53890 to f1c5fa8 Compare October 9, 2026 09:08
@lorisleiva
lorisleiva marked this pull request as ready for review October 9, 2026 09:11
@lorisleiva
lorisleiva merged commit 63a960a into main Oct 9, 2026
2 of 4 checks passed
@lorisleiva
lorisleiva deleted the 10-02-add_v1_to_v2_upgrade_converters_for_types_and_values branch October 9, 2026 09:11
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