Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(schema): fix OASv3 schema generation fails when model used in @OneOf has kind property #2424

Merged
merged 1 commit into from
Sep 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/specs/schema/src/components/anyMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export function anyMapper(input: any, options: JsonSchemaOptions = {}): any {
return toRef(enumSchema, enumSchema.toJSON(options), options);
}

if (input.kind) {
const kind = oneOfMapper(input.kind, "map");
if (input.$kind && input.$isJsonDocument) {
const kind = oneOfMapper(input.$kind, "map");
const schema = execMapper(kind, input, mapGenericsOptions(options));

return input.canRef ? toRef(input, schema, options) : schema;
Expand Down
3 changes: 2 additions & 1 deletion packages/specs/schema/src/domain/JsonMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {execMapper} from "../registries/JsonSchemaMapperContainer";
export class JsonMap<T> extends Map<string, any> {
[key: string]: any;

kind: string = "map";
$kind: string = "map";
readonly $isJsonDocument = true;

constructor(obj: Partial<T> = {}) {
super();
Expand Down
2 changes: 1 addition & 1 deletion packages/specs/schema/src/domain/JsonMedia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {JsonMap} from "./JsonMap";
import {JsonSchema} from "./JsonSchema";

export class JsonMedia extends JsonMap<OS3MediaType<JsonSchema>> {
kind: string = "operationMedia";
$kind: string = "operationMedia";

groups: string[] = [];
groupsName: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/specs/schema/src/domain/JsonOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface JsonOperationOptions extends OS3Operation<JsonSchema, JsonParam
}

export class JsonOperation extends JsonMap<JsonOperationOptions> {
kind: string = "operation";
$kind: string = "operation";

readonly operationPaths: Map<string, JsonMethodPath> = new Map();
#status: number;
Expand Down
3 changes: 2 additions & 1 deletion packages/specs/schema/src/domain/JsonOperationPathsMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import {OperationMethods} from "../constants/httpMethods";
import {JsonMethodPath} from "./JsonOperation";

export class JsonOperationPathsMap extends Map<string, JsonMethodPath> {
kind: string = "operationPaths";
$kind: string = "operationPaths";
readonly $isJsonDocument = true;

setOperationPath(operationPath: JsonMethodPath) {
if (operationPath.method !== OperationMethods.CUSTOM) {
Expand Down
2 changes: 1 addition & 1 deletion packages/specs/schema/src/domain/JsonParameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {formatParameterType} from "./JsonParameterTypes";
import {JsonSchema} from "./JsonSchema";

export class JsonParameter extends JsonMap<OS3Parameter<JsonSchema>> implements NestedGenerics {
kind = "operationInParameter";
$kind = "operationInParameter";

nestedGenerics: Type<any>[][] = [];
groups: string[];
Expand Down
2 changes: 1 addition & 1 deletion packages/specs/schema/src/domain/JsonRequestBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {JsonSchema} from "./JsonSchema";
export type JsonRequestBodyOptions = OS3RequestBody<JsonSchema>;

export class JsonRequestBody extends JsonMap<JsonRequestBodyOptions> {
kind = "operationRequestBody";
$kind = "operationRequestBody";

constructor(obj: Partial<JsonRequestBodyOptions> = {}) {
super(obj);
Expand Down
2 changes: 1 addition & 1 deletion packages/specs/schema/src/domain/JsonResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {JsonSchema} from "./JsonSchema";
export type JsonResponseOptions = OS3Response<JsonSchema, string | JsonHeader>;

export class JsonResponse extends JsonMap<JsonResponseOptions> {
kind: string = "operationResponse";
$kind: string = "operationResponse";

status: number;

Expand Down
7 changes: 3 additions & 4 deletions packages/specs/schema/src/domain/JsonSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function mapToJsonSchema(item: any): any {
return (item as any[]).map(mapToJsonSchema);
}

if (item.isStore || item.isJsonSchema || item.isLazyRef) {
if (item.isStore || item.$isJsonDocument || item.isLazyRef) {
return item;
}

Expand All @@ -75,9 +75,8 @@ function mapToJsonSchema(item: any): any {
}

export class JsonSchema extends Map<string, any> implements NestedGenerics {
kind: string = "schema";

readonly isJsonSchema = true;
readonly $kind: string = "schema";
readonly $isJsonDocument = true;
readonly $hooks = new Hooks();
readonly $required: Set<string> = new Set();
readonly $allow: any[] = [];
Expand Down
6 changes: 3 additions & 3 deletions packages/specs/schema/src/utils/inlineEnums.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ describe("inlineEnums()", () => {
const result = inlineEnums(
{
enum: {
isJsonSchema: true,
$isJsonDocument: true,
toJSON() {
return {enum: ["type"]};
}
Expand All @@ -26,7 +26,7 @@ describe("inlineEnums()", () => {
{
type: "object",
enum: {
isJsonSchema: true,
$isJsonDocument: true,
toJSON() {
return {enum: ["type"]};
}
Expand All @@ -46,7 +46,7 @@ describe("inlineEnums()", () => {
{
type: "string",
enum: {
isJsonSchema: true,
$isJsonDocument: true,
toJSON() {
return {enum: ["type"]};
}
Expand Down
2 changes: 1 addition & 1 deletion packages/specs/schema/src/utils/inlineEnums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {JsonSchema} from "../domain/JsonSchema";
import {JsonSchemaOptions} from "../interfaces/JsonSchemaOptions";

export function inlineEnums(obj: any, schema: JsonSchema, options: JsonSchemaOptions) {
if (options.inlineEnums && obj.enum?.isJsonSchema) {
if (options.inlineEnums && obj.enum?.$isJsonDocument) {
obj.enum = obj.enum.toJSON().enum;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Discriminator with kind property should generate the spec 1`] = `
Object {
"components": Object {
"schemas": Object {
"FirstImpl": Object {
"properties": Object {
"kind": Object {
"enum": Array [
"json",
],
"type": "string",
},
"type": Object {
"enum": Array [
"one",
"two",
],
"example": "one",
"type": "string",
},
},
"type": "object",
},
"ParentModel": Object {
"properties": Object {
"test": Object {
"discriminator": Object {
"propertyName": "type",
},
"oneOf": Array [
Object {
"$ref": "#/components/schemas/FirstImpl",
},
Object {
"$ref": "#/components/schemas/SecondImpl",
},
],
"required": Array [
"type",
],
},
},
"type": "object",
},
"SecondImpl": Object {
"properties": Object {
"prop": Object {
"type": "string",
},
"type": Object {
"enum": Array [
"one",
"two",
],
"example": "two",
"type": "string",
},
},
"type": "object",
},
},
},
"paths": Object {
"/test": Object {
"get": Object {
"operationId": "testGet",
"parameters": Array [],
"responses": Object {
"200": Object {
"content": Object {
"application/json": Object {
"schema": Object {
"items": Object {
"$ref": "#/components/schemas/ParentModel",
},
"type": "array",
},
},
},
"description": "Success",
},
},
"tags": Array [
"Test",
],
},
},
},
"tags": Array [
Object {
"name": "Test",
},
],
}
`;
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import {Controller} from "@tsed/di";
import {BodyParams, PathParams} from "@tsed/platform-params";
import * as Path from "path";
import {
DiscriminatorKey,
DiscriminatorValue,
Enum,
Get,
getJsonSchema,
getSpec,
JsonEntityStore,
Name,
OneOf,
Partial,
Patch,
Expand Down Expand Up @@ -1287,4 +1290,51 @@ describe("Discriminator", () => {
expect(JsonEntityStore.from(Event).isDiscriminatorChild).toEqual(false);
});
});
describe("with kind property", () => {
it("should generate the spec", () => {
enum Discriminator {
ONE = "one",
TWO = "two"
}

abstract class BaseModel {
@Enum(Discriminator.ONE, Discriminator.TWO)
@DiscriminatorKey()
public type!: Discriminator.ONE | Discriminator.TWO;
}

@DiscriminatorValue(Discriminator.ONE)
class FirstImpl extends BaseModel {
public declare type: Discriminator.ONE;

@Enum("json")
public kind!: "json";
}

@DiscriminatorValue(Discriminator.TWO)
class SecondImpl extends BaseModel {
public declare type: Discriminator.TWO;

@Property()
public prop!: string;
}

class ParentModel {
@OneOf(FirstImpl, SecondImpl)
public test?: FirstImpl | SecondImpl;
}

@Controller("/test")
@Name("Test")
class TestController {
@Get()
@Returns(200, Array).Of(ParentModel)
public get(): Promise<ParentModel> {
return null as any;
}
}

expect(getSpec(TestController)).toMatchSnapshot();
});
});
});
5 changes: 3 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"resolveJsonModule": true,
"esModuleInterop": true,
"allowJs": true,
"moduleResolution": "node"
"moduleResolution": "node",
"skipLibCheck": true
},
"references": [
{
Expand Down Expand Up @@ -172,5 +173,5 @@
"path": "./packages/security/oidc-provider-plugin-wildcard-redirect-uri"
}
],
"exclude": ["node_modules", "docs", "docs-references"]
"exclude": ["**/node_modules/**", "docs", "docs-references"]
}
Loading