oas 20.10.1 → 20.10.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.
@@ -77,6 +77,14 @@ function reducer(definition, opts) {
77
77
  }
78
78
  // Stringify and parse so we get a full non-reference clone of the API definition to work with.
79
79
  var reduced = JSON.parse(JSON.stringify(definition));
80
+ // Retain any root-level security definitions.
81
+ if ('security' in reduced) {
82
+ Object.values(reduced.security).forEach(function (sec) {
83
+ Object.keys(sec).forEach(function (scheme) {
84
+ $refs.add("#/components/securitySchemes/".concat(scheme));
85
+ });
86
+ });
87
+ }
80
88
  if ('paths' in reduced) {
81
89
  Object.keys(reduced.paths).forEach(function (path) {
82
90
  var pathLC = path.toLowerCase();
@@ -1,7 +1,9 @@
1
+ import type { MediaTypeExample } from '../lib/get-mediatype-examples';
1
2
  import type * as RMOAS from '../rmoas.types';
2
3
  export type ResponseExamples = {
3
- mediaTypes: Record<string, RMOAS.MediaTypeObject>;
4
+ mediaTypes: Record<string, MediaTypeExample[]>;
4
5
  status: string;
6
+ onlyHeaders?: boolean;
5
7
  }[];
6
8
  /**
7
9
  * Retrieve a collection of response examples keyed, by their media type.
@@ -50,8 +50,7 @@ exports.isFunc = isFunc;
50
50
  // `predicate` can be used to discriminate the stripping further,
51
51
  // by preserving the key's place in the object based on its value.
52
52
  // @todo make this have a better type than `any`
53
- function deeplyStripKey(input, keyToStrip, predicate // eslint-disable-line @typescript-eslint/no-unused-vars
54
- ) {
53
+ function deeplyStripKey(input, keyToStrip, predicate) {
55
54
  if (predicate === void 0) { predicate = function (obj, key) { return true; }; }
56
55
  if (typeof input !== 'object' || Array.isArray(input) || input === null || !keyToStrip) {
57
56
  return input;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oas",
3
- "version": "20.10.1",
3
+ "version": "20.10.3",
4
4
  "description": "Comprehensive tooling for working with OpenAPI definitions",
5
5
  "license": "MIT",
6
6
  "author": "ReadMe <support@readme.io> (https://readme.com)",
@@ -32,16 +32,17 @@
32
32
  },
33
33
  "scripts": {
34
34
  "build": "tsc",
35
- "lint": "eslint . --ext .js,.ts",
35
+ "lint": "npm run lint:types; npm run lint:js; npm run lint:docs; npm run prettier",
36
+ "lint:js": "eslint . --ext .js,.ts",
36
37
  "lint:docs": "npx -y alex .",
38
+ "lint:types": "tsc --noEmit",
37
39
  "prebuild": "rm -rf dist/",
38
40
  "prepack": "npm run build",
39
41
  "prepare": "husky install",
40
- "pretest": "npm run lint",
41
- "prettier": "prettier --list-different \"./**/**.{js,ts,md}\"",
42
- "prettier:write": "prettier --list-different --write \"./**/**.{js,ts,md}\"",
43
- "test": "tsc; jest --coverage",
44
- "test-watch": "tsc; jest --watch",
42
+ "pretest": "npm run build",
43
+ "prettier": "prettier --check .",
44
+ "prettier:fix": "prettier --check --write .",
45
+ "test": "vitest --coverage",
45
46
  "watch": "tsc --watch"
46
47
  },
47
48
  "dependencies": {
@@ -57,21 +58,20 @@
57
58
  "remove-undefined-objects": "^3.0.0"
58
59
  },
59
60
  "devDependencies": {
60
- "@commitlint/cli": "^17.6.6",
61
- "@commitlint/config-conventional": "^17.6.6",
62
- "@readme/eslint-config": "^10.6.2",
63
- "@readme/oas-examples": "^5.11.1",
61
+ "@commitlint/cli": "^17.7.1",
62
+ "@commitlint/config-conventional": "^17.7.0",
63
+ "@readme/eslint-config": "^12.1.0",
64
+ "@readme/oas-examples": "^5.12.0",
64
65
  "@readme/openapi-parser": "^2.5.0",
65
- "@types/jest": "^29.5.3",
66
66
  "@types/json-schema-merge-allof": "^0.6.1",
67
67
  "@types/memoizee": "^0.4.6",
68
- "@types/node": "^20.4.1",
69
- "eslint": "^8.44.0",
68
+ "@types/node": "^20.5.3",
69
+ "@vitest/coverage-v8": "^0.34.2",
70
+ "eslint": "^8.47.0",
70
71
  "husky": "^8.0.3",
71
- "jest": "^29.6.1",
72
- "prettier": "^2.8.8",
73
- "ts-jest": "^29.1.1",
74
- "typescript": "^5.1.6"
72
+ "prettier": "^3.0.2",
73
+ "typescript": "^5.1.6",
74
+ "vitest": "^0.34.2"
75
75
  },
76
76
  "prettier": "@readme/eslint-config/prettier",
77
77
  "commitlint": {
@@ -77,8 +77,8 @@ export function mediaTypes(definition: OASDocument) {
77
77
  // into `['application/json', 'text/xml']`.
78
78
  return Object.keys(res.value);
79
79
  })
80
- .flat()
81
- )
80
+ .flat(),
81
+ ),
82
82
  );
