Skip to content

Align WithElements typing with runtime naming - #1

Merged
myabc merged 1 commit into
mainfrom
fix/element-naming-rule
Aug 10, 2026
Merged

Align WithElements typing with runtime naming#1
myabc merged 1 commit into
mainfrom
fix/element-naming-rule

Conversation

@myabc

@myabc myabc commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Ticket

N/A — internal architecture review of this library.

Stacked on #6 (vitest browser-mode migration): the branch is rebased onto code-maintenance/vitest, so this PR's file list shows #6's commit until #6 lands on main (GitHub's stack feature blocks retargeting the base). Chain: #6 ← this ← #2#4.

What are you trying to accomplish?

Give the element-naming rule (static elements key → xElement/xElements/hasXElement + attribute-override suffix) a single owner. It was spread across helpers.ts, blessing.ts, and types.ts — and the type already disagreed with the runtime: WithElements<{menu_item: string}> produced menu_itemElement vs runtime menuItemElement (documented as a README caveat instead of fixed). Different keys could also silently collide on generated names (foo/_foohasFooElement).

What approach did you choose and why?

  • New src/element-definition.ts owns the rule at runtime (elementDefinition, mergeElementDefinitions) and type level (Camelize<K> mirroring the camelize regex exactly). String helpers become private; types.ts folded in.
  • WithElements now camelizes like the runtime — keys pass verbatim. Compile-surface breaking for snake_case-typed consumers (changeset: minor).
  • Cross-key name collisions warn; later definition wins per property (previous Object.assign semantics). Colliding names get a union type, forcing callers to narrow — an intersection would hide the pathology.
  • Acronym dasherization (htmlURLhtml-u-r-l) locked in by tests, Stimulus-compatible.
  • New typecheck script gates test/types.test-d.ts in CI; build cleans dist/ first. CONTEXT.md records glossary + decisions.

Verification: bun test 40 pass, bun run typecheck clean, bun run build clean.

Merge checklist

  • Added/updated tests
  • Lookbook docs n/a — npm library; README + CONTEXT.md updated
  • Tested major browsers n/a — no browser-dependent behavior

Copilot AI lite review requested due to automatic review settings August 10, 2026 18:06
@myabc myabc changed the title Align WithElements typing with runtime naming Align WithElements typing with runtime naming Aug 10, 2026

Copilot AI 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.

Pull request overview

This PR centralizes the static elements naming rule (runtime + TypeScript) into a single module, aligns WithElements typing with the runtime camelization behavior, and adds CI/typecheck coverage plus characterization tests around collisions and acronym dasherization.

Changes:

  • Introduces src/element-definition.ts as the single owner for element accessor naming (runtime) and Camelize/WithElements (types).
  • Updates the blessing implementation to consume merged element definitions and warn on cross-key generated-name collisions.
  • Adds type-level assertions + CI typecheck, expands tests, and updates docs/changeset accordingly.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/types.test-d.ts Adds tsc-checked type-level assertions for Camelize/WithElements.
test/helpers.test.ts Removes tests for string helpers now made private/relocated.
test/element-definition.test.ts Adds runtime tests for naming, sample-table lockstep, and collision warnings.
test/blessing.test.ts Adds integration/characterization tests for acronym overrides and collision behavior.
src/types.ts Removes old WithElements typing (moved/rewritten).
src/helpers.ts Removes exported string transforms; keeps readInheritableStaticObjectPairs.
src/element-definition.ts New module implementing runtime naming + type-level Camelize/WithElements.
src/blessing.ts Switches to mergeElementDefinitions + ElementDefinition to generate properties.
README.md Updates documentation to reflect runtime-aligned camelization in WithElements.
package.json Cleans dist/ before build; adds typecheck script.
index.ts Re-exports WithElements from the new module.
CONTEXT.md Records glossary + decisions (acronym lock-in, collision policy, type/runtime lockstep).
.github/workflows/test.yml Adds bun run typecheck step in CI.
.changeset/warm-planes-refactor.md Documents the typing alignment + collision warning behavior as a minor change.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/element-definition.ts
Comment thread package.json
"sideEffects": false,
"scripts": {
"build": "bun build ./index.ts --outdir dist --format esm --external @hotwired/stimulus && tsc -p tsconfig.build.json",
"build": "rm -rf dist && bun build ./index.ts --outdir dist --format esm --external @hotwired/stimulus && tsc -p tsconfig.build.json",
The element-naming rule (key -> xElement/xElements/hasXElement +
attribute suffix) was smeared across helpers.ts, blessing.ts, and
types.ts, with no single owner. types.ts re-encoded it by hand and
already disagreed with the runtime: WithElements<{menu_item}> produced
menu_itemElement while the runtime generated menuItemElement.

- add src/element-definition.ts as single owner of the naming rule,
  runtime (elementDefinition, mergeElementDefinitions) and type level
  (Camelize mirroring the camelize regex exactly; ASCII-only,
  tail-recursive to avoid TS2589 on long keys)
- warn when different raw keys collide on a generated property name
  (foo/_foo share hasFooElement; foo's predicate vs hasFoo's getter);
  later definition wins per property, as before. Same-key subclass
  overrides stay silent
- type each generated name as the union of every role producing it:
  non-colliding keys keep exact accessor types, colliding names (e.g.
  hasFooElement from foo + hasFoo) force callers to narrow, since
  runtime key order decides. Numeric keys are stringified before
  Camelize, matching Object.keys
- lock in acronym dasherization (htmlURL -> html-u-r-l) with tests
- gate type assertions (test/types.test-d.ts) via new typecheck
  script; clean dist before build so stale declarations cannot ship
- record domain glossary and decisions in CONTEXT.md
@myabc
myabc force-pushed the fix/element-naming-rule branch from 0c23166 to 5d606a3 Compare August 10, 2026 20:48
@myabc
myabc merged commit a2c096d into main Aug 10, 2026
3 checks passed
@github-actions github-actions Bot mentioned this pull request Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Development

Successfully merging this pull request may close these issues.

2 participants