Skip to content

refactor: replace internal weak-registry with Atom.family - #99

Merged
lucas-barake merged 2 commits into
mainfrom
refactor/atom-family-registries
Jul 10, 2026
Merged

refactor: replace internal weak-registry with Atom.family#99
lucas-barake merged 2 commits into
mainfrom
refactor/atom-family-registries

Conversation

@lucas-barake

Copy link
Copy Markdown
Owner

What

Deletes packages/form/src/internal/weak-registry.ts — a hand-rolled WeakRef + FinalizationRegistry keyed-memoization helper — and replaces every use of it in FormAtoms.ts with effect v4's native Atom.family, which implements the exact same mechanism (including the identical Map fallback for environments without WeakRef/FinalizationRegistry).

Net: -154/+146 lines, all of the get/compare/set boilerplate gone.

Design

Composite { path, schema } family keys preserve the schema-identity recreation behavior. getOrCreateValidationAtom and getOrCreateFieldAtoms previously kept a side Map<string, Schema.Top> and recreated atoms when the schema instance for a path changed (contract-tested in "recreates field atoms when schema changes for the same path"). Since getOrCreateFieldAtoms/getOrCreateValidationAtom are on the public FormAtoms interface, a different-schema call for the same path is reachable, so the behavior is not dead and was kept. Atom.family compares keys with structural Hash/Equal: in a plain-object key, path compares by value and schema (a non-plain object) by reference — so a fresh { path, schema } literal with the same schema reference hits the memoized entry, and a different schema instance yields a new one. Verified by executing the pinned effect@4.0.0-beta.52 before designing (fresh literals memoize; different schema ref creates; two separately-built identical schemas are not Equal, matching the old === check exactly).

Reset iteration via key maps. Atom.family does not expose iteration, but resetValidationAtoms must visit every created validation atom and zero every fieldValidationCountAtom. Two plain Map<string, key>s record the latest key per path (paths are bounded by the form's field/array-item structure, so no GC concern); reset iterates them and calls family(key) to obtain each entry. If an entry was garbage-collected, family(key) recreates a fresh atom and the Atom.Reset write / count-to-0 write is a harmless no-op — same observable behavior as the old registry, which simply skipped collected entries. These maps also subsume the old validationSchemaRegistry/fieldSchemaRegistry.

Plain-object bundles memoize directly. Atom.family is generic over T extends object, not atom-specific, so the FieldAtoms and PublicFieldAtoms bundles are returned straight from their families with no extra memo layer.

isDirtyAtom family keyed by path only. The old code shared one isDirtyAtomsRegistry between getOrCreateFieldAtoms and getFieldIsDirty so the dirty atom survives a schema-driven bundle recreation; a dedicated isDirtyAtomFamily(path) keeps that sharing, and the now-redundant getFieldIsDirty wrapper is inlined.

Breaking change (beta)

FormAtoms.validationAtomsRegistry and FormAtoms.fieldAtomsRegistry are removed from the public interface along with the WeakRegistry type. They were only used by two tests in this repo (updated to assert instance identity through getOrCreateFieldAtoms/getOrCreateValidationAtom, which is a stronger check than the old "registry entry is defined"). External consumers should use those getters instead.

Tests

  • All existing tests pass unchanged in intent (303 passing; the only edits are the two tests that poked the removed registries).
  • New: "returns the same atoms for repeated calls with the same path and schema" — locks the memoization contract for field atoms, validation atoms, and public field atoms.
  • New: "resets validation state and per-field validation counts for every created field" — creates two field atom sets with failing checks, triggers both validations to Failure, bumps both counts, resets, and asserts both validation atoms return to Initial and both counts to 0.

pnpm vitest run (303 passed), pnpm check:types, and pnpm lint are green.

@lucas-barake
lucas-barake merged commit e1239e8 into main Jul 10, 2026
4 checks passed
@lucas-barake
lucas-barake deleted the refactor/atom-family-registries branch July 10, 2026 02:35
@github-actions github-actions Bot mentioned this pull request Jul 10, 2026
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.

1 participant