Skip to content

Commit aab686d

Browse files
authored
feat: Make the behavior of anyOf equivalent to oneOf (#70)
1 parent 253154b commit aab686d

File tree

7 files changed

+205
-5
lines changed

7 files changed

+205
-5
lines changed

scripts/testCodeGen.ts

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const main = () => {
3535
});
3636

3737
Writer.generateSplitCode("test/api.test.domain/index.yml", "test/code/split");
38+
Writer.generateSplitCode("test/multi-type.test.domain/index.yml", "test/code/mulit-type-test.domain");
3839

3940
Writer.generateParameter("test/api.test.domain/index.yml", "test/code/parameter/api.test.domain.json");
4041
Writer.generateParameter("test/infer.domain/index.yml", "test/code/parameter/infer.domain.json");

src/internal/OpenApiTools/toTypeNode.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import DotProp from "dot-prop";
22
import ts from "typescript";
33

44
import type { OpenApi } from "../../types";
5-
import { UnsetTypeError } from "../Exception";
65
import { UnSupportError } from "../Exception";
76
import * as Logger from "../Logger";
87
import { Factory } from "../TsGenerator";
@@ -65,8 +64,12 @@ export const generateMultiTypeNode = (
6564
typeNodes,
6665
});
6766
}
68-
// TODO Feature Development: Calculate intersection types
69-
return factory.TypeNode.create({ type: "never" });
67+
/**
68+
* If you see this comment and have an idea for an AnyOf type output, please submit an Issue.
69+
*/
70+
return factory.UnionTypeNode.create({
71+
typeNodes,
72+
});
7073
};
7174

