Skip to content

Commit 78cd982

Browse files
committed
Group union enums when intersecting allOf
Signed-off-by: Sora Morimoto <[email protected]>
1 parent 859fc64 commit 78cd982

File tree

5 files changed

+637
-4
lines changed

5 files changed

+637
-4
lines changed

.changeset/witty-pumas-itch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"swagger-typescript-api": patch
3+
---
4+
5+
Ensure enums combined via allOf intersect with grouped union values.

src/schema-parser/complex-schema-parsers/all-of.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ import { MonoSchemaParser } from "../mono-schema-parser.js";
44
export class AllOfSchemaParser extends MonoSchemaParser {
55
override parse() {
66
const ignoreTypes = [this.config.Ts.Keyword.Any];
7-
const combined = this.schema.allOf.map((childSchema) =>
8-
this.schemaParserFabric.getInlineParseContent(
7+
const combined = this.schema.allOf.map((childSchema) => {
8+
const content = this.schemaParserFabric.getInlineParseContent(
99
this.schemaUtils.makeAddRequiredToChildSchema(this.schema, childSchema),
1010
null,
1111
this.schemaPath,
12-
),
13-
);
12+
);
13+
14+
if (content?.includes(this.config.Ts.Keyword.Union)) {
15+
return this.config.Ts.ExpressionGroup(content);
16+
}
17+
18+
return content;
19+
});
1420
const filtered = this.schemaUtils.filterSchemaContents(
1521
combined,
1622
(content) => !ignoreTypes.includes(content),

tests/__snapshots__/extended.test.ts.snap

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10292,6 +10292,306 @@ export class Api<
1029210292
"
1029310293
`;
1029410294

10295+
exports[`extended > 'enum-allof' 1`] = `
10296+
"/* eslint-disable */
10297+
/* tslint:disable */
10298+
// @ts-nocheck
10299+
/*
10300+
* ---------------------------------------------------------------
10301+
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
10302+
* ## ##
10303+
* ## AUTHOR: acacode ##
10304+
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
10305+
* ---------------------------------------------------------------
10306+
*/
10307+
10308+
export enum Digit {
10309+
Zero = "zero",
10310+
One = "one",
10311+
Two = "two",
10312+
Three = "three",
10313+
Four = "four",
10314+
Five = "five",
10315+
Six = "six",
10316+
Seven = "seven",
10317+
Eight = "eight",
10318+
Nine = "nine",
10319+
}
10320+
10321+
export type Even = Digit & EvenEnum;
10322+
10323+
export enum EvenEnum {
10324+
Zero = "zero",
10325+
Two = "two",
10326+
Four = "four",
10327+
Six = "six",
10328+
Eight = "eight",
10329+
}
10330+
10331+
export type QueryParamsType = Record<string | number, any>;
10332+
export type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">;
10333+
10334+
export interface FullRequestParams extends Omit<RequestInit, "body"> {
10335+
/** set parameter to \`true\` for call \`securityWorker\` for this request */
10336+
secure?: boolean;
10337+
/** request path */
10338+
path: string;
10339+
/** content type of request body */
10340+
type?: ContentType;
10341+
/** query params */
10342+
query?: QueryParamsType;
10343+
/** format of response (i.e. response.json() -> format: "json") */
10344+
format?: ResponseFormat;
10345+
/** request body */
10346+
body?: unknown;
10347+
/** base url */
10348+
baseUrl?: string;
10349+
/** request cancellation token */
10350+
cancelToken?: CancelToken;
10351+
}
10352+
10353+
export type RequestParams = Omit<
10354+
FullRequestParams,
10355+
"body" | "method" | "query" | "path"
10356+
>;
10357+
10358+
export interface ApiConfig<SecurityDataType = unknown> {
10359+
baseUrl?: string;
10360+
baseApiParams?: Omit<RequestParams, "baseUrl" | "cancelToken" | "signal">;
10361+
securityWorker?: (
10362+
securityData: SecurityDataType | null,
10363+
) => Promise<RequestParams | void> | RequestParams | void;
10364+
customFetch?: typeof fetch;
10365+
}
10366+
10367+
export interface HttpResponse<D extends unknown, E extends unknown = unknown>
10368+
extends Response {
10369+
data: D;
10370+
error: E;
10371+
}
10372+
10373+
type CancelToken = Symbol | string | number;
10374+
10375+
export enum ContentType {
10376+
Json = "application/json",
10377+
JsonApi = "application/vnd.api+json",
10378+
FormData = "multipart/form-data",
10379+
UrlEncoded = "application/x-www-form-urlencoded",
10380+
Text = "text/plain",
10381+
}
10382+
10383+
export class HttpClient<SecurityDataType = unknown> {
10384+
public baseUrl: string = "";
10385+
private securityData: SecurityDataType | null = null;
10386+
private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
10387+
private abortControllers = new Map<CancelToken, AbortController>();
10388+
private customFetch = (...fetchParams: Parameters<typeof fetch>) =>
10389+
fetch(...fetchParams);
10390+
10391+
private baseApiParams: RequestParams = {
10392+
credentials: "same-origin",
10393+
headers: {},
10394+
redirect: "follow",
10395+
referrerPolicy: "no-referrer",
10396+
};
10397+
10398+
constructor(apiConfig: ApiConfig<SecurityDataType> = {}) {
10399+
Object.assign(this, apiConfig);
10400+
}
10401+
10402+
public setSecurityData = (data: SecurityDataType | null) => {
10403+
this.securityData = data;
10404+
};
10405+
10406+
protected encodeQueryParam(key: string, value: any) {
10407+
const encodedKey = encodeURIComponent(key);
10408+
return \`\${encodedKey}=\${encodeURIComponent(typeof value === "number" ? value : \`\${value}\`)}\`;
10409+
}
10410+
10411+
protected addQueryParam(query: QueryParamsType, key: string) {
10412+
return this.encodeQueryParam(key, query[key]);
10413+
}
10414+
10415+
protected addArrayQueryParam(query: QueryParamsType, key: string) {
10416+
const value = query[key];
10417+
return value.map((v: any) => this.encodeQueryParam(key, v)).join("&");
10418+
}
10419+
10420+
protected toQueryString(rawQuery?: QueryParamsType): string {
10421+
const query = rawQuery || {};
10422+
const keys = Object.keys(query).filter(
10423+
(key) => "undefined" !== typeof query[key],
10424+
);
10425+
return keys
10426+
.map((key) =>
10427+
Array.isArray(query[key])
10428+
? this.addArrayQueryParam(query, key)
10429+
: this.addQueryParam(query, key),
10430+
)
10431+
.join("&");
10432+
}
10433+
10434+
protected addQueryParams(rawQuery?: QueryParamsType): string {
10435+
const queryString = this.toQueryString(rawQuery);
10436+
return queryString ? \`?\${queryString}\` : "";
10437+
}
10438+
10439+
private contentFormatters: Record<ContentType, (input: any) => any> = {
10440+
[ContentType.Json]: (input: any) =>
10441+
input !== null && (typeof input === "object" || typeof input === "string")
10442+
? JSON.stringify(input)
10443+
: input,
10444+
[ContentType.JsonApi]: (input: any) =>
10445+
input !== null && (typeof input === "object" || typeof input === "string")
10446+
? JSON.stringify(input)
10447+
: input,
10448+
[ContentType.Text]: (input: any) =>
10449+
input !== null && typeof input !== "string"
10450+
? JSON.stringify(input)
10451+
: input,
10452+
[ContentType.FormData]: (input: any) => {
10453+
if (input instanceof FormData) {
10454+
return input;
10455+
}
10456+
10457+
return Object.keys(input || {}).reduce((formData, key) => {
10458+
const property = input[key];
10459+
formData.append(
10460+
key,
10461+
property instanceof Blob
10462+
? property
10463+
: typeof property === "object" && property !== null
10464+
? JSON.stringify(property)
10465+
: \`\${property}\`,
10466+
);
10467+
return formData;
10468+
}, new FormData());
10469+
},
10470+
[ContentType.UrlEncoded]: (input: any) => this.toQueryString(input),
10471+
};
10472+
10473+
protected mergeRequestParams(
10474+
params1: RequestParams,
10475+
params2?: RequestParams,
10476+
): RequestParams {
10477+
return {
10478+
...this.baseApiParams,
10479+
...params1,
10480+
...(params2 || {}),
10481+
headers: {
10482+
...(this.baseApiParams.headers || {}),
10483+
...(params1.headers || {}),
10484+
...((params2 && params2.headers) || {}),
10485+
},
10486+
};
10487+
}
10488+
10489+
protected createAbortSignal = (
10490+
cancelToken: CancelToken,
10491+
): AbortSignal | undefined => {
10492+
if (this.abortControllers.has(cancelToken)) {
10493+
const abortController = this.abortControllers.get(cancelToken);
10494+
if (abortController) {
10495+
return abortController.signal;
10496+
}
10497+
return void 0;
10498+
}
10499+
10500+
const abortController = new AbortController();
10501+
this.abortControllers.set(cancelToken, abortController);
10502+
return abortController.signal;
10503+
};
10504+
10505+
public abortRequest = (cancelToken: CancelToken) => {
10506+
const abortController = this.abortControllers.get(cancelToken);
10507+
10508+
if (abortController) {
10509+
abortController.abort();
10510+
this.abortControllers.delete(cancelToken);
10511+
}
10512+
};
10513+
10514+
public request = async <T = any, E = any>({
10515+
body,
10516+
secure,
10517+
path,
10518+
type,
10519+
query,
10520+
format,
10521+
baseUrl,
10522+
cancelToken,
10523+
...params
10524+
}: FullRequestParams): Promise<HttpResponse<T, E>> => {
10525+
const secureParams =
10526+
((typeof secure === "boolean" ? secure : this.baseApiParams.secure) &&
10527+
this.securityWorker &&
10528+
(await this.securityWorker(this.securityData))) ||
10529+
{};
10530+
const requestParams = this.mergeRequestParams(params, secureParams);
10531+
const queryString = query && this.toQueryString(query);
10532+
const payloadFormatter = this.contentFormatters[type || ContentType.Json];
10533+
const responseFormat = format || requestParams.format;
10534+
10535+
return this.customFetch(
10536+
\`\${baseUrl || this.baseUrl || ""}\${path}\${queryString ? \`?\${queryString}\` : ""}\`,
10537+
{
10538+
...requestParams,
10539+
headers: {
10540+
...(requestParams.headers || {}),
10541+
...(type && type !== ContentType.FormData
10542+
? { "Content-Type": type }
10543+
: {}),
10544+
},
10545+
signal:
10546+
(cancelToken
10547+
? this.createAbortSignal(cancelToken)
10548+
: requestParams.signal) || null,
10549+
body:
10550+
typeof body === "undefined" || body === null
10551+
? null
10552+
: payloadFormatter(body),
10553+
},
10554+
).then(async (response) => {
10555+
const r = response as HttpResponse<T, E>;
10556+
r.data = null as unknown as T;
10557+
r.error = null as unknown as E;
10558+
10559+
const data = !responseFormat
10560+
? r
10561+
: await response[responseFormat]()
10562+
.then((data) => {
10563+
if (r.ok) {
10564+
r.data = data;
10565+
} else {
10566+
r.error = data;
10567+
}
10568+
return r;
10569+
})
10570+
.catch((e) => {
10571+
r.error = e;
10572+
return r;
10573+
});
10574+
10575+
if (cancelToken) {
10576+
this.abortControllers.delete(cancelToken);
10577+
}
10578+
10579+
if (!response.ok) throw data;
10580+
return data;
10581+
});
10582+
};
10583+
}
10584+
10585+
/**
10586+
* @title Enum allOf
10587+
* @version 1.0.0
10588+
*/
10589+
export class Api<
10590+
SecurityDataType extends unknown,
10591+
> extends HttpClient<SecurityDataType> {}
10592+
"
10593+
`;
10594+
1029510595
exports[`extended > 'enum-type-mismatch' 1`] = `
1029610596
"/* eslint-disable */
1029710597
/* tslint:disable */

0 commit comments

Comments
 (0)