swagger-client 3.27.1 → 3.27.3

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 (48) hide show
  1. package/dist/swagger-client.browser.js +10806 -11986
  2. package/dist/swagger-client.browser.min.js +1 -1
  3. package/dist/swagger-client.browser.min.js.map +1 -1
  4. package/es/execute/index.js +5 -8
  5. package/es/execute/oas3/build-request.js +22 -1
  6. package/es/http/index.js +6 -370
  7. package/es/http/serializers/request/file.js +46 -0
  8. package/es/http/serializers/request/format.js +143 -0
  9. package/es/http/serializers/request/index.js +111 -0
  10. package/es/http/serializers/response/index.js +55 -0
  11. package/es/index.js +2 -1
  12. package/es/resolver/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/errors/SchemaRefError.js +3 -0
  13. package/es/resolver/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/visitors/dereference.js +5 -4
  14. package/es/{specmap → resolver/specmap}/helpers.js +1 -1
  15. package/es/{specmap → resolver/specmap}/lib/refs.js +8 -8
  16. package/es/resolver/strategies/generic/index.js +1 -1
  17. package/es/resolver/strategies/generic/resolve.js +1 -1
  18. package/lib/execute/index.js +8 -11
  19. package/lib/execute/oas3/build-request.js +22 -1
  20. package/lib/http/index.js +6 -379
  21. package/lib/http/serializers/request/file.js +53 -0
  22. package/lib/http/serializers/request/format.js +147 -0
  23. package/lib/http/serializers/request/index.js +117 -0
  24. package/lib/http/serializers/response/index.js +63 -0
  25. package/lib/index.js +34 -33
  26. package/lib/resolver/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/errors/SchemaRefError.js +7 -0
  27. package/lib/resolver/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/visitors/dereference.js +6 -5
  28. package/lib/{specmap → resolver/specmap}/helpers.js +1 -1
  29. package/lib/{specmap → resolver/specmap}/lib/refs.js +8 -8
  30. package/lib/resolver/strategies/generic/index.js +1 -1
  31. package/lib/resolver/strategies/generic/resolve.js +1 -1
  32. package/package.json +1 -1
  33. package/es/resolver/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/errors/index.js +0 -7
  34. package/es/specmap/lib/create-error.js +0 -17
  35. package/lib/resolver/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/errors/index.js +0 -11
  36. package/lib/specmap/lib/create-error.js +0 -21
  37. /package/es/{specmap → resolver/specmap}/index.js +0 -0
  38. /package/es/{specmap → resolver/specmap}/lib/all-of.js +0 -0
  39. /package/es/{specmap → resolver/specmap}/lib/context-tree.js +0 -0
  40. /package/es/{specmap → resolver/specmap}/lib/index.js +0 -0
  41. /package/es/{specmap → resolver/specmap}/lib/parameters.js +0 -0
  42. /package/es/{specmap → resolver/specmap}/lib/properties.js +0 -0
  43. /package/lib/{specmap → resolver/specmap}/index.js +0 -0
  44. /package/lib/{specmap → resolver/specmap}/lib/all-of.js +0 -0
  45. /package/lib/{specmap → resolver/specmap}/lib/context-tree.js +0 -0
  46. /package/lib/{specmap → resolver/specmap}/lib/index.js +0 -0
  47. /package/lib/{specmap → resolver/specmap}/lib/parameters.js +0 -0
  48. /package/lib/{specmap → resolver/specmap}/lib/properties.js +0 -0
@@ -1,9 +1,10 @@
1
1
  import cookie from 'cookie';
2
2
  import { isPlainObject } from 'is-plain-object';
3
+ import { ApiDOMStructuredError } from '@swagger-api/apidom-error';
3
4
  import { url } from '@swagger-api/apidom-reference/configuration/empty';
4
5
  import { DEFAULT_BASE_URL, DEFAULT_OPENAPI_3_SERVER } from '../constants.js';