83
83
 
84
84
  results.sort();
@@ -103,7 +103,7 @@ export function parameterSerialization(definition: OASDocument) {
103
103
  */
104
104
  export function polymorphism(definition: OASDocument) {
105
105
  const results = Array.from(
106
- new Set(query(['$..allOf^', '$..anyOf^', '$..oneOf^'], definition).map(res => refizePointer(res.pointer)))
106
+ new Set(query(['$..allOf^', '$..anyOf^', '$..oneOf^'], definition).map(res => refizePointer(res.pointer))),
107
107
  );
108
108
 
109
109
  results.sort();
@@ -179,6 +179,6 @@ export function xml(definition: OASDocument) {
179
179
  "$..responses..['text/xml-external-parsed-entity']",
180
180
  '$..responses[*].content[?(@property.match(/\\+xml$/i))]',
181
181
  ],
182
- definition
182
+ definition,
183
183
  ).map(res => refizePointer(res.pointer));
184
184
  }
@@ -23,8 +23,8 @@ export function codeSampleLanguages(definition: OASDocument) {
23
23
  new Set(
24
24
  query(["$..['x-readme']['samples-languages']", "$..['x-samples-languages']"], definition)
25
25
  .map(res => res.value as string)
26
- .reduce((prev, next) => prev.concat(next), [])
27
- )
26
+ .reduce((prev, next) => prev.concat(next), []),
27
+ ),
28
28
  );
29
29
 
30
30
  results.sort();
@@ -47,9 +47,9 @@ export function codeSamplesDisabled(definition: OASDocument) {
47
47
  "$..paths[*]..['x-samples-enabled']^",
48
48
  "$..paths[*]..['x-readme']['samples-enabled']^^",
49
49
  ],
50
- definition
51
- ).map(res => refizePointer(res.pointer))
52
- )
50
+ definition,
51
+ ).map(res => refizePointer(res.pointer)),
52
+ ),
53
53
  );
54
54
  }
55
55
 
@@ -69,9 +69,9 @@ export function corsProxyDisabled(definition: OASDocument) {
69
69
  "$..paths[*]..['x-proxy-enabled']^",
70
70
  "$..paths[*]..['x-readme']['proxy-enabled']^^",
71
71
  ],
72
- definition
73
- ).map(res => refizePointer(res.pointer))
74
- )
72
+ definition,
73
+ ).map(res => refizePointer(res.pointer)),
74
+ ),
75
75
  );
76
76
  }
77
77
 
@@ -104,7 +104,7 @@ export function explorerDisabled(definition: OASDocument) {
104
104
  "$..paths[*]..['x-explorer-enabled']^",
105
105
  "$..paths[*]..['x-readme']['explorer-enabled']^^",
106
106
  ],
107
- definition
107
+ definition,
108
108
  ).map(res => refizePointer(res.pointer));
109
109
  }
110
110
 
package/src/index.ts CHANGED
@@ -463,7 +463,7 @@ export default class Oas {
463
463
  }
464
464
 
465
465
  return original;
466
- })
466
+ }),
467
467
  );
468
468
  }
469
469
 
