feat(motoko): emit type alias names as PascalCase#729
Open
feat(motoko): emit type alias names as PascalCase#729
Conversation
Candid type aliases are now rendered in UpperCamelCase in generated Motoko bindings (e.g. `my_type` → `MyType`). When two names would map to the same UpperCamelCase form (e.g. `A` and `a`), the collision is detected and the original escaped name is kept instead. `Self` is always reserved as it is emitted verbatim by the actor declaration. All-separator inputs (e.g. `_`) that produce an empty transform also fall back to the original name. Adds `to_upper_camel_case`, `escape_str` (string-returning escape helper reused by both `escape` and the collision fallback), and `type_display_name` which performs the collision check against the full `TypeEnv`. All printer functions now accept `env: &TypeEnv`, mirroring the TypeScript binding generator. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Click to see raw report |
Co-authored-by: Cursor <cursoragent@cursor.com>
- Introduce BindingCtx<'a> (Copy+Clone) bundling env + precomputed names map, threaded through all printer functions instead of bare &TypeEnv. compile_inner handles the lifetime split. - build_names() runs one O(N) pass over env to count PascalCase collisions, then assigns display names in a second pass — replaces the previous O(N²) per-type env scan. - to_pascal_case() simplified: just requires lowercase first char, no artificial domain restrictions needed since build_names sees all names at once and detects collisions via count map. - Rename Ctx → BindingCtx; pp_defs uses ctx.names[id] (infallible). - Add pascal_collision.did and self_type.did test fixtures covering two-name PascalCase collisions, verbatim env-key collisions, and the Self reservation guard. - CHANGELOG: document breaking PascalCase rename. Co-authored-by: Cursor <cursoragent@cursor.com>
- build_names: pass 1 assigns collision-free escape_str fallbacks, pass 2 upgrades to PascalCase where unclaimed — no implicit ordering dependency, fallback collisions provably impossible. - to_pascal_case simplified: just requires lowercase first char. - Rename Ctx → BindingCtx; pp_defs uses ctx.names[id] (infallible). - Remove dead env.0.contains_key collision proxy. - Trim comments throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is motivated by caffeinelabs/mops-ic#7, where I plan to set up automatic regeneration of the management canister Motoko package — idiomatic naming is essential when the output is consumed directly without manual editing.
What
Generated Motoko bindings now render type alias names in PascalCase (e.g.
my_type→MyType,list→List).Why
Motoko types are conventionally PascalCase — the stdlib, the language spec, and the compiler's own style all follow this. Generated bindings that emit
type my_type = ...are immediately out of place: developers either tolerate the inconsistency or write manual re-alias wrappers every time. This change makes generated code idiomatic and directly usable without wrapping.Migration
Rename any references to generated type aliases from their old snake_case form to PascalCase:
Edge cases handled
Aandaboth →A), the collider keeps its original escaped name. The first name alphabetically wins the PascalCase slot.Selfreservation: always reserved —pp_actoremits it verbatim for the actor declaration._) fall back to the escaped original.These guarantees ensure generated bindings always compile.