5
- import stockHttp, { mergeInQueryOrForm } from '../http/index.js';
6
- import createError from '../specmap/lib/create-error.js';
6
+ import stockHttp from '../http/index.js';
7
+ import { serializeRequest } from '../http/serializers/request/index.js';
7
8
  import SWAGGER2_PARAMETER_BUILDERS from './swagger2/parameter-builders.js';
8
9
  import * as OAS3_PARAMETER_BUILDERS from './oas3/parameter-builders.js';
9
10
  import oas3BuildRequest from './oas3/build-request.js';
@@ -38,10 +39,7 @@ const parseURIReference = uriReference => {
38
39
  };
39
40
  }
40
41
  };
41
- const OperationNotFoundError = createError('OperationNotFoundError', function cb(message, extra, oriError) {
42
- this.originalError = oriError;
43
- Object.assign(this, extra || {});
44
- });
42
+ class OperationNotFoundError extends ApiDOMStructuredError {}
45
43
  const findParametersWithName = (name, parameters) => parameters.filter(p => p.name === name);
46
44
 
47
45
  // removes parameters that have duplicate 'in' and 'name' properties
@@ -272,8 +270,7 @@ export function buildRequest(options) {
272
270
 
273
271
  // Will add the query object into the URL, if it exists
274
272
  // ... will also create a FormData instance, if multipart/form-data (eg: a file)
275
- mergeInQueryOrForm(req);
276
- return req;
273
+ return serializeRequest(req);
277
274
  }
278
275
  const stripNonAlpha = str => str ? str.replace(/\W/g, '') : null;
279
276
 
@@ -61,11 +61,32 @@ export default function buildRequest(options, req) {
61
61
  const encoding = (_requestBodyDef$conte = (_requestBodyDef$conte2 = requestBodyDef.content[requestContentType]) === null || _requestBodyDef$conte2 === void 0 ? void 0 : _requestBodyDef$conte2.encoding) !== null && _requestBodyDef$conte !== void 0 ? _requestBodyDef$conte : {};
62
62
  req.form = {};
63
63
  Object.keys(requestBody).forEach(k => {
64
+ let value;
65
+ try {
66
+ value = JSON.parse(requestBody[k]);
67
+ } catch {
68
+ value = requestBody[k];
69
+ }
64
70
  req.form[k] = {
65
- value: requestBody[k],
71
+ value,
66
72
  encoding: encoding[k] || {}
67
73
  };
68
74
  });
75
+ } else if (typeof requestBody === 'string') {
76
+ var _requestBodyDef$conte3, _requestBodyDef$conte4;
77
+ const encoding = (_requestBodyDef$conte3 = (_requestBodyDef$conte4 = requestBodyDef.content[requestContentType]) === null || _requestBodyDef$conte4 === void 0 ? void 0 : _requestBodyDef$conte4.encoding) !== null && _requestBodyDef$conte3 !== void 0 ? _requestBodyDef$conte3 : {};
78
+ try {
79
+ req.form = {};
80
+ const form = JSON.parse(requestBody);
81
+ Object.entries(form).forEach(([key, value]) => {
82
+ req.form[key] = {
83
+ value,
84
+ encoding: encoding[key] || {}
85
+ };
86
+ });
87
+ } catch {
88
+ req.form = requestBody;
89
+ }
69
90
  } else {
70
91
  req.form = requestBody;
71
92
  }
package/es/http/index.js CHANGED
@@ -1,13 +1,7 @@
1
- import qs from 'qs';
2
- import jsYaml from 'js-yaml';
3
1
  import '../helpers/fetch-polyfill.node.js';
4
- import { valueEncoder } from '../execute/oas3/style-serializer.js';
5
-
6
- // For testing
7
- export const self = {
8
- serializeRes,
9
- mergeInQueryOrForm
10
- };
2
+ import { serializeRequest } from './serializers/request/index.js';
3
+ import { serializeResponse } from './serializers/response/index.js';
4
+ export { serializeResponse as serializeRes };
11
5
 
12
6
  // Handles fetch-like syntax and the case where there is only one object passed-in
