Skip to content

Add support for OAS 3.2 nested tags via parent field in @tagMetadata#9577

Draft
Copilot wants to merge 10 commits intomainfrom
copilot/add-oas-32-nested-tags-support
Draft

Add support for OAS 3.2 nested tags via parent field in @tagMetadata#9577
Copilot wants to merge 10 commits intomainfrom
copilot/add-oas-32-nested-tags-support

Conversation

Copy link
Contributor

Copilot AI commented Feb 4, 2026

Add support for OAS 3.2 Nested Tags

  • Update TypeSpec.OpenAPI.TagMetadata model to include parent field in decorators.tsp
  • Update generated TypeScript types for TagMetadata interface
  • Add parent field handling to resolveDocumentTags() in openapi.ts
    • For OpenAPI 3.2: emit parent field natively
    • For OpenAPI 3.0/3.1: drop the field entirely (not supported in these versions)
  • Add comprehensive tests for parent field in 3.0, 3.1, and 3.2
  • Update documentation with examples
  • Address review feedback to drop field instead of converting to x-parent
  • Run pnpm format to fix formatting issues

Summary

This PR adds support for OpenAPI 3.2 nested tags by introducing a parent field in the @tagMetadata decorator.

Changes: 7 files, 98 insertions, 8 deletions

The implementation correctly handles version differences:

  • OpenAPI 3.2: Emits parent field natively
  • OpenAPI 3.0/3.1: Drops the parent field entirely (not supported in these versions)
Original prompt

This section details on the original issue you should resolve

<issue_title>Add support for OAS 3.2 Nested Tags</issue_title>
<issue_description>### Clear and concise description of the problem

According to OAS 3.2 spec tags now can have parent field, allowing to create tags hierarchy.

https://spec.openapis.org/oas/v3.2.0.html#tag-object

I couldn't find any documentation around it and seems like it wasn't yet implemented.

I'm proposing to to extend default @tag decorator to accept now variadic amount of strings.

@tag("parent1", "parent2", "actual-tag")
op myop(): void

In this case all strings will represent hierarchy path.

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>we need to add support for parent in @tagMetadata decorator. Note that this property only is supported in openapi 3.2, when emitting 3.0 or 3.1 it should be dropped.</agent_instructions>

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

@timotheeguerin that might more be part of the `@tagMetadata`

Like this but without the x-
playground

@service
@tagMetadata("pet", #{
  description: "Pet"
})
@tagMetadata("cat", #{
  description: "Cat",
  `x-parent`: "pet",
})
namespace My;

