@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.
Files changed (104) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +52 -52
  3. package/assets/client/angular/angular-service.utils.ts +82 -82
  4. package/assets/client/angular/request-builder.ts +377 -377
  5. package/assets/client/fetch/fetch-client.utils.ts +52 -52
  6. package/assets/client/k6/request-builder.js +419 -419
  7. package/assets/client/k6/request-builder.ts +341 -341
  8. package/assets/stubs/easy-network-stub/easy-network-stub.utils.ts +259 -259
  9. package/esm/src/generators/models/models.d.ts +1 -1
  10. package/esm/src/generators/models/models.d.ts.map +1 -1
  11. package/esm/src/generators/services/angular-services/angular-service-generator.js +9 -9
  12. package/esm/src/generators/services/easy-network-stub/easy-network-stub-generator.js +9 -9
  13. package/esm/src/generators/services/fetch-clients/fetch-client-generator.js +2 -2
  14. package/esm/src/generators/services/k6-clients/k6-client-generator.js +11 -11
  15. package/package.json +1 -1
  16. package/script/src/generators/models/models.d.ts +1 -1
  17. package/script/src/generators/models/models.d.ts.map +1 -1
  18. package/script/src/generators/services/angular-services/angular-service-generator.js +9 -9
  19. package/script/src/generators/services/easy-network-stub/easy-network-stub-generator.js +9 -9
  20. package/script/src/generators/services/fetch-clients/fetch-client-generator.js +2 -2
  21. package/script/src/generators/services/k6-clients/k6-client-generator.js +11 -11
  22. package/src/mod.ts +7 -0
  23. package/src/src/assets.ts +9 -0
  24. package/src/src/ast/_index.ts +54 -0
  25. package/src/src/ast/common.ts +1 -0
  26. package/src/src/ast/index.ts +1 -0
  27. package/src/src/ast/node.ts +10 -0
  28. package/src/src/ast/nodes/argument.ts +40 -0
  29. package/src/src/ast/nodes/array-type.ts +49 -0
  30. package/src/src/ast/nodes/arrow-function.ts +91 -0
  31. package/src/src/ast/nodes/call.ts +55 -0
  32. package/src/src/ast/nodes/class.ts +133 -0
  33. package/src/src/ast/nodes/constructor-parameter.ts +70 -0
  34. package/src/src/ast/nodes/constructor.ts +77 -0
  35. package/src/src/ast/nodes/decorator.ts +76 -0
  36. package/src/src/ast/nodes/doc-tag.ts +291 -0
  37. package/src/src/ast/nodes/doc.ts +102 -0
  38. package/src/src/ast/nodes/enum-value.ts +72 -0
  39. package/src/src/ast/nodes/enum.ts +77 -0
  40. package/src/src/ast/nodes/export.ts +54 -0
  41. package/src/src/ast/nodes/function-type.ts +60 -0
  42. package/src/src/ast/nodes/function.ts +107 -0
  43. package/src/src/ast/nodes/generic-parameter.ts +71 -0
  44. package/src/src/ast/nodes/indexer.ts +60 -0
  45. package/src/src/ast/nodes/interface.ts +117 -0
  46. package/src/src/ast/nodes/intersection-type.ts +67 -0
  47. package/src/src/ast/nodes/lookup-type.ts +53 -0
  48. package/src/src/ast/nodes/method.ts +138 -0
  49. package/src/src/ast/nodes/object-type.ts +52 -0
  50. package/src/src/ast/nodes/object.ts +48 -0
  51. package/src/src/ast/nodes/parameter.ts +85 -0
  52. package/src/src/ast/nodes/property-accessor.ts +173 -0
  53. package/src/src/ast/nodes/property.ts +192 -0
  54. package/src/src/ast/nodes/reference.ts +194 -0
  55. package/src/src/ast/nodes/string.ts +49 -0
  56. package/src/src/ast/nodes/tuple.ts +53 -0
  57. package/src/src/ast/nodes/type-alias.ts +75 -0
  58. package/src/src/ast/nodes/typeof.ts +42 -0
  59. package/src/src/ast/nodes/types.ts +40 -0
  60. package/src/src/ast/nodes/union-type.ts +62 -0
  61. package/src/src/ast/nodes/variable.ts +73 -0
  62. package/src/src/ast/references/angular.ts +24 -0
  63. package/src/src/ast/references/easy-network-stub.ts +21 -0
  64. package/src/src/ast/references/index.ts +5 -0
  65. package/src/src/ast/references/k6.ts +8 -0
  66. package/src/src/ast/references/rxjs.ts +7 -0
  67. package/src/src/ast/references/typescript.ts +35 -0
  68. package/src/src/ast/utils/get-type-script-builder-options.ts +19 -0
  69. package/src/src/ast/utils/to-ts-node.ts +27 -0
  70. package/src/src/ast/utils/write-ts-generic-parameters.ts +25 -0
  71. package/src/src/ast/utils/write-ts-members.ts +28 -0
  72. package/src/src/ast/utils/write-ts-nodes.ts +35 -0
  73. package/src/src/ast/utils/write-ts-parameters.ts +25 -0
  74. package/src/src/common-results.ts +26 -0
  75. package/src/src/config.ts +89 -0
  76. package/src/src/file-builder.ts +136 -0
  77. package/src/src/generators/file-generator.ts +15 -0
  78. package/src/src/generators/index.ts +6 -0
  79. package/src/src/generators/models/index.ts +3 -0
  80. package/src/src/generators/models/model-generator.ts +469 -0
  81. package/src/src/generators/models/models-generator.ts +108 -0
  82. package/src/src/generators/models/models.ts +121 -0
  83. package/src/src/generators/services/angular-services/angular-service-generator.ts +406 -0
  84. package/src/src/generators/services/angular-services/angular-services-generator.ts +295 -0
  85. package/src/src/generators/services/angular-services/index.ts +3 -0
  86. package/src/src/generators/services/angular-services/models.ts +277 -0
  87. package/src/src/generators/services/angular-services/refs.ts +54 -0
  88. package/src/src/generators/services/easy-network-stub/easy-network-stub-generator.ts +242 -0
  89. package/src/src/generators/services/easy-network-stub/easy-network-stubs-generator.ts +211 -0
  90. package/src/src/generators/services/easy-network-stub/index.ts +3 -0
  91. package/src/src/generators/services/easy-network-stub/models.ts +124 -0
  92. package/src/src/generators/services/easy-network-stub/refs.ts +45 -0
  93. package/src/src/generators/services/fetch-clients/fetch-client-generator.ts +267 -0
  94. package/src/src/generators/services/fetch-clients/fetch-clients-generator.ts +163 -0
  95. package/src/src/generators/services/fetch-clients/index.ts +3 -0
  96. package/src/src/generators/services/fetch-clients/models.ts +130 -0
  97. package/src/src/generators/services/fetch-clients/refs.ts +21 -0
  98. package/src/src/generators/services/k6-clients/index.ts +3 -0
  99. package/src/src/generators/services/k6-clients/k6-client-generator.ts +465 -0
  100. package/src/src/generators/services/k6-clients/k6-clients-generator.ts +171 -0
  101. package/src/src/generators/services/k6-clients/models.ts +247 -0
  102. package/src/src/generators/services/k6-clients/refs.ts +16 -0
  103. package/src/src/import-collection.ts +236 -0
  104. 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
+ }