@@ -481,7 +481,7 @@ export default class Oas {
481
481
  * If you prefer to first look for a webhook with this path and method.
482
482
  */
483
483
  isWebhook?: boolean;
484
- } = {}
484
+ } = {},
485
485
  ) {
486
486
  // If we're unable to locate an operation for this path+method combination within the API
487
487
  // definition, we should still set an empty schema on the operation in the `Operation` class
@@ -806,7 +806,7 @@ export default class Oas {
806
806
  * Preserve component schema names within themselves as a `title`.
807
807
  */
808
808
  preserveRefAsJSONSchemaTitle?: boolean;
809
- } = { preserveRefAsJSONSchemaTitle: false }
809
+ } = { preserveRefAsJSONSchemaTitle: false },
810
810
  ) {
811
811
  if (this.dereferencing.complete) {
812
812
  return new Promise(resolve => {
@@ -9,7 +9,7 @@ import * as RMOAS from '../rmoas.types';
9
9
  */
10
10
  export default function dedupeCommonParameters(
11
11
  parameters: RMOAS.ParameterObject[],
12
- commonParameters: RMOAS.ParameterObject[]
12
+ commonParameters: RMOAS.ParameterObject[],
13
13
  ) {
14
14
  return commonParameters.filter((param: RMOAS.ParameterObject) => {
15
15
  return !parameters.find((param2: RMOAS.ParameterObject) => {
@@ -45,13 +45,13 @@ function getKey(user: RMOAS.User, scheme: RMOAS.KeyedSecuritySchemeObject): auth
45
45
  export function getByScheme(
46
46
  user: RMOAS.User,
47
47
  scheme = <RMOAS.KeyedSecuritySchemeObject>{},
48
- selectedApp?: string | number
48
+ selectedApp?: string | number,
49
49
  ): authKey {
50
50
  if (user?.keys && user.keys.length) {
51
51
  if (selectedApp) {
52
52
  return getKey(
53
53
  user.keys.find(key => key.name === selectedApp),
54
- scheme
54
+ scheme,
55
55
  );
56
56
  }
57
57
 
@@ -72,7 +72,7 @@ export function getByScheme(
72
72
  export default function getAuth(
73
73
  api: OpenAPIV3.Document | OpenAPIV3_1.Document,
74
74
  user: RMOAS.User,
75
- selectedApp?: string | number
75
+ selectedApp?: string | number,
76
76
  ) {
77
77
  return Object.keys(api?.components?.securitySchemes || {})
78
78
  .map(scheme => {
@@ -85,7 +85,7 @@ export default function getAuth(
85
85
  ...(api.components.securitySchemes[scheme] as RMOAS.SecuritySchemeObject),
86
86
  _key: scheme,
87
87
  },
88
- selectedApp
88
+ selectedApp,
89
89
  ),
90
90
  };
91
91
  })
@@ -34,7 +34,7 @@ export default function getMediaTypeExamples(
34
34
  * If you wish to include data that's flatted as `writeOnly`.
35
35
  */
36
36
  includeWriteOnly?: boolean;
37
- } = {}
37
+ } = {},
38
38
  ) {
39
39
  if (mediaTypeObject.example) {
40
40
  return [
@@ -12,14 +12,14 @@ export default {
12
12
  json: (contentType: string): boolean => {
13
13
  return matchesMediaType(
14
14
  ['application/json', 'application/x-json', 'text/json', 'text/x-json', '+json'],
15
- contentType
15
+ contentType,
16
16
  );
17
17
  },
18
18
 
19
19
  multipart: (contentType: string): boolean => {
20
20
  return matchesMediaType(
21
21
  ['multipart/mixed', 'multipart/related', 'multipart/form-data', 'multipart/alternative'],
22
- contentType
22
+ contentType,
23
23
  );
24
24
  },
25
25
 
@@ -37,7 +37,7 @@ export default {
37
37
  'text/xml-external-parsed-entity',
38
38
  '+xml',
39
39
  ],
40
- contentType
40
+ contentType,
41
41
  );
42
42
  },
43
43
  };
@@ -193,7 +193,7 @@ function isRequestBodySchema(schema: unknown): schema is RMOAS.RequestBodyObject
193
193
  function searchForValueByPropAndPointer(
194
194
  property: 'example' | 'default',
195
195
  pointer: string,
196
- schemas: toJSONSchemaOptions['prevExampleSchemas'] | toJSONSchemaOptions['prevDefaultSchemas'] = []
196
+ schemas: toJSONSchemaOptions['prevExampleSchemas'] | toJSONSchemaOptions['prevDefaultSchemas'] = [],
197
197
  ) {
198
198
  if (!schemas.length || !pointer.length) {
199
199
  return undefined;
@@ -289,7 +289,7 @@ function searchForValueByPropAndPointer(
289
289
  */
290
290
  export default function toJSONSchema(
291
291
  data: RMOAS.SchemaObject | boolean,
292
- opts: toJSONSchemaOptions = {}
292
+ opts: toJSONSchemaOptions = {},
293
293
  ): RMOAS.SchemaObject {
294
294
  let schema = data === true ? {} : { ...data };
295
295
  const schemaAdditionalProperties = RMOAS.isSchema(schema) ? schema.additionalProperties : null;
@@ -421,12 +421,12 @@ export default function toJSONSchema(
421
421
  if ('properties' in schema) {
422
422
  schema[polyType][idx] = toJSONSchema(
423
423
  { allOf: [item, { properties: schema.properties }] } as RMOAS.SchemaObject,
424
- polyOptions
424
+ polyOptions,
425
425
  );
426
426
  } else if ('items' in schema) {
427
427
  schema[polyType][idx] = toJSONSchema(
428
428
  { allOf: [item, { items: schema.items }] } as RMOAS.SchemaObject,
429
- polyOptions
429
+ polyOptions,
430
430
  );
431
431
  } else {
432
432
  schema[polyType][idx] = toJSONSchema(item as RMOAS.SchemaObject, polyOptions);
@@ -88,6 +88,15 @@ export default function reducer(definition: OASDocument, opts: ReducerOptions =
88
88
  // Stringify and parse so we get a full non-reference clone of the API definition to work with.
89
89
  const reduced = JSON.parse(JSON.stringify(definition)) as OASDocument;
90
90
 
91
+ // Retain any root-level security definitions.
92
+ if ('security' in reduced) {
93
+ Object.values(reduced.security).forEach(sec => {
94
+ Object.keys(sec).forEach(scheme => {
95
+ $refs.add(`#/components/securitySchemes/${scheme}`);
96
+ });
97
+ });
98
+ }
99
+
91
100
  if ('paths' in reduced) {
92
101
  Object.keys(reduced.paths).forEach(path => {
93
102
  const pathLC = path.toLowerCase();
@@ -39,9 +39,9 @@ export default function getCallbackExamples(operation: RMOAS.OperationObject) {
39
39
  example,
40
40
  };
41
41
  });
42
- })
42
+ }),
43
43
  )
44
44
  .filter(Boolean);
45
- })
45
+ }),
46
46
  );
47
47
  }
@@ -79,7 +79,7 @@ export interface getParametersAsJSONSchemaOptions {
79
79
  export default function getParametersAsJSONSchema(
80
80
  operation: Operation,
81
81
  api: OASDocument,
82
- opts?: getParametersAsJSONSchemaOptions
82
+ opts?: getParametersAsJSONSchemaOptions,
83
83
  ) {
84
84
  let hasCircularRefs = false;
85
85
  let hasDiscriminatorMappingRefs = false;
@@ -33,7 +33,7 @@ function buildHeadersSchema(
33
33
  * just make sure to return your transformed schema.
34
34
  */
35
35
  transformer?: (schema: SchemaObject) => SchemaObject;
36
- }
36
+ },
37
37
  ) {
38
38
  const headers = response.headers;
39
39
 
@@ -99,7 +99,7 @@ export default function getResponseAsJSONSchema(
99
99
  * name, just make sure to return your transformed schema.
100
100
  */
101
101
  transformer?: (schema: SchemaObject) => SchemaObject;
102
- }
102
+ },
103
103
  ) {
104
104
  const response = operation.getResponseByStatusCode(statusCode);
105
105
  const jsonSchema = [];
@@ -5,8 +5,9 @@ import getMediaTypeExamples from '../lib/get-mediatype-examples';
5
5
  import { isRef } from '../rmoas.types';
6
6
 
7
7
  export type ResponseExamples = {
8
- mediaTypes: Record<string, RMOAS.MediaTypeObject>;
8
+ mediaTypes: Record<string, MediaTypeExample[]>;
9
9
  status: string;
10
+ onlyHeaders?: boolean;
10
11
  }[];
11
12
 
12
13
  /**
package/src/operation.ts CHANGED
@@ -170,7 +170,7 @@ export default class Operation {
170
170
  * security schemes, rather than returning `false`.
171
171
  */
172
172
  getSecurityWithTypes(
173
- filterInvalid = false
173
+ filterInvalid = false,
174
174
  ): (false | (false | { security: RMOAS.KeyedSecuritySchemeObject; type: SecurityType })[])[] {
175
175
  const securityRequirements = this.getSecurity();
176
176
 
@@ -233,23 +233,26 @@ export default class Operation {
233
233
  prepareSecurity(): Record<SecurityType, RMOAS.KeyedSecuritySchemeObject[]> {
234
234
  const securitiesWithTypes = this.getSecurityWithTypes();
235
235
 
236
- return securitiesWithTypes.reduce((prev, securities) => {
237
- if (!securities) return prev;
236
+ return securitiesWithTypes.reduce(
237
+ (prev, securities) => {
238
+ if (!securities) return prev;
238
239
 
239
- securities.forEach(security => {
240
- // Remove non-existent schemes
241
- if (!security) return;
242
- if (!prev[security.type]) prev[security.type] = [];
240
+ securities.forEach(security => {
241
+ // Remove non-existent schemes
242
+ if (!security) return;
243
+ if (!prev[security.type]) prev[security.type] = [];
243
244
 
244
- // Only add schemes we haven't seen yet.
245
- const exists = prev[security.type].findIndex(sec => sec._key === security.security._key);
246
- if (exists < 0) {
247
- prev[security.type].push(security.security);
248
- }
249
- });
245
+ // Only add schemes we haven't seen yet.
246
+ const exists = prev[security.type].findIndex(sec => sec._key === security.security._key);
247
+ if (exists < 0) {
248
+ prev[security.type].push(security.security);
249
+ }
250
+ });
250
251
 
251
- return prev;
252
- }, {} as Record<SecurityType, RMOAS.KeyedSecuritySchemeObject[]>);
252
+ return prev;
253
+ },
254
+ {} as Record<SecurityType, RMOAS.KeyedSecuritySchemeObject[]>,
255
+ );
253
256
  }
254
257
 
255
258
  getHeaders(): Operation['headers'] {
@@ -281,7 +284,7 @@ export default class Operation {
281
284
  if (p.in && p.in === 'header') return p.name;
282
285
  return undefined;
283
286
  })
284
- .filter(p => p)
287
+ .filter(p => p),
285
288
  );
286
289
  }
287
290
 
@@ -291,7 +294,7 @@ export default class Operation {
291
294
  .filter(r => (this.schema.responses[r] as RMOAS.ResponseObject).headers)
292
295
  .map(r =>
293
296
  // Remove the reference object because we will have already dereferenced
294
- Object.keys((this.schema.responses[r] as RMOAS.ResponseObject).headers)
297
+ Object.keys((this.schema.responses[r] as RMOAS.ResponseObject).headers),
295
298
  )
296
299
  .reduce((a, b) => a.concat(b), []);
297
300
  }
@@ -313,7 +316,7 @@ export default class Operation {
313
316
  if (this.schema.responses) {
314
317
  if (
315
318
  Object.keys(this.schema.responses).some(
316
- response => !!(this.schema.responses[response] as RMOAS.ResponseObject).content
319
+ response => !!(this.schema.responses[response] as RMOAS.ResponseObject).content,
317
320
  )
318
321
  ) {
319
322
  if (!this.headers.request.includes('Accept')) this.headers.request.push('Accept');
@@ -501,7 +504,7 @@ export default class Operation {
501
504
  * name, just make sure to return your transformed schema.
502
505
  */
503
506
  transformer?: (schema: RMOAS.SchemaObject) => RMOAS.SchemaObject;
504
- } = {}
507
+ } = {},
505
508
  ) {
506
509
  return getResponseAsJSONSchema(this, this.api, statusCode, {
507
510
  includeDiscriminatorMappingRefs: true,
@@ -804,7 +807,7 @@ export class Callback extends Operation {
804
807
  method: RMOAS.HttpMethods,
805
808
  operation: RMOAS.OperationObject,
806
809
  identifier: string,
807
- parentPathItem: RMOAS.PathItemObject
810
+ parentPathItem: RMOAS.PathItemObject,
808
811
  ) {
809
812
  super(oas, path, method, operation);
810
813
 
@@ -80,7 +80,7 @@ function sampleFromSchema(
80
80
  * If you wish to include data that's flatted as `writeOnly`.
81
81
  */
82
82
  includeWriteOnly?: boolean;
83
- } = {}
83
+ } = {},
84
84
  ): string | number | boolean | null | unknown[] | Record<string, unknown> | undefined {
85
85
  const objectifySchema = objectify(schema);
86
86
  let { type } = objectifySchema;
@@ -96,7 +96,7 @@ function sampleFromSchema(
96
96
  defaultResolver: mergeJSONSchemaAllOf.options.resolvers.title,
97
97
  },
98
98
  }),
99
- opts
99
+ opts,
100
100
  );
101
101
  } catch (error) {
102
102
  return undefined;
@@ -49,7 +49,7 @@ export function isFunc(thing: unknown): thing is Function {
49
49
  export function deeplyStripKey(
50
50
  input: unknown,
51
51
  keyToStrip: string,
52
- predicate = (obj: unknown, key?: string): boolean => true // eslint-disable-line @typescript-eslint/no-unused-vars
52
+ predicate = (obj: unknown, key?: string): boolean => true, // eslint-disable-line @typescript-eslint/no-unused-vars
53
53
  ): any | RMOAS.SchemaObject {
54
54
  if (typeof input !== 'object' || Array.isArray(input) || input === null || !keyToStrip) {
55
55
  return input;