Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 22, 2025

Implementation Plan for OpenAPI 3.2.0 defaultMapping Support ✅

  • Explore codebase and understand discriminated union handling
  • Create unit tests for defaultMapping feature
    • Test default variant included in oneOf
    • Test defaultMapping property in discriminator (3.2.0 only)
    • Test that mapping includes default variant for versions < 3.2
  • Create OpenAPI 3.2 schema emitter (schema-emitter-3-2.ts)
    • Extend OpenAPI 3.1 emitter
    • Override discriminatedUnion method
    • Add default variant to oneOf array
    • Add defaultMapping to discriminator (3.2.0 only)
  • Update openapi-spec-mappings.ts to use new 3.2 emitter
  • Update base schema emitter for versions < 3.2
  • Run tests and verify changes
  • Format code and add changelog entry
  • Add cspell dictionary entries

Summary

This PR implements support for OpenAPI 3.2.0 defaultMapping property in discriminated unions as specified in the OpenAPI 3.2.0 specification.

Problem

When a discriminated union has a default variant (unnamed variant), it was previously:

  • Not included in the oneOf array
  • Not referenced in the discriminator at all

This meant the default variant was essentially lost in the OpenAPI output.

Solution

For OpenAPI 3.2.0:

  • Default variant is included in the oneOf array
  • Default variant is referenced via discriminator.defaultMapping property
  • Default variant's discriminator value is NOT in the mapping object

For OpenAPI 3.0.0 and 3.1.0:

  • Default variant is included in the oneOf array
  • Default variant's discriminator value IS in the mapping object (backward compatibility)

Example TypeSpec Input:

