feat(openapi): add array form for @tagMetadata to control tag declaration order#10770
feat(openapi): add array form for @tagMetadata to control tag declaration order#10770Copilot wants to merge 11 commits into
Conversation
Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/bf960a34-147a-499e-8598-bc0d9d392ade Co-authored-by: baywet <[email protected]>
|
@copilot add multiple test cases if we don't have them already: one where a tag is used at the operation level, but not defined at the tagMetadata/service level to see where it "inserts" itself. one where a tag is used at the operation level, and defined at the tagMetadata/service level to see where it "inserts" itself. |
commit: |
…data Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/3880bfa8-c4e5-41a8-b869-3b0c5826805e Co-authored-by: baywet <[email protected]>
Added two new tests in commit 76ffa16:
|
|
You can try these changes here
|
markcowl
left a comment
There was a problem hiding this comment.
I don't think we can take this, as it is a breaking behavior change. If the order of tags is important, I think the best non-breaking short term solution would be to allow arrays in @tagMetadata. I think the longer term solution is probably here: #10771
…tion order Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/5a953c5e-8c14-4879-a745-545eccdc0609 Co-authored-by: baywet <[email protected]>
Co-authored-by: baywet <[email protected]>
…ecorator execution) Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/5a953c5e-8c14-4879-a745-545eccdc0609 Co-authored-by: baywet <[email protected]>
Done. The PR has been restarted with the new approach based on the guidance in the issue comment. What changed:
Array form usage: @service()
@tagMetadata(#[
#{ name: "First Tag", description: "First tag description" },
#{ name: "Second Tag", description: "Second tag description" },
])
namespace PetStore {}Mixing error example: @tagMetadata(#[#{ name: "tag1" }])
@tagMetadata("tag2", #{}) // error: mixed-tag-metadata-form
namespace PetStore {}Commit: ef9f21d |
| /** | ||
| * Metadata for a single tag used by operations. | ||
| */ | ||
| export interface TagMetadataRecord { |
There was a problem hiding this comment.
didn't we already have this type generated in packages/openapi/generated-defs/TypeSpec.OpenAPI.ts and TagMetadataWithName is there now too
There was a problem hiding this comment.
You're right — TagMetadataWithName is generated in generated-defs/TypeSpec.OpenAPI.ts. However, the auto-generated version has readonly fields and no JSDoc, which causes api-extractor to fail with ae-undocumented errors (since it's reachable from the exported TagMetadataDecorator signature). We need to keep a JSDoc-annotated version in types.ts for the public API surface.
I've removed the intermediate TagMetadataRecord base type in commit bccdd84 — TagMetadataWithName in types.ts now has its fields inlined directly, eliminating that extra layer of duplication.
Co-authored-by: Timothee Guerin <[email protected]>
|
All changed packages have been documented.
Show changes
|
…3rd arg with array form, use array form in converter Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/7e3b7c92-f41b-4910-be5a-10404eacab1e Co-authored-by: baywet <[email protected]>
Done in commit bccdd84. The converter's @tagMetadata(#[
#{ name: "pet", description: "Everything about your Pets", externalDocs: #{ url: "...", description: "..." } },
#{ name: "store", description: "...", externalDocs: #{ ... } },
#{ name: "user", description: "Operations about user" }
])Snapshot tests for |
| } | ||
|
|
||
| const tagItems = tags.map((tag) => { | ||
| const fields: string[] = [`name: "${tag.name}"`]; |
There was a problem hiding this comment.
@copilot it doesn't look like the import logic supports importing the parent and the kind fields from OpenAPI 3.2.0. Check that we have tests/implementation for those, if not add it
There was a problem hiding this comment.
Added support in commit 7d824e7:
parent(natively supported in TypeSpec'sTagMetadata): passed through fromOpenAPITag3_2.parentand emitted asparent: "..."in the array form.kind(not natively supported in TypeSpec'sTagMetadata): emitted as`x-kind`: "..."extension, since TypeSpec only allowsx--prefixed extension keys.
Changes:
interfaces.ts: addedparent?: stringandkind?: stringtoTypeSpecTagMetadatatransform-tags.ts: destructures both fields from the tag object (safely undefined for 3.0/3.1 docs)generate-tags.ts: emitsparentand`x-kind`fields when present- Added
specs/tag-metadata-3-2/service.yml(3.2.0 spec with all three variants) and its generated snapshot - Added unit tests in
convert-openapi3-doc.test.tscovering 3.2 conversion and 3.0/3.1 passthrough
…in converter Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/533945d5-814d-4408-aa70-ff6d7adf3b4b Co-authored-by: baywet <[email protected]>
|
@copilot handle the conflicts here. We had done some changes in this PR for parent/kind/summary of tags that were actually already implemented in another PR |
…ata) Co-authored-by: baywet <[email protected]>
…ta test Co-authored-by: baywet <[email protected]>
Done. The merge conflicts have been resolved in commit
Since |
Adds a new array form for the
@tagMetadatadecorator that lets authors explicitly specify tags and their order in a single decorator call, rather than relying on the bottom-up decorator execution order.Changes
packages/openapi/lib/decorators.tsp: AddedTagMetadataWithNamemodel; updated@tagMetadatasignature to acceptstring | TagMetadataWithName[]with the second parameter optional (only used in inline form).packages/openapi/generated-defs/TypeSpec.OpenAPI.ts: Regenerated with newTagMetadataWithNameinterface (includingsummaryandkindfields) and updatedTagMetadataDecoratortype.packages/openapi/src/lib.ts: Addedmixed-tag-metadata-formdiagnostic — emitted when mixing the array form and inline form on the same namespace. Addedtag-metadata-array-with-metadata-argdiagnostic — emitted when the secondtagMetadataargument is provided alongside the array form.packages/openapi/src/types.ts: Added publicly documentedTagMetadataWithNameinterface (withsummaryandkindfields).packages/openapi/src/index.ts: Exported new public type.packages/openapi/src/decorators.ts: State storage changed from{ [name: string]: TagMetadata }toTagMetadataWithName[]; handles both inline and array forms; reports error on mixing or on using the second argument with the array form.packages/openapi3/src/openapi.ts: UpdatedresolveDocumentTagsto iterate the new array-based state.packages/openapi3/src/cli/actions/convert/generators/generate-tags.ts: Updated the OpenAPI→TypeSpec converter to emit@tagMetadata(#[...])(array form) instead of multiple inline calls, ensuring import/export order symmetry. Emitsparent,summary, andkindfields natively for OpenAPI 3.2.0 tags.packages/openapi3/src/cli/actions/convert/transforms/transform-tags.ts: Passes throughparent,summary, andkindfields fromOpenAPITag3_2; readssummaryandkindfromx-oai-summary/x-oai-kindextensions as fallbacks for OpenAPI 3.0/3.1 documents.packages/openapi3/src/cli/actions/convert/interfaces.ts: Addedparent,summary, andkindfields toTypeSpecTagMetadata.packages/openapi/test/decorators.test.ts: Updated existing tests for the new array return type; added tests for array form, mixing error, and second-argument-with-array-form error.packages/openapi3/test/tagmetadata.test.ts: Added tests for array form ordering, operation-tag insertion behavior, and parent/child tag scenarios.packages/openapi3/test/tsp-openapi3/convert-openapi3-doc.test.ts: Added unit tests verifying converter handling of OpenAPI 3.2.0parent,summary, andkindtag fields, andx-oai-extension fallbacks for 3.0/3.1 documents.tag-metadata,playground-http-service,petstore-swagger,tag-metadata-3-2): Updated to reflect the new array form emitted by the converter.Array form example
Tags are emitted in the exact order specified in the array.
Mixing forms is an error
Using both forms on the same namespace reports a
mixed-tag-metadata-formdiagnostic:Passing the second argument with the array form is an error
Converter output
The OpenAPI→TypeSpec converter now emits the array form so that tag order in the source OpenAPI document is preserved in the output TypeSpec. OpenAPI 3.2.0
parent,summary, andkindtag fields are emitted natively. For OpenAPI 3.0/3.1 documents,summaryandkindare also read fromx-oai-summaryandx-oai-kindextensions:Tag insertion behavior (unchanged)
@tag) and not declared with@tagMetadataappear first in the output.@tagMetadatafollow in their stored order.@tagMetadatais emitted exactly once, at its@tagMetadata-declared position with its metadata.