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