Skip to content

feat: add deduplicateRefsIgnoringKeys option to structural hash - #682

Open
klear-jason wants to merge 6 commits into
bcherny:masterfrom
klear-jason:feat/deduplicate-refs-ignoring-keys
Open

feat: add deduplicateRefsIgnoringKeys option to structural hash#682
klear-jason wants to merge 6 commits into
bcherny:masterfrom
klear-jason:feat/deduplicate-refs-ignoring-keys

Conversation

@klear-jason

@klear-jason klear-jason commented May 7, 2026

Copy link
Copy Markdown

Adds a new deduplicateRefsIgnoringKeys option (default []) that excludes specified schema keys from the structural hash used to deduplicate $ref types.

The canonical use case: when the same $ref appears on multiple properties with different description values, deduplicateRefsIgnoringKeys: ['description'] causes those properties to share a single type declaration instead of generating suffixed duplicates (MoneySchema, MoneySchema1…). Descriptions are preserved as JSDoc on the property rather than forking a new type.

Note: This PR depends on #678 and should be reviewed/merged after it. The diff currently appears large because the fork includes #678's commits which haven't landed on upstream master yet. Once #678 is merged, I'll rebase this branch — the actual change is only 3 files, +25 / -5 lines.

uprising8664 and others added 6 commits December 20, 2025 19:28
- Add structural hash-based deduplication for schemas with same title
- Track emitted type names in generator to prevent duplicate declarations
- Schemas with identical title and structure now reuse same type definition
- Different structures with same title get unique numbered names (e.g. Option, Option1)
- Add comprehensive test coverage for duplicate sub-schema scenarios
Add four test fixtures covering:
- NAMED_ENUM dedup with matching title
- NAMED_ENUM dedup without title (property name match)
- UNNAMED_ENUM dedup with matching title
- Mixed scenario (identical + non-identical enums)
Previously the dedup cache in standaloneName() only activated when
schema.title was present. Without a title, identical enum schemas on
same-named properties bypassed the cache and received fresh names
(Status, Status1, Status2...) instead of deduplicating.

Remove the if (schema.title) guard so the cache runs whenever name
is available. Change cache key from ${schema.title}::${hash} to
${name}::${hash} to cover all named schemas.
…attern

declareEnums() used object-identity dedup (Set<AST>). Two distinct AST
objects with the same standaloneName both emitted declarations, producing
duplicates in the output.

Add emittedNames: Set<string> parameter (default new Set<string>()) and
check ast.standaloneName before emitting, matching the existing pattern
in declareNamedInterfaces() and declareNamedTypes(). Pass emittedNames
through all 5 recursive call sites (ARRAY, UNION, INTERSECTION, TUPLE,
INTERFACE). Each declare function retains its own independent set.
New snapshots for four duplicate-enum fixtures, each showing a single
declaration instead of duplicates.

Existing real-world snapshots (FHIR, Azure, schemaStore, arrayAdditionalItems)
are reduced where previously-duplicate enum and interface declarations are now
correctly deduplicated. All 169 tests pass.
Adds a new deduplicateRefsIgnoringKeys option (default []) that excludes specified schema keys from the structural hash used to deduplicate $ref types.

The canonical use case: when the same $ref appears on multiple properties with different description values, deduplicateRefsIgnoringKeys: ['description'] causes those properties to share a single type declaration instead of generating suffixed duplicates (MoneySchema, MoneySchema1…). Descriptions are preserved as JSDoc on the property rather than forking a new type.

Builds on the structural hash deduplication introduced in this branch.
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