Skip to content

Commit 26f2b68

Browse files
authored
Merge pull request #973 from jacobinu/fix/angular-tree-shakeable
2 parents 7e84960 + 8f7a14f commit 26f2b68

File tree

21 files changed

+3176
-2
lines changed

21 files changed

+3176
-2
lines changed

.changeset/ninety-windows-accept.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@hey-api/openapi-ts': patch
3+
---
4+
5+
fix: handle tree-shakeable angular client case

packages/openapi-ts/src/compiler/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ export class TypeScriptFile {
168168
}
169169

170170
export const compiler = {
171+
anonymousFunction: types.createAnonymousFunction,
171172
arrayLiteralExpression: types.createArrayLiteralExpression,
172173
arrowFunction: types.createArrowFunction,
173174
awaitExpression: types.createAwaitExpression,

packages/openapi-ts/src/compiler/types.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,44 @@ export const createArrowFunction = ({
298298
return expression;
299299
};
300300

301+
/**
302+
* Create anonymous function type expression.
303+
*/
304+
export const createAnonymousFunction = ({
305+
async,
306+
comment,
307+
multiLine,
308+
parameters = [],
309+
returnType,
310+
statements = [],
311+
types = [],
312+
}: {
313+
async?: boolean;
314+
comment?: Comments;
315+
multiLine?: boolean;
316+
parameters?: FunctionParameter[];
317+
returnType?: string | ts.TypeNode;
318+
statements?: ts.Statement[];
319+
types?: FunctionTypeParameter[];
320+
}) => {
321+
const expression = ts.factory.createFunctionExpression(
322+
async ? [ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword)] : undefined,
323+
undefined,
324+
undefined,
325+
types ? toTypeParameters(types) : undefined,
326+
toParameterDeclarations(parameters),
327+
returnType ? createTypeNode(returnType) : undefined,
328+
ts.factory.createBlock(statements, multiLine),
329+
);
330+
331+
addLeadingComments({
332+
comments: comment,
333+
node: expression,
334+
});
335+
336+
return expression;
337+
};
338+
301339
/**
302340
* Create Array type expression.
303341
* @param arr - The array to create.

packages/openapi-ts/src/generate/services.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ const processService = ({
610610

611611
if (!config.services.asClass && !config.name) {
612612
for (const operation of service.operations) {
613-
const expression = compiler.arrowFunction({
613+
const compileFunctionParams = {
614614
parameters: toOperationParamType(client, operation),
615615
returnType: isStandalone
616616
? undefined
@@ -622,7 +622,11 @@ const processService = ({
622622
onClientImport,
623623
),
624624
types: isStandalone ? [throwOnErrorTypeGeneric] : undefined,
625-
});
625+
};
626+
const expression =
627+
config.client.name === 'angular'
628+
? compiler.anonymousFunction(compileFunctionParams)
629+
: compiler.arrowFunction(compileFunctionParams);
626630
const statement = compiler.constVariable({
627631
comment: toOperationComment(operation),
628632
exportConst: true,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { ApiRequestOptions } from './ApiRequestOptions';
2+
import type { ApiResult } from './ApiResult';
3+
4+
export class ApiError extends Error {
5+
public readonly url: string;
6+
public readonly status: number;
7+
public readonly statusText: string;
8+
public readonly body: unknown;
9+
public readonly request: ApiRequestOptions;
10+
11+
constructor(request: ApiRequestOptions, response: ApiResult, message: string) {
12+
super(message);
13+
14+
this.name = 'ApiError';
15+
this.url = response.url;
16+
this.status = response.status;
17+
this.statusText = response.statusText;
18+
this.body = response.body;
19+
this.request = request;
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export type ApiRequestOptions<T = unknown> = {
2+
readonly body?: any;
3+
readonly cookies?: Record<string, unknown>;
4+
readonly errors?: Record<number | string, string>;
5+
readonly formData?: Record<string, unknown> | any[] | Blob | File;
6+
readonly headers?: Record<string, unknown>;
7+
readonly mediaType?: string;
8+
readonly method:
9+
| 'DELETE'
10+
| 'GET'
11+
| 'HEAD'
12+
| 'OPTIONS'
13+
| 'PATCH'
14+
| 'POST'
15+
| 'PUT';
16+
readonly path?: Record<string, unknown>;
17+
readonly query?: Record<string, unknown>;
18+
readonly responseHeader?: string;
19+
readonly responseTransformer?: (data: unknown) => Promise<T>;
20+
readonly url: string;
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export type ApiResult<TData = any> = {
2+
readonly body: TData;
3+
readonly ok: boolean;
4+
readonly status: number;
5+
readonly statusText: string;
6+
readonly url: string;
7+
};
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { HttpResponse } from '@angular/common/http';
2+
import type { ApiRequestOptions } from './ApiRequestOptions';
3+
4+
type Headers = Record<string, string>;
5+
type Middleware<T> = (value: T) => T | Promise<T>;
6+
type Resolver<T> = (options: ApiRequestOptions<T>) => Promise<T>;
7+
8+
export class Interceptors<T> {
9+
_fns: Middleware<T>[];
10+
11+
constructor() {
12+
this._fns = [];
13+
}
14+
15+
eject(fn: Middleware<T>): void {
16+
const index = this._fns.indexOf(fn);
17+
if (index !== -1) {
18+
this._fns = [...this._fns.slice(0, index), ...this._fns.slice(index + 1)];
19+
}
20+
}
21+
22+
use(fn: Middleware<T>): void {
23+
this._fns = [...this._fns, fn];
24+
}
25+
}
26+
27+
export type OpenAPIConfig = {
28+
BASE: string;
29+
CREDENTIALS: 'include' | 'omit' | 'same-origin';
30+
ENCODE_PATH?: ((path: string) => string) | undefined;
31+
HEADERS?: Headers | Resolver<Headers> | undefined;
32+
PASSWORD?: string | Resolver<string> | undefined;
33+
TOKEN?: string | Resolver<string> | undefined;
34+
USERNAME?: string | Resolver<string> | undefined;
35+
VERSION: string;
36+
WITH_CREDENTIALS: boolean;
37+
interceptors: {
38+
response: Interceptors<HttpResponse<any>>;
39+
};
40+
};
41+
42+
export const OpenAPI: OpenAPIConfig = {
43+
BASE: 'http://localhost:3000/base',
44+
CREDENTIALS: 'include',
45+
ENCODE_PATH: undefined,
46+
HEADERS: undefined,
47+
PASSWORD: undefined,
48+
TOKEN: undefined,
49+
USERNAME: undefined,
50+
VERSION: '1.0',
51+
WITH_CREDENTIALS: false,
52+
interceptors: {
53+
response: new Interceptors(),
54+
},
55+
};

0 commit comments

Comments
 (0)