Skip to content

Commit

Permalink
Fix circular reference not always inlining array properties (#2810)
Browse files Browse the repository at this point in the history
fix #2796
  • Loading branch information
timotheeguerin authored Feb 1, 2024
1 parent 3186305 commit 05c8597
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/rich-grapes-wink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@typespec/openapi3": patch
---

Fix circular reference would not always inline array properties

This file was deleted.

1 change: 1 addition & 0 deletions packages/openapi3/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"watch": "tsc -p . --watch",
"lint-typespec-library": "tsp compile . --warn-as-error --import @typespec/library-linter --no-emit",
"test": "vitest run",
"test:watch": "vitest -w",
"test:ui": "vitest --ui",
"test-official": "vitest run --coverage --reporter=junit --reporter=default --no-file-parallelism",
"lint": "eslint . --ext .ts --max-warnings=0",
Expand Down
14 changes: 12 additions & 2 deletions packages/openapi3/src/schema-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter<
// Attach any additional OpenAPI extensions
this.#attachExtensions(program, prop, additionalProps);

if (schema && isRef) {
if (schema && isRef && !(prop.type.kind === "Model" && isArrayModelType(program, prop.type))) {
if (Object.keys(additionalProps).length === 0) {
return schema;
} else {
Expand All @@ -370,7 +370,7 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter<
delete schema.anyOf;
}

const merged = new ObjectBuilder(schema);
const merged = ensureObjectBuilder(schema);
for (const [key, value] of Object.entries(additionalProps)) {
merged.set(key, value);
}
Expand Down Expand Up @@ -947,6 +947,16 @@ function includeDerivedModel(model: Model): boolean {
);
}

function ensureObjectBuilder<
T extends Record<string, unknown> | Placeholder<Record<string, unknown>> | undefined,
>(type: T | ObjectBuilder<T>): ObjectBuilder<T> {
if (type instanceof ObjectBuilder) {
return type;
} else {
return new ObjectBuilder(type);
}
}

const B = {
array: <T>(items: T[]): ArrayBuilder<T> => {
const builder = new ArrayBuilder<T>();
Expand Down
33 changes: 32 additions & 1 deletion packages/openapi3/test/array.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { deepStrictEqual, ok, strictEqual } from "assert";
import { describe, it } from "vitest";
import { oapiForModel } from "./test-host.js";
import { oapiForModel, openApiFor } from "./test-host.js";

describe("openapi3: Array", () => {
it("defines array inline", async () => {
Expand All @@ -19,6 +19,37 @@ describe("openapi3: Array", () => {
});
});

it("keeps array inline in circular reference with extra properties", async () => {
const res = await openApiFor(
`
model Root {
value: Parent[];
}
model Parent {
@OpenAPI.extension("x-someFieldAttr", true)
children?: Child[];
}
model Child {
@OpenAPI.extension("x-someFieldAttr", true)
parents?: Parent[];
}
`
);

deepStrictEqual(res.components.schemas.Parent.properties.children, {
type: "array",
items: { $ref: "#/components/schemas/Child" },
"x-someFieldAttr": true,
});
deepStrictEqual(res.components.schemas.Child.properties.parents, {
type: "array",
items: { $ref: "#/components/schemas/Parent" },
"x-someFieldAttr": true,
});
});

it("define a named array using model is", async () => {
const res = await oapiForModel(
"Pet",
Expand Down

0 comments on commit 05c8597

Please sign in to comment.