@goast/typescript 0.0.1
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/README.md +11 -0
- package/assets/client/fetch/types.ts +9 -0
- package/assets/client/fetch/url-builder.ts +36 -0
- package/assets/service/angular/api-configuration.ts +18 -0
- package/assets/service/angular/base-service.ts +29 -0
- package/assets/service/angular/request-builder.ts +368 -0
- package/assets/service/angular/response-handlers.ts +127 -0
- package/assets/service/angular/strict-http-response.ts +8 -0
- package/cjs/index.js +9 -0
- package/cjs/lib/common-results.js +2 -0
- package/cjs/lib/config.js +15 -0
- package/cjs/lib/file-builder.js +244 -0
- package/cjs/lib/generators/file-generator.js +26 -0
- package/cjs/lib/generators/index.js +7 -0
- package/cjs/lib/generators/models/index.js +6 -0
- package/cjs/lib/generators/models/model-generator.js +317 -0
- package/cjs/lib/generators/models/models-generator.js +67 -0
- package/cjs/lib/generators/models/models.js +6 -0
- package/cjs/lib/generators/services/angular-services/angular-service-generator.js +360 -0
- package/cjs/lib/generators/services/angular-services/angular-services-generator.js +122 -0
- package/cjs/lib/generators/services/angular-services/index.js +6 -0
- package/cjs/lib/generators/services/angular-services/models.js +5 -0
- package/cjs/lib/generators/services/fetch-clients/fetch-client-generator.js +240 -0
- package/cjs/lib/generators/services/fetch-clients/fetch-clients-generator.js +83 -0
- package/cjs/lib/generators/services/fetch-clients/index.js +6 -0
- package/cjs/lib/generators/services/fetch-clients/models.js +5 -0
- package/cjs/lib/import-collection.js +116 -0
- package/cjs/lib/utils.js +56 -0
- package/cjs/package.json +1 -0
- package/esm/index.js +6 -0
- package/esm/lib/common-results.js +1 -0
- package/esm/lib/config.js +12 -0
- package/esm/lib/file-builder.js +240 -0
- package/esm/lib/generators/file-generator.js +22 -0
- package/esm/lib/generators/index.js +4 -0
- package/esm/lib/generators/models/index.js +3 -0
- package/esm/lib/generators/models/model-generator.js +313 -0
- package/esm/lib/generators/models/models-generator.js +63 -0
- package/esm/lib/generators/models/models.js +3 -0
- package/esm/lib/generators/services/angular-services/angular-service-generator.js +356 -0
- package/esm/lib/generators/services/angular-services/angular-services-generator.js +118 -0
- package/esm/lib/generators/services/angular-services/index.js +3 -0
- package/esm/lib/generators/services/angular-services/models.js +2 -0
- package/esm/lib/generators/services/fetch-clients/fetch-client-generator.js +236 -0
- package/esm/lib/generators/services/fetch-clients/fetch-clients-generator.js +79 -0
- package/esm/lib/generators/services/fetch-clients/index.js +3 -0
- package/esm/lib/generators/services/fetch-clients/models.js +2 -0
- package/esm/lib/import-collection.js +112 -0
- package/esm/lib/utils.js +48 -0
- package/package.json +29 -0
- package/types/index.d.ts +6 -0
- package/types/lib/common-results.d.ts +11 -0
- package/types/lib/config.d.ts +13 -0
- package/types/lib/file-builder.d.ts +110 -0
- package/types/lib/generators/file-generator.d.ts +11 -0
- package/types/lib/generators/index.d.ts +4 -0
- package/types/lib/generators/models/index.d.ts +3 -0
- package/types/lib/generators/models/model-generator.d.ts +40 -0
- package/types/lib/generators/models/models-generator.d.ts +23 -0
- package/types/lib/generators/models/models.d.ts +29 -0
- package/types/lib/generators/services/angular-services/angular-service-generator.d.ts +53 -0
- package/types/lib/generators/services/angular-services/angular-services-generator.d.ts +29 -0
- package/types/lib/generators/services/angular-services/index.d.ts +3 -0
- package/types/lib/generators/services/angular-services/models.d.ts +41 -0
- package/types/lib/generators/services/fetch-clients/fetch-client-generator.d.ts +43 -0
- package/types/lib/generators/services/fetch-clients/fetch-clients-generator.d.ts +24 -0
- package/types/lib/generators/services/fetch-clients/index.d.ts +3 -0
- package/types/lib/generators/services/fetch-clients/models.d.ts +34 -0
- package/types/lib/import-collection.d.ts +21 -0
- package/types/lib/utils.d.ts +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export class UrlBuilder {
|
|
2
|
+
private path: string = '';
|
|
3
|
+
private pathParams: Record<string, string> = {};
|
|
4
|
+
private queryParams: Record<string, string> = {};
|
|
5
|
+
|
|
6
|
+
constructor(private readonly baseUrl?: string) {}
|
|
7
|
+
|
|
8
|
+
public withPath(path: string) {
|
|
9
|
+
this.path += path.startsWith('/') ? path : '/' + path;
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public withPathParam(name: string, value: unknown) {
|
|
14
|
+
this.pathParams[name] = String(value);
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public withQueryParam(name: string, value: unknown) {
|
|
19
|
+
if (value === undefined || value === null) {
|
|
20
|
+
if (name in this.queryParams) {
|
|
21
|
+
delete this.queryParams[name];
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
this.queryParams[name] = String(value);
|
|
25
|
+
}
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public build() {
|
|
30
|
+
const queryString = Object.keys(this.queryParams)
|
|
31
|
+
.map((key) => `${key}=${this.queryParams[key]}`)
|
|
32
|
+
.join('&');
|
|
33
|
+
const path = this.path.replace(/\{([^}]+)\}/g, (_, name) => this.pathParams[name]);
|
|
34
|
+
return `${this.baseUrl}${path || '/'}${queryString ? '?' + queryString : ''}`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Global configuration
|
|
5
|
+
*/
|
|
6
|
+
@Injectable({
|
|
7
|
+
providedIn: 'root',
|
|
8
|
+
})
|
|
9
|
+
export class ApiConfiguration {
|
|
10
|
+
rootUrl: string = '@ROOT_URL@';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Parameters for `ApiModule.forRoot()`
|
|
15
|
+
*/
|
|
16
|
+
export interface ApiConfigurationParams {
|
|
17
|
+
rootUrl?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { HttpClient } from '@angular/common/http';
|
|
2
|
+
import { Injectable } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
import { ApiConfiguration } from './api-configuration';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Base class for services
|
|
8
|
+
*/
|
|
9
|
+
@Injectable()
|
|
10
|
+
export class BaseService {
|
|
11
|
+
constructor(protected config: ApiConfiguration, protected http: HttpClient) {}
|
|
12
|
+
|
|
13
|
+
private _rootUrl: string = '';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Returns the root url for all operations in this service. If not set directly in this
|
|
17
|
+
* service, will fallback to `ApiConfiguration.rootUrl`.
|
|
18
|
+
*/
|
|
19
|
+
get rootUrl(): string {
|
|
20
|
+
return this._rootUrl || this.config.rootUrl;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Sets the root URL for API operations in this service.
|
|
25
|
+
*/
|
|
26
|
+
set rootUrl(rootUrl: string) {
|
|
27
|
+
this._rootUrl = rootUrl;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { HttpRequest, HttpParameterCodec, HttpParams, HttpHeaders, HttpContext } from '@angular/common/http';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Custom parameter codec to correctly handle the plus sign in parameter
|
|
5
|
+
* values. See https://github.com/angular/angular/issues/18261
|
|
6
|
+
*/
|
|
7
|
+
class ParameterCodec implements HttpParameterCodec {
|
|
8
|
+
encodeKey(key: string): string {
|
|
9
|
+
return encodeURIComponent(key);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
encodeValue(value: string): string {
|
|
13
|
+
return encodeURIComponent(value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
decodeKey(key: string): string {
|
|
17
|
+
return decodeURIComponent(key);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
decodeValue(value: string): string {
|
|
21
|
+
return decodeURIComponent(value);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const ParameterCodecInstance = new ParameterCodec();
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Defines the options for appending a parameter
|
|
28
|
+
*/
|
|
29
|
+
interface ParameterOptions {
|
|
30
|
+
style?: string;
|
|
31
|
+
explode?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Base class for a parameter
|
|
36
|
+
*/
|
|
37
|
+
abstract class Parameter {
|
|
38
|
+
constructor(
|
|
39
|
+
public name: string,
|
|
40
|
+
public value: any,
|
|
41
|
+
public options: ParameterOptions,
|
|
42
|
+
defaultStyle: string,
|
|
43
|
+
defaultExplode: boolean
|
|
44
|
+
) {
|
|
45
|
+
this.options = options || {};
|
|
46
|
+
if (this.options.style === null || this.options.style === undefined) {
|
|
47
|
+
this.options.style = defaultStyle;
|
|
48
|
+
}
|
|
49
|
+
if (this.options.explode === null || this.options.explode === undefined) {
|
|
50
|
+
this.options.explode = defaultExplode;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
serializeValue(value: any, separator = ','): string {
|
|
55
|
+
if (value === null || value === undefined) {
|
|
56
|
+
return '';
|
|
57
|
+
} else if (value instanceof Array) {
|
|
58
|
+
return value
|
|
59
|
+
.map((v) => this.serializeValue(v).split(separator).join(encodeURIComponent(separator)))
|
|
60
|
+
.join(separator);
|
|
61
|
+
} else if (typeof value === 'object') {
|
|
62
|
+
const array: string[] = [];
|
|
63
|
+
for (const key of Object.keys(value)) {
|
|
64
|
+
let propVal = value[key];
|
|
65
|
+
if (propVal !== null && propVal !== undefined) {
|
|
66
|
+
propVal = this.serializeValue(propVal).split(separator).join(encodeURIComponent(separator));
|
|
67
|
+
if (this.options.explode) {
|
|
68
|
+
array.push(`${key}=${propVal}`);
|
|
69
|
+
} else {
|
|
70
|
+
array.push(key);
|
|
71
|
+
array.push(propVal);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return array.join(separator);
|
|
76
|
+
} else {
|
|
77
|
+
return String(value);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A parameter in the operation path
|
|
84
|
+
*/
|
|
85
|
+
class PathParameter extends Parameter {
|
|
86
|
+
constructor(name: string, value: any, options: ParameterOptions) {
|
|
87
|
+
super(name, value, options, 'simple', false);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
append(path: string): string {
|
|
91
|
+
let value = this.value;
|
|
92
|
+
if (value === null || value === undefined) {
|
|
93
|
+
value = '';
|
|
94
|
+
}
|
|
95
|
+
let prefix = this.options.style === 'label' ? '.' : '';
|
|
96
|
+
const separator = this.options.explode ? (prefix === '' ? ',' : prefix) : ',';
|
|
97
|
+
let alreadySerialized = false;
|
|
98
|
+
if (this.options.style === 'matrix') {
|
|
99
|
+
// The parameter name is just used as prefix, except in some cases...
|
|
100
|
+
prefix = `;${this.name}=`;
|
|
101
|
+
if (this.options.explode && typeof value === 'object') {
|
|
102
|
+
prefix = ';';
|
|
103
|
+
if (value instanceof Array) {
|
|
104
|
+
// For arrays we have to repeat the name for each element
|
|
105
|
+
value = value.map((v) => `${this.name}=${this.serializeValue(v, ';')}`);
|
|
106
|
+
value = value.join(';');
|
|
107
|
+
alreadySerialized = true;
|
|
108
|
+
} else {
|
|
109
|
+
// For objects we have to put each the key / value pairs
|
|
110
|
+
value = this.serializeValue(value, ';');
|
|
111
|
+
alreadySerialized = true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
value = prefix + (alreadySerialized ? value : this.serializeValue(value, separator));
|
|
116
|
+
// Replace both the plain variable and the corresponding variant taking in the prefix and explode into account
|
|
117
|
+
path = path.replace(`{${this.name}}`, value);
|
|
118
|
+
path = path.replace(`{${prefix}${this.name}${this.options.explode ? '*' : ''}}`, value);
|
|
119
|
+
return path;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
123
|
+
// @ts-ignore
|
|
124
|
+
serializeValue(value: any, separator = ','): string {
|
|
125
|
+
let result = typeof value === 'string' ? encodeURIComponent(value) : super.serializeValue(value, separator);
|
|
126
|
+
result = result.replace(/%3D/g, '=');
|
|
127
|
+
result = result.replace(/%3B/g, ';');
|
|
128
|
+
result = result.replace(/%2C/g, ',');
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* A parameter in the query
|
|
135
|
+
*/
|
|
136
|
+
class QueryParameter extends Parameter {
|
|
137
|
+
constructor(name: string, value: any, options: ParameterOptions) {
|
|
138
|
+
super(name, value, options, 'form', true);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
append(params: HttpParams): HttpParams {
|
|
142
|
+
if (this.value instanceof Array) {
|
|
143
|
+
// Array serialization
|
|
144
|
+
if (this.options.explode) {
|
|
145
|
+
for (const v of this.value) {
|
|
146
|
+
params = params.append(this.name, this.serializeValue(v));
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
const separator =
|
|
150
|
+
this.options.style === 'spaceDelimited' ? ' ' : this.options.style === 'pipeDelimited' ? '|' : ',';
|
|
151
|
+
return params.append(this.name, this.serializeValue(this.value, separator));
|
|
152
|
+
}
|
|
153
|
+
} else if (this.value !== null && typeof this.value === 'object') {
|
|
154
|
+
// Object serialization
|
|
155
|
+
if (this.options.style === 'deepObject') {
|
|
156
|
+
// Append a parameter for each key, in the form `name[key]`
|
|
157
|
+
for (const key of Object.keys(this.value)) {
|
|
158
|
+
const propVal = this.value[key];
|
|
159
|
+
if (propVal !== null && propVal !== undefined) {
|
|
160
|
+
params = params.append(`${this.name}[${key}]`, this.serializeValue(propVal));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} else if (this.options.explode) {
|
|
164
|
+
// Append a parameter for each key without using the parameter name
|
|
165
|
+
for (const key of Object.keys(this.value)) {
|
|
166
|
+
const propVal = this.value[key];
|
|
167
|
+
if (propVal !== null && propVal !== undefined) {
|
|
168
|
+
params = params.append(key, this.serializeValue(propVal));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
// Append a single parameter whose values are a comma-separated list of key,value,key,value...
|
|
173
|
+
const array: any[] = [];
|
|
174
|
+
for (const key of Object.keys(this.value)) {
|
|
175
|
+
const propVal = this.value[key];
|
|
176
|
+
if (propVal !== null && propVal !== undefined) {
|
|
177
|
+
array.push(key);
|
|
178
|
+
array.push(propVal);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
params = params.append(this.name, this.serializeValue(array));
|
|
182
|
+
}
|
|
183
|
+
} else if (this.value !== null && this.value !== undefined) {
|
|
184
|
+
// Plain value
|
|
185
|
+
params = params.append(this.name, this.serializeValue(this.value));
|
|
186
|
+
}
|
|
187
|
+
return params;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* A parameter in the HTTP request header
|
|
193
|
+
*/
|
|
194
|
+
class HeaderParameter extends Parameter {
|
|
195
|
+
constructor(name: string, value: any, options: ParameterOptions) {
|
|
196
|
+
super(name, value, options, 'simple', false);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
append(headers: HttpHeaders): HttpHeaders {
|
|
200
|
+
if (this.value !== null && this.value !== undefined) {
|
|
201
|
+
if (this.value instanceof Array) {
|
|
202
|
+
for (const v of this.value) {
|
|
203
|
+
headers = headers.append(this.name, this.serializeValue(v));
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
headers = headers.append(this.name, this.serializeValue(this.value));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return headers;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Helper to build http requests from parameters
|
|
215
|
+
*/
|
|
216
|
+
export class RequestBuilder {
|
|
217
|
+
private _path = new Map<string, PathParameter>();
|
|
218
|
+
private _query = new Map<string, QueryParameter>();
|
|
219
|
+
private _header = new Map<string, HeaderParameter>();
|
|
220
|
+
_bodyContent: any | null;
|
|
221
|
+
_bodyContentType?: string;
|
|
222
|
+
|
|
223
|
+
constructor(public rootUrl: string, public operationPath: string, public method: string) {}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Sets a path parameter
|
|
227
|
+
*/
|
|
228
|
+
path(name: string, value: any, options?: ParameterOptions): void {
|
|
229
|
+
this._path.set(name, new PathParameter(name, value, options || {}));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Sets a query parameter
|
|
234
|
+
*/
|
|
235
|
+
query(name: string, value: any, options?: ParameterOptions): void {
|
|
236
|
+
this._query.set(name, new QueryParameter(name, value, options || {}));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Sets a header parameter
|
|
241
|
+
*/
|
|
242
|
+
header(name: string, value: any, options?: ParameterOptions): void {
|
|
243
|
+
this._header.set(name, new HeaderParameter(name, value, options || {}));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Sets the body content, along with the content type
|
|
248
|
+
*/
|
|
249
|
+
body(value: any, contentType = 'application/json'): void {
|
|
250
|
+
if (value instanceof Blob) {
|
|
251
|
+
this._bodyContentType = value.type;
|
|
252
|
+
} else {
|
|
253
|
+
this._bodyContentType = contentType;
|
|
254
|
+
}
|
|
255
|
+
if (this._bodyContentType === 'application/x-www-form-urlencoded' && value !== null && typeof value === 'object') {
|
|
256
|
+
// Handle URL-encoded data
|
|
257
|
+
const pairs: Array<[string, string]> = [];
|
|
258
|
+
for (const key of Object.keys(value)) {
|
|
259
|
+
let val = value[key];
|
|
260
|
+
if (!(val instanceof Array)) {
|
|
261
|
+
val = [val];
|
|
262
|
+
}
|
|
263
|
+
for (const v of val) {
|
|
264
|
+
const formValue = this.formDataValue(v);
|
|
265
|
+
if (formValue !== null) {
|
|
266
|
+
pairs.push([key, formValue]);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
this._bodyContent = pairs.map((p) => `${encodeURIComponent(p[0])}=${encodeURIComponent(p[1])}`).join('&');
|
|
271
|
+
} else if (this._bodyContentType === 'multipart/form-data') {
|
|
272
|
+
// Handle multipart form data
|
|
273
|
+
const formData = new FormData();
|
|
274
|
+
if (value !== null && value !== undefined) {
|
|
275
|
+
for (const key of Object.keys(value)) {
|
|
276
|
+
const val = value[key];
|
|
277
|
+
if (val instanceof Array) {
|
|
278
|
+
for (const v of val) {
|
|
279
|
+
const toAppend = this.formDataValue(v);
|
|
280
|
+
if (toAppend !== null) {
|
|
281
|
+
formData.append(key, toAppend);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
const toAppend = this.formDataValue(val);
|
|
286
|
+
if (toAppend !== null) {
|
|
287
|
+
formData.set(key, toAppend);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
this._bodyContent = formData;
|
|
293
|
+
} else {
|
|
294
|
+
// The body is the plain content
|
|
295
|
+
this._bodyContent = value;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private formDataValue(value: any): any {
|
|
300
|
+
if (value === null || value === undefined) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
if (value instanceof Blob) {
|
|
304
|
+
return value;
|
|
305
|
+
}
|
|
306
|
+
if (typeof value === 'object') {
|
|
307
|
+
return JSON.stringify(value);
|
|
308
|
+
}
|
|
309
|
+
return String(value);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Builds the request with the current set parameters
|
|
314
|
+
*/
|
|
315
|
+
build<T = any>(options?: {
|
|
316
|
+
/** Which content types to accept */
|
|
317
|
+
accept?: string;
|
|
318
|
+
|
|
319
|
+
/** The expected response type */
|
|
320
|
+
responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';
|
|
321
|
+
|
|
322
|
+
/** Whether to report progress on uploads / downloads */
|
|
323
|
+
reportProgress?: boolean;
|
|
324
|
+
|
|
325
|
+
/** Allow passing HttpContext for HttpClient */
|
|
326
|
+
context?: HttpContext;
|
|
327
|
+
}): HttpRequest<T> {
|
|
328
|
+
options = options || {};
|
|
329
|
+
|
|
330
|
+
// Path parameters
|
|
331
|
+
let path = this.operationPath;
|
|
332
|
+
for (const pathParam of this._path.values()) {
|
|
333
|
+
path = pathParam.append(path);
|
|
334
|
+
}
|
|
335
|
+
const url = this.rootUrl + path;
|
|
336
|
+
|
|
337
|
+
// Query parameters
|
|
338
|
+
let httpParams = new HttpParams({
|
|
339
|
+
encoder: ParameterCodecInstance,
|
|
340
|
+
});
|
|
341
|
+
for (const queryParam of this._query.values()) {
|
|
342
|
+
httpParams = queryParam.append(httpParams);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Header parameters
|
|
346
|
+
let httpHeaders = new HttpHeaders();
|
|
347
|
+
if (options.accept) {
|
|
348
|
+
httpHeaders = httpHeaders.append('Accept', options.accept);
|
|
349
|
+
}
|
|
350
|
+
for (const headerParam of this._header.values()) {
|
|
351
|
+
httpHeaders = headerParam.append(httpHeaders);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Request content headers
|
|
355
|
+
if (this._bodyContentType && !(this._bodyContent instanceof FormData)) {
|
|
356
|
+
httpHeaders = httpHeaders.set('Content-Type', this._bodyContentType);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Perform the request
|
|
360
|
+
return new HttpRequest<T>(this.method.toUpperCase(), url, this._bodyContent, {
|
|
361
|
+
params: httpParams,
|
|
362
|
+
headers: httpHeaders,
|
|
363
|
+
responseType: options.responseType,
|
|
364
|
+
reportProgress: options.reportProgress,
|
|
365
|
+
context: options.context,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { HttpErrorResponse } from '@angular/common/http';
|
|
2
|
+
|
|
3
|
+
import { StrictHttpResponse } from './strict-http-response';
|
|
4
|
+
|
|
5
|
+
type Response = { status: string; content: unknown };
|
|
6
|
+
type PickRsp<T extends Response, K extends T['status']> = Exclude<T, Exclude<T, { status: K }>>;
|
|
7
|
+
type ExcludeRsp<T extends Response, K extends T['status']> = Exclude<T, { status: K }>;
|
|
8
|
+
type Handeled<T extends string | number | symbol> = { [K in T]: true };
|
|
9
|
+
type SuccessCode = `2${number}`;
|
|
10
|
+
type SuccessCodes<T extends Response> = Exclude<T['status'], Exclude<T['status'], SuccessCode>>;
|
|
11
|
+
type ErrorCode = `${4 | 5}${number}` | 'other';
|
|
12
|
+
type ErrorCodes<T extends Response> = Exclude<T['status'], Exclude<T['status'], ErrorCode>>;
|
|
13
|
+
type RemoveVoid<T> = T extends void ? never : T;
|
|
14
|
+
|
|
15
|
+
export class ResponseHandler<
|
|
16
|
+
I extends Response,
|
|
17
|
+
S extends I,
|
|
18
|
+
E extends Handeled<Exclude<I['status'], S['status']>>,
|
|
19
|
+
O
|
|
20
|
+
> {
|
|
21
|
+
private readonly _dummy?: E;
|
|
22
|
+
private readonly _response: I;
|
|
23
|
+
private _isHandeled = false;
|
|
24
|
+
public result: O | PromiseLike<O> = undefined!;
|
|
25
|
+
|
|
26
|
+
constructor(response: I) {
|
|
27
|
+
this._response = response;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public handle<T extends Exclude<S['status'], 'other'>, U = undefined>(
|
|
31
|
+
status: T[] | T,
|
|
32
|
+
handler?: (r: PickRsp<S, T>, status: string) => U | PromiseLike<U>
|
|
33
|
+
) {
|
|
34
|
+
const newThis = this.as<ExcludeRsp<S, T>, Handeled<T | keyof E>, RemoveVoid<U>>();
|
|
35
|
+
const matches = Array.isArray(status)
|
|
36
|
+
? (status as string[]).indexOf(this._response.status.toString()) >= 0
|
|
37
|
+
: this._response.status.toString() === status;
|
|
38
|
+
if (matches && !this._isHandeled) {
|
|
39
|
+
this._isHandeled = true;
|
|
40
|
+
if (handler) {
|
|
41
|
+
newThis.result = handler(this._response as PickRsp<S, T>, this._response.status) as
|
|
42
|
+
| RemoveVoid<U>
|
|
43
|
+
| PromiseLike<RemoveVoid<U>>;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return newThis;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public handleSuccess<T = undefined>(handler?: (r: PickRsp<S, SuccessCode>, status: string) => T | PromiseLike<T>) {
|
|
50
|
+
const newThis = this.as<ExcludeRsp<S, SuccessCode>, Handeled<SuccessCodes<S> | keyof E>, RemoveVoid<T>>();
|
|
51
|
+
const matches = this._response.status.startsWith('2');
|
|
52
|
+
if (matches && !this._isHandeled) {
|
|
53
|
+
this._isHandeled = true;
|
|
54
|
+
if (handler) {
|
|
55
|
+
newThis.result = handler(this._response as PickRsp<S, SuccessCode>, this._response.status) as
|
|
56
|
+
| RemoveVoid<T>
|
|
57
|
+
| PromiseLike<RemoveVoid<T>>;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return newThis;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public handleError<T = undefined>(handler?: (r: PickRsp<S, ErrorCode>, status: string) => T | PromiseLike<T>) {
|
|
64
|
+
const newThis = this.as<ExcludeRsp<S, ErrorCode>, Handeled<ErrorCodes<S> | keyof E>, RemoveVoid<T>>();
|
|
65
|
+
const matches = this._response.status.startsWith('4') || this._response.status.startsWith('5');
|
|
66
|
+
if (matches && !this._isHandeled) {
|
|
67
|
+
this._isHandeled = true;
|
|
68
|
+
if (handler) {
|
|
69
|
+
newThis.result = handler(this._response as PickRsp<S, ErrorCode>, this._response.status) as
|
|
70
|
+
| RemoveVoid<T>
|
|
71
|
+
| PromiseLike<RemoveVoid<T>>;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return newThis;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public throwOnError() {
|
|
78
|
+
const newThis = this.as<ExcludeRsp<S, ErrorCode>, Handeled<ErrorCodes<S> | keyof E>, never>();
|
|
79
|
+
const matches = this._response.status.startsWith('4') || this._response.status.startsWith('5');
|
|
80
|
+
if (matches && !this._isHandeled) {
|
|
81
|
+
throw new UnhandeledResponseError(this._response);
|
|
82
|
+
}
|
|
83
|
+
return newThis;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private as<NewS extends I, NewE extends Handeled<Exclude<I['status'], NewS['status']>>, NewO>() {
|
|
87
|
+
return this as unknown as ResponseHandler<I, NewS, NewE, O | NewO>;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class UnhandeledResponseError extends Error {
|
|
92
|
+
public readonly response: Response;
|
|
93
|
+
|
|
94
|
+
constructor(response: Response) {
|
|
95
|
+
super(`The response with status code '${response.status}' was not handeled.`, { cause: response });
|
|
96
|
+
this.response = response;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export type ResponseHandlerFn<T extends Response, O> = (
|
|
101
|
+
handler: ResponseHandler<T, T, object, never>
|
|
102
|
+
) => ResponseHandler<T, never, { [K in T['status']]: true }, O>;
|
|
103
|
+
|
|
104
|
+
export function handleResponse<R extends Response, O>(
|
|
105
|
+
response: Promise<StrictHttpResponse<unknown>>,
|
|
106
|
+
handler: ResponseHandlerFn<R, O>
|
|
107
|
+
): Promise<O> {
|
|
108
|
+
return response
|
|
109
|
+
.then(
|
|
110
|
+
(r: StrictHttpResponse<unknown>) =>
|
|
111
|
+
<R>{
|
|
112
|
+
status: r.status.toString(),
|
|
113
|
+
content: r.body,
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
.catch((e: HttpErrorResponse) => {
|
|
117
|
+
if (!e.status) throw e;
|
|
118
|
+
return <R>{
|
|
119
|
+
status: e.status.toString(),
|
|
120
|
+
content: e.error,
|
|
121
|
+
};
|
|
122
|
+
})
|
|
123
|
+
.then((r: R) => {
|
|
124
|
+
const h = new ResponseHandler<R, R, object, never>(r);
|
|
125
|
+
return handler(h).result;
|
|
126
|
+
});
|
|
127
|
+
}
|
package/cjs/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./lib/common-results"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./lib/config"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./lib/generators"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./lib/file-builder"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./lib/import-collection"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./lib/utils"), exports);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultTypeScriptGeneratorConfig = void 0;
|
|
4
|
+
exports.defaultTypeScriptGeneratorConfig = {
|
|
5
|
+
charsTreatedAsEmptyLine: ['{'],
|
|
6
|
+
indent: { type: 'spaces', count: 2 },
|
|
7
|
+
importModuleTransformer: 'omit-extension',
|
|
8
|
+
typeNameCasing: 'pascal',
|
|
9
|
+
methodNameCasing: 'camel',
|
|
10
|
+
propertyNameCasing: 'camel',
|
|
11
|
+
enumValueNameCasing: 'pascal',
|
|
12
|
+
constantCasing: { casing: 'snake', wordCasing: 'all-upper' },
|
|
13
|
+
preferUnknown: true,
|
|
14
|
+
useSingleQuotes: true,
|
|
15
|
+
};
|