@discriminated(#{discriminatorPropertyName: "taxonomic_family", envelope: "none"})
union Animal {
  Dog,
  felidae: Cat,
  muscidae: Ferret
}

model Dog {
  taxonomic_family: "canidae";
}

model Cat {
  taxonomic_family: "felidae";
}

model Ferret {
  taxonomic_family: "muscidae";
}

OpenAPI 3.2.0 Output:

components:
  schemas:
    Animal:
      type: object
      oneOf:
        - $ref: '#/components/schemas/Cat'
        - $ref: '#/components/schemas/Ferret'
        - $ref: '#/components/schemas/Dog'  # ✅ Default variant included
      discriminator:
        propertyName: taxonomic_family
        defaultMapping: '#/components/schemas/Dog'  # ✅ New in 3.2.0
        mapping:
          felidae: '#/components/schemas/Cat'
          muscidae: '#/components/schemas/Ferret'
          # ✅ canidae NOT in mapping for 3.2.0

Changes Made:

  1. packages/compiler/src/core/helpers/discriminator-utils.ts

    • Fixed bug where defaultVariant was not being returned in DiscriminatedUnion structure
  2. packages/openapi3/src/schema-emitter-3-2.ts (NEW)

    • Created OpenAPI 3.2-specific schema emitter extending 3.1 emitter
    • Implements discriminatedUnion method with defaultMapping support
  3. packages/openapi3/src/schema-emitter.ts

    • Updated base discriminatedUnion method to include default variant in oneOf
    • Added #addDefaultVariantToMapping method for versions < 3.2
    • Added #getStringValueFromType helper method
  4. packages/openapi3/src/openapi-spec-mappings.ts

    • Updated to use new 3.2 schema emitter for OpenAPI 3.2.0
  5. packages/openapi3/test/union-schema.test.ts

    • Added comprehensive tests for all OpenAPI versions
    • Tests verify different behavior for 3.0/3.1 vs 3.2.0
  6. .chronus/changes/openapi3-default-mapping-2025-12-22-14-42-58.md

    • Added changelog entry documenting the feature
  7. cspell.yaml

    • Added taxonomic family names to dictionary (canidae, felidae, muscidae)

Test Results:

✅ All OpenAPI 3 tests passing (2356 tests)
✅ All compiler tests passing (3531 tests)
✅ No linting errors
✅ Code formatted with prettier
✅ No breaking changes to existing functionality

References:

Original prompt

This section details on the original issue you should resolve

<issue_title>OpenAPI emitter - add support for OpenAPI 3.2.0 defaultMapping for discriminated unions</issue_title>
<issue_description>### Clear and concise description of the problem

The following TypeSpec definition

@discriminated(#{discriminatorPropertyName: "taxonomic_family", envelope: "none"})
union Animal {
  Dog,
  felidae: Cat,
  muscidae: Ferret
}

model Dog {
  taxonomic_family: "canidae"
}

model Cat {
  taxonomic_family: "felidae"
}

model Ferret {
  taxonomic_family: "muscidae"
}

Results in the following OpenAPI 3.2.0 description

openapi: 3.2.0
info:
  title: (title)
  version: 0.0.0
tags: []
paths: {}
components:
  schemas:
    Animal:
      type: object
      oneOf:
        - $ref: '#/components/schemas/Cat'
        - $ref: '#/components/schemas/Ferret'
      discriminator:
        propertyName: taxonomic_family
        mapping:
          felidae: '#/components/schemas/Cat'
          muscidae: '#/components/schemas/Ferret'
    Cat:
      type: object
      required:
        - taxonomic_family
      properties:
        taxonomic_family:
          type: string
          enum:
            - felidae
    Dog:
      type: object
      required:
        - taxonomic_family
      properties:
        taxonomic_family:
          type: string
          enum:
            - canidae
    Ferret:
      type: object
      required:
        - taxonomic_family
      properties:
        taxonomic_family:
          type: string
          enum:
            - muscidae

For any OpenAPI version, the dog component schema should be present in the oneOf section. For any OpenAPI version prior to 3.2.0, a canidae entry should be present in the mapping.
This is because:

  • Dog model is discoverable from the union (it's the default value)
  • It has one value that's known in advance and can be mapped (through discovering the discriminator property)

In addition to those changes, when emitting OpenAPI 3.2.0, since Dog is the default member of the union, and since their can be only one default member in union definitions, there should be a "defaultMapping" property on the discriminator object. Here is an example of what it should look like

      discriminator:
        propertyName: taxonomic_family
        defaultMapping: '#/components/schemas/Dog'
        mapping:
          felidae: '#/components/schemas/Cat'
          muscidae: '#/components/schemas/Ferret'

Checklist

  • Follow our Code of Conduct
  • Read the docs.
  • Check that there isn't already an issue that request the same feature to avoid creating a duplicate.</issue_description>

<agent_instructions>make sure you run the format command before any commit.
make sure you follow the conventional commits convention.
when done, make sure you run npx @chronus/chronus add to add a new feature changelog entry.
start by defining unit tests first.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 3 commits December 22, 2025 14:29
- Add defaultVariant to DiscriminatedUnion return value in compiler
- Create OpenAPI 3.2 schema emitter extending 3.1 emitter
- Support defaultMapping property in discriminator for OpenAPI 3.2.0
- Include default variant in oneOf array for all versions
- Add default variant discriminator value to mapping for versions < 3.2
- Use defaultMapping instead of mapping entry for OpenAPI 3.2.0

Co-authored-by: baywet <[email protected]>
Copilot AI changed the title [WIP] Add support for OpenAPI 3.2.0 defaultMapping for discriminated unions Add OpenAPI 3.2.0 defaultMapping support for discriminated unions Dec 22, 2025
Copilot AI requested a review from baywet December 22, 2025 14:54
@baywet baywet marked this pull request as ready for review December 22, 2025 15:08
@baywet baywet enabled auto-merge December 22, 2025 15:08
@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 22, 2025

Open in StackBlitz

npm i https://pkg.pr.new/microsoft/typespec/@typespec/compiler@9262
npm i https://pkg.pr.new/microsoft/typespec/@typespec/openapi@9262
npm i https://pkg.pr.new/microsoft/typespec/@typespec/openapi3@9262

commit: 67fa547

@baywet
Copy link
Member

baywet commented Dec 22, 2025

@copilot add the following words to the cspell configuration, do not make any other changes:

  • canidae
  • muscidae
  • felidae

Copy link
Contributor Author

Copilot AI commented Dec 22, 2025

@copilot add the following words to the cspell configuration, do not make any other changes:

  • canidae
  • muscidae
    ...

Added the three taxonomic family names to cspell.yaml in commit 72f701d

Copilot AI requested a review from baywet December 22, 2025 15:19
@github-actions
Copy link
Contributor

github-actions bot commented Dec 29, 2025

All changed packages have been documented.

  • @typespec/compiler
  • @typespec/openapi3
Show changes

@typespec/compiler - feature ✏️

Add support for OpenAPI 3.2.0 defaultMapping in discriminated unions. When a discriminated union has a default variant (unnamed variant), it is now properly emitted:,> - For OpenAPI 3.2.0: The default variant is included in oneOf array and referenced via discriminator.defaultMapping property,> - For OpenAPI 3.0 and 3.1: The default variant is included in oneOf array and its discriminator value is added to the discriminator.mapping object

@typespec/openapi3 - feature ✏️

Add support for OpenAPI 3.2.0 defaultMapping in discriminated unions. When a discriminated union has a default variant (unnamed variant), it is now properly emitted:,> - For OpenAPI 3.2.0: The default variant is included in oneOf array and referenced via discriminator.defaultMapping property,> - For OpenAPI 3.0 and 3.1: The default variant is included in oneOf array and its discriminator value is added to the discriminator.mapping object

@markcowl
Copy link
Contributor

/azp run typespec - PR Tools

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@azure-sdk
Copy link
Collaborator

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

@baywet baywet added this pull request to the merge queue Dec 30, 2025
Merged via the queue into main with commit abc9827 Dec 30, 2025
23 checks passed
@baywet baywet deleted the copilot/add-openapi-defaultmapping-support branch December 30, 2025 21:27
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.

OpenAPI emitter - add support for OpenAPI 3.2.0 defaultMapping for discriminated unions

4 participants