13
7
  // (which will have the URL as a property). Also serializes the response.
@@ -21,7 +15,7 @@ export default async function http(url, request = {}) {
21
15
  // Serializes query, for convenience
22
16
  // Should be the last thing we do, as its hard to mutate the URL with
23
17
  // the search string, but much easier to manipulate the req.query object
24
- self.mergeInQueryOrForm(request);
18
+ request = serializeRequest(request);
25
19
 
26
20
  // Newlines in header values cause weird error messages from `window.fetch`,
27
21
  // so let's message them out.
@@ -56,7 +50,7 @@ export default async function http(url, request = {}) {
56
50
  let res;
57
51
  try {
58
52
  res = await (request.userFetch || fetch)(request.url, request);
59
- res = await self.serializeRes(res, url, request);
53
+ res = await serializeResponse(res, url, request);
60
54
  if (request.responseInterceptor) {
61
55
  res = (await request.responseInterceptor(res)) || res;
62
56
  }
@@ -82,364 +76,6 @@ export default async function http(url, request = {}) {
82
76
  return res;
83
77
  }
84
78
 
85
- // exported for testing
86
- export const shouldDownloadAsText = (contentType = '') => /(json|xml|yaml|text)\b/.test(contentType);
87
- function parseBody(body, contentType) {
88
- if (contentType && (contentType.indexOf('application/json') === 0 || contentType.indexOf('+json') > 0)) {
89
- return JSON.parse(body);
90
- }
91
- return jsYaml.load(body);
92
- }
93
-
94
- // Serialize the response, returns a promise with headers and the body part of the hash
95
- export function serializeRes(oriRes, url, {
96
- loadSpec = false
97
- } = {}) {
98
- const res = {
99
- ok: oriRes.ok,
100
- url: oriRes.url || url,
101
- status: oriRes.status,
102
- statusText: oriRes.statusText,
103
- headers: serializeHeaders(oriRes.headers)
104
- };
105
- const contentType = res.headers['content-type'];
106
- const useText = loadSpec || shouldDownloadAsText(contentType);
107
- const getBody = useText ? oriRes.text : oriRes.blob || oriRes.buffer;
108
- return getBody.call(oriRes).then(body => {
109
- res.text = body;
110
- res.data = body;
111
- if (useText) {
112
- try {
113
- const obj = parseBody(body, contentType);
114
- res.body = obj;
115
- res.obj = obj;
116
- } catch (e) {
117
- res.parseError = e;
118
- }
119
- }
120
- return res;
121
- });
122
- }
123
- function serializeHeaderValue(value) {
124
- const isMulti = value.includes(', ');
125
- return isMulti ? value.split(', ') : value;
126
- }
127
-
128
- // Serialize headers into a hash, where mutliple-headers result in an array.
129
- //
130
- // eg: Cookie: one
131
- // Cookie: two
132
- // = { Cookie: [ "one", "two" ]
133
- export function serializeHeaders(headers = {}) {
134
- if (typeof headers.entries !== 'function') return {};
135
- return Array.from(headers.entries()).reduce((acc, [header, value]) => {
136
- acc[header] = serializeHeaderValue(value);
137
- return acc;
138
- }, {});
139
- }
140
- export function isFile(obj, navigatorObj) {
141
- if (!navigatorObj && typeof navigator !== 'undefined') {
142
- // eslint-disable-next-line no-undef
143
- navigatorObj = navigator;
144
- }
145
- if (navigatorObj && navigatorObj.product === 'ReactNative') {
146
- if (obj && typeof obj === 'object' && typeof obj.uri === 'string') {
147
- return true;
148
- }
149
- return false;
150
- }
151
- if (typeof File !== 'undefined' && obj instanceof File) {
152
- return true;
153
- }
154
- if (typeof Blob !== 'undefined' && obj instanceof Blob) {
155
- return true;
156
- }
157
- if (ArrayBuffer.isView(obj)) {
158
- return true;
159
- }
160
- return obj !== null && typeof obj === 'object' && typeof obj.pipe === 'function';
161
- }
162
- function isArrayOfFile(obj, navigatorObj) {
163
- return Array.isArray(obj) && obj.some(v => isFile(v, navigatorObj));
164
- }
165
- const STYLE_SEPARATORS = {
166
- form: ',',
167
- spaceDelimited: '%20',
168
- pipeDelimited: '|'
169
- };
170
- const SEPARATORS = {
171
- csv: ',',
172
- ssv: '%20',
173
- tsv: '%09',
174
- pipes: '|'
175
- };
176
-
177
- /**
178
- * Specialized sub-class of File class, that only
179
- * accepts string data and retain this data in `data`
180
- * public property throughout the lifecycle of its instances.
181
- *
182
- * This sub-class is exclusively used only when Encoding Object
183
- * is defined within the Media Type Object (OpenAPI 3.x.y).
184
- */
185
- class FileWithData extends File {
186
- constructor(data, name = '', options = {}) {
187
- super([data], name, options);
188
- this.data = data;
189
- }
190
- valueOf() {
191
- return this.data;
192
- }
193
- toString() {
194
- return this.valueOf();
195
- }
196
- }
197
-
198
- // Formats a key-value and returns an array of key-value pairs.
199
- //
200
- // Return value example 1: [['color', 'blue']]
201
- // Return value example 2: [['color', 'blue,black,brown']]
202
- // Return value example 3: [['color', ['blue', 'black', 'brown']]]
203
- // Return value example 4: [['color', 'R,100,G,200,B,150']]
204
- // Return value example 5: [['R', '100'], ['G', '200'], ['B', '150']]
205
- // Return value example 6: [['color[R]', '100'], ['color[G]', '200'], ['color[B]', '150']]
206
- function formatKeyValue(key, input, skipEncoding = false) {
207
- const {
208
- collectionFormat,
209
- allowEmptyValue,
210
- serializationOption,
211
- encoding
212
- } = input;
213
- // `input` can be string
214
- const value = typeof input === 'object' && !Array.isArray(input) ? input.value : input;
215
- const encodeFn = skipEncoding ? k => k.toString() : k => encodeURIComponent(k);
216
- const encodedKey = encodeFn(key);
217
- if (typeof value === 'undefined' && allowEmptyValue) {
218
- return [[encodedKey, '']];
219
- }
220
-
221
- // file
222
- if (isFile(value) || isArrayOfFile(value)) {
223
- return [[encodedKey, value]];
224
- }
225
-
226
- // for OAS 3 Parameter Object for serialization
227
- if (serializationOption) {
228
- return formatKeyValueBySerializationOption(key, value, skipEncoding, serializationOption);
229
- }
230
-
231
- // for OAS 3 Encoding Object
232
- if (encoding) {
233
- if ([typeof encoding.style, typeof encoding.explode, typeof encoding.allowReserved].some(type => type !== 'undefined')) {
234
- const {
235
- style,
236
- explode,
237
- allowReserved
238
- } = encoding;
239
- return formatKeyValueBySerializationOption(key, value, skipEncoding, {
240
- style,
241
- explode,
242
- allowReserved
243
- });
244
- }
245
- if (typeof encoding.contentType === 'string') {
246
- if (encoding.contentType.startsWith('application/json')) {
247
- // if value is a string, assume value is already a JSON string
248
- const json = typeof value === 'string' ? value : JSON.stringify(value);
249
- const encodedJson = encodeFn(json);
250
- const file = new FileWithData(encodedJson, 'blob', {
251
- type: encoding.contentType
252
- });
253
- return [[encodedKey, file]];
254
- }
255
- const encodedData = encodeFn(String(value));
256
- const blob = new FileWithData(encodedData, 'blob', {
257
- type: encoding.contentType
258
- });
259
- return [[encodedKey, blob]];
260
- }
261
-
262
- // Primitive
263
- if (typeof value !== 'object') {
264
- return [[encodedKey, encodeFn(value)]];
265
- }
266
-
267
- // Array of primitives
268
- if (Array.isArray(value) && value.every(v => typeof v !== 'object')) {
269
- return [[encodedKey, value.map(encodeFn).join(',')]];
270
- }
271
-
272
- // Array or object
273
- return [[encodedKey, encodeFn(JSON.stringify(value))]];
274
- }
275
-
276
- // for OAS 2 Parameter Object
277
- // Primitive
278
- if (typeof value !== 'object') {
279
- return [[encodedKey, encodeFn(value)]];
280
- }
281
-
282
- // Array
283
- if (Array.isArray(value)) {
284
- if (collectionFormat === 'multi') {
285
- // In case of multipart/formdata, it is used as array.
286
- // Otherwise, the caller will convert it to a query by qs.stringify.
287
- return [[encodedKey, value.map(encodeFn)]];
288
- }
289
- return [[encodedKey, value.map(encodeFn).join(SEPARATORS[collectionFormat || 'csv'])]];
290
- }
291
-
292
- // Object
293
- return [[encodedKey, '']];
294
- }
295
- function formatKeyValueBySerializationOption(key, value, skipEncoding, serializationOption) {
296
- const style = serializationOption.style || 'form';
297
- const explode = typeof serializationOption.explode === 'undefined' ? style === 'form' : serializationOption.explode;
298
- // eslint-disable-next-line no-nested-ternary
299
- const escape = skipEncoding ? false : serializationOption && serializationOption.allowReserved ? 'unsafe' : 'reserved';
300
- const encodeFn = v => valueEncoder(v, escape);
301
- const encodeKeyFn = skipEncoding ? k => k : k => encodeFn(k);
302
- if (typeof value === 'string') {
303
- try {
304
- value = JSON.parse(value);
305
- } catch {
306
- // can't parse the value so treat it as as a simple string
307
- }
308
- }
309
-
310
- // Primitive
311
- if (typeof value !== 'object') {
312
- return [[encodeKeyFn(key), encodeFn(value)]];
313
- }
314
-
315
- // Array
316
- if (Array.isArray(value)) {
317
- if (explode) {
318
- // In case of multipart/formdata, it is used as array.
319
- // Otherwise, the caller will convert it to a query by qs.stringify.
320
- return [[encodeKeyFn(key), value.map(encodeFn)]];
321
- }
322
- return [[encodeKeyFn(key), value.map(encodeFn).join(STYLE_SEPARATORS[style])]];
323
- }
324
-
325
- // Object
326
- if (style === 'deepObject') {
327
- return Object.keys(value).map(valueKey => [encodeKeyFn(`${key}[${valueKey}]`), encodeFn(value[valueKey])]);
328
- }
329
- if (explode) {
330
- return Object.keys(value).map(valueKey => [encodeKeyFn(valueKey), encodeFn(value[valueKey])]);
331
- }
332
- return [[encodeKeyFn(key), Object.keys(value).map(valueKey => [`${encodeKeyFn(valueKey)},${encodeFn(value[valueKey])}`]).join(',')]];
333
- }
334
- function buildFormData(reqForm) {
335
- /**
336
- * Build a new FormData instance, support array as field value
337
- * OAS2.0 - when collectionFormat is multi
338
- * OAS3.0 - when explode of Encoding Object is true
339
- *
340
- * This function explicitly handles Buffers (for backward compatibility)
341
- * if provided as a values to FormData. FormData can only handle USVString
342
- * or Blob.
343
- *
344
- * @param {Object} reqForm - ori req.form
345
- * @return {FormData} - new FormData instance
346
- */
347
- return Object.entries(reqForm).reduce((formData, [name, input]) => {
348
- // eslint-disable-next-line no-restricted-syntax
349
- for (const [key, value] of formatKeyValue(name, input, true)) {
350
- if (Array.isArray(value)) {
351
- // eslint-disable-next-line no-restricted-syntax
352
- for (const v of value) {
353
- if (ArrayBuffer.isView(v)) {
354
- const blob = new Blob([v]);
355
- formData.append(key, blob);
356
- } else {
357
- formData.append(key, v);
358
- }
359
- }
360
- } else if (ArrayBuffer.isView(value)) {
361
- const blob = new Blob([value]);
362
- formData.append(key, blob);
363
- } else {
364
- formData.append(key, value);
365
- }
366
- }
367
- return formData;
368
- }, new FormData());
369
- }
370
-
371
- // Encodes an object using appropriate serializer.
372
- export function encodeFormOrQuery(data) {
373
- /**
374
- * Encode parameter names and values
375
- * @param {Object} result - parameter names and values
376
- * @param {string} parameterName - Parameter name
377
- * @return {object} encoded parameter names and values
378
- */
379
- const encodedQuery = Object.keys(data).reduce((result, parameterName) => {
380
- // eslint-disable-next-line no-restricted-syntax
381
- for (const [key, value] of formatKeyValue(parameterName, data[parameterName])) {
382
- if (value instanceof FileWithData) {
383
- result[key] = value.valueOf();
384
- } else {
385
- result[key] = value;
386
- }
387
- }
388
- return result;
389
- }, {});
390
- return qs.stringify(encodedQuery, {
391
- encode: false,
392
- indices: false
393
- }) || '';
394
- }
395
-
396
- // If the request has a `query` object, merge it into the request.url, and delete the object
397
- // If file and/or multipart, also create FormData instance
398
- export function mergeInQueryOrForm(req = {}) {
399
- const {
400
- url = '',
401
- query,
402
- form
403
- } = req;
404
- const joinSearch = (...strs) => {
405
- const search = strs.filter(a => a).join('&'); // Only truthy value
406
- return search ? `?${search}` : ''; // Only add '?' if there is a str
407
- };
408
- if (form) {
409
- const hasFile = Object.keys(form).some(key => {
410
- const {
411
- value
412
- } = form[key];
413
- return isFile(value) || isArrayOfFile(value);
414
- });
415
- const contentType = req.headers['content-type'] || req.headers['Content-Type'];
416
- if (hasFile || /multipart\/form-data/i.test(contentType)) {
417
- const formdata = buildFormData(req.form);
418
- req.formdata = formdata;
419
- req.body = formdata;
420
- } else {
421
- req.body = encodeFormOrQuery(form);
422
- }
423
- delete req.form;
424
- }
425
- if (query) {
426
- const [baseUrl, oriSearch] = url.split('?');
427
- let newStr = '';
428
- if (oriSearch) {
429
- const oriQuery = qs.parse(oriSearch);
430
- const keysToRemove = Object.keys(query);
431
- keysToRemove.forEach(key => delete oriQuery[key]);
432
- newStr = qs.stringify(oriQuery, {
433
- encode: true
434
- });
435
- }
436
- const finalStr = joinSearch(newStr, encodeFormOrQuery(query));
437
- req.url = baseUrl + finalStr;
438
- delete req.query;
439
- }
440
- return req;
441
- }
442
-
443
79
  // Wrap a http function ( there are otherways to do this, consider this deprecated )
444
80
  export function makeHttp(httpFn, preFetch, postFetch) {
445
81
  postFetch = postFetch || (a => a);
@@ -450,7 +86,7 @@ export function makeHttp(httpFn, preFetch, postFetch) {
450
86
  url: req
451
87
  };
452
88
  }
453
- self.mergeInQueryOrForm(req);
89
+ req = serializeRequest(req);
454
90
  req = preFetch(req);
455
91
  return postFetch(httpFn(req));
456
92
  };
@@ -0,0 +1,46 @@
1
+ export function isFile(obj, navigatorObj) {
2
+ if (!navigatorObj && typeof navigator !== 'undefined') {
3
+ // eslint-disable-next-line no-undef
4
+ navigatorObj = navigator;
5
+ }
6
+ if (navigatorObj && navigatorObj.product === 'ReactNative') {
7
+ if (obj && typeof obj === 'object' && typeof obj.uri === 'string') {
8
+ return true;
9
+ }
10
+ return false;
11
+ }
12
+ if (typeof File !== 'undefined' && obj instanceof File) {
13
+ return true;
14
+ }
15
+ if (typeof Blob !== 'undefined' && obj instanceof Blob) {
16
+ return true;
17
+ }
18
+ if (ArrayBuffer.isView(obj)) {
19
+ return true;
20
+ }
21
+ return obj !== null && typeof obj === 'object' && typeof obj.pipe === 'function';
22
+ }
23
+ export function isArrayOfFile(obj, navigatorObj) {
24
+ return Array.isArray(obj) && obj.some(v => isFile(v, navigatorObj));
25
+ }
26
+
27
+ /**
28
+ * Specialized sub-class of File class, that only
29
+ * accepts string data and retain this data in `data`
30
+ * public property throughout the lifecycle of its instances.
31
+ *
32
+ * This sub-class is exclusively used only when Encoding Object
33
+ * is defined within the Media Type Object (OpenAPI 3.x.y).
34
+ */
35
+ export class FileWithData extends File {
36
+ constructor(data, name = '', options = {}) {
37
+ super([data], name, options);
38
+ this.data = data;
39
+ }
40
+ valueOf() {
41
+ return this.data;
42
+ }
43
+ toString() {
44
+ return this.valueOf();
45
+ }
46
+ }
@@ -0,0 +1,143 @@
1
+ import { isFile, isArrayOfFile, FileWithData } from './file.js';
2
+ import { valueEncoder } from '../../../execute/oas3/style-serializer.js';
3
+ const STYLE_SEPARATORS = {
4
+ form: ',',
5
+ spaceDelimited: '%20',
6
+ pipeDelimited: '|'
7
+ };
8
+ const SEPARATORS = {
9
+ csv: ',',
10
+ ssv: '%20',
11
+ tsv: '%09',
12
+ pipes: '|'
13
+ };
14
+
15
+ // Formats a key-value and returns an array of key-value pairs.
16
+ //
17
+ // Return value example 1: [['color', 'blue']]
18
+ // Return value example 2: [['color', 'blue,black,brown']]
19
+ // Return value example 3: [['color', ['blue', 'black', 'brown']]]
20
+ // Return value example 4: [['color', 'R,100,G,200,B,150']]
21
+ // Return value example 5: [['R', '100'], ['G', '200'], ['B', '150']]
22
+ // Return value example 6: [['color[R]', '100'], ['color[G]', '200'], ['color[B]', '150']]
23
+ export default function formatKeyValue(key, input, skipEncoding = false) {
24
+ const {
25
+ collectionFormat,
26
+ allowEmptyValue,
27
+ serializationOption,
28
+ encoding
29
+ } = input;
30
+ // `input` can be string
31
+ const value = typeof input === 'object' && !Array.isArray(input) ? input.value : input;
32
+ const encodeFn = skipEncoding ? k => k.toString() : k => encodeURIComponent(k);
33
+ const encodedKey = encodeFn(key);
34
+ if (typeof value === 'undefined' && allowEmptyValue) {
35
+ return [[encodedKey, '']];
36
+ }
37
+
38
+ // file
39
+ if (isFile(value) || isArrayOfFile(value)) {
40
+ return [[encodedKey, value]];
41
+ }
42
+
43
+ // for OAS 3 Parameter Object for serialization
44
+ if (serializationOption) {
45
+ return formatKeyValueBySerializationOption(key, value, skipEncoding, serializationOption);
46
+ }
47
+
48
+ // for OAS 3 Encoding Object
49
+ if (encoding) {
50
+ if ([typeof encoding.style, typeof encoding.explode, typeof encoding.allowReserved].some(type => type !== 'undefined')) {
51
+ const {
52
+ style,
53
+ explode,
54
+ allowReserved
55
+ } = encoding;
56
+ return formatKeyValueBySerializationOption(key, value, skipEncoding, {
57
+ style,
58
+ explode,
59
+ allowReserved
60
+ });
61
+ }
62
+ if (typeof encoding.contentType === 'string') {
63
+ if (encoding.contentType.startsWith('application/json')) {
64
+ // if value is a string, assume value is already a JSON string
65
+ const json = typeof value === 'string' ? value : JSON.stringify(value);
66
+ const encodedJson = encodeFn(json);
67
+ const file = new FileWithData(encodedJson, 'blob', {
68
+ type: encoding.contentType
69
+ });
70
+ return [[encodedKey, file]];
71
+ }
72
+ const encodedData = encodeFn(String(value));
73
+ const blob = new FileWithData(encodedData, 'blob', {
74
+ type: encoding.contentType
75
+ });
76
+ return [[encodedKey, blob]];
77
+ }
78
+
79
+ // Primitive
80
+ if (typeof value !== 'object') {
81
+ return [[encodedKey, encodeFn(value)]];
82
+ }
83
+
84
+ // Array of primitives
85
+ if (Array.isArray(value) && value.every(v => typeof v !== 'object')) {
86
+ return [[encodedKey, value.map(encodeFn).join(',')]];
87
+ }
88
+
89
+ // Array or object
90
+ return [[encodedKey, encodeFn(JSON.stringify(value))]];
91
+ }
92
+
93
+ // for OAS 2 Parameter Object
94
+ // Primitive
95
+ if (typeof value !== 'object') {
96
+ return [[encodedKey, encodeFn(value)]];
97
+ }
98
+
99
+ // Array
100
+ if (Array.isArray(value)) {
101
+ if (collectionFormat === 'multi') {
102
+ // In case of multipart/formdata, it is used as array.
103
+ // Otherwise, the caller will convert it to a query by qs.stringify.
104
+ return [[encodedKey, value.map(encodeFn)]];
105
+ }
106
+ return [[encodedKey, value.map(encodeFn).join(SEPARATORS[collectionFormat || 'csv'])]];
107
+ }
108
+
109
+ // Object
110
+ return [[encodedKey, '']];
111
+ }
112
+ function formatKeyValueBySerializationOption(key, value, skipEncoding, serializationOption) {
113
+ const style = serializationOption.style || 'form';
114
+ const explode = typeof serializationOption.explode === 'undefined' ? style === 'form' : serializationOption.explode;
115
+ // eslint-disable-next-line no-nested-ternary
116
+ const escape = skipEncoding ? false : serializationOption && serializationOption.allowReserved ? 'unsafe' : 'reserved';
117
+ const encodeFn = v => valueEncoder(v, escape);
118
+ const encodeKeyFn = skipEncoding ? k => k : k => encodeFn(k);
119
+
120
+ // Primitive
121
+ if (typeof value !== 'object') {
122
+ return [[encodeKeyFn(key), encodeFn(value)]];
123
+ }
124
+
125
+ // Array
126
+ if (Array.isArray(value)) {
127
+ if (explode) {
128
+ // In case of multipart/formdata, it is used as array.
129
+ // Otherwise, the caller will convert it to a query by qs.stringify.
130
+ return [[encodeKeyFn(key), value.map(encodeFn)]];
131
+ }
132
+ return [[encodeKeyFn(key), value.map(encodeFn).join(STYLE_SEPARATORS[style])]];
133
+ }
134
+
135
+ // Object
136
+ if (style === 'deepObject') {
137
+ return Object.keys(value).map(valueKey => [encodeKeyFn(`${key}[${valueKey}]`), encodeFn(value[valueKey])]);
138
+ }
139
+ if (explode) {
140
+ return Object.keys(value).map(valueKey => [encodeKeyFn(valueKey), encodeFn(value[valueKey])]);
141
+ }
142
+ return [[encodeKeyFn(key), Object.keys(value).map(valueKey => [`${encodeKeyFn(valueKey)},${encodeFn(value[valueKey])}`]).join(',')]];
143
+ }