Skip to content

Commit

Permalink
Support @summary on data types in OpenAPI3, emitting title (#2597)
Browse files Browse the repository at this point in the history
  • Loading branch information
bterlson authored Oct 23, 2023
1 parent eb849c2 commit be937a8
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 5 deletions.
10 changes: 10 additions & 0 deletions common/changes/@typespec/openapi3/title_2023-10-20-17-49.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@typespec/openapi3",
"comment": "Support `@summary` on data types which emits the JSON Schema `title` property.",
"type": "none"
}
],
"packageName": "@typespec/openapi3"
}
20 changes: 20 additions & 0 deletions packages/openapi3/src/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1470,6 +1470,11 @@ function createOAPIEmitter(program: Program, options: ResolvedOpenAPI3EmitterOpt
schema.enum = values;
}

const title = getSummary(program, e);
if (title) {
schema.title = title;
}

return schema;
function enumMemberType(member: EnumMember) {
if (typeof member.value === "number") {
Expand Down Expand Up @@ -1537,6 +1542,11 @@ function createOAPIEmitter(program: Program, options: ResolvedOpenAPI3EmitterOpt
if (schemaMembers.length === 1) {
// we can just return the single schema member after applying nullable
const schema = schemaMembers[0].schema;
applyIntrinsicDecorators(union, schema);
const title = getSummary(program, union);
if (title) {
schema.title = title;
}
const type = schemaMembers[0].type;

if (nullable) {
Expand Down Expand Up @@ -1707,6 +1717,11 @@ function createOAPIEmitter(program: Program, options: ResolvedOpenAPI3EmitterOpt
if (Object.keys(properties).length > 0) {
modelSchema.properties = properties;
}
const title = getSummary(program, model);
if (title) {
modelSchema.title = title;
}

// Attach any OpenAPI extensions
attachExtensions(program, model, modelSchema);
return modelSchema;
Expand Down Expand Up @@ -1833,6 +1848,11 @@ function createOAPIEmitter(program: Program, options: ResolvedOpenAPI3EmitterOpt
newTarget.format = "password";
}

const title = getSummary(program, typespecType);
if (title) {
newTarget.title = title;
}

const values = getKnownValues(program, typespecType as any);
if (values) {
return {
Expand Down
14 changes: 13 additions & 1 deletion packages/openapi3/test/array.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { deepStrictEqual, ok } from "assert";
import { deepStrictEqual, ok, strictEqual } from "assert";
import { oapiForModel } from "./test-host.js";

describe("openapi3: Array", () => {
Expand Down Expand Up @@ -149,6 +149,18 @@ describe("openapi3: Array", () => {
});
});

it("supports summary", async () => {
const res = await oapiForModel(
"Foo",
`
@summary("FooArray")
model Foo is string[];
`
);

strictEqual(res.schemas.Foo.title, "FooArray");
});

it("can specify tuple defaults using tuple syntax", async () => {
const res = await oapiForModel(
"Pet",
Expand Down
18 changes: 16 additions & 2 deletions packages/openapi3/test/enums.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { expectDiagnostics } from "@typespec/compiler/testing";
import { diagnoseOpenApiFor } from "./test-host.js";
import { strictEqual } from "assert";
import { diagnoseOpenApiFor, oapiForModel } from "./test-host.js";

describe("openapi3: models", () => {
describe("openapi3: enums", () => {
it("throws diagnostics for empty enum definitions", async () => {
const diagnostics = await diagnoseOpenApiFor(`enum PetType {}`);

Expand All @@ -19,4 +20,17 @@ describe("openapi3: models", () => {
message: "Enums are not supported unless all options are literals of the same type.",
});
});

it("supports summary on enums", async () => {
const res = await oapiForModel(
"Foo",
`
@summary("FooEnum")
enum Foo {
y: 0;
};
`
);
strictEqual(res.schemas.Foo.title, "FooEnum");
});
});
15 changes: 15 additions & 0 deletions packages/openapi3/test/models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,21 @@ describe("openapi3: models", () => {
});
});

it("supports summary on models and model properties", async () => {
const res = await oapiForModel(
"Foo",
`
@summary("FooModel")
model Foo {
@summary("YProp")
y: int32;
};
`
);
strictEqual(res.schemas.Foo.title, "FooModel");
strictEqual(res.schemas.Foo.properties.y.title, "YProp");
});

describe("referencing another property as type", () => {
it("use the type of the other property", async () => {
const res = await oapiForModel(
Expand Down
12 changes: 11 additions & 1 deletion packages/openapi3/test/primitive-types.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { deepStrictEqual, ok } from "assert";
import { deepStrictEqual, ok, strictEqual } from "assert";
import { OpenAPI3Schema } from "../src/types.js";
import { oapiForModel } from "./test-host.js";

Expand Down Expand Up @@ -215,6 +215,16 @@ describe("openapi3: primitives", () => {
});
});

it("supports summary on custom scalars", async () => {
const res = await oapiForModel(
"Foo",
`
@summary("FooScalar") scalar Foo extends string;
`
);
strictEqual(res.schemas.Foo.title, "FooScalar");
});

describe("using @encode decorator", () => {
async function testEncode(
scalar: string,
Expand Down
23 changes: 22 additions & 1 deletion packages/openapi3/test/union-schema.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expectDiagnostics } from "@typespec/compiler/testing";
import { deepStrictEqual, ok } from "assert";
import { deepStrictEqual, ok, strictEqual } from "assert";
import { diagnoseOpenApiFor, oapiForModel, openApiFor } from "./test-host.js";

describe("openapi3: union type", () => {
Expand Down Expand Up @@ -375,4 +375,25 @@ describe("openapi3: union type", () => {
"Empty unions are not supported for OpenAPI v3 - enums must have at least one value.",
});
});

it("supports summary on unions and union variants", async () => {
const res = await oapiForModel(
"Foo",
`
@summary("FooUnion")
union Foo {
int32;
Bar;
}
@summary("BarUnion")
union Bar {
string;
}
`
);
strictEqual(res.schemas.Foo.title, "FooUnion");
strictEqual(res.schemas.Bar.title, "BarUnion");
});
});

0 comments on commit be937a8

Please sign in to comment.