@goast/typescript 0.5.1-k6.3 → 0.5.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/LICENSE +21 -21
- package/README.md +52 -52
- package/assets/client/angular/angular-service.utils.ts +82 -82
- package/assets/client/angular/request-builder.ts +377 -377
- package/assets/client/fetch/fetch-client.utils.ts +52 -52
- package/assets/client/k6/request-builder.js +419 -419
- package/assets/client/k6/request-builder.ts +341 -341
- package/assets/stubs/easy-network-stub/easy-network-stub.utils.ts +259 -259
- package/esm/src/generators/models/models.d.ts +1 -1
- package/esm/src/generators/models/models.d.ts.map +1 -1
- package/esm/src/generators/services/angular-services/angular-service-generator.js +9 -9
- package/esm/src/generators/services/easy-network-stub/easy-network-stub-generator.js +9 -9
- package/esm/src/generators/services/fetch-clients/fetch-client-generator.js +2 -2
- package/esm/src/generators/services/k6-clients/k6-client-generator.js +11 -11
- package/package.json +1 -1
- package/script/src/generators/models/models.d.ts +1 -1
- package/script/src/generators/models/models.d.ts.map +1 -1
- package/script/src/generators/services/angular-services/angular-service-generator.js +9 -9
- package/script/src/generators/services/easy-network-stub/easy-network-stub-generator.js +9 -9
- package/script/src/generators/services/fetch-clients/fetch-client-generator.js +2 -2
- package/script/src/generators/services/k6-clients/k6-client-generator.js +11 -11
- package/src/mod.ts +7 -0
- package/src/src/assets.ts +9 -0
- package/src/src/ast/_index.ts +54 -0
- package/src/src/ast/common.ts +1 -0
- package/src/src/ast/index.ts +1 -0
- package/src/src/ast/node.ts +10 -0
- package/src/src/ast/nodes/argument.ts +40 -0
- package/src/src/ast/nodes/array-type.ts +49 -0
- package/src/src/ast/nodes/arrow-function.ts +91 -0
- package/src/src/ast/nodes/call.ts +55 -0
- package/src/src/ast/nodes/class.ts +133 -0
- package/src/src/ast/nodes/constructor-parameter.ts +70 -0
- package/src/src/ast/nodes/constructor.ts +77 -0
- package/src/src/ast/nodes/decorator.ts +76 -0
- package/src/src/ast/nodes/doc-tag.ts +291 -0
- package/src/src/ast/nodes/doc.ts +102 -0
- package/src/src/ast/nodes/enum-value.ts +72 -0
- package/src/src/ast/nodes/enum.ts +77 -0
- package/src/src/ast/nodes/export.ts +54 -0
- package/src/src/ast/nodes/function-type.ts +60 -0
- package/src/src/ast/nodes/function.ts +107 -0
- package/src/src/ast/nodes/generic-parameter.ts +71 -0
- package/src/src/ast/nodes/indexer.ts +60 -0
- package/src/src/ast/nodes/interface.ts +117 -0
- package/src/src/ast/nodes/intersection-type.ts +67 -0
- package/src/src/ast/nodes/lookup-type.ts +53 -0
- package/src/src/ast/nodes/method.ts +138 -0
- package/src/src/ast/nodes/object-type.ts +52 -0
- package/src/src/ast/nodes/object.ts +48 -0
- package/src/src/ast/nodes/parameter.ts +85 -0
- package/src/src/ast/nodes/property-accessor.ts +173 -0
- package/src/src/ast/nodes/property.ts +192 -0
- package/src/src/ast/nodes/reference.ts +194 -0
- package/src/src/ast/nodes/string.ts +49 -0
- package/src/src/ast/nodes/tuple.ts +53 -0
- package/src/src/ast/nodes/type-alias.ts +75 -0
- package/src/src/ast/nodes/typeof.ts +42 -0
- package/src/src/ast/nodes/types.ts +40 -0
- package/src/src/ast/nodes/union-type.ts +62 -0
- package/src/src/ast/nodes/variable.ts +73 -0
- package/src/src/ast/references/angular.ts +24 -0
- package/src/src/ast/references/easy-network-stub.ts +21 -0
- package/src/src/ast/references/index.ts +5 -0
- package/src/src/ast/references/k6.ts +8 -0
- package/src/src/ast/references/rxjs.ts +7 -0
- package/src/src/ast/references/typescript.ts +35 -0
- package/src/src/ast/utils/get-type-script-builder-options.ts +19 -0
- package/src/src/ast/utils/to-ts-node.ts +27 -0
- package/src/src/ast/utils/write-ts-generic-parameters.ts +25 -0
- package/src/src/ast/utils/write-ts-members.ts +28 -0
- package/src/src/ast/utils/write-ts-nodes.ts +35 -0
- package/src/src/ast/utils/write-ts-parameters.ts +25 -0
- package/src/src/common-results.ts +26 -0
- package/src/src/config.ts +89 -0
- package/src/src/file-builder.ts +136 -0
- package/src/src/generators/file-generator.ts +15 -0
- package/src/src/generators/index.ts +6 -0
- package/src/src/generators/models/index.ts +3 -0
- package/src/src/generators/models/model-generator.ts +469 -0
- package/src/src/generators/models/models-generator.ts +108 -0
- package/src/src/generators/models/models.ts +121 -0
- package/src/src/generators/services/angular-services/angular-service-generator.ts +406 -0
- package/src/src/generators/services/angular-services/angular-services-generator.ts +295 -0
- package/src/src/generators/services/angular-services/index.ts +3 -0
- package/src/src/generators/services/angular-services/models.ts +277 -0
- package/src/src/generators/services/angular-services/refs.ts +54 -0
- package/src/src/generators/services/easy-network-stub/easy-network-stub-generator.ts +242 -0
- package/src/src/generators/services/easy-network-stub/easy-network-stubs-generator.ts +211 -0
- package/src/src/generators/services/easy-network-stub/index.ts +3 -0
- package/src/src/generators/services/easy-network-stub/models.ts +124 -0
- package/src/src/generators/services/easy-network-stub/refs.ts +45 -0
- package/src/src/generators/services/fetch-clients/fetch-client-generator.ts +267 -0
- package/src/src/generators/services/fetch-clients/fetch-clients-generator.ts +163 -0
- package/src/src/generators/services/fetch-clients/index.ts +3 -0
- package/src/src/generators/services/fetch-clients/models.ts +130 -0
- package/src/src/generators/services/fetch-clients/refs.ts +21 -0
- package/src/src/generators/services/k6-clients/index.ts +3 -0
- package/src/src/generators/services/k6-clients/k6-client-generator.ts +465 -0
- package/src/src/generators/services/k6-clients/k6-clients-generator.ts +171 -0
- package/src/src/generators/services/k6-clients/models.ts +247 -0
- package/src/src/generators/services/k6-clients/refs.ts +16 -0
- package/src/src/import-collection.ts +236 -0
- package/src/src/utils.ts +72 -0
|
@@ -1,419 +1,419 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import http from 'k6/http';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Defines the options for appending a parameter
|
|
7
|
-
* @typedef {object} ParameterOptions
|
|
8
|
-
* @property {string} [style]
|
|
9
|
-
* @property {boolean} [explode]
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Base class for a parameter
|
|
14
|
-
* @abstract
|
|
15
|
-
* @property {string} name
|
|
16
|
-
* @property {*} value
|
|
17
|
-
* @property {ParameterOptions} options
|
|
18
|
-
*/
|
|
19
|
-
class Parameter {
|
|
20
|
-
/**
|
|
21
|
-
* @param {string} name
|
|
22
|
-
* @param {*} value
|
|
23
|
-
* @param {ParameterOptions} options
|
|
24
|
-
* @param {string} defaultStyle
|
|
25
|
-
* @param {boolean} defaultExplode
|
|
26
|
-
*/
|
|
27
|
-
constructor(name, value, options, defaultStyle, defaultExplode) {
|
|
28
|
-
this.name = name;
|
|
29
|
-
this.value = value;
|
|
30
|
-
this.options = options || {};
|
|
31
|
-
if (this.options.style === null || this.options.style === undefined) {
|
|
32
|
-
this.options.style = defaultStyle;
|
|
33
|
-
}
|
|
34
|
-
if (this.options.explode === null || this.options.explode === undefined) {
|
|
35
|
-
this.options.explode = defaultExplode;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @param {*} value
|
|
41
|
-
* @param {string} separator
|
|
42
|
-
* @returns {string}
|
|
43
|
-
*/
|
|
44
|
-
serializeValue(value, separator = ',') {
|
|
45
|
-
if (value === null || value === undefined) {
|
|
46
|
-
return '';
|
|
47
|
-
} else if (value instanceof Array) {
|
|
48
|
-
return value
|
|
49
|
-
.map((v) => this.serializeValue(v).split(separator).join(encodeURIComponent(separator)))
|
|
50
|
-
.join(separator);
|
|
51
|
-
} else if (typeof value === 'object') {
|
|
52
|
-
/** @type {string[]} */
|
|
53
|
-
const array = [];
|
|
54
|
-
for (const key of Object.keys(value)) {
|
|
55
|
-
let propVal = value[key];
|
|
56
|
-
if (propVal !== null && propVal !== undefined) {
|
|
57
|
-
propVal = this.serializeValue(propVal).split(separator).join(encodeURIComponent(separator));
|
|
58
|
-
if (this.options.explode) {
|
|
59
|
-
array.push(`${key}=${propVal}`);
|
|
60
|
-
} else {
|
|
61
|
-
array.push(key);
|
|
62
|
-
array.push(propVal);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return array.join(separator);
|
|
67
|
-
} else {
|
|
68
|
-
return String(value);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* A parameter in the operation path
|
|
75
|
-
* @param {string} name
|
|
76
|
-
* @param {*} value
|
|
77
|
-
* @param {ParameterOptions} options
|
|
78
|
-
*/
|
|
79
|
-
class PathParameter extends Parameter {
|
|
80
|
-
/**
|
|
81
|
-
* @param {string} name
|
|
82
|
-
* @param {*} value
|
|
83
|
-
* @param {ParameterOptions} options
|
|
84
|
-
*/
|
|
85
|
-
constructor(name, value, options) {
|
|
86
|
-
super(name, value, options, 'simple', false);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* @param {string} path
|
|
91
|
-
* @returns {string}
|
|
92
|
-
*/
|
|
93
|
-
append(path) {
|
|
94
|
-
let value = this.value;
|
|
95
|
-
if (value === null || value === undefined) {
|
|
96
|
-
value = '';
|
|
97
|
-
}
|
|
98
|
-
let prefix = this.options.style === 'label' ? '.' : '';
|
|
99
|
-
const separator = this.options.explode ? (prefix === '' ? ',' : prefix) : ',';
|
|
100
|
-
let alreadySerialized = false;
|
|
101
|
-
if (this.options.style === 'matrix') {
|
|
102
|
-
// The parameter name is just used as prefix, except in some cases...
|
|
103
|
-
prefix = `;${this.name}=`;
|
|
104
|
-
if (this.options.explode && typeof value === 'object') {
|
|
105
|
-
prefix = ';';
|
|
106
|
-
if (value instanceof Array) {
|
|
107
|
-
// For arrays we have to repeat the name for each element
|
|
108
|
-
value = value.map((v) => `${this.name}=${this.serializeValue(v, ';')}`);
|
|
109
|
-
value = value.join(';');
|
|
110
|
-
alreadySerialized = true;
|
|
111
|
-
} else {
|
|
112
|
-
// For objects we have to put each the key / value pairs
|
|
113
|
-
value = this.serializeValue(value, ';');
|
|
114
|
-
alreadySerialized = true;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
value = prefix + (alreadySerialized ? value : this.serializeValue(value, separator));
|
|
119
|
-
// Replace both the plain variable and the corresponding variant taking in the prefix and explode into account
|
|
120
|
-
path = path.replace(`{${this.name}}`, value);
|
|
121
|
-
path = path.replace(`{${prefix}${this.name}${this.options.explode ? '*' : ''}}`, value);
|
|
122
|
-
return path;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* @override
|
|
127
|
-
* @param {*} value
|
|
128
|
-
* @param {string} separator
|
|
129
|
-
* @returns {string}
|
|
130
|
-
*/
|
|
131
|
-
serializeValue(value, separator = ',') {
|
|
132
|
-
let result = typeof value === 'string' ? encodeURIComponent(value) : super.serializeValue(value, separator);
|
|
133
|
-
result = result.replace(/%3D/g, '=');
|
|
134
|
-
result = result.replace(/%3B/g, ';');
|
|
135
|
-
result = result.replace(/%2C/g, ',');
|
|
136
|
-
return result;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* A parameter in the query
|
|
142
|
-
* @param {string} name
|
|
143
|
-
* @param {*} value
|
|
144
|
-
* @param {ParameterOptions} options
|
|
145
|
-
*/
|
|
146
|
-
class QueryParameter extends Parameter {
|
|
147
|
-
/**
|
|
148
|
-
* @param {string} name
|
|
149
|
-
* @param {*} value
|
|
150
|
-
* @param {ParameterOptions} options
|
|
151
|
-
*/
|
|
152
|
-
constructor(name, value, options) {
|
|
153
|
-
super(name, value, options, 'form', true);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* @param {string} params
|
|
158
|
-
* @returns {string}
|
|
159
|
-
*/
|
|
160
|
-
append(params) {
|
|
161
|
-
if (this.value instanceof Array) {
|
|
162
|
-
// Array serialization
|
|
163
|
-
if (this.options.explode) {
|
|
164
|
-
for (const v of this.value) {
|
|
165
|
-
params = `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}=${this.serializeValue(v)}`;
|
|
166
|
-
}
|
|
167
|
-
} else {
|
|
168
|
-
const separator = this.options.style === 'spaceDelimited'
|
|
169
|
-
? ' '
|
|
170
|
-
: this.options.style === 'pipeDelimited'
|
|
171
|
-
? '|'
|
|
172
|
-
: ',';
|
|
173
|
-
return `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}=${
|
|
174
|
-
this.serializeValue(this.value, separator)
|
|
175
|
-
}`;
|
|
176
|
-
}
|
|
177
|
-
} else if (this.value !== null && typeof this.value === 'object') {
|
|
178
|
-
// Object serialization
|
|
179
|
-
if (this.options.style === 'deepObject') {
|
|
180
|
-
// Append a parameter for each key, in the form `name[key]`
|
|
181
|
-
for (const key of Object.keys(this.value)) {
|
|
182
|
-
const propVal = this.value[key];
|
|
183
|
-
if (propVal !== null && propVal !== undefined) {
|
|
184
|
-
params = `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}[${
|
|
185
|
-
encodeURIComponent(
|
|
186
|
-
key,
|
|
187
|
-
)
|
|
188
|
-
}]=${this.serializeValue(propVal)}`;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
} else if (this.options.explode) {
|
|
192
|
-
// Append a parameter for each key without using the parameter name
|
|
193
|
-
for (const key of Object.keys(this.value)) {
|
|
194
|
-
const propVal = this.value[key];
|
|
195
|
-
if (propVal !== null && propVal !== undefined) {
|
|
196
|
-
params = `${params}${params ? '&' : '?'}${encodeURIComponent(key)}=${this.serializeValue(propVal)}`;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
} else {
|
|
200
|
-
// Append a single parameter whose values are a comma-separated list of key,value,key,value...
|
|
201
|
-
const array = [];
|
|
202
|
-
for (const key of Object.keys(this.value)) {
|
|
203
|
-
const propVal = this.value[key];
|
|
204
|
-
if (propVal !== null && propVal !== undefined) {
|
|
205
|
-
array.push(key);
|
|
206
|
-
array.push(propVal);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
params = `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}=${this.serializeValue(array)}`;
|
|
210
|
-
}
|
|
211
|
-
} else if (this.value !== null && this.value !== undefined) {
|
|
212
|
-
// Plain value
|
|
213
|
-
params = `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}=${this.serializeValue(this.value)}`;
|
|
214
|
-
}
|
|
215
|
-
return params;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* A parameter in the HTTP request header
|
|
221
|
-
*/
|
|
222
|
-
class HeaderParameter extends Parameter {
|
|
223
|
-
/**
|
|
224
|
-
* @param {string} name
|
|
225
|
-
* @param {*} value
|
|
226
|
-
* @param {ParameterOptions} options
|
|
227
|
-
*/
|
|
228
|
-
constructor(name, value, options) {
|
|
229
|
-
super(name, value, options, 'simple', false);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* @param {Object.<string, string>} headers
|
|
234
|
-
* @returns {Object.<string, string>}
|
|
235
|
-
*/
|
|
236
|
-
append(headers) {
|
|
237
|
-
if (this.value !== null && this.value !== undefined) {
|
|
238
|
-
if (this.value instanceof Array) {
|
|
239
|
-
throw new Error('Array header values are not supported');
|
|
240
|
-
} else {
|
|
241
|
-
headers[this.name] = this.serializeValue(this.value);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return headers;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Helper to build http requests from parameters
|
|
250
|
-
* @property {string} rootUrl
|
|
251
|
-
* @property {string} operationPath
|
|
252
|
-
* @property {string} method
|
|
253
|
-
*/
|
|
254
|
-
export class RequestBuilder {
|
|
255
|
-
/**
|
|
256
|
-
* @param {string} rootUrl
|
|
257
|
-
* @param {string} operationPath
|
|
258
|
-
* @param {string} method
|
|
259
|
-
*/
|
|
260
|
-
constructor(rootUrl, operationPath, method) {
|
|
261
|
-
this.rootUrl = rootUrl;
|
|
262
|
-
this.operationPath = operationPath;
|
|
263
|
-
this.method = method;
|
|
264
|
-
this._path = new Map();
|
|
265
|
-
this._query = new Map();
|
|
266
|
-
this._header = new Map();
|
|
267
|
-
this._bodyContent = null;
|
|
268
|
-
this._bodyContentType = undefined;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Sets a path parameter
|
|
273
|
-
* @param {string} name
|
|
274
|
-
* @param {*} value
|
|
275
|
-
* @param {ParameterOptions} [options]
|
|
276
|
-
*/
|
|
277
|
-
path(name, value, options) {
|
|
278
|
-
this._path.set(name, new PathParameter(name, value, options || {}));
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Sets a query parameter
|
|
283
|
-
* @param {string} name
|
|
284
|
-
* @param {*} value
|
|
285
|
-
* @param {ParameterOptions} [options]
|
|
286
|
-
*/
|
|
287
|
-
query(name, value, options) {
|
|
288
|
-
this._query.set(name, new QueryParameter(name, value, options || {}));
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Sets a header parameter
|
|
293
|
-
* @param {string} name
|
|
294
|
-
* @param {*} value
|
|
295
|
-
* @param {ParameterOptions} [options]
|
|
296
|
-
*/
|
|
297
|
-
header(name, value, options) {
|
|
298
|
-
this._header.set(name, new HeaderParameter(name, value, options || {}));
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Sets the body content, along with the content type
|
|
303
|
-
* @param {*} value
|
|
304
|
-
* @param {string} [contentType]
|
|
305
|
-
*/
|
|
306
|
-
body(value, contentType = 'application/json') {
|
|
307
|
-
this._bodyContentType = contentType;
|
|
308
|
-
if (this._bodyContentType === 'application/x-www-form-urlencoded' && value !== null && typeof value === 'object') {
|
|
309
|
-
// Handle URL-encoded data
|
|
310
|
-
/** @type {[string, string][]} */
|
|
311
|
-
const pairs = [];
|
|
312
|
-
for (const key of Object.keys(value)) {
|
|
313
|
-
let val = value[key];
|
|
314
|
-
if (!(val instanceof Array)) {
|
|
315
|
-
val = [val];
|
|
316
|
-
}
|
|
317
|
-
for (const v of val) {
|
|
318
|
-
const formValue = this.formDataValue(v);
|
|
319
|
-
if (formValue !== null) {
|
|
320
|
-
pairs.push([key, formValue]);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
this._bodyContent = pairs.map((p) => `${encodeURIComponent(p[0])}=${encodeURIComponent(p[1])}`).join('&');
|
|
325
|
-
} else if (this._bodyContentType.indexOf('json') !== -1 && value !== null && typeof value === 'object') {
|
|
326
|
-
this._bodyContent = JSON.stringify(value);
|
|
327
|
-
} else {
|
|
328
|
-
// The body is the plain content
|
|
329
|
-
this._bodyContent = value;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* @private
|
|
335
|
-
* @param {*} value
|
|
336
|
-
* @returns {*}
|
|
337
|
-
*/
|
|
338
|
-
formDataValue(value) {
|
|
339
|
-
if (value === null || value === undefined) {
|
|
340
|
-
return null;
|
|
341
|
-
}
|
|
342
|
-
if (typeof value === 'object') {
|
|
343
|
-
return JSON.stringify(value);
|
|
344
|
-
}
|
|
345
|
-
return String(value);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* @typedef {object} BuildOptions
|
|
350
|
-
* @property {string} [accept]
|
|
351
|
-
* @property {import('k6/http').Params} [params]
|
|
352
|
-
*/
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Builds the request with the current set parameters
|
|
356
|
-
* @param {BuildOptions} [options]
|
|
357
|
-
* @returns {import('k6/http').Response}
|
|
358
|
-
*/
|
|
359
|
-
build(options) {
|
|
360
|
-
// Perform the request
|
|
361
|
-
return http.request(...this.buildRequestParams(options));
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Builds the request with the current set parameters
|
|
366
|
-
* @param {BuildOptions} [options]
|
|
367
|
-
* @returns {Promise<import('k6/http').Response>}
|
|
368
|
-
*/
|
|
369
|
-
buildAsync(options) {
|
|
370
|
-
// Perform the request
|
|
371
|
-
return http.asyncRequest(...this.buildRequestParams(options));
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* @private
|
|
376
|
-
* @param {BuildOptions} [options]
|
|
377
|
-
* @returns {Parameters<typeof import('k6/http').request>}
|
|
378
|
-
*/
|
|
379
|
-
buildRequestParams(options) {
|
|
380
|
-
options = options || {};
|
|
381
|
-
|
|
382
|
-
// Path parameters
|
|
383
|
-
let path = this.operationPath;
|
|
384
|
-
for (const pathParam of this._path.values()) {
|
|
385
|
-
path = pathParam.append(path);
|
|
386
|
-
}
|
|
387
|
-
const url = this.rootUrl + path;
|
|
388
|
-
|
|
389
|
-
// Query parameters
|
|
390
|
-
let httpParams = '';
|
|
391
|
-
for (const queryParam of this._query.values()) {
|
|
392
|
-
httpParams = queryParam.append(httpParams);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Header parameters
|
|
396
|
-
/** @type {Object.<string, string>} */
|
|
397
|
-
let httpHeaders = {};
|
|
398
|
-
if (options.accept) {
|
|
399
|
-
httpHeaders['Accept'] = options.accept;
|
|
400
|
-
}
|
|
401
|
-
for (const headerParam of this._header.values()) {
|
|
402
|
-
httpHeaders = headerParam.append(httpHeaders);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Request content headers
|
|
406
|
-
if (this._bodyContentType) {
|
|
407
|
-
httpHeaders['Content-Type'] = this._bodyContentType;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
return [
|
|
411
|
-
this.method.toUpperCase(),
|
|
412
|
-
url + httpParams,
|
|
413
|
-
this._bodyContent,
|
|
414
|
-
Object.assign({}, options.params, {
|
|
415
|
-
headers: Object.assign({}, httpHeaders, options.params ? options.params.headers : {}),
|
|
416
|
-
}),
|
|
417
|
-
];
|
|
418
|
-
}
|
|
419
|
-
}
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import http from 'k6/http';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Defines the options for appending a parameter
|
|
7
|
+
* @typedef {object} ParameterOptions
|
|
8
|
+
* @property {string} [style]
|
|
9
|
+
* @property {boolean} [explode]
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Base class for a parameter
|
|
14
|
+
* @abstract
|
|
15
|
+
* @property {string} name
|
|
16
|
+
* @property {*} value
|
|
17
|
+
* @property {ParameterOptions} options
|
|
18
|
+
*/
|
|
19
|
+
class Parameter {
|
|
20
|
+
/**
|
|
21
|
+
* @param {string} name
|
|
22
|
+
* @param {*} value
|
|
23
|
+
* @param {ParameterOptions} options
|
|
24
|
+
* @param {string} defaultStyle
|
|
25
|
+
* @param {boolean} defaultExplode
|
|
26
|
+
*/
|
|
27
|
+
constructor(name, value, options, defaultStyle, defaultExplode) {
|
|
28
|
+
this.name = name;
|
|
29
|
+
this.value = value;
|
|
30
|
+
this.options = options || {};
|
|
31
|
+
if (this.options.style === null || this.options.style === undefined) {
|
|
32
|
+
this.options.style = defaultStyle;
|
|
33
|
+
}
|
|
34
|
+
if (this.options.explode === null || this.options.explode === undefined) {
|
|
35
|
+
this.options.explode = defaultExplode;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {*} value
|
|
41
|
+
* @param {string} separator
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
serializeValue(value, separator = ',') {
|
|
45
|
+
if (value === null || value === undefined) {
|
|
46
|
+
return '';
|
|
47
|
+
} else if (value instanceof Array) {
|
|
48
|
+
return value
|
|
49
|
+
.map((v) => this.serializeValue(v).split(separator).join(encodeURIComponent(separator)))
|
|
50
|
+
.join(separator);
|
|
51
|
+
} else if (typeof value === 'object') {
|
|
52
|
+
/** @type {string[]} */
|
|
53
|
+
const array = [];
|
|
54
|
+
for (const key of Object.keys(value)) {
|
|
55
|
+
let propVal = value[key];
|
|
56
|
+
if (propVal !== null && propVal !== undefined) {
|
|
57
|
+
propVal = this.serializeValue(propVal).split(separator).join(encodeURIComponent(separator));
|
|
58
|
+
if (this.options.explode) {
|
|
59
|
+
array.push(`${key}=${propVal}`);
|
|
60
|
+
} else {
|
|
61
|
+
array.push(key);
|
|
62
|
+
array.push(propVal);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return array.join(separator);
|
|
67
|
+
} else {
|
|
68
|
+
return String(value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A parameter in the operation path
|
|
75
|
+
* @param {string} name
|
|
76
|
+
* @param {*} value
|
|
77
|
+
* @param {ParameterOptions} options
|
|
78
|
+
*/
|
|
79
|
+
class PathParameter extends Parameter {
|
|
80
|
+
/**
|
|
81
|
+
* @param {string} name
|
|
82
|
+
* @param {*} value
|
|
83
|
+
* @param {ParameterOptions} options
|
|
84
|
+
*/
|
|
85
|
+
constructor(name, value, options) {
|
|
86
|
+
super(name, value, options, 'simple', false);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {string} path
|
|
91
|
+
* @returns {string}
|
|
92
|
+
*/
|
|
93
|
+
append(path) {
|
|
94
|
+
let value = this.value;
|
|
95
|
+
if (value === null || value === undefined) {
|
|
96
|
+
value = '';
|
|
97
|
+
}
|
|
98
|
+
let prefix = this.options.style === 'label' ? '.' : '';
|
|
99
|
+
const separator = this.options.explode ? (prefix === '' ? ',' : prefix) : ',';
|
|
100
|
+
let alreadySerialized = false;
|
|
101
|
+
if (this.options.style === 'matrix') {
|
|
102
|
+
// The parameter name is just used as prefix, except in some cases...
|
|
103
|
+
prefix = `;${this.name}=`;
|
|
104
|
+
if (this.options.explode && typeof value === 'object') {
|
|
105
|
+
prefix = ';';
|
|
106
|
+
if (value instanceof Array) {
|
|
107
|
+
// For arrays we have to repeat the name for each element
|
|
108
|
+
value = value.map((v) => `${this.name}=${this.serializeValue(v, ';')}`);
|
|
109
|
+
value = value.join(';');
|
|
110
|
+
alreadySerialized = true;
|
|
111
|
+
} else {
|
|
112
|
+
// For objects we have to put each the key / value pairs
|
|
113
|
+
value = this.serializeValue(value, ';');
|
|
114
|
+
alreadySerialized = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
value = prefix + (alreadySerialized ? value : this.serializeValue(value, separator));
|
|
119
|
+
// Replace both the plain variable and the corresponding variant taking in the prefix and explode into account
|
|
120
|
+
path = path.replace(`{${this.name}}`, value);
|
|
121
|
+
path = path.replace(`{${prefix}${this.name}${this.options.explode ? '*' : ''}}`, value);
|
|
122
|
+
return path;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @override
|
|
127
|
+
* @param {*} value
|
|
128
|
+
* @param {string} separator
|
|
129
|
+
* @returns {string}
|
|
130
|
+
*/
|
|
131
|
+
serializeValue(value, separator = ',') {
|
|
132
|
+
let result = typeof value === 'string' ? encodeURIComponent(value) : super.serializeValue(value, separator);
|
|
133
|
+
result = result.replace(/%3D/g, '=');
|
|
134
|
+
result = result.replace(/%3B/g, ';');
|
|
135
|
+
result = result.replace(/%2C/g, ',');
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* A parameter in the query
|
|
142
|
+
* @param {string} name
|
|
143
|
+
* @param {*} value
|
|
144
|
+
* @param {ParameterOptions} options
|
|
145
|
+
*/
|
|
146
|
+
class QueryParameter extends Parameter {
|
|
147
|
+
/**
|
|
148
|
+
* @param {string} name
|
|
149
|
+
* @param {*} value
|
|
150
|
+
* @param {ParameterOptions} options
|
|
151
|
+
*/
|
|
152
|
+
constructor(name, value, options) {
|
|
153
|
+
super(name, value, options, 'form', true);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @param {string} params
|
|
158
|
+
* @returns {string}
|
|
159
|
+
*/
|
|
160
|
+
append(params) {
|
|
161
|
+
if (this.value instanceof Array) {
|
|
162
|
+
// Array serialization
|
|
163
|
+
if (this.options.explode) {
|
|
164
|
+
for (const v of this.value) {
|
|
165
|
+
params = `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}=${this.serializeValue(v)}`;
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
const separator = this.options.style === 'spaceDelimited'
|
|
169
|
+
? ' '
|
|
170
|
+
: this.options.style === 'pipeDelimited'
|
|
171
|
+
? '|'
|
|
172
|
+
: ',';
|
|
173
|
+
return `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}=${
|
|
174
|
+
this.serializeValue(this.value, separator)
|
|
175
|
+
}`;
|
|
176
|
+
}
|
|
177
|
+
} else if (this.value !== null && typeof this.value === 'object') {
|
|
178
|
+
// Object serialization
|
|
179
|
+
if (this.options.style === 'deepObject') {
|
|
180
|
+
// Append a parameter for each key, in the form `name[key]`
|
|
181
|
+
for (const key of Object.keys(this.value)) {
|
|
182
|
+
const propVal = this.value[key];
|
|
183
|
+
if (propVal !== null && propVal !== undefined) {
|
|
184
|
+
params = `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}[${
|
|
185
|
+
encodeURIComponent(
|
|
186
|
+
key,
|
|
187
|
+
)
|
|
188
|
+
}]=${this.serializeValue(propVal)}`;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} else if (this.options.explode) {
|
|
192
|
+
// Append a parameter for each key without using the parameter name
|
|
193
|
+
for (const key of Object.keys(this.value)) {
|
|
194
|
+
const propVal = this.value[key];
|
|
195
|
+
if (propVal !== null && propVal !== undefined) {
|
|
196
|
+
params = `${params}${params ? '&' : '?'}${encodeURIComponent(key)}=${this.serializeValue(propVal)}`;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
// Append a single parameter whose values are a comma-separated list of key,value,key,value...
|
|
201
|
+
const array = [];
|
|
202
|
+
for (const key of Object.keys(this.value)) {
|
|
203
|
+
const propVal = this.value[key];
|
|
204
|
+
if (propVal !== null && propVal !== undefined) {
|
|
205
|
+
array.push(key);
|
|
206
|
+
array.push(propVal);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
params = `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}=${this.serializeValue(array)}`;
|
|
210
|
+
}
|
|
211
|
+
} else if (this.value !== null && this.value !== undefined) {
|
|
212
|
+
// Plain value
|
|
213
|
+
params = `${params}${params ? '&' : '?'}${encodeURIComponent(this.name)}=${this.serializeValue(this.value)}`;
|
|
214
|
+
}
|
|
215
|
+
return params;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* A parameter in the HTTP request header
|
|
221
|
+
*/
|
|
222
|
+
class HeaderParameter extends Parameter {
|
|
223
|
+
/**
|
|
224
|
+
* @param {string} name
|
|
225
|
+
* @param {*} value
|
|
226
|
+
* @param {ParameterOptions} options
|
|
227
|
+
*/
|
|
228
|
+
constructor(name, value, options) {
|
|
229
|
+
super(name, value, options, 'simple', false);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @param {Object.<string, string>} headers
|
|
234
|
+
* @returns {Object.<string, string>}
|
|
235
|
+
*/
|
|
236
|
+
append(headers) {
|
|
237
|
+
if (this.value !== null && this.value !== undefined) {
|
|
238
|
+
if (this.value instanceof Array) {
|
|
239
|
+
throw new Error('Array header values are not supported');
|
|
240
|
+
} else {
|
|
241
|
+
headers[this.name] = this.serializeValue(this.value);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return headers;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Helper to build http requests from parameters
|
|
250
|
+
* @property {string} rootUrl
|
|
251
|
+
* @property {string} operationPath
|
|
252
|
+
* @property {string} method
|
|
253
|
+
*/
|
|
254
|
+
export class RequestBuilder {
|
|
255
|
+
/**
|
|
256
|
+
* @param {string} rootUrl
|
|
257
|
+
* @param {string} operationPath
|
|
258
|
+
* @param {string} method
|
|
259
|
+
*/
|
|
260
|
+
constructor(rootUrl, operationPath, method) {
|
|
261
|
+
this.rootUrl = rootUrl;
|
|
262
|
+
this.operationPath = operationPath;
|
|
263
|
+
this.method = method;
|
|
264
|
+
this._path = new Map();
|
|
265
|
+
this._query = new Map();
|
|
266
|
+
this._header = new Map();
|
|
267
|
+
this._bodyContent = null;
|
|
268
|
+
this._bodyContentType = undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Sets a path parameter
|
|
273
|
+
* @param {string} name
|
|
274
|
+
* @param {*} value
|
|
275
|
+
* @param {ParameterOptions} [options]
|
|
276
|
+
*/
|
|
277
|
+
path(name, value, options) {
|
|
278
|
+
this._path.set(name, new PathParameter(name, value, options || {}));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Sets a query parameter
|
|
283
|
+
* @param {string} name
|
|
284
|
+
* @param {*} value
|
|
285
|
+
* @param {ParameterOptions} [options]
|
|
286
|
+
*/
|
|
287
|
+
query(name, value, options) {
|
|
288
|
+
this._query.set(name, new QueryParameter(name, value, options || {}));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Sets a header parameter
|
|
293
|
+
* @param {string} name
|
|
294
|
+
* @param {*} value
|
|
295
|
+
* @param {ParameterOptions} [options]
|
|
296
|
+
*/
|
|
297
|
+
header(name, value, options) {
|
|
298
|
+
this._header.set(name, new HeaderParameter(name, value, options || {}));
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Sets the body content, along with the content type
|
|
303
|
+
* @param {*} value
|
|
304
|
+
* @param {string} [contentType]
|
|
305
|
+
*/
|
|
306
|
+
body(value, contentType = 'application/json') {
|
|
307
|
+
this._bodyContentType = contentType;
|
|
308
|
+
if (this._bodyContentType === 'application/x-www-form-urlencoded' && value !== null && typeof value === 'object') {
|
|
309
|
+
// Handle URL-encoded data
|
|
310
|
+
/** @type {[string, string][]} */
|
|
311
|
+
const pairs = [];
|
|
312
|
+
for (const key of Object.keys(value)) {
|
|
313
|
+
let val = value[key];
|
|
314
|
+
if (!(val instanceof Array)) {
|
|
315
|
+
val = [val];
|
|
316
|
+
}
|
|
317
|
+
for (const v of val) {
|
|
318
|
+
const formValue = this.formDataValue(v);
|
|
319
|
+
if (formValue !== null) {
|
|
320
|
+
pairs.push([key, formValue]);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
this._bodyContent = pairs.map((p) => `${encodeURIComponent(p[0])}=${encodeURIComponent(p[1])}`).join('&');
|
|
325
|
+
} else if (this._bodyContentType.indexOf('json') !== -1 && value !== null && typeof value === 'object') {
|
|
326
|
+
this._bodyContent = JSON.stringify(value);
|
|
327
|
+
} else {
|
|
328
|
+
// The body is the plain content
|
|
329
|
+
this._bodyContent = value;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* @private
|
|
335
|
+
* @param {*} value
|
|
336
|
+
* @returns {*}
|
|
337
|
+
*/
|
|
338
|
+
formDataValue(value) {
|
|
339
|
+
if (value === null || value === undefined) {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
if (typeof value === 'object') {
|
|
343
|
+
return JSON.stringify(value);
|
|
344
|
+
}
|
|
345
|
+
return String(value);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* @typedef {object} BuildOptions
|
|
350
|
+
* @property {string} [accept]
|
|
351
|
+
* @property {import('k6/http').Params} [params]
|
|
352
|
+
*/
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Builds the request with the current set parameters
|
|
356
|
+
* @param {BuildOptions} [options]
|
|
357
|
+
* @returns {import('k6/http').Response}
|
|
358
|
+
*/
|
|
359
|
+
build(options) {
|
|
360
|
+
// Perform the request
|
|
361
|
+
return http.request(...this.buildRequestParams(options));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Builds the request with the current set parameters
|
|
366
|
+
* @param {BuildOptions} [options]
|
|
367
|
+
* @returns {Promise<import('k6/http').Response>}
|
|
368
|
+
*/
|
|
369
|
+
buildAsync(options) {
|
|
370
|
+
// Perform the request
|
|
371
|
+
return http.asyncRequest(...this.buildRequestParams(options));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @private
|
|
376
|
+
* @param {BuildOptions} [options]
|
|
377
|
+
* @returns {Parameters<typeof import('k6/http').request>}
|
|
378
|
+
*/
|
|
379
|
+
buildRequestParams(options) {
|
|
380
|
+
options = options || {};
|
|
381
|
+
|
|
382
|
+
// Path parameters
|
|
383
|
+
let path = this.operationPath;
|
|
384
|
+
for (const pathParam of this._path.values()) {
|
|
385
|
+
path = pathParam.append(path);
|
|
386
|
+
}
|
|
387
|
+
const url = this.rootUrl + path;
|
|
388
|
+
|
|
389
|
+
// Query parameters
|
|
390
|
+
let httpParams = '';
|
|
391
|
+
for (const queryParam of this._query.values()) {
|
|
392
|
+
httpParams = queryParam.append(httpParams);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Header parameters
|
|
396
|
+
/** @type {Object.<string, string>} */
|
|
397
|
+
let httpHeaders = {};
|
|
398
|
+
if (options.accept) {
|
|
399
|
+
httpHeaders['Accept'] = options.accept;
|
|
400
|
+
}
|
|
401
|
+
for (const headerParam of this._header.values()) {
|
|
402
|
+
httpHeaders = headerParam.append(httpHeaders);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Request content headers
|
|
406
|
+
if (this._bodyContentType && this._bodyContentType !== 'multipart/form-data') {
|
|
407
|
+
httpHeaders['Content-Type'] = this._bodyContentType;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return [
|
|
411
|
+
this.method.toUpperCase(),
|
|
412
|
+
url + httpParams,
|
|
413
|
+
this._bodyContent,
|
|
414
|
+
Object.assign({}, options.params, {
|
|
415
|
+
headers: Object.assign({}, httpHeaders, options.params ? options.params.headers : {}),
|
|
416
|
+
}),
|
|
417
|
+
];
|
|
418
|
+
}
|
|
419
|
+
}
|