@goast/typescript 0.2.13 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/client/angular/angular-service.utils.ts +62 -8
- package/cjs/lib/generators/services/angular-services/angular-service-generator.js +4 -2
- package/cjs/lib/generators/services/angular-services/refs.js +1 -0
- package/esm/lib/generators/services/angular-services/angular-service-generator.js +4 -2
- package/esm/lib/generators/services/angular-services/refs.js +1 -0
- package/package.json +1 -1
- package/types/lib/generators/services/angular-services/refs.d.ts +7 -0
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
import { HttpErrorResponse, HttpEvent, HttpResponse } from '@angular/common/http';
|
|
2
|
-
import { Observable, filter,
|
|
2
|
+
import { Observable, Subscription, filter, take, map, catchError, EMPTY } from 'rxjs';
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export type AbortablePromise<T> = {
|
|
5
|
+
abort(): void;
|
|
6
|
+
then<TResult1 = T, TResult2 = never>(
|
|
7
|
+
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
|
|
8
|
+
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null,
|
|
9
|
+
): AbortablePromise<TResult1 | TResult2>;
|
|
10
|
+
catch<TResult = never>(
|
|
11
|
+
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null,
|
|
12
|
+
): AbortablePromise<T | TResult>;
|
|
13
|
+
finally(onfinally?: (() => void) | undefined | null): AbortablePromise<T>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function waitForResponse<T extends HttpResponse<any> | HttpErrorResponse>(
|
|
5
17
|
httpEvents: Observable<HttpEvent<any>>,
|
|
6
18
|
options: { errorResponseTypes: Record<number, 'text' | 'json'> },
|
|
7
|
-
):
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
): AbortablePromise<T> {
|
|
20
|
+
return firstValueFromAbortable<T>(
|
|
21
|
+
httpEvents.pipe(
|
|
22
|
+
filter((event) => event instanceof HttpResponse),
|
|
23
|
+
map((response) => response as T),
|
|
24
|
+
),
|
|
25
|
+
).catch((error) => {
|
|
12
26
|
if (error instanceof HttpErrorResponse) {
|
|
13
27
|
if (options.errorResponseTypes[error.status] === 'json' && typeof error.error === 'string') {
|
|
14
28
|
return new HttpErrorResponse({
|
|
@@ -22,5 +36,45 @@ export async function waitForResponse<T extends HttpResponse<any> | HttpErrorRes
|
|
|
22
36
|
return error as T;
|
|
23
37
|
}
|
|
24
38
|
throw error;
|
|
25
|
-
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function firstValueFromAbortable<T>(observable: Observable<T>): AbortablePromise<T> {
|
|
43
|
+
let subscription: Subscription | undefined = undefined;
|
|
44
|
+
let _reject: ((reason?: any) => void) | undefined = undefined;
|
|
45
|
+
const abortFn = () => {
|
|
46
|
+
if (!subscription) {
|
|
47
|
+
throw new Error('Not subscribed yet.');
|
|
48
|
+
}
|
|
49
|
+
subscription.unsubscribe();
|
|
50
|
+
_reject?.(new DOMException('The request has been aborted.', 'AbortError'));
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return createAbortablePromise(
|
|
54
|
+
new Promise<T>((resolve, reject) => {
|
|
55
|
+
_reject = reject;
|
|
56
|
+
subscription = observable
|
|
57
|
+
.pipe(
|
|
58
|
+
take(1),
|
|
59
|
+
catchError((e: unknown) => {
|
|
60
|
+
reject(e);
|
|
61
|
+
return EMPTY;
|
|
62
|
+
}),
|
|
63
|
+
)
|
|
64
|
+
.subscribe((x: T) => resolve(x));
|
|
65
|
+
}),
|
|
66
|
+
abortFn,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function createAbortablePromise<T>(promise: Promise<T>, abortFn: () => void) {
|
|
71
|
+
const thenFn = promise.then.bind(promise);
|
|
72
|
+
const catchFn = promise.catch.bind(promise);
|
|
73
|
+
const finallyFn = promise.finally?.bind(promise);
|
|
74
|
+
return Object.assign(promise, {
|
|
75
|
+
then: (...args: any[]) => createAbortablePromise(thenFn(...args), abortFn),
|
|
76
|
+
catch: (...args: any[]) => createAbortablePromise(catchFn(...args), abortFn),
|
|
77
|
+
finally: finallyFn ? (...args: any[]) => createAbortablePromise(finallyFn(...args), abortFn) : undefined,
|
|
78
|
+
abort: abortFn,
|
|
79
|
+
});
|
|
26
80
|
}
|
|
@@ -153,7 +153,9 @@ class DefaultTypeScriptAngularServiceGenerator extends file_generator_1.TypeScri
|
|
|
153
153
|
getClass(ctx) {
|
|
154
154
|
return ast_1.ts.class(this.getServiceClassName(ctx), {
|
|
155
155
|
doc: ast_1.ts.doc({ description: ctx.service.description }),
|
|
156
|
-
decorators: [
|
|
156
|
+
decorators: [
|
|
157
|
+
ast_1.ts.decorator(ast_1.ts.refs.angular.injectable(), ctx.config.provideKind === 'root' ? [ast_1.ts.toNode({ providedIn: 'root' })] : []),
|
|
158
|
+
],
|
|
157
159
|
export: true,
|
|
158
160
|
extends: ctx.refs.apiBaseService(),
|
|
159
161
|
members: [
|
|
@@ -172,7 +174,7 @@ class DefaultTypeScriptAngularServiceGenerator extends file_generator_1.TypeScri
|
|
|
172
174
|
const hasParams = this.hasEndpointParams(ctx, endpoint);
|
|
173
175
|
const paramsOptional = !endpoint.parameters.some((p) => p.required) && !((_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.required);
|
|
174
176
|
const responseModelType = ast_1.ts.reference(this.getResponseModelName(ctx, endpoint), this.getResponseModelFilePath(ctx));
|
|
175
|
-
const returnType =
|
|
177
|
+
const returnType = ctx.refs.abortablePromise([responseModelType]);
|
|
176
178
|
const accept = (_d = (_c = (_b = this.getEndpointSuccessResponse(ctx, endpoint)) === null || _b === void 0 ? void 0 : _b.contentOptions[0]) === null || _c === void 0 ? void 0 : _c.type) !== null && _d !== void 0 ? _d : '*/*';
|
|
177
179
|
const responseType = this.contentTypeToResponseType(accept);
|
|
178
180
|
return ast_1.ts.method(this.getEndpointMethodName(ctx, endpoint), {
|
|
@@ -10,6 +10,7 @@ function getReferenceFactories(options) {
|
|
|
10
10
|
const utilsDirPath = (0, path_1.resolve)(options.outputDir, options.utilsDirPath);
|
|
11
11
|
return {
|
|
12
12
|
// angular-service.utils.ts
|
|
13
|
+
abortablePromise: ast_1.ts.reference.genericFactory('AbortablePromise', (0, path_1.join)(utilsDirPath, 'angular-service.utils.ts')),
|
|
13
14
|
waitForResponse: ast_1.ts.reference.genericFactory('waitForResponse', (0, path_1.join)(utilsDirPath, 'angular-service.utils.ts')),
|
|
14
15
|
// request-builder.ts
|
|
15
16
|
requestBuilder: ast_1.ts.reference.factory('RequestBuilder', (0, path_1.join)(utilsDirPath, 'request-builder.ts')),
|
|
@@ -150,7 +150,9 @@ export class DefaultTypeScriptAngularServiceGenerator extends TypeScriptFileGene
|
|
|
150
150
|
getClass(ctx) {
|
|
151
151
|
return ts.class(this.getServiceClassName(ctx), {
|
|
152
152
|
doc: ts.doc({ description: ctx.service.description }),
|
|
153
|
-
decorators: [
|
|
153
|
+
decorators: [
|
|
154
|
+
ts.decorator(ts.refs.angular.injectable(), ctx.config.provideKind === 'root' ? [ts.toNode({ providedIn: 'root' })] : []),
|
|
155
|
+
],
|
|
154
156
|
export: true,
|
|
155
157
|
extends: ctx.refs.apiBaseService(),
|
|
156
158
|
members: [
|
|
@@ -169,7 +171,7 @@ export class DefaultTypeScriptAngularServiceGenerator extends TypeScriptFileGene
|
|
|
169
171
|
const hasParams = this.hasEndpointParams(ctx, endpoint);
|
|
170
172
|
const paramsOptional = !endpoint.parameters.some((p) => p.required) && !((_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.required);
|
|
171
173
|
const responseModelType = ts.reference(this.getResponseModelName(ctx, endpoint), this.getResponseModelFilePath(ctx));
|
|
172
|
-
const returnType =
|
|
174
|
+
const returnType = ctx.refs.abortablePromise([responseModelType]);
|
|
173
175
|
const accept = (_d = (_c = (_b = this.getEndpointSuccessResponse(ctx, endpoint)) === null || _b === void 0 ? void 0 : _b.contentOptions[0]) === null || _c === void 0 ? void 0 : _c.type) !== null && _d !== void 0 ? _d : '*/*';
|
|
174
176
|
const responseType = this.contentTypeToResponseType(accept);
|
|
175
177
|
return ts.method(this.getEndpointMethodName(ctx, endpoint), {
|
|
@@ -7,6 +7,7 @@ export function getReferenceFactories(options) {
|
|
|
7
7
|
const utilsDirPath = resolve(options.outputDir, options.utilsDirPath);
|
|
8
8
|
return {
|
|
9
9
|
// angular-service.utils.ts
|
|
10
|
+
abortablePromise: ts.reference.genericFactory('AbortablePromise', join(utilsDirPath, 'angular-service.utils.ts')),
|
|
10
11
|
waitForResponse: ts.reference.genericFactory('waitForResponse', join(utilsDirPath, 'angular-service.utils.ts')),
|
|
11
12
|
// request-builder.ts
|
|
12
13
|
requestBuilder: ts.reference.factory('RequestBuilder', join(utilsDirPath, 'request-builder.ts')),
|
package/package.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { ts } from '../../../ast';
|
|
2
2
|
import type { TypeScriptAngularServicesGeneratorConfig } from './models';
|
|
3
3
|
export declare function getReferenceFactories(options: TypeScriptAngularServicesGeneratorConfig): {
|
|
4
|
+
abortablePromise: (<TBuilder extends import("@goast/core").SourceBuilder<never>>(generics: [ts.Type<TBuilder>]) => ts.Reference<TBuilder, never>) & {
|
|
5
|
+
refName: string;
|
|
6
|
+
moduleNameOrfilePath: import("@goast/core").Nullable<string>;
|
|
7
|
+
infer: <TBuilder_1 extends import("@goast/core").SourceBuilder<never>>() => ts.Reference<TBuilder_1, never>;
|
|
8
|
+
} & {
|
|
9
|
+
moduleNameOrfilePath: string;
|
|
10
|
+
};
|
|
4
11
|
waitForResponse: (<TBuilder extends import("@goast/core").SourceBuilder<never>>(generics: [ts.Type<TBuilder>]) => ts.Reference<TBuilder, never>) & {
|
|
5
12
|
refName: string;
|
|
6
13
|
moduleNameOrfilePath: import("@goast/core").Nullable<string>;
|