7275
const nullable = (factory: Factory.Type, typeNode: ts.TypeNode, nullable: boolean): ts.TypeNode => {

src/internal/ResolveReference/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ export { OpenApi };
99

1010
export type ObjectLike = { [key: string]: any };
1111

12-
const escapeFromJsonCyclic = (obj: any) => JSON.parse(JSON.stringify(obj));
12+
const escapeFromJsonCyclic = (obj: any) => {
13+
if (!obj) {
14+
return obj;
15+
}
16+
return JSON.parse(JSON.stringify(obj));
17+
};
1318

1419
const isObject = (value: any): value is ObjectLike => {
1520
return !!value && value !== null && !Array.isArray(value) && typeof value === "object";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Multi Type apiClient 1`] = `
4+
"//
5+
// Generated by @himenon/openapi-typescript-code-generator
6+
//
7+
// OpenApi : 3.0.1
8+
//
9+
// License : MIT
10+
//
11+
12+
13+
import { Schemas } from \\"./types\\";
14+
export interface RequestBody$putAnyOf {
15+
\\"application/json\\": Schemas.Cat | Schemas.Dog;
16+
}
17+
export interface RequestBody$patchOneOf {
18+
\\"application/json\\": Schemas.Cat | Schemas.Dog;
19+
}
20+
export type RequestContentType$putAnyOf = keyof RequestBody$putAnyOf;
21+
export interface Params$putAnyOf {
22+
requestBody: RequestBody$putAnyOf[\\"application/json\\"];
23+
}
24+
export type RequestContentType$patchOneOf = keyof RequestBody$patchOneOf;
25+
export interface Params$patchOneOf {
26+
requestBody: RequestBody$patchOneOf[\\"application/json\\"];
27+
}
28+
export type HttpMethod = \\"GET\\" | \\"PUT\\" | \\"POST\\" | \\"DELETE\\" | \\"OPTIONS\\" | \\"HEAD\\" | \\"PATCH\\" | \\"TRACE\\";
29+
export interface ObjectLike {
30+
[key: string]: any;
31+
}
32+
export interface QueryParameter {
33+
value: any;
34+
style?: \\"form\\" | \\"spaceDelimited\\" | \\"pipeDelimited\\" | \\"deepObject\\";
35+
explode: boolean;
36+
}
37+
export interface QueryParameters {
38+
[key: string]: QueryParameter;
39+
}
40+
export type SuccessResponses = void;
41+
export namespace ErrorResponse {
42+
export type putAnyOf = void;
43+
export type patchOneOf = void;
44+
}
45+
export interface ApiClient<RequestOption> {
46+
request: <T = SuccessResponses>(httpMethod: HttpMethod, url: string, headers: ObjectLike | any, requestBody: ObjectLike | any, queryParameters: QueryParameters | undefined, options?: RequestOption) => Promise<T>;
47+
}
48+
export class Client<RequestOption> {
49+
private baseUrl: string;
50+
constructor(private apiClient: ApiClient<RequestOption>, baseUrl: string) { this.baseUrl = baseUrl.replace(/\\\\/$/, \\"\\"); }
51+
/**
52+
* operationId: putAnyOf
53+
* Request URI: /pets
54+
*/
55+
public async putAnyOf(params: Params$putAnyOf, option?: RequestOption): Promise<void> {
56+
const url = this.baseUrl + \`/pets\`;
57+
const headers = {
58+
\\"Content-Type\\": \\"application/json\\"
59+
};
60+
return this.apiClient.request(\\"PUT\\", url, headers, params.requestBody, undefined, option);
61+
}
62+
/**
63+
* operationId: patchOneOf
64+
* Request URI: /pets
65+
*/
66+
public async patchOneOf(params: Params$patchOneOf, option?: RequestOption): Promise<void> {
67+
const url = this.baseUrl + \`/pets\`;
68+
const headers = {
69+
\\"Content-Type\\": \\"application/json\\"
70+
};
71+
return this.apiClient.request(\\"PATCH\\", url, headers, params.requestBody, undefined, option);
72+
}
73+
}
74+
"
75+
`;
76+
77+
exports[`Multi Type types 1`] = `
78+
"//
79+
// Generated by @himenon/openapi-typescript-code-generator
80+
//
81+
// OpenApi : 3.0.1
82+
//
83+
// License : MIT
84+
//
85+
86+
87+
export namespace Schemas {
88+
export interface Pet {
89+
pet_type: string;
90+
}
91+
export type Dog = Schemas.Pet & {
92+
bark?: boolean;
93+
breed?: \\"Dingo\\" | \\"Husky\\" | \\"Retriever\\" | \\"Shepherd\\";
94+
};
95+
export type Cat = Schemas.Pet & {
96+
hunts?: boolean;
97+
age?: number;
98+
};
99+
}
100+
"
101+
`;
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
4+
import * as Utils from "../utils";
5+
6+
describe("Multi Type", () => {
7+
test("types", () => {
8+
const generateCode = fs.readFileSync(path.join(__dirname, "../code/mulit-type-test.domain/types.ts"), { encoding: "utf-8" });
9+
const text = Utils.replaceVersionInfo(generateCode);
10+
expect(text).toMatchSnapshot();
11+
});
12+
13+
test("apiClient", () => {
14+
const generateCode = fs.readFileSync(path.join(__dirname, "../code/mulit-type-test.domain/apiClient.ts"), { encoding: "utf-8" });
15+
const text = Utils.replaceVersionInfo(generateCode);
16+
expect(text).toMatchSnapshot();
17+
});
18+
});

test/api.test.domain/index.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ components:
266266
- type: string
267267
- type: number
268268
- type: boolean
269+
269270
responses:
270271
Continue:
271272
description: |
@@ -413,7 +414,7 @@ paths:
413414
200:
414415
description: Search Book Result
415416
content:
416-
application/json:
417+
application/json:
417418
schema:
418419
type: object
419420
properties:

test/multi-type.test.domain/index.yml

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
openapi: 3.0.1
2+
info:
3+
version: 1.0.0
4+
title: multi-type.test.domain
5+
description: Library test schema
6+
license:
7+
name: MIT
8+
9+
servers:
10+
- url: "http://multi-type.test.domain/"
11+
description: Development Environment
12+
13+
components:
14+
schemas:
15+
Pet:
16+
type: object
17+
required:
18+
- pet_type
19+
properties:
20+
pet_type:
21+
type: string
22+
discriminator:
23+
propertyName: pet_type
24+
Dog:
25+
allOf:
26+
- $ref: "#/components/schemas/Pet"
27+
- type: object
28+
# all other properties specific to a `Dog`
29+
properties:
30+
bark:
31+
type: boolean
32+
breed:
33+
type: string
34+
enum: [Dingo, Husky, Retriever, Shepherd]
35+
Cat:
36+
allOf:
37+
- $ref: "#/components/schemas/Pet"
38+
- type: object
39+
properties:
40+
hunts:
41+
type: boolean
42+
age:
43+
type: integer
44+
45+
paths:
46+
/pets:
47+
put:
48+
operationId: putAnyOf
49+
requestBody:
50+
content:
51+
application/json:
52+
schema:
53+
anyOf:
54+
- $ref: "#/components/schemas/Cat"
55+
- $ref: "#/components/schemas/Dog"
56+
responses:
57+
"200":
58+
description: Updated
59+
60+
patch:
61+
operationId: patchOneOf
62+
requestBody:
63+
content:
64+
application/json:
65+
schema:
66+
oneOf:
67+
- $ref: "#/components/schemas/Cat"
68+
- $ref: "#/components/schemas/Dog"
69+
responses:
70+
"200":
71+
description: Updated

0 commit comments

Comments
 (0)