Fix handling decorators for union variants in JSONSchema emitter (#3398)

Fixes #3391

Also refactored a minor problem of using a deprecated reexport of
`DuplicateTracker`, not it's referenced from `@typespec/compiler/utils`
directly, and another small typo.

---------

Co-authored-by: Timothee Guerin <timothee.guerin@outlook.com>
Co-authored-by: Timothee Guerin <tiguerin@microsoft.com>
This commit is contained in:
Vitalii Kryvenko 2024-05-20 22:57:40 +03:00 коммит произвёл GitHub
Родитель d14b0d7b63
Коммит ccd67cf071
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
5 изменённых файлов: 61 добавлений и 4 удалений

Просмотреть файл

@ -0,0 +1,7 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: internal
packages:
- "@typespec/compiler"
---
Doc

Просмотреть файл

@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: fix
packages:
- "@typespec/json-schema"
---
Fix decorators application for union variants

Просмотреть файл

@ -118,7 +118,7 @@ export type EmitterOutput<T> = EmitEntity<T> | Placeholder<T> | T;
* literals, and any type referenced inside anywhere inside the model and any * literals, and any type referenced inside anywhere inside the model and any
* of the referenced types' references. * of the referenced types' references.
* *
* In both cases, context is an object. It strongly recommended that the context * In both cases, context is an object. It's strongly recommended that the context
* object either contain only primitive types, or else only reference immutable * object either contain only primitive types, or else only reference immutable
* objects. * objects.
* *

Просмотреть файл

@ -1,7 +1,6 @@
import { import {
BooleanLiteral, BooleanLiteral,
DiagnosticTarget, DiagnosticTarget,
DuplicateTracker,
Enum, Enum,
EnumMember, EnumMember,
IntrinsicType, IntrinsicType,
@ -52,6 +51,7 @@ import {
SourceFileScope, SourceFileScope,
TypeEmitter, TypeEmitter,
} from "@typespec/compiler/emitter-framework"; } from "@typespec/compiler/emitter-framework";
import { DuplicateTracker } from "@typespec/compiler/utils";
import { stringify } from "yaml"; import { stringify } from "yaml";
import { import {
JsonSchemaDeclaration, JsonSchemaDeclaration,
@ -328,7 +328,14 @@ export class JsonSchemaEmitter extends TypeEmitter<Record<string, any>, JSONSche
} }
unionVariant(variant: UnionVariant): EmitterOutput<object> { unionVariant(variant: UnionVariant): EmitterOutput<object> {
return this.emitter.emitTypeReference(variant.type); const variantType = this.emitter.emitTypeReference(variant.type);
compilerAssert(variantType.kind === "code", "Unexpected non-code result from emit reference");
const result = new ObjectBuilder(variantType.value);
this.#applyConstraints(variant, result);
return result;
} }
modelPropertyReference(property: ModelProperty): EmitterOutput<object> { modelPropertyReference(property: ModelProperty): EmitterOutput<object> {
@ -513,7 +520,7 @@ export class JsonSchemaEmitter extends TypeEmitter<Record<string, any>, JSONSche
} }
#applyConstraints( #applyConstraints(
type: Scalar | Model | ModelProperty | Union | Enum, type: Scalar | Model | ModelProperty | Union | UnionVariant | Enum,
schema: ObjectBuilder<unknown> schema: ObjectBuilder<unknown>
) { ) {
const applyConstraint = (fn: (p: Program, t: Type) => any, key: string) => { const applyConstraint = (fn: (p: Program, t: Type) => any, key: string) => {

Просмотреть файл

@ -87,4 +87,39 @@ describe("emitting unions", () => {
const Foo = schemas["Foo.json"]; const Foo = schemas["Foo.json"];
assert.strictEqual(Foo["x-foo"], true); assert.strictEqual(Foo["x-foo"], true);
}); });
it("handles decorators on variants", async () => {
const schemas = await emitSchema(`
union Foo {
@doc("doc text")
@summary("summary text")
@extension("x-key", Json<"x-value">)
bar: string;
@doc("other model doc")
@summary("other model summary")
@extension("x-key-2", Json<"x-value-2">)
baz: OtherModel;
}
model OtherModel {}
`);
const Foo = schemas["Foo.json"];
assert.deepStrictEqual(Foo.anyOf, [
{
description: "doc text",
title: "summary text",
type: "string",
"x-key": "x-value",
},
{
$ref: "OtherModel.json",
description: "other model doc",
title: "other model summary",
"x-key-2": "x-value-2",
},
]);
});
}); });