@readme/oas-to-har 15.0.0 → 17.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,45 @@
1
+ ## 17.0.0 (2022-04-22)
2
+
3
+ > **BREAKING RELEASE**
4
+ >
5
+ > Node 12 is no longer supported.
6
+
7
+ * chore: adding some more exclusions into the npmignore list ([25b3121](https://github.com/readmeio/oas-to-har/commit/25b3121))
8
+ * chore(deps-dev): bump @readme/oas-examples from 4.5.0 to 5.0.0 (#75) ([845535b](https://github.com/readmeio/oas-to-har/commit/845535b)), closes [#75](https://github.com/readmeio/oas-to-har/issues/75)
9
+ * chore(deps-dev): bump eslint from 8.11.0 to 8.12.0 (#73) ([c26d37c](https://github.com/readmeio/oas-to-har/commit/c26d37c)), closes [#73](https://github.com/readmeio/oas-to-har/issues/73)
10
+ * chore(deps-dev): bump prettier from 2.6.0 to 2.6.1 (#72) ([24613fc](https://github.com/readmeio/oas-to-har/commit/24613fc)), closes [#72](https://github.com/readmeio/oas-to-har/issues/72)
11
+ * chore(deps): bump actions/checkout from 2.4.0 to 3 (#71) ([38c66a7](https://github.com/readmeio/oas-to-har/commit/38c66a7)), closes [#71](https://github.com/readmeio/oas-to-har/issues/71)
12
+ * chore(deps): bump oas from 18.0.6 to 18.1.0 (#74) ([93c2bc4](https://github.com/readmeio/oas-to-har/commit/93c2bc4)), closes [#74](https://github.com/readmeio/oas-to-har/issues/74)
13
+ * fix: code cleanup (#79) ([245dcbb](https://github.com/readmeio/oas-to-har/commit/245dcbb)), closes [#79](https://github.com/readmeio/oas-to-har/issues/79)
14
+ * fix: support for allowReserved (#76) ([f609297](https://github.com/readmeio/oas-to-har/commit/f609297)), closes [#76](https://github.com/readmeio/oas-to-har/issues/76)
15
+ * fix: support for multi-level deepObjects (#77) ([b287f68](https://github.com/readmeio/oas-to-har/commit/b287f68)), closes [#77](https://github.com/readmeio/oas-to-har/issues/77)
16
+ * feat: browser testing! (#78) ([5ebe4d4](https://github.com/readmeio/oas-to-har/commit/5ebe4d4)), closes [#78](https://github.com/readmeio/oas-to-har/issues/78)
17
+
18
+
19
+
20
+ ## 16.1.0 (2022-03-23)
21
+
22
+ * chore: removing some docs from the repo as they're in our .github/ repo now ([f3d81c3](https://github.com/readmeio/oas-to-har/commit/f3d81c3))
23
+ * chore(deps): bumping out of date deps ([0d7add6](https://github.com/readmeio/oas-to-har/commit/0d7add6))
24
+ * fix: issue where null-assigned object properties would be filtered out (#70) ([9d51794](https://github.com/readmeio/oas-to-har/commit/9d51794)), closes [#70](https://github.com/readmeio/oas-to-har/issues/70)
25
+
26
+
27
+
28
+ ## 16.0.0 (2022-03-08)
29
+
30
+ * chore(deps-dev): bump @commitlint/cli from 16.1.0 to 16.2.1 (#65) ([d1ce5b5](https://github.com/readmeio/oas-to-har/commit/d1ce5b5)), closes [#65](https://github.com/readmeio/oas-to-har/issues/65)
31
+ * chore(deps-dev): bump @commitlint/config-conventional (#62) ([51ad7f3](https://github.com/readmeio/oas-to-har/commit/51ad7f3)), closes [#62](https://github.com/readmeio/oas-to-har/issues/62)
32
+ * chore(deps-dev): bump @readme/eslint-config from 8.2.0 to 8.5.0 (#67) ([adae50c](https://github.com/readmeio/oas-to-har/commit/adae50c)), closes [#67](https://github.com/readmeio/oas-to-har/issues/67)
33
+ * chore(deps-dev): bump eslint from 8.8.0 to 8.10.0 (#63) ([31c1aa3](https://github.com/readmeio/oas-to-har/commit/31c1aa3)), closes [#63](https://github.com/readmeio/oas-to-har/issues/63)
34
+ * chore(deps-dev): bump jest from 27.4.7 to 27.5.1 (#64) ([d99e123](https://github.com/readmeio/oas-to-har/commit/d99e123)), closes [#64](https://github.com/readmeio/oas-to-har/issues/64)
35
+ * chore(deps): bump actions/setup-node from 2.5.1 to 3 (#61) ([362859e](https://github.com/readmeio/oas-to-har/commit/362859e)), closes [#61](https://github.com/readmeio/oas-to-har/issues/61)
36
+ * chore(deps): upgrading oas to v18 (#69) ([3a5a54d](https://github.com/readmeio/oas-to-har/commit/3a5a54d)), closes [#69](https://github.com/readmeio/oas-to-har/issues/69)
37
+ * docs: incorporating alex into our documentation workflow (#68) ([6b20368](https://github.com/readmeio/oas-to-har/commit/6b20368)), closes [#68](https://github.com/readmeio/oas-to-har/issues/68)
38
+ * feat: moving to our new remove-undefined-objects package (#59) ([d35a014](https://github.com/readmeio/oas-to-har/commit/d35a014)), closes [#59](https://github.com/readmeio/oas-to-har/issues/59)
39
+ * feat(styles): add space and pipe delimited support for objects per 3.1 (#60) ([49e2d13](https://github.com/readmeio/oas-to-har/commit/49e2d13)), closes [#60](https://github.com/readmeio/oas-to-har/issues/60)
40
+
41
+
42
+
1
43
  ## 15.0.0 (2022-02-03)
2
44
 
3
45
  > **BREAKING RELEASE**
package/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2021 ReadMe
1
+ Copyright © 2022 ReadMe
2
2
 
3
3
  Permission to use, copy, modify, and/or distribute this software for any purpose
4
4
  with or without fee is hereby granted, provided that the above copyright notice
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Utility to transform an OAS operation into a [HAR](http://www.softwareishard.com/blog/har-12-spec/) representation
4
4
 
5
- [![Build](https://github.com/readmeio/oas-to-har/workflows/CI/badge.svg)](https://github.com/readmeio/oas-to-har)
5
+ [![Build](https://github.com/readmeio/oas-to-har/workflows/CI/badge.svg)](https://github.com/readmeio/oas-to-har/) [![](https://img.shields.io/npm/v/@readme/oas-to-har)](https://npm.im/@readme/oas-to-har)
6
6
 
7
7
  [![](https://d3vv6lp55qjaqc.cloudfront.net/items/1M3C3j0I0s0j3T362344/Untitled-2.png)](https://readme.io)
8
8
 
@@ -15,14 +15,37 @@ npm install --save @readme/oas-to-har
15
15
  ## Usage
16
16
 
17
17
  ```js
18
- const Oas = require('oas');
18
+ const Oas = require('oas').default;
19
19
  const oasToHar = require('@readme/oas-to-har');
20
20
 
21
- const spec = new Oas('petstore.json');
22
- console.log(oasToHar(spec, { path: '/pets', method: 'post'}));
21
+ const petstore = require('./petstore.json');
22
+
23
+ const spec = new Oas(petstore);
24
+ console.log(oasToHar(spec, spec.operation('/pets', 'post')));
25
+ ```
26
+
27
+ ```json
28
+ {
29
+ log: {
30
+ entries: [
31
+ {
32
+ request: {
33
+ cookies: [],
34
+ headers: [],
35
+ headersSize: 0,
36
+ queryString: [],
37
+ bodySize: 0,
38
+ method: 'POST',
39
+ url: 'http://petstore.swagger.io/v2/pets',
40
+ httpVersion: 'HTTP/1.1'
41
+ }
42
+ }
43
+ ]
44
+ }
45
+ }
23
46
  ```
24
47
 
25
- ### `oasToHar(har, operationSchema, values, auth, opts) => Object`
48
+ ### `oasToHar(oas, operationSchema, values, auth, opts) => Object`
26
49
 
27
50
  - `oas` *{Oas}*: Instance of our [oas/tooling](https://npm.im/oas) class.
28
51
  - `operationSchema` *{Object\|Operation}*: Can either be an object with `path` and `method` properties (that exist in the supplied OAS), or an instance of our `Operation` class from [oas/tooling](https://npm.im/oas) - accessed through `new Oas(spec).operation(path, method)`.
@@ -36,10 +59,3 @@ console.log(oasToHar(spec, { path: '/pets', method: 'post'}));
36
59
  - `server` — If the supplied OAS has multiple severs or server variables you can use this to set which server and variables to use. Shape of it should be: `{ selected: Integer, variables: { ...key-values }}`. `selected` should coorespond to index of the `servers` array in your OAS.
37
60
  - `auth` *{Object}*: Authentication information for the request.
38
61
  - `opts.proxyUrl` *{Boolean}*: Boolean to toggle if composed HAR objects should have their `url` be sent through our CORS-friendly proxy. Defaults to `false`.
39
-
40
- ## Credits
41
- [Jon Ursenbach](https://github.com/erunion)
42
-
43
- ## License
44
-
45
- ISC
package/karma.conf.js ADDED
@@ -0,0 +1,14 @@
1
+ const { karmaConfig } = require('@jsdevtools/karma-config');
2
+ const { host } = require('@jsdevtools/host-environment');
3
+
4
+ module.exports = karmaConfig({
5
+ sourceDir: '.',
6
+ fixtures: ['test/__datasets__/*.json'],
7
+ browsers: {
8
+ chrome: true,
9
+ firefox: true,
10
+ safari: host.os.mac,
11
+ edge: false,
12
+ ie: false,
13
+ },
14
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@readme/oas-to-har",
3
3
  "description": "Utility to transform an OAS operation into a HAR representation",
4
- "version": "15.0.0",
4
+ "version": "17.0.0",
5
5
  "main": "src/index.js",
6
6
  "author": "Jon Ursenbach <jon@ursenba.ch>",
7
7
  "license": "ISC",
@@ -10,7 +10,7 @@
10
10
  "url": "git://github.com/readmeio/oas-to-har.git"
11
11
  },
12
12
  "engines": {
13
- "node": "^12 || ^14 || ^16"
13
+ "node": ">=14"
14
14
  },
15
15
  "scripts": {
16
16
  "lint": "eslint .",
@@ -18,24 +18,32 @@
18
18
  "pretest": "npm run lint",
19
19
  "prettier": "prettier --list-different --write \"./**/**.{js}\"",
20
20
  "release": "npx conventional-changelog-cli -i CHANGELOG.md -s && git add CHANGELOG.md",
21
- "test": "jest --coverage"
21
+ "test:browser": "karma start --single-run",
22
+ "test:browser:chrome": "karma start --browsers=Chrome --single-run=false",
23
+ "test:browser:debug": "karma start --single-run=false",
24
+ "test": "nyc mocha"
22
25
  },
23
26
  "dependencies": {
24
- "@readme/oas-extensions": "^14.1.1",
25
- "oas": "^17.7.1",
26
- "parse-data-url": "^4.0.1"
27
+ "@readme/oas-extensions": "^14.2.0",
28
+ "oas": "^18.0.6",
29
+ "parse-data-url": "^4.0.1",
30
+ "qs": "^6.10.3",
31
+ "remove-undefined-objects": "^1.1.0"
27
32
  },
28
33
  "devDependencies": {
29
- "@commitlint/cli": "^16.1.0",
34
+ "@commitlint/cli": "^16.2.3",
30
35
  "@commitlint/config-conventional": "^16.0.0",
31
- "@readme/eslint-config": "^8.1.2",
32
- "@readme/oas-examples": "^4.3.3",
33
- "datauri": "^4.1.0",
34
- "eslint": "^8.7.0",
36
+ "@jsdevtools/host-environment": "^2.1.2",
37
+ "@jsdevtools/karma-config": "^3.1.7",
38
+ "@readme/eslint-config": "^8.5.1",
39
+ "@readme/oas-examples": "^5.0.0",
40
+ "chai": "^4.3.6",
41
+ "eslint": "^8.11.0",
42
+ "har-validator": "^5.1.5",
35
43
  "husky": "^7.0.4",
36
- "jest": "^27.4.7",
37
- "jest-expect-har": "^3.0.1",
38
- "prettier": "^2.5.1"
44
+ "mocha": "^9.2.2",
45
+ "nyc": "^15.1.0",
46
+ "prettier": "^2.6.0"
39
47
  },
40
48
  "prettier": "@readme/eslint-config/prettier",
41
49
  "commitlint": {
package/src/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  const extensions = require('@readme/oas-extensions');
2
2
  const { Operation, utils } = require('oas');
3
3
  const parseDataUrl = require('parse-data-url');
4
+ const { default: removeUndefinedObjects } = require('remove-undefined-objects');
4
5
 
5
6
  const configureSecurity = require('./lib/configure-security');
6
- const removeUndefinedObjects = require('./lib/remove-undefined-objects');
7
7
  const formatStyle = require('./lib/style-formatting');
8
8
 
9
9
  const { jsonSchemaTypes } = utils;
@@ -11,8 +11,8 @@ const { jsonSchemaTypes } = utils;
11
11
  function formatter(values, param, type, onlyIfExists) {
12
12
  if (param.style) {
13
13
  const value = values[type][param.name];
14
- // Note: Technically we could send everything through the format style and choose the proper default for each
15
- // `in` type (e.g. query defaults to form).
14
+ // Note: Technically we could send everything through the format style and choose the proper
15
+ // default for each `in` type (e.g. query defaults to form).
16
16
  return formatStyle(value, param);
17
17
  }
18
18
 
@@ -26,18 +26,20 @@ function formatter(values, param, type, onlyIfExists) {
26
26
  } else if (param.required && param.schema && param.schema.default) {
27
27
  value = param.schema.default;
28
28
  } else if (type === 'path') {
29
- // If we don't have any values for the path parameter, just use the name of the parameter as the value so we don't
30
- // try try to build a URL to something like `https://example.com/undefined`.
29
+ // If we don't have any values for the path parameter, just use the name of the parameter as the
30
+ // value so we don't try try to build a URL to something like `https://example.com/undefined`.
31
31
  return param.name;
32
32
  }
33
33
 
34
- // Handle file uploads. Specifically arrays of file uploads which need to be formatted very specifically.
34
+ // Handle file uploads. Specifically arrays of file uploads which need to be formatted very
35
+ // specifically.
35
36
  if (param.schema && param.schema.type === 'array' && param.schema.items && param.schema.items.format === 'binary') {
36
37
  return JSON.stringify(value);
37
38
  }
38
39
 
39
40
  if (value !== undefined) {
40
- // Query params should always be formatted, even if they don't have a `style` serialization configured.
41
+ // Query params should always be formatted, even if they don't have a `style` serialization
42
+ // configured.
41
43
  if (type === 'query') {
42
44
  return formatStyle(value, param);
43
45
  }
@@ -77,7 +79,8 @@ function multipartBodyToFormatterParams(multipartBody, oasMediaTypeObject) {
77
79
  .filter(Boolean);
78
80
  }
79
81
 
80
- // Pretty sure that we'll never have anything but an object for multipart bodies, so returning empty array if we get anything else.
82
+ // Pretty sure that we'll never have anything but an object for multipart bodies, so returning
83
+ // empty array if we get anything else.
81
84
  return [];
82
85
  }
83
86
 
@@ -118,12 +121,14 @@ function appendHarValue(harParam, name, value, addtlData = {}) {
118
121
  if (typeof value === 'undefined') return;
119
122
 
120
123
  if (Array.isArray(value)) {
121
- // If the formatter gives us an array, we're expected to add each array value as a new parameter item with the same parameter name
124
+ // If the formatter gives us an array, we're expected to add each array value as a new
125
+ // parameter item with the same parameter name
122
126
  value.forEach(singleValue => {
123
127
  appendHarValue(harParam, name, singleValue);
124
128
  });
125
129
  } else if (typeof value === 'object' && value !== null) {
126
- // If the formatter gives us an object, we're expected to add each property value as a new parameter item, each with the name of the property
130
+ // If the formatter gives us an object, we're expected to add each property value as a new
131
+ // parameter item, each with the name of the property
127
132
  Object.keys(value).forEach(key => {
128
133
  appendHarValue(harParam, key, value[key]);
129
134
  });
@@ -143,8 +148,8 @@ module.exports = (
143
148
  values = {},
144
149
  auth = {},
145
150
  opts = {
146
- // If true, the operation URL will be rewritten and prefixed with https://try.readme.io/ in order to funnel requests
147
- // through our CORS-friendly proxy.
151
+ // If true, the operation URL will be rewritten and prefixed with https://try.readme.io/ in
152
+ // order to funnel requests through our CORS-friendly proxy.
148
153
  proxyUrl: false,
149
154
  }
150
155
  ) => {
@@ -196,7 +201,8 @@ module.exports = (
196
201
  // Find the path parameter or set a default value if it does not exist
197
202
  const parameter = parameters.find(param => param.name === key) || { name: key };
198
203
 
199
- // The library that handles our style processing already encodes uri elements. For everything else we need to handle it here.
204
+ // The library that handles our style processing already encodes uri elements. For everything
205
+ // else we need to handle it here.
200
206
  if (!parameter.style) {
201
207
  return encodeURIComponent(formatter(formData, parameter, 'path'));
202
208
  }
@@ -316,8 +322,9 @@ module.exports = (
316
322
  har.postData.mimeType = 'multipart/form-data';
317
323
  har.postData.params = [];
318
324
 
319
- // Discover all `{ type: string, format: binary }` properties the schema. If there are any, then that means
320
- // that we're dealing with a `multipart/form-data` request and need to treat the payload as `postData.params`.
325
+ // Discover all `{ type: string, format: binary }` properties the schema. If there are
326
+ // any, then that means that we're dealing with a `multipart/form-data` request and
327
+ // need to treat the payload as `postData.params`.
321
328
  const binaryTypes = Object.keys(requestBody.schema.properties).filter(
322
329
  key => requestBody.schema.properties[key].format === 'binary'
323
330
  );
@@ -333,9 +340,10 @@ module.exports = (
333
340
 
334
341
  const value = formatter(formData, param, 'body', true);
335
342
 
336
- // If we're dealing with a binary type, and the value is a valid data URL we should parse out any
337
- // available filename and content type to send along with the parameter to interpreters like `fetch-har`
338
- // can make sense of it and send a usable payload.
343
+ // If we're dealing with a binary type, and the value is a valid data URL we should
344
+ // parse out any available filename and content type to send along with the
345
+ // parameter to interpreters like `fetch-har` can make sense of it and send a usable
346
+ // payload.
339
347
  const addtlData = {};
340
348
 
341
349
  if (binaryTypes.includes(name)) {
@@ -355,17 +363,21 @@ module.exports = (
355
363
  har.postData.mimeType = contentType;
356
364
 
357
365
  // Handle arbitrary JSON input via a string.
358
- // In OAS you usually find this in an application/json content type.
359
- // with a schema type=string, format=json.
360
- // In the UI this is represented by an arbitrary text input
361
- // This ensures we remove any newlines or tabs and use a clean json block in the example
366
+ //
367
+ // In OAS you usually find this in an `application/json` content type with a schema
368
+ // `type=string, format=json`. In the UI this is represented by an arbitrary text input.
369
+ //
370
+ // This ensures we remove any newlines or tabs and use a clean JSON block in the
371
+ // example.
362
372
  if (requestBody.schema.type === 'string') {
363
373
  har.postData.text = JSON.stringify(JSON.parse(cleanBody));
364
374
  } else {
365
- // Handle formatted JSON objects that have properties that accept arbitrary JSON
366
- // Find all `{ type: string, format: json }` properties in the schema because we need to manually JSON.parse
367
- // them before submit, otherwise they'll be escaped instead of actual objects.
368
- // We also only want values that the user has entered, so we drop any undefined cleanBody keys
375
+ // Handle formatted JSON objects that have properties that accept arbitrary JSON.
376
+ //
377
+ // Find all `{ type: string, format: json }` properties in the schema because we need
378
+ // to manually `JSON.parse` them before submit, otherwise they'll be escaped instead
379
+ // of actual objects. We also only want values that the user has entered, so we drop
380
+ // any `undefined` `cleanBody` keys
369
381
  const jsonTypes = Object.keys(requestBody.schema.properties).filter(
370
382
  key => requestBody.schema.properties[key].format === 'json' && cleanBody[key] !== undefined
371
383
  );
@@ -380,7 +392,8 @@ module.exports = (
380
392
  }
381
393
  });
382
394
 
383
- // `RAW_BODY` is a ReadMe-specific thing where we'll interpret its contents as raw JSON.
395
+ // `RAW_BODY` is a ReadMe-specific thing where we'll interpret its contents as
396
+ // raw JSON.
384
397
  if (typeof cleanBody.RAW_BODY !== 'undefined') {
385
398
  cleanBody = cleanBody.RAW_BODY;
386
399
  }
@@ -395,10 +408,8 @@ module.exports = (
395
408
  }
396
409
  }
397
410
  } catch (e) {
398
- // you should log this error if you're debugging why data is showing up in text, when it should show up in params
399
- // console.log('catching ', e);
400
- // If anything above fails for whatever reason, assume that whatever we had is invalid JSON and just treat it
401
- // as raw text.
411
+ // If anything above fails for whatever reason, assume that whatever we had is invalid
412
+ // JSON and just treat it as raw text.
402
413
  har.postData.text = stringify(formData.body);
403
414
  }
404
415
  } else {
@@ -412,8 +423,9 @@ module.exports = (
412
423
  }
413
424
  }
414
425
 
415
- // Add a `Content-Type` header if there are any body values setup above or if there is a schema defined, but only do
416
- // so if we don't already have a `Content-Type` present as it's impossible for a request to have multiple.
426
+ // Add a `Content-Type` header if there are any body values setup above or if there is a schema
427
+ // defined, but only do so if we don't already have a `Content-Type` present as it's impossible
428
+ // for a request to have multiple.
417
429
  if ((har.postData.text || (requestBody && Object.keys(requestBody.schema).length)) && !hasContentType) {
418
430
  har.headers.push({
419
431
  name: 'Content-Type',
@@ -1,6 +1,7 @@
1
+ const qs = require('qs');
1
2
  const stylize = require('./style-serializer');
2
3
 
3
- // Certain styles don't support empty values, This function tracks that list
4
+ // Certain styles don't support empty values.
4
5
  function shouldNotStyleEmptyValues(parameter) {
5
6
  return ['simple', 'spaceDelimited', 'pipeDelimited', 'deepObject'].includes(parameter.style);
6
7
  }
@@ -9,9 +10,12 @@ function shouldNotStyleReservedHeader(parameter) {
9
10
  return ['accept', 'authorization', 'content-type'].includes(parameter.name.toLowerCase());
10
11
  }
11
12
 
12
- // Note: This isn't necessarily part of the spec. Behavior for the value 'undefined' is, well, undefined.
13
- // This code makes our system look better. If we wanted to be more accurate, we might want to remove this,
14
- // restore the un-fixed behavior for undefined and have our UI pass in empty string instead of undefined.
13
+ /**
14
+ * Note: This isn't necessarily part of the spec. Behavior for the value 'undefined' is, well,
15
+ * undefined. This code makes our system look better. If we wanted to be more accurate, we might
16
+ * want to remove this, restore the un-fixed behavior for undefined and have our UI pass in empty
17
+ * string instead of undefined.
18
+ */
15
19
  function removeUndefinedForPath(value) {
16
20
  let finalValue = value;
17
21
 
@@ -41,35 +45,43 @@ function stylizeValue(value, parameter) {
41
45
 
42
46
  // Some styles don't work with empty values. We catch those there
43
47
  if (shouldNotStyleEmptyValues(parameter) && (typeof finalValue === 'undefined' || finalValue === '')) {
44
- // Paths need return an unstyled empty string instead of undefined so it's ignored in the final path string
48
+ // Paths need return an unstyled empty string instead of undefined so it's ignored in the final
49
+ // path string.
45
50
  if (parameter.in === 'path') {
46
51
  return '';
47
52
  }
48
- // Everything but path should return undefined when unstyled so it's ignored in the final parameter array
53
+
54
+ // Everything but path should return undefined when unstyled so it's ignored in the final
55
+ // parameter array.
49
56
  return undefined;
50
57
  }
51
58
 
52
- // Every style that adds their style to empty values should use emptystring for path parameters instead of undefined to avoid the string 'undefined'
59
+ // Every style that adds their style to empty values should use emptystring for path parameters
60
+ // instead of undefined to avoid the string `undefined`.
53
61
  if (parameter.in === 'path') {
54
62
  finalValue = removeUndefinedForPath(finalValue);
55
63
  }
56
64
 
57
- // Eventhough `Accept`, `Authorization`, and `Content-Type` headers can be defined as parameters, they should be
58
- // completely ignored when it comes to serialization.
59
- //
60
- // > If in is "header" and the name field is "Accept", "Content-Type" or "Authorization", the parameter definition
61
- // > SHALL be ignored.
62
- //
63
- // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#fixed-fields-10
65
+ /**
66
+ * Eventhough `Accept`, `Authorization`, and `Content-Type` headers can be defined as parameters,
67
+ * they should be completely ignored when it comes to serialization.
68
+ *
69
+ * > If in is "header" and the name field is "Accept", "Content-Type" or "Authorization", the
70
+ * > parameter definition SHALL be ignored.
71
+ *
72
+ * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#fixed-fields-10}
73
+ */
64
74
  if (parameter.in === 'header' && shouldNotStyleReservedHeader(parameter)) {
65
75
  return value;
66
76
  }
67
77
 
68
- // All parameter types have a default `style` format so if they don't have one prescribed we should still conform to
69
- // what the spec defines.
70
- //
71
- // https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#user-content-parameterstyle
72
- // https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#user-content-parameterstyle
78
+ /**
79
+ * All parameter types have a default `style` format so if they don't have one prescribed we
80
+ * should still conform to what the spec defines.
81
+ *
82
+ * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#user-content-parameterstyle}
83
+ * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#user-content-parameterstyle}
84
+ */
73
85
  let style = parameter.style;
74
86
  if (!style) {
75
87
  if (parameter.in === 'query') {
@@ -85,10 +97,12 @@ function stylizeValue(value, parameter) {
85
97
 
86
98
  let explode = parameter.explode;
87
99
  if (explode === undefined && style === 'form') {
88
- // Per the spec if no `explode` is present but `style` is `form` then `explode` should default to `true`.
89
- //
90
- // https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#user-content-parameterexplode
91
- // https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#user-content-parameterexplode
100
+ /**
101
+ * Per the spec if no `explode` is present but `style` is `form` then `explode` should default to `true`.
102
+ *
103
+ * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#user-content-parameterexplode}
104
+ * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#user-content-parameterexplode}
105
+ */
92
106
  explode = true;
93
107
  }
94
108
 
@@ -98,15 +112,49 @@ function stylizeValue(value, parameter) {
98
112
  key: parameter.name,
99
113
  style,
100
114
  explode,
101
- /*
102
- TODO: this parameter is optional to stylize. It defaults to false, and can accept falsy, truthy, or "unsafe".
103
- I do not know if it is correct for query to use this. See style-serializer for more info
104
- */
115
+ /**
116
+ * @todo this parameter is optional to stylize. It defaults to false, and can accept falsy, truthy, or "unsafe".
117
+ * I do not know if it is correct for query to use this. See style-serializer for more info
118
+ */
105
119
  escape: true,
120
+ ...(parameter.in === 'query' ? { isAllowedReserved: parameter.allowReserved || false } : {}),
106
121
  });
107
122
  }
108
123
 
109
- // Explode is handled on its own, because style-serializer doesn't return what we expect for proper HAR output
124
+ function handleDeepObject(value, parameter) {
125
+ return qs
126
+ .stringify(value, {
127
+ // eslint-disable-next-line consistent-return
128
+ encoder(str, defaultEncoder, charset, type) {
129
+ if (type === 'key') {
130
+ // `str` will be here as `dog[treats][0]` but because the `qs` library doesn't have any
131
+ // awareness of our OpenAPI parameters we need to rewrite it to slap the `parameter.name`
132
+ // to the top, like `pets[dog][treats][0]`.
133
+ const prefixedKey = str
134
+ .split(/[[\]]/g)
135
+ .filter(Boolean)
136
+ .map(k => `[${k}]`)
137
+ .join('');
138
+
139
+ return `${parameter.name}${prefixedKey}`;
140
+ } else if (type === 'value') {
141
+ return stylizeValue(str, parameter);
142
+ }
143
+ },
144
+ })
145
+ .split('&')
146
+ .map(item => {
147
+ const split = item.split('=');
148
+ return {
149
+ label: split[0],
150
+ // `qs` will coerce null values into being `undefined` string but we want to preserve them.
151
+ value: split[1] === 'undefined' ? null : split[1],
152
+ };
153
+ });
154
+ }
155
+
156
+ // Explode is handled on its own, because style-serializer doesn't return what we expect for proper
157
+ // HAR output.
110
158
  function handleExplode(value, parameter) {
111
159
  if (Array.isArray(value)) {
112
160
  return value.map(val => {
@@ -118,12 +166,13 @@ function handleExplode(value, parameter) {
118
166
  const newObj = {};
119
167
 
120
168
  Object.keys(value).forEach(key => {
121
- const stylizedValue = stylizeValue(value[key], parameter);
122
-
123
169
  if (parameter.style === 'deepObject') {
124
- newObj[`${parameter.name}[${key}]`] = stylizedValue;
170
+ const deepObjs = handleDeepObject(value, parameter);
171
+ deepObjs.forEach(obj => {
172
+ newObj[obj.label] = obj.value;
173
+ });
125
174
  } else {
126
- newObj[key] = stylizedValue;
175
+ newObj[key] = stylizeValue(value[key], parameter);
127
176
  }
128
177
  });
129
178
 
@@ -148,10 +197,15 @@ module.exports = function formatStyle(value, parameter) {
148
197
  return undefined;
149
198
  }
150
199
 
151
- // This custom explode logic allows us to bubble up arrays and objects to be handled differently by our HAR transformer
152
- // We need this because the stylizeValue function assumes we're building strings, not richer data types
153
- // The first part of this conditional checks if explode is enabled. Explode is disabled for everything by default except for forms.
154
- // The second part of this conditional bypasses the custom explode logic for headers, because they work differently, and stylizeValue is accurate
200
+ // This custom explode logic allows us to bubble up arrays and objects to be handled differently
201
+ // by our HAR transformer. We need this because the `stylizeValue` function assumes we're building
202
+ // strings, not richer data types.
203
+ //
204
+ // The first part of this conditional checks if `explode` is enabled. Explode is disabled for
205
+ // everything by default except for forms.
206
+ //
207
+ // The second part of this conditional bypasses the custom explode logic for headers, because they
208
+ // work differently, and `stylizeValue` is accurate.
155
209
  if (shouldExplode(parameter)) {
156
210
  return handleExplode(value, parameter);
157
211
  }
@@ -16,8 +16,8 @@ function isURIEncoded(value) {
16
16
  try {
17
17
  return decodeURIComponent(value) !== value;
18
18
  } catch (err) {
19
- // `decodeURIComponent` will throw an exception if a string that has an un-encoded percent sign in it (like 20%),
20
- // so if it's throwing we can just assume that the value hasn't been encoded.
19
+ // `decodeURIComponent` will throw an exception if a string that has an un-encoded percent sign
20
+ // in it (like 20%), o if it's throwing we can just assume that the value hasn't been encoded.
21
21
  return false;
22
22
  }
23
23
  }
@@ -36,7 +36,7 @@ module.exports = function stylize(config) {
36
36
 
37
37
  module.exports.encodeDisallowedCharacters = function encodeDisallowedCharacters(
38
38
  str,
39
- { escape, returnIfEncoded = false } = {}, // eslint-disable-line default-param-last
39
+ { escape, returnIfEncoded = false, isAllowedReserved } = {}, // eslint-disable-line default-param-last
40
40
  parse
41
41
  ) {
42
42
  if (typeof str === 'number') {
@@ -61,17 +61,16 @@ module.exports.encodeDisallowedCharacters = function encodeDisallowedCharacters(
61
61
  return JSON.parse(str);
62
62
  }
63
63
 
64
- // In ES6 you can do this quite easily by using the new ... spread operator.
65
- // This causes the string iterator (another new ES6 feature) to be used internally,
66
- // and because that iterator is designed to deal with
67
- // code points rather than UCS-2/UTF-16 code units.
64
+ // In ES6 you can do this quite easily by using the new ... spread operator. This causes the
65
+ // string iterator (another new ES6 feature) to be used internally, and because that iterator is
66
+ // designed to deal with code points rather than UCS-2/UTF-16 code units.
68
67
  return [...str]
69
68
  .map(char => {
70
69
  if (isRfc3986Unreserved(char)) {
71
70
  return char;
72
71
  }
73
72
 
74
- if (isRfc3986Reserved(char) && escape === 'unsafe') {
73
+ if (isRfc3986Reserved(char) && (escape === 'unsafe' || isAllowedReserved)) {
75
74
  return char;
76
75
  }
77
76
 
@@ -86,142 +85,255 @@ module.exports.encodeDisallowedCharacters = function encodeDisallowedCharacters(
86
85
  .join('');
87
86
  };
88
87
 
89
- function encodeArray({ location, key, value, style, explode, escape }) {
88
+ /**
89
+ * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#style-examples}
90
+ */
91
+ function encodeArray({ location, key, value, style, explode, escape, isAllowedReserved = false }) {
90
92
  const valueEncoder = str =>
91
93
  module.exports.encodeDisallowedCharacters(str, {
92
94
  escape,
93
95
  returnIfEncoded: location === 'query',
96
+ isAllowedReserved,
94
97
  });
95
98
 
96
- if (style === 'simple') {
97
- return value.map(val => valueEncoder(val)).join(',');
98
- }
99
-
100
- if (style === 'label') {
101
- return `.${value.map(val => valueEncoder(val)).join('.')}`;
102
- }
103
-
104
- if (style === 'matrix') {
105
- return value
106
- .map(val => valueEncoder(val))
107
- .reduce((prev, curr) => {
108
- if (!prev || explode) {
109
- return `${prev || ''};${key}=${curr}`;
110
- }
111
- return `${prev},${curr}`;
112
- }, '');
113
- }
114
-
115
- if (style === 'form') {
116
- const after = explode ? `&${key}=` : ',';
117
- return value.map(val => valueEncoder(val)).join(after);
118
- }
119
-
120
- if (style === 'spaceDelimited') {
121
- const after = explode ? `${key}=` : '';
122
- return value.map(val => valueEncoder(val)).join(` ${after}`);
99
+ switch (style) {
100
+ /**
101
+ * @example <caption>`style: simple`</caption>
102
+ * `["blue","black","brown"]` → `blue,black,brown`
103
+ */
104
+ case 'simple':
105
+ return value.map(val => valueEncoder(val)).join(',');
106
+
107
+ /**
108
+ * @example <caption>`style: label`</caption>
109
+ * `["blue","black","brown"]` → `.blue.black.brown`
110
+ */
111
+ case 'label':
112
+ return `.${value.map(val => valueEncoder(val)).join('.')}`;
113
+
114
+ /**
115
+ * @example <caption>`style: matrix` + `explode: true`</caption>
116
+ * `["blue","black","brown"]` → `;color=blue;color=black;color=brown`
117
+ *
118
+ * @example <caption>`style: matrix` + `explode: false` (the default behavior)</caption>
119
+ * `["blue","black","brown"]` → `;color=blue,black,brown `
120
+ */
121
+ case 'matrix':
122
+ return value
123
+ .map(val => valueEncoder(val))
124
+ .reduce((prev, curr) => {
125
+ if (!prev || explode) {
126
+ return `${prev || ''};${key}=${curr}`;
127
+ }
128
+ return `${prev},${curr}`;
129
+ }, '');
130
+
131
+ /**
132
+ * @example <caption>`style: form` + `explode: true`</caption>
133
+ * `["blue","black","brown"]` → `color=blue&color=black&color=brown`
134
+ *
135
+ * @example <caption>`style: form` + `explode: false` (the default behavior)</caption>
136
+ * `["blue","black","brown"]` → `ccolor=blue,black,brown`
137
+ */
138
+ case 'form':
139
+ return value.map(val => valueEncoder(val)).join(explode ? `&${key}=` : ',');
140
+
141
+ /**
142
+ * @example <caption>`style: spaceDelimited`</caption>
143
+ * `["blue","black","brown"]` → `blue%20black%20brown`
144
+ */
145
+ case 'spaceDelimited':
146
+ return value.map(val => valueEncoder(val)).join(` ${explode ? `${key}=` : ''}`);
147
+
148
+ /**
149
+ * @example <caption>`style: pipeDelimited`</caption>
150
+ * `["blue","black","brown"]` → `blue|black|brown`
151
+ */
152
+ case 'pipeDelimited':
153
+ return value.map(val => valueEncoder(val)).join(`|${explode ? `${key}=` : ''}`);
154
+
155
+ default:
156
+ return undefined;
123
157
  }
124
-
125
- if (style === 'pipeDelimited') {
126
- const after = explode ? `${key}=` : '';
127
- return value.map(val => valueEncoder(val)).join(`|${after}`);
128
- }
129
-
130
- return undefined;
131
158
  }
132
159
 
133
- function encodeObject({ location, key, value, style, explode, escape }) {
160
+ /**
161
+ * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#style-examples}
162
+ */
163
+ function encodeObject({ location, key, value, style, explode, escape, isAllowedReserved = false }) {
134
164
  const valueEncoder = str =>
135
165
  module.exports.encodeDisallowedCharacters(str, {
136
166
  escape,
137
167
  returnIfEncoded: location === 'query',
168
+ isAllowedReserved,
138
169
  });
139
170
 
140
171
  const valueKeys = Object.keys(value);
141
172
 
142
- if (style === 'simple') {
143
- return valueKeys.reduce((prev, curr) => {
144
- const val = valueEncoder(value[curr]);
145
- const middleChar = explode ? '=' : ',';
146
- const prefix = prev ? `${prev},` : '';
173
+ switch (style) {
174
+ /**
175
+ * @example <caption>`style: simple` + `explode: true`</caption>
176
+ * `{ "R": 100, "G": 200, "B": 150 }` → `R=100,G=200,B=150`
177
+ *
178
+ * @example <caption>`style: simple` + `explode: false` (the default behavior)</caption>
179
+ * `{ "R": 100, "G": 200, "B": 150 }` → `R,100,G,200,B,150`
180
+ */
181
+ case 'simple':
182
+ return valueKeys.reduce((prev, curr) => {
183
+ const val = valueEncoder(value[curr]);
184
+ const middleChar = explode ? '=' : ',';
185
+ const prefix = prev ? `${prev},` : '';
186
+
187
+ return `${prefix}${curr}${middleChar}${val}`;
188
+ }, '');
147
189
 
148
- return `${prefix}${curr}${middleChar}${val}`;
149
- }, '');
150
- }
190
+ /**
191
+ * @example <caption>`style: label` + `explode: true`</caption>
192
+ * `{ "R": 100, "G": 200, "B": 150 }` → `.R=100.G=200.B=150`
193
+ *
194
+ * @example <caption>`style: label` + `explode: false` (the default behavior)</caption>
195
+ * `{ "R": 100, "G": 200, "B": 150 }` → `.R.100.G.200.B.150`
196
+ */
197
+ case 'label':
198
+ return valueKeys.reduce((prev, curr) => {
199
+ const val = valueEncoder(value[curr]);
200
+ const middleChar = explode ? '=' : '.';
201
+ const prefix = prev ? `${prev}.` : '.';
202
+
203
+ return `${prefix}${curr}${middleChar}${val}`;
204
+ }, '');
151
205
 
152
- if (style === 'label') {
153
- return valueKeys.reduce((prev, curr) => {
154
- const val = valueEncoder(value[curr]);
155
- const middleChar = explode ? '=' : '.';
156
- const prefix = prev ? `${prev}.` : '.';
206
+ /**
207
+ * @example <caption>`style: matrix` + `explode: true`</caption>
208
+ * `{ "R": 100, "G": 200, "B": 150 }` → `;R=100;G=200;B=150`
209
+ *
210
+ * @example <caption>`style: matrix` + `explode: false` (the default behavior)</caption>
211
+ * `{ "R": 100, "G": 200, "B": 150 }` → `;color=R,100,G,200,B,150`
212
+ */
213
+ case 'matrix':
214
+ if (explode) {
215
+ return valueKeys.reduce((prev, curr) => {
216
+ const val = valueEncoder(value[curr]);
217
+ const prefix = prev ? `${prev};` : ';';
218
+
219
+ return `${prefix}${curr}=${val}`;
220
+ }, '');
221
+ }
157
222
 
158
- return `${prefix}${curr}${middleChar}${val}`;
159
- }, '');
160
- }
223
+ return valueKeys.reduce((prev, curr) => {
224
+ const val = valueEncoder(value[curr]);
225
+ const prefix = prev ? `${prev},` : `;${key}=`;
161
226
 
162
- if (style === 'matrix' && explode) {
163
- return valueKeys.reduce((prev, curr) => {
164
- const val = valueEncoder(value[curr]);
165
- const prefix = prev ? `${prev};` : ';';
227
+ return `${prefix}${curr},${val}`;
228
+ }, '');
166
229
 
167
- return `${prefix}${curr}=${val}`;
168
- }, '');
169
- }
230
+ /**
231
+ * @example <caption>`style: form` + `explode: true`</caption>
232
+ * `{ "R": 100, "G": 200, "B": 150 }` → `R=100&G=200&B=150`
233
+ *
234
+ * @example <caption>`style: form` + `explode: false` (the default behavior)</caption>
235
+ * `{ "R": 100, "G": 200, "B": 150 }` → `color=R,100,G,200,B,150`
236
+ */
237
+ case 'form':
238
+ return valueKeys.reduce((prev, curr) => {
239
+ const val = valueEncoder(value[curr]);
240
+ const prefix = prev ? `${prev}${explode ? '&' : ','}` : '';
241
+ const separator = explode ? '=' : ',';
242
+
243
+ return `${prefix}${curr}${separator}${val}`;
244
+ }, '');
170
245
 
171
- if (style === 'matrix') {
172
- // no explode
173
- return valueKeys.reduce((prev, curr) => {
174
- const val = valueEncoder(value[curr]);
175
- const prefix = prev ? `${prev},` : `;${key}=`;
246
+ /**
247
+ * @example <caption>`style: spaceDelimited`</caption>
248
+ * `{ "R": 100, "G": 200, "B": 150 }` → `R%20100%20G%20200%20B%20150`
249
+ */
250
+ case 'spaceDelimited':
251
+ return valueKeys.reduce((prev, curr) => {
252
+ const val = valueEncoder(value[curr]);
253
+ const prefix = prev ? `${prev} ` : '';
176
254
 
177
- return `${prefix}${curr},${val}`;
178
- }, '');
179
- }
255
+ return `${prefix}${curr} ${val}`;
256
+ }, '');
180
257
 
181
- if (style === 'form') {
182
- return valueKeys.reduce((prev, curr) => {
183
- const val = valueEncoder(value[curr]);
184
- const prefix = prev ? `${prev}${explode ? '&' : ','}` : '';
185
- const separator = explode ? '=' : ',';
258
+ /**
259
+ * @example <caption>`style: pipeDelimited`</caption>
260
+ * `{ "R": 100, "G": 200, "B": 150 }` → `R|100|G|200|B|150`
261
+ */
262
+ case 'pipeDelimited':
263
+ return valueKeys.reduce((prev, curr) => {
264
+ const val = valueEncoder(value[curr]);
265
+ const prefix = prev ? `${prev}|` : '';
186
266
 
187
- return `${prefix}${curr}${separator}${val}`;
188
- }, '');
189
- }
267
+ return `${prefix}${curr}|${val}`;
268
+ }, '');
190
269
 
191
- return undefined;
270
+ /**
271
+ * @example <caption>`style: deepObject`</caption>
272
+ * `{ "R": 100, "G": 200, "B": 150 }` → `color[R]=100&color[G]=200&color[B]=150`
273
+ */
274
+ case 'deepObject':
275
+ return valueKeys.reduce(curr => {
276
+ const val = valueEncoder(value[curr], {}, true);
277
+ return `${val}`;
278
+ }, '');
279
+
280
+ default:
281
+ return undefined;
282
+ }
192
283
  }
193
284
 
194
- function encodePrimitive({ location, key, value, style, escape }) {
285
+ /**
286
+ * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#style-examples}
287
+ */
288
+ function encodePrimitive({ location, key, value, style, escape, isAllowedReserved = false }) {
195
289
  const valueEncoder = str =>
196
290
  module.exports.encodeDisallowedCharacters(str, {
197
291
  escape,
198
292
  returnIfEncoded: location === 'query' || location === 'body',
293
+ isAllowedReserved,
199
294
  });
200
295
 
201
- if (style === 'simple') {
202
- return valueEncoder(value);
203
- }
204
-
205
- if (style === 'label') {
206
- return `.${valueEncoder(value)}`;
207
- }
296
+ switch (style) {
297
+ /**
298
+ * @example <caption>`style: simple`</caption>
299
+ * `blue` → `blue`
300
+ */
301
+ case 'simple':
302
+ return valueEncoder(value);
303
+
304
+ /**
305
+ * @example <caption>`style: label`</caption>
306
+ * `blue` → `.blue`
307
+ */
308
+ case 'label':
309
+ return `.${valueEncoder(value)}`;
310
+
311
+ /**
312
+ * @example <caption>`style: matrix`</caption>
313
+ * `blue` → `;color=blue`
314
+ */
315
+ case 'matrix':
316
+ if (value === '') {
317
+ return `;${key}`;
318
+ }
208
319
 
209
- if (style === 'matrix') {
210
- // This conditional added by Aaron to be more accurate to the spec
211
- if (value === '') {
212
- return `;${key}`;
213
- }
320
+ return `;${key}=${valueEncoder(value)}`;
214
321
 
215
- return `;${key}=${valueEncoder(value)}`;
216
- }
322
+ /**
323
+ * @example <caption>`style: form`</caption>
324
+ * `blue` → `color=blue`
325
+ */
326
+ case 'form':
327
+ return valueEncoder(value);
217
328
 
218
- if (style === 'form') {
219
- return valueEncoder(value);
220
- }
329
+ /**
330
+ * @example <caption>`style: deepObject`</caption>
331
+ * `blue` → n/a
332
+ */
333
+ case 'deepObject':
334
+ return valueEncoder(value, {}, true);
221
335
 
222
- if (style === 'deepObject') {
223
- return valueEncoder(value, {}, true);
336
+ default:
337
+ return undefined;
224
338
  }
225
-
226
- return undefined;
227
339
  }
@@ -1,7 +0,0 @@
1
- ## 🧰 What's being changed?
2
-
3
- Describe in detail what this PR is for.
4
-
5
- ## 🧬 Testing
6
-
7
- Provide as much information as you can on how to test what you've done.
@@ -1,26 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: github-actions
4
- directory: "/"
5
- schedule:
6
- interval: monthly
7
- reviewers:
8
- - erunion
9
- labels:
10
- - dependencies
11
- commit-message:
12
- prefix: chore(deps)
13
- prefix-development: chore(deps-dev)
14
-
15
- - package-ecosystem: npm
16
- directory: "/"
17
- schedule:
18
- interval: monthly
19
- open-pull-requests-limit: 10
20
- reviewers:
21
- - erunion
22
- labels:
23
- - dependencies
24
- commit-message:
25
- prefix: chore(deps)
26
- prefix-development: chore(deps-dev)
@@ -1,24 +0,0 @@
1
- name: CI
2
-
3
- on: [push]
4
-
5
- jobs:
6
- build:
7
- runs-on: ubuntu-latest
8
- strategy:
9
- matrix:
10
- node-version: [12.x, 14.x, 16.x]
11
-
12
- steps:
13
- - uses: actions/checkout@v2.4.0
14
-
15
- - name: Use Node.js ${{ matrix.node-version }}
16
- uses: actions/setup-node@v2.5.1
17
- with:
18
- node-version: ${{ matrix.node-version }}
19
-
20
- - name: Install deps
21
- run: npm ci
22
-
23
- - name: Run tests
24
- run: npm test
@@ -1,35 +0,0 @@
1
- name: "CodeQL"
2
-
3
- on:
4
- push:
5
- branches: [ main ]
6
- pull_request:
7
- branches: [ main ]
8
- schedule:
9
- - cron: '0 0 1 * *'
10
-
11
- jobs:
12
- analyze:
13
- name: Analyze
14
- runs-on: ubuntu-latest
15
- permissions:
16
- actions: read
17
- contents: read
18
- security-events: write
19
-
20
- strategy:
21
- fail-fast: false
22
- matrix:
23
- language: [ 'javascript' ]
24
-
25
- steps:
26
- - name: Checkout repository
27
- uses: actions/checkout@v2.4.0
28
-
29
- - name: Initialize CodeQL
30
- uses: github/codeql-action/init@v1
31
- with:
32
- languages: ${{ matrix.language }}
33
-
34
- - name: Perform CodeQL Analysis
35
- uses: github/codeql-action/analyze@v1
package/.husky/commit-msg DELETED
@@ -1,4 +0,0 @@
1
- #!/bin/sh
2
- . "$(dirname "$0")/_/husky.sh"
3
-
4
- npx commitlint --edit $1
@@ -1,128 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- We as members, contributors, and leaders pledge to make participation in our
6
- community a harassment-free experience for everyone, regardless of age, body
7
- size, visible or invisible disability, ethnicity, sex characteristics, gender
8
- identity and expression, level of experience, education, socio-economic status,
9
- nationality, personal appearance, race, religion, or sexual identity
10
- and orientation.
11
-
12
- We pledge to act and interact in ways that contribute to an open, welcoming,
13
- diverse, inclusive, and healthy community.
14
-
15
- ## Our Standards
16
-
17
- Examples of behavior that contributes to a positive environment for our
18
- community include:
19
-
20
- * Demonstrating empathy and kindness toward other people
21
- * Being respectful of differing opinions, viewpoints, and experiences
22
- * Giving and gracefully accepting constructive feedback
23
- * Accepting responsibility and apologizing to those affected by our mistakes,
24
- and learning from the experience
25
- * Focusing on what is best not just for us as individuals, but for the
26
- overall community
27
-
28
- Examples of unacceptable behavior include:
29
-
30
- * The use of sexualized language or imagery, and sexual attention or
31
- advances of any kind
32
- * Trolling, insulting or derogatory comments, and personal or political attacks
33
- * Public or private harassment
34
- * Publishing others' private information, such as a physical or email
35
- address, without their explicit permission
36
- * Other conduct which could reasonably be considered inappropriate in a
37
- professional setting
38
-
39
- ## Enforcement Responsibilities
40
-
41
- Community leaders are responsible for clarifying and enforcing our standards of
42
- acceptable behavior and will take appropriate and fair corrective action in
43
- response to any behavior that they deem inappropriate, threatening, offensive,
44
- or harmful.
45
-
46
- Community leaders have the right and responsibility to remove, edit, or reject
47
- comments, commits, code, wiki edits, issues, and other contributions that are
48
- not aligned to this Code of Conduct, and will communicate reasons for moderation
49
- decisions when appropriate.
50
-
51
- ## Scope
52
-
53
- This Code of Conduct applies within all community spaces, and also applies when
54
- an individual is officially representing the community in public spaces.
55
- Examples of representing our community include using an official e-mail address,
56
- posting via an official social media account, or acting as an appointed
57
- representative at an online or offline event.
58
-
59
- ## Enforcement
60
-
61
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
- reported to the community leaders responsible for enforcement at
63
- [support+coc@readme.io](mailto:support+coc@readme.io).
64
- All complaints will be reviewed and investigated promptly and fairly.
65
-
66
- All community leaders are obligated to respect the privacy and security of the
67
- reporter of any incident.
68
-
69
- ## Enforcement Guidelines
70
-
71
- Community leaders will follow these Community Impact Guidelines in determining
72
- the consequences for any action they deem in violation of this Code of Conduct:
73
-
74
- ### 1. Correction
75
-
76
- **Community Impact**: Use of inappropriate language or other behavior deemed
77
- unprofessional or unwelcome in the community.
78
-
79
- **Consequence**: A private, written warning from community leaders, providing
80
- clarity around the nature of the violation and an explanation of why the
81
- behavior was inappropriate. A public apology may be requested.
82
-
83
- ### 2. Warning
84
-
85
- **Community Impact**: A violation through a single incident or series
86
- of actions.
87
-
88
- **Consequence**: A warning with consequences for continued behavior. No
89
- interaction with the people involved, including unsolicited interaction with
90
- those enforcing the Code of Conduct, for a specified period of time. This
91
- includes avoiding interactions in community spaces as well as external channels
92
- like social media. Violating these terms may lead to a temporary or
93
- permanent ban.
94
-
95
- ### 3. Temporary Ban
96
-
97
- **Community Impact**: A serious violation of community standards, including
98
- sustained inappropriate behavior.
99
-
100
- **Consequence**: A temporary ban from any sort of interaction or public
101
- communication with the community for a specified period of time. No public or
102
- private interaction with the people involved, including unsolicited interaction
103
- with those enforcing the Code of Conduct, is allowed during this period.
104
- Violating these terms may lead to a permanent ban.
105
-
106
- ### 4. Permanent Ban
107
-
108
- **Community Impact**: Demonstrating a pattern of violation of community
109
- standards, including sustained inappropriate behavior, harassment of an
110
- individual, or aggression toward or disparagement of classes of individuals.
111
-
112
- **Consequence**: A permanent ban from any sort of public interaction within
113
- the community.
114
-
115
- ## Attribution
116
-
117
- This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
- version 2.0, available at
119
- https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120
-
121
- Community Impact Guidelines were inspired by [Mozilla's code of conduct
122
- enforcement ladder](https://github.com/mozilla/diversity).
123
-
124
- [homepage]: https://www.contributor-covenant.org
125
-
126
- For answers to common questions about this code of conduct, see the FAQ at
127
- https://www.contributor-covenant.org/faq. Translations are available at
128
- https://www.contributor-covenant.org/translations.
package/SECURITY.md DELETED
@@ -1,12 +0,0 @@
1
- # Security Policy
2
-
3
- ## Reporting a Vulnerability
4
-
5
- If there are any vulnerabilities in `@readme/oas-to-har`, don't hesitate to _report them_.
6
-
7
- Please email security@readme.io and describe what you've found.
8
-
9
- - If you have a fix, explain or attach it.
10
- - In the near time, expect a reply with the required steps. Also, there may be a demand for a pull request which include the fixes.
11
-
12
- > You should not disclose the vulnerability publicly if you haven't received an answer in some weeks. If the vulnerability is rejected, you may post it publicly within some hour of rejection, unless the rejection is withdrawn within that time period. After the vulnerability has been fixed, you may disclose the vulnerability details publicly over some days.
@@ -1,56 +0,0 @@
1
- function isEmptyObject(obj) {
2
- // Then remove all empty objects from the top level object
3
- return typeof obj === 'object' && Object.keys(obj).length === 0;
4
- }
5
-
6
- // Modified from here: https://stackoverflow.com/a/43781499
7
- function stripEmptyObjects(obj) {
8
- let cleanObj = obj;
9
-
10
- Object.keys(cleanObj).forEach(key => {
11
- let value = cleanObj[key];
12
-
13
- if (typeof value === 'object' && !Array.isArray(cleanObj) && value !== null) {
14
- // Recurse, strip out empty objects from children
15
- value = stripEmptyObjects(value);
16
-
17
- // Then remove all empty objects from the top level object
18
- if (isEmptyObject(value)) {
19
- delete cleanObj[key];
20
- } else {
21
- cleanObj[key] = value;
22
- }
23
- } else if (value === null) {
24
- delete cleanObj[key];
25
- }
26
- });
27
-
28
- if (Array.isArray(cleanObj)) {
29
- // Since deleting a key from an array will retain an undefined value in that array, we need to
30
- // filter them out.
31
- cleanObj = cleanObj.filter(function (el) {
32
- return el !== undefined;
33
- });
34
- }
35
-
36
- return cleanObj;
37
- }
38
-
39
- function removeUndefinedObjects(obj) {
40
- // JSON.stringify removes undefined values. Though `[undefined]` will be converted with this to
41
- // `[null]`, we'll clean that up next.
42
- let withoutUndefined = JSON.parse(JSON.stringify(obj));
43
-
44
- // Then we recursively remove all empty objects and nullish arrays.
45
- withoutUndefined = stripEmptyObjects(withoutUndefined);
46
-
47
- // If the only thing that's leftover is an empty object
48
- // then return nothing so we don't end up with default
49
- // code samples with:
50
- // --data '{}'
51
- if (isEmptyObject(withoutUndefined)) return undefined;
52
-
53
- return withoutUndefined;
54
- }
55
-
56
- module.exports = removeUndefinedObjects;