@tag("cat")
op test(): string;
```</body></comment_new>
<comment_new><author>@timotheeguerin</author><body>
Oh I wouldn't say it's done, we still need to allow putting parent directly without `x-`. And what does that mean for 3.1 and 3.0. One option is to add the x- if someone try to use it but emit 3.0 or 3.1</body></comment_new>
</comments>

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

- Updated TagMetadata model to include parent field
- Modified openapi.ts to convert parent to x-parent for 3.0/3.1
- Added comprehensive tests for all OpenAPI versions
- Tests passing for parent field in 3.2, x-parent in 3.0/3.1

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service bot added lib:openapi meta:website TypeSpec.io updates emitter:openapi3 Issues for @typespec/openapi3 emitter labels Feb 4, 2026
- Added example of nested tags using parent field
- Rebuilt packages to update generated types

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for OAS 3.2 nested tags feature Add support for OAS 3.2 nested tags via parent field in @tagMetadata Feb 4, 2026
Copilot AI requested a review from timotheeguerin February 4, 2026 15:19
const tagData: OpenAPI3Tag = { name: name, ...tag };
// For OpenAPI 3.0 and 3.1, convert 'parent' to 'x-parent' extension
if (specVersion !== "3.2.0" && "parent" in tagData) {
(tagData as any)["x-parent"] = tagData.parent;
Copy link
Member

Choose a reason for hiding this comment

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

why as any is the type incorrect?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in d9e4bfd. Changed to use tag.parent from the source TagMetadata object to check for parent existence, and only use a type assertion on the delete operation with an explicit { parent?: string } type instead of as any.

@timotheeguerin
Copy link
Member

@copilot need to make sure you do a full build and commit the generated files. ANd run pnpm format to format the files

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 4, 2026

Open in StackBlitz

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

commit: 6facdb9

- Changed from using 'as any' to a more type-safe approach
- Use tag.parent from source TagMetadata to check parent existence
- Only use type assertion on delete operation with explicit type

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
- Updated README.md with parent field example
- Updated decorators.md with parent field example
- Generated files from full build

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 4, 2026

@copilot need to make sure you do a full build and commit the generated files. ANd run pnpm format to format the files

Done in c831ac7. Ran full build and pnpm format, committed the generated documentation files.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • telemetry.astro.build
    • Triggering command: /usr/local/bin/node node /home/REDACTED/work/typespec/typespec/website/node_modules/.bin/../astro/astro.js build sh sion�� ebsite/src/content/docs/docs/emitters/openapi3/reference node ules/.bin/sh n --local --verbsh . node node tool�� lmstxt --output-dir ../../website/src/content/docs/docs/libraries/http/reference ./specs e signature &amp;&amp; tscsh node st/node-gyp-bin/tsx ./.scripts/regen-compiler-docs.ts node (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@timotheeguerin
Copy link
Member

@copilot pull latest change from main and resolve merge conflicts

- Integrated parent field conversion logic into refactored resolveDocumentTags function
- Updated test imports to match main branch changes
- Preserved parent field tests for all OpenAPI versions

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 5, 2026

@copilot pull latest change from main and resolve merge conflicts

Merged main branch in 2cd4f77. Resolved conflicts by integrating the parent field conversion logic into the refactored resolveDocumentTags function that was added in main.

@microsoft-github-policy-service microsoft-github-policy-service bot added emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp emitter:client:python Issue for the Python client emitter: @typespec/http-client-python eng labels Feb 5, 2026
@timotheeguerin
Copy link
Member

@copilot there is still conflict with main, please fix. The PR now has way too many changes showing up

Copy link
Contributor Author

Copilot AI commented Feb 5, 2026

@copilot there is still conflict with main, please fix. The PR now has way too many changes showing up

I've rebased the branch onto the latest main (4de4d3f). The branch now contains only the relevant changes (7 files, 101 insertions, 8 deletions) and no longer shows the extra commits that were merged from main.

The commits are now:

  • 4d5223a: Initial plan
  • 9bd2fb8: Add support for parent field in @tagMetadata decorator
  • d71f0ae: Update documentation with parent field example
  • f3a0666: Add generated documentation files for parent field
  • 323ac1d: Add parent field conversion logic to resolveDocumentTags

However, I'm unable to force-push this rebased branch due to authentication restrictions. The rebased branch exists locally and is ready, but needs to be pushed manually or the PR may need to be recreated from this clean state.

@timotheeguerin
Copy link
Member

@copilot revert the last push and rebase your change of main

Copy link
Contributor Author

Copilot AI commented Feb 5, 2026

@copilot revert the last push and rebase your change of main

I've successfully rebased the branch onto the latest main (4de4d3f). The local branch now has a clean history with only 3 commits and 7 files changed (101 insertions, 8 deletions):

Commits:

  • 3314b17: Add support for parent field in @tagMetadata decorator
  • 6a9cf0e: Update documentation with parent field example
  • 7f223d9: Add generated documentation files for parent field

However, I cannot force-push the rebased branch due to git authentication restrictions. The report_progress tool attempts to rebase again which creates conflicts since it's trying to rebase commits that are already in main.

Could you please either:

  1. Manually force-push from your end, or
  2. Grant permission for force-push operations, or
  3. Close this PR and I can create a new one with the clean commits?

The local branch is ready and all changes are correct.

const tagData: OpenAPI3Tag = { name: name, ...tag };
// For OpenAPI 3.0 and 3.1, convert 'parent' to 'x-parent' extension
if (specVersion !== "3.2.0" && tag.parent) {
tagData["x-parent"] = tag.parent;
Copy link
Member

Choose a reason for hiding this comment

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

@copilot it should drop the field not add x-parent

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in da7c83a. Changed the implementation to drop the parent field entirely for OpenAPI 3.0 and 3.1 (removed the x-parent conversion). Now only OpenAPI 3.2 emits the parent field.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 5, 2026

❌ There is undocummented changes. Run chronus add to add a changeset or click here.

The following packages have changes but are not documented.

  • @typespec/openapi
  • @typespec/openapi3
Show changes

- Changed implementation to drop parent field entirely for 3.0/3.1
- Updated tests to reflect parent field is dropped (not converted)
- Only OpenAPI 3.2 emits the parent field

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
deepStrictEqual(res.tags, [
{
name: "ChildTag",
description: "Child tag",
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this have X-Parent?

Copy link
Member

Choose a reason for hiding this comment

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

We decided not too, and just dropped and would add it if someone asked with options.

{
name: "ChildTag",
description: "Child tag",
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this have X-Parent?

@timotheeguerin
Copy link
Member

@copilot run pnpm format exactly the format check is failing

- Removed extra blank line in tagmetadata.test.ts

Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 5, 2026

@copilot run pnpm format exactly the format check is failing

Done in 6facdb9. Ran pnpm format after doing a full build, fixed formatting issue (removed extra blank line).

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • telemetry.astro.build
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/typespec/typespec/website/node_modules/.bin/../astro/astro.js build node tool�� ebsite/src/conte--llmstxt . /.bin/node --import @typespec/librar/home/REDACTED/work/typespec/typespec/packages/http-specs/node_modules�� --no-emit node /nod�� gen-extern-signature node de/node/bin/sh --no-emit l/reference (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

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

Labels

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp emitter:client:python Issue for the Python client emitter: @typespec/http-client-python emitter:openapi3 Issues for @typespec/openapi3 emitter eng lib:openapi meta:website TypeSpec.io updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for OAS 3.2 Nested Tags

3 participants