Skip to content

fix(http): apply the merge patch transform to the base model - #12299

Open
om singhal (Om-singhaI) wants to merge 1 commit into
microsoft:mainfrom
Om-singhaI:fix/merge-patch-base-model
Open

om singhal (Om-singhaI) wants to merge 1 commit into
microsoft:mainfrom
Om-singhaI:fix/merge-patch-base-model

Conversation

@Om-singhaI

Copy link
Copy Markdown
Contributor

Fixes #11534

The merge patch mutator in packages/http/src/merge-patch.ts transforms the properties and indexer of a model, but the clone keeps baseModel pointing at the original base. So for model Widget extends Base, MergePatchUpdate<Widget> emitted allOf: [{ $ref: Base }], inherited required properties stayed required, and {} was rejected. Nested WidgetMergePatchUpdateOrCreate had the same allOf.

The Model mutator now runs baseModel through the same mutator and sets the result on the clone. The base gets the matching name, such as BaseMergePatchUpdate or BaseMergePatchUpdateOrCreate, and is shared with MergePatchUpdate<Base>. Inherited properties follow the model's own rules: a required id becomes optional but not nullable, optional ones also take null, and a discriminator on the base stays required. I kept the base instead of flattening so emitters still see the inheritance and discriminator. A patched base's discriminator mapping still lists the unpatched derived models, as MergePatchUpdate<Pet> does today.

Two changes to note:

  1. A visible inherited @path or other metadata property now reports merge-patch-contains-metadata, as the model's own properties do. On main it only got the metadata-ignored warning.
  2. A base with @friendlyName now gets a patched copy with the same friendly name, so openapi3 reports duplicate-type-name when the original base is also emitted. Nested models already hit this on main. Happy to fix that here too.

Smaller output changes: a Record<Thing> base now patches its values, and a read only inherited @key @path no longer warns.

I added three cases to packages/http/test/merge-patch.test.ts, one to packages/openapi3/test/merge-patch.test.ts, and a changeset.

Testing, built from this branch:

  • vitest run test/merge-patch.test.ts: 40 passed in packages/http and 7 in packages/openapi3. With src/merge-patch.ts from main, the 4 new cases fail.
  • vitest run: 433 passed in packages/http, 2713 in packages/openapi3 (two workers).
  • The issue's snippet as OpenAPI 3.1: {}, {"label":"x"} and {"label":null} now validate against WidgetPatch.

The merge patch mutator transformed the properties and indexer of a
model but left the clone's baseModel pointing at the original base. For
a model that uses extends, MergePatchUpdate emitted an allOf to the
unpatched base, so inherited required properties stayed required and an
empty patch was rejected.

The base model now goes through the same mutator, so it is emitted as
BaseMergePatchUpdate (or its OrCreate and ReplaceOnly variants) and the
inherited properties follow the same rules as the model's own.
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
1 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Friendly-named base models can cause duplicate schema names and break previously valid OpenAPI emission.

1 open issue
What changed in this PR

Fixes #11534 by applying HTTP merge-patch transforms to base models, so inherited properties follow patch rules while preserving inheritance.

Changes:

  • Transform base models using the matching merge-patch mode.
  • Add inheritance, discriminator, and OpenAPI schema regression tests.
  • Document the fix and diagnostic changes.
File Description
packages/​openapi3/​test/​merge-patch.test.ts Verify patched base schema references.
packages/​http/​test/​merge-patch.test.ts Cover inherited properties, discriminators, and nested transforms.
packages/​http/​src/​merge-patch.ts Transform and assign patched base models.
.chronus/​changes/​fix-merge-patch-base-model-2026-9-16-18-59-38.md Document inheritance behavior and diagnostic changes.

Review effort: Balanced

if (model.baseModel) {
// Inherited properties are part of the patch document too, so the base model goes
// through the same transform instead of pointing at the original base.
const base = cachedMutateSubgraph(program, self, model.baseModel).type;

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:openapi3 Issues for @typespec/openapi3 emitter lib:http

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: MergePatchUpdate keeps allOf on the unpatched base, so an empty merge patch is rejected

2 participants