oas 17.8.1 → 18.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.
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Lookup a reference pointer within an OpenAPI definition and return the schema that it resolves to.
3
3
  *
4
+ * @deprecated
4
5
  * @param $ref Reference to look up a schema for.
5
6
  * @param definitions OpenAPI definition to look for the `$ref` pointer in.
6
7
  */
@@ -15,9 +15,8 @@ export declare type SchemaWrapper = {
15
15
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameterObject}
16
16
  */
17
17
  export declare const types: Record<keyof RMOAS.OASDocument, string>;
18
- /**
19
- * @param operation
20
- * @param api
21
- * @param globalDefaults
22
- */
23
- export default function getParametersAsJsonSchema(operation: Operation, api: OASDocument, globalDefaults?: {}): SchemaWrapper[];
18
+ export default function getParametersAsJsonSchema(operation: Operation, api: OASDocument, opts?: {
19
+ globalDefaults?: Record<string, unknown>;
20
+ mergeIntoBodyAndMetadata?: boolean;
21
+ retainDeprecatedProperties?: boolean;
22
+ }): SchemaWrapper[];
@@ -1,7 +1,6 @@
1
1
  import type { RequestBodyExamples } from './operation/get-requestbody-examples';
2
2
  import type { CallbackExamples } from './operation/get-callback-examples';
3
3
  import type { ResponseExamples } from './operation/get-response-examples';
4
- import type { SchemaWrapper } from './operation/get-parameters-as-json-schema';
5
4
  import * as RMOAS from './rmoas.types';
6
5
  declare type SecurityType = 'Basic' | 'Bearer' | 'Query' | 'Header' | 'Cookie' | 'OAuth2' | 'http' | 'apiKey';
7
6
  export default class Operation {
@@ -44,10 +43,6 @@ export default class Operation {
44
43
  request: string[];
45
44
  response: string[];
46
45
  };
47
- /**
48
- * All parameters and request bodies converted into JSON Schema.
49
- */
50
- parameterJsonSchema: SchemaWrapper[];
51
46
  constructor(api: RMOAS.OASDocument, path: string, method: RMOAS.HttpMethods, operation: RMOAS.OperationObject);
52
47
  getSummary(): string;
53
48
  getDescription(): string;
@@ -127,9 +122,19 @@ export default class Operation {
127
122
  * Convert the operation into an array of JSON Schema schemas for each available type of parameter available on the
128
123
  * operation.
129
124
  *
130
- * @param globalDefaults Contains an object of user defined schema defaults.
131
- */
132
- getParametersAsJsonSchema(globalDefaults?: Record<string, unknown>): SchemaWrapper[];
125
+ * @param opts
126
+ * @param opts.globalDefaults Contains an object of user defined schema defaults.
127
+ * @param opts.mergeIntoBodyAndMetadata If you want the output to be two objects: body (contains
128
+ * `body` and `formData` JSON Schema) and metadata (contains `path`, `query`, `cookie`, and
129
+ * `header`).
130
+ * @param opts.retainDeprecatedProperties If you wish to **not** split out deprecated properties
131
+ * into a separate `deprecatedProps` object.
132
+ */
133
+ getParametersAsJsonSchema(opts?: {
134
+ globalDefaults?: Record<string, unknown>;
135
+ mergeIntoBodyAndMetadata?: boolean;
136
+ retainDeprecatedProperties?: boolean;
137
+ }): import("./operation/get-parameters-as-json-schema").SchemaWrapper[];
133
138
  /**
134
139
  * Get a single response for this status code, formatted as JSON schema.
135
140
  *
@@ -111,6 +111,7 @@ export declare type HeaderObject = OpenAPIV3.HeaderObject | OpenAPIV3_1.HeaderOb
111
111
  * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schemaObject}
112
112
  */
113
113
  export declare type SchemaObject = (OpenAPIV3.SchemaObject | OpenAPIV3_1.SchemaObject | JSONSchema) & {
114
+ $schema?: string;
114
115
  deprecated?: boolean;
115
116
  readOnly?: boolean;
116
117
  writeOnly?: boolean;
package/@types/utils.d.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  import findSchemaDefinition from './lib/find-schema-definition';
2
- import getSchema from './lib/get-schema';
3
2
  declare const supportedMethods: Set<string>;
4
3
  declare const _default: {
5
4
  findSchemaDefinition: typeof findSchemaDefinition;
6
- getSchema: typeof getSchema;
7
5
  jsonSchemaTypes: Record<string, string>;
8
6
  matchesMimeType: {
9
7
  formUrlEncoded: (mimeType: string) => boolean;
package/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## 18.0.0 (2022-03-08)
2
+
3
+ > **BREAKING CHANGE**
4
+ >
5
+ > The method signature for `Operation.getParametersAsJsonSchema()` has been slightly altered and the `getSchema` export has been removed. If you don't use any of the tooling library offered by this library then you don't need to do anything!
6
+
7
+ * chore(deps-dev): bumping dev deps ([08833bb](https://github.com/readmeio/oas/commit/08833bb))
8
+ * docs: integrating alex into our documentation process (#618) ([4c08f13](https://github.com/readmeio/oas/commit/4c08f13)), closes [#618](https://github.com/readmeio/oas/issues/618)
9
+ * feat: adding new options to `getParametersAsJsonSchema` (#617) ([7b17b9f](https://github.com/readmeio/oas/commit/7b17b9f)), closes [#617](https://github.com/readmeio/oas/issues/617)
10
+ * feat: removing getSchema, deprecating findSchemaDefinition (#600) ([161611f](https://github.com/readmeio/oas/commit/161611f)), closes [#600](https://github.com/readmeio/oas/issues/600)
11
+
12
+
13
+
1
14
  ## <small>17.8.1 (2022-03-04)</small>
2
15
 
3
16
  * fix: typo in the `--pattern` option ([42db80a](https://github.com/readmeio/oas/commit/42db80a))
@@ -8,6 +8,7 @@ var jsonpointer_1 = __importDefault(require("jsonpointer"));
8
8
  /**
9
9
  * Lookup a reference pointer within an OpenAPI definition and return the schema that it resolves to.
10
10
  *
11
+ * @deprecated
11
12
  * @param $ref Reference to look up a schema for.
12
13
  * @param definitions OpenAPI definition to look for the `$ref` pointer in.
13
14
  */
@@ -54,7 +54,8 @@ exports.types = {
54
54
  body: 'Body Params',
55
55
  cookie: 'Cookie Params',
56
56
  formData: 'Form Data',
57
- header: 'Headers'
57
+ header: 'Headers',
58
+ metadata: 'Metadata'
58
59
  };
59
60
  function getSchemaVersionString(schema, api) {
60
61
  // If we're not on version 3.1.0, we always fall back to the default schema version for pre 3.1.0
@@ -77,19 +78,18 @@ function getSchemaVersionString(schema, api) {
77
78
  function cloneObject(obj) {
78
79
  return JSON.parse(JSON.stringify(obj));
79
80
  }
80
- /**
81
- * @param operation
82
- * @param api
83
- * @param globalDefaults
84
- */
85
- function getParametersAsJsonSchema(operation, api, globalDefaults) {
81
+ function getParametersAsJsonSchema(operation, api, opts) {
86
82
  var _a;
87
- if (globalDefaults === void 0) { globalDefaults = {}; }
88
83
  var hasCircularRefs = false;
89
84
  function refLogger() {
90
85
  hasCircularRefs = true;
91
86
  }
92
87
  function getDeprecated(schema, type) {
88
+ // If we wish to retain deprecated properties then we shouldn't split them out into the
89
+ // `deprecatedProps` object.
90
+ if (opts.retainDeprecatedProperties) {
91
+ return null;
92
+ }
93
93
  // If there's no properties, bail
94
94
  if (!schema || !schema.properties)
95
95
  return null;
@@ -107,7 +107,11 @@ function getParametersAsJsonSchema(operation, api, globalDefaults) {
107
107
  });
108
108
  // We know this is the right type. todo: don't use as
109
109
  deprecatedBody.properties = allDeprecatedProps;
110
- var deprecatedSchema = (0, openapi_to_json_schema_1["default"])(deprecatedBody, { globalDefaults: globalDefaults, prevSchemas: [], refLogger: refLogger });
110
+ var deprecatedSchema = (0, openapi_to_json_schema_1["default"])(deprecatedBody, {
111
+ globalDefaults: opts.globalDefaults,
112
+ prevSchemas: [],
113
+ refLogger: refLogger
114
+ });
111
115
  // Check if the schema wasn't created or there's no deprecated properties
112
116
  if (Object.keys(deprecatedSchema).length === 0 || Object.keys(deprecatedSchema.properties).length === 0) {
113
117
  return null;
@@ -152,7 +156,7 @@ function getParametersAsJsonSchema(operation, api, globalDefaults) {
152
156
  // We're cloning the request schema because we've had issues with request schemas that were dereferenced being
153
157
  // processed multiple times because their component is also processed.
154
158
  var requestSchema = cloneObject(mediaTypeObject.schema);
155
- var cleanedSchema = (0, openapi_to_json_schema_1["default"])(requestSchema, { globalDefaults: globalDefaults, prevSchemas: prevSchemas, refLogger: refLogger });
159
+ var cleanedSchema = (0, openapi_to_json_schema_1["default"])(requestSchema, { globalDefaults: opts.globalDefaults, prevSchemas: prevSchemas, refLogger: refLogger });
156
160
  // If this schema is **still** empty, don't bother returning it.
157
161
  if (!Object.keys(cleanedSchema).length) {
158
162
  return null;
@@ -177,7 +181,7 @@ function getParametersAsJsonSchema(operation, api, globalDefaults) {
177
181
  Object.keys(api.components[componentType]).forEach(function (schemaName) {
178
182
  var componentSchema = cloneObject(api.components[componentType][schemaName]);
179
183
  components[componentType][schemaName] = (0, openapi_to_json_schema_1["default"])(componentSchema, {
180
- globalDefaults: globalDefaults,
184
+ globalDefaults: opts.globalDefaults,
181
185
  refLogger: refLogger
182
186
  });
183
187
  });
@@ -187,7 +191,8 @@ function getParametersAsJsonSchema(operation, api, globalDefaults) {
187
191
  }
188
192
  function transformParameters() {
189
193
  var operationParams = operation.getParameters();
190
- return Object.keys(exports.types).map(function (type) {
194
+ var transformed = Object.keys(exports.types)
195
+ .map(function (type) {
191
196
  var required = [];
192
197
  // This `as` actually *could* be a ref, but we don't want refs to pass through here, so `.in` will never match `type`
193
198
  var parameters = operationParams.filter(function (param) { return param["in"] === type; });
@@ -212,7 +217,7 @@ function getParametersAsJsonSchema(operation, api, globalDefaults) {
212
217
  currentSchema.deprecated = current.deprecated;
213
218
  schema = __assign(__assign({}, (0, openapi_to_json_schema_1["default"])(currentSchema, {
214
219
  currentLocation: "/".concat(current.name),
215
- globalDefaults: globalDefaults,
220
+ globalDefaults: opts.globalDefaults,
216
221
  refLogger: refLogger
217
222
  })), {
218
223
  // Note: this applies a $schema version to each field in the larger schema object. It's not really *correct*
@@ -255,7 +260,7 @@ function getParametersAsJsonSchema(operation, api, globalDefaults) {
255
260
  currentSchema.deprecated = current.deprecated;
256
261
  schema = __assign(__assign({}, (0, openapi_to_json_schema_1["default"])(currentSchema, {
257
262
  currentLocation: "/".concat(current.name),
258
- globalDefaults: globalDefaults,
263
+ globalDefaults: opts.globalDefaults,
259
264
  refLogger: refLogger
260
265
  })), {
261
266
  // Note: this applies a $schema version to each field in the larger schema object. It's not really *correct*
@@ -286,7 +291,32 @@ function getParametersAsJsonSchema(operation, api, globalDefaults) {
286
291
  schema: schema,
287
292
  deprecatedProps: getDeprecated(schema, type)
288
293
  };
289
- });
294
+ })
295
+ .filter(Boolean);
296
+ if (!opts.mergeIntoBodyAndMetadata) {
297
+ return transformed;
298
+ }
299
+ // If we want to merge parameters into a single metadata entry then we need to pull all
300
+ // available schemas and `deprecatedProps` (if we don't want to retain them via the
301
+ // `retainDeprecatedProps` option) under one roof.
302
+ var deprecatedProps = transformed.map(function (r) { var _a; return ((_a = r.deprecatedProps) === null || _a === void 0 ? void 0 : _a.schema) || null; }).filter(Boolean);
303
+ return [
304
+ {
305
+ type: 'metadata',
306
+ label: exports.types.metadata,
307
+ schema: {
308
+ allOf: transformed.map(function (r) { return r.schema; })
309
+ },
310
+ deprecatedProps: deprecatedProps.length
311
+ ? {
312
+ type: 'metadata',
313
+ schema: {
314
+ allOf: deprecatedProps
315
+ }
316
+ }
317
+ : null
318
+ },
319
+ ];
290
320
  }
291
321
  // If this operation neither has any parameters or a request body then we should return null because there won't be
292
322
  // any JSON Schema.
package/dist/operation.js CHANGED
@@ -382,14 +382,17 @@ var Operation = /** @class */ (function () {
382
382
  * Convert the operation into an array of JSON Schema schemas for each available type of parameter available on the
383
383
  * operation.
384
384
  *
385
- * @param globalDefaults Contains an object of user defined schema defaults.
385
+ * @param opts
386
+ * @param opts.globalDefaults Contains an object of user defined schema defaults.
387
+ * @param opts.mergeIntoBodyAndMetadata If you want the output to be two objects: body (contains
388
+ * `body` and `formData` JSON Schema) and metadata (contains `path`, `query`, `cookie`, and
389
+ * `header`).
390
+ * @param opts.retainDeprecatedProperties If you wish to **not** split out deprecated properties
391
+ * into a separate `deprecatedProps` object.
386
392
  */
387
- Operation.prototype.getParametersAsJsonSchema = function (globalDefaults) {
388
- if (this.parameterJsonSchema) {
389
- return this.parameterJsonSchema;
390
- }
391
- this.parameterJsonSchema = (0, get_parameters_as_json_schema_1["default"])(this, this.api, globalDefaults);
392
- return this.parameterJsonSchema;
393
+ Operation.prototype.getParametersAsJsonSchema = function (opts) {
394
+ if (opts === void 0) { opts = {}; }
395
+ return (0, get_parameters_as_json_schema_1["default"])(this, this.api, opts);
393
396
  };
394
397
  /**
395
398
  * Get a single response for this status code, formatted as JSON schema.
package/dist/utils.js CHANGED
@@ -5,14 +5,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  exports.__esModule = true;
6
6
  exports.supportedMethods = void 0;
7
7
  var find_schema_definition_1 = __importDefault(require("./lib/find-schema-definition"));
8
- var get_schema_1 = __importDefault(require("./lib/get-schema"));
9
8
  var matches_mimetype_1 = __importDefault(require("./lib/matches-mimetype"));
10
9
  var get_parameters_as_json_schema_1 = require("./operation/get-parameters-as-json-schema");
11
10
  var supportedMethods = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']);
12
11
  exports.supportedMethods = supportedMethods;
13
12
  exports["default"] = {
14
13
  findSchemaDefinition: find_schema_definition_1["default"],
15
- getSchema: get_schema_1["default"],
16
14
  jsonSchemaTypes: get_parameters_as_json_schema_1.types,
17
15
  matchesMimeType: matches_mimetype_1["default"]
18
16
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oas",
3
- "version": "17.8.1",
3
+ "version": "18.0.0",
4
4
  "description": "Working with OpenAPI definitions is hard. This makes it easier.",
5
5
  "license": "MIT",
6
6
  "author": "ReadMe <support@readme.io> (https://readme.com)",
@@ -37,10 +37,11 @@
37
37
  "scripts": {
38
38
  "build": "tsc",
39
39
  "lint": "eslint . --ext .js,.ts",
40
+ "lint:docs": "alex . .github/",
40
41
  "prebuild": "rm -rf dist/ @types/",
41
42
  "prepack": "npm run build",
42
43
  "prepare": "husky install",
43
- "pretest": "npm run lint",
44
+ "pretest": "npm run lint && npm run lint:docs",
44
45
  "prettier": "prettier --list-different --write \"./**/**.{js,ts}\"",
45
46
  "release": "npx conventional-changelog-cli -i CHANGELOG.md -s && git add CHANGELOG.md",
46
47
  "test": "tsc; jest --coverage",
@@ -67,11 +68,12 @@
67
68
  "devDependencies": {
68
69
  "@commitlint/cli": "^16.0.1",
69
70
  "@commitlint/config-conventional": "^16.0.0",
70
- "@readme/eslint-config": "^8.4.1",
71
+ "@readme/eslint-config": "^8.5.0",
71
72
  "@readme/oas-examples": "^4.3.2",
72
73
  "@types/jest": "^27.0.2",
73
74
  "@types/json-schema-merge-allof": "^0.6.1",
74
75
  "@types/memoizee": "^0.4.6",
76
+ "alex": "^10.0.0",
75
77
  "eslint": "^8.6.0",
76
78
  "eslint-plugin-jsdoc": "^37.0.3",
77
79
  "husky": "^7.0.2",
@@ -4,6 +4,7 @@ import jsonpointer from 'jsonpointer';
4
4
  /**
5
5
  * Lookup a reference pointer within an OpenAPI definition and return the schema that it resolves to.
6
6
  *
7
+ * @deprecated
7
8
  * @param $ref Reference to look up a schema for.
8
9
  * @param definitions OpenAPI definition to look for the `$ref` pointer in.
9
10
  */
@@ -28,6 +28,7 @@ export const types: Record<keyof RMOAS.OASDocument, string> = {
28
28
  cookie: 'Cookie Params',
29
29
  formData: 'Form Data',
30
30
  header: 'Headers',
31
+ metadata: 'Metadata', // This a special type reserved for https://npm.im/api
31
32
  };
32
33
 
33
34
  function getSchemaVersionString(schema: SchemaObject, api: OASDocument): string {
@@ -56,12 +57,15 @@ function cloneObject<T>(obj: T): T {
56
57
  return JSON.parse(JSON.stringify(obj));
57
58
  }
58
59
 
59
- /**
60
- * @param operation
61
- * @param api
62
- * @param globalDefaults
63
- */
64
- export default function getParametersAsJsonSchema(operation: Operation, api: OASDocument, globalDefaults = {}) {
60
+ export default function getParametersAsJsonSchema(
61
+ operation: Operation,
62
+ api: OASDocument,
63
+ opts?: {
64
+ globalDefaults?: Record<string, unknown>;
65
+ mergeIntoBodyAndMetadata?: boolean;
66
+ retainDeprecatedProperties?: boolean;
67
+ }
68
+ ) {
65
69
  let hasCircularRefs = false;
66
70
 
67
71
  function refLogger() {
@@ -69,6 +73,12 @@ export default function getParametersAsJsonSchema(operation: Operation, api: OAS
69
73
  }
70
74
 
71
75
  function getDeprecated(schema: SchemaObject, type: string) {
76
+ // If we wish to retain deprecated properties then we shouldn't split them out into the
77
+ // `deprecatedProps` object.
78
+ if (opts.retainDeprecatedProperties) {
79
+ return null;
80
+ }
81
+
72
82
  // If there's no properties, bail
73
83
  if (!schema || !schema.properties) return null;
74
84
  // Clone the original schema so this doesn't interfere with it
@@ -88,7 +98,11 @@ export default function getParametersAsJsonSchema(operation: Operation, api: OAS
88
98
 
89
99
  // We know this is the right type. todo: don't use as
90
100
  (deprecatedBody.properties as Record<string, SchemaObject>) = allDeprecatedProps;
91
- const deprecatedSchema = toJSONSchema(deprecatedBody, { globalDefaults, prevSchemas: [], refLogger });
101
+ const deprecatedSchema = toJSONSchema(deprecatedBody, {
102
+ globalDefaults: opts.globalDefaults,
103
+ prevSchemas: [],
104
+ refLogger,
105
+ });
92
106
 
93
107
  // Check if the schema wasn't created or there's no deprecated properties
94
108
  if (Object.keys(deprecatedSchema).length === 0 || Object.keys(deprecatedSchema.properties).length === 0) {
@@ -142,7 +156,7 @@ export default function getParametersAsJsonSchema(operation: Operation, api: OAS
142
156
  // We're cloning the request schema because we've had issues with request schemas that were dereferenced being
143
157
  // processed multiple times because their component is also processed.
144
158
  const requestSchema = cloneObject(mediaTypeObject.schema);
145
- const cleanedSchema = toJSONSchema(requestSchema, { globalDefaults, prevSchemas, refLogger });
159
+ const cleanedSchema = toJSONSchema(requestSchema, { globalDefaults: opts.globalDefaults, prevSchemas, refLogger });
146
160
 
147
161
  // If this schema is **still** empty, don't bother returning it.
148
162
  if (!Object.keys(cleanedSchema).length) {
@@ -176,7 +190,7 @@ export default function getParametersAsJsonSchema(operation: Operation, api: OAS
176
190
  Object.keys(api.components[componentType]).forEach(schemaName => {
177
191
  const componentSchema = cloneObject(api.components[componentType][schemaName]);
178
192
  components[componentType][schemaName] = toJSONSchema(componentSchema as RMOAS.SchemaObject, {
179
- globalDefaults,
193
+ globalDefaults: opts.globalDefaults,
180
194
  refLogger,
181
195
  });
182
196
  });
@@ -189,118 +203,146 @@ export default function getParametersAsJsonSchema(operation: Operation, api: OAS
189
203
  function transformParameters(): SchemaWrapper[] {
190
204
  const operationParams = operation.getParameters();
191
205
 
192
- return Object.keys(types).map(type => {
193
- const required: string[] = [];
206
+ const transformed = Object.keys(types)
207
+ .map(type => {
208
+ const required: string[] = [];
194
209
 
195
- // This `as` actually *could* be a ref, but we don't want refs to pass through here, so `.in` will never match `type`
196
- const parameters = operationParams.filter(param => (param as RMOAS.ParameterObject).in === type);
197
- if (parameters.length === 0) {
198
- return null;
199
- }
210
+ // This `as` actually *could* be a ref, but we don't want refs to pass through here, so `.in` will never match `type`
211
+ const parameters = operationParams.filter(param => (param as RMOAS.ParameterObject).in === type);
212
+ if (parameters.length === 0) {
213
+ return null;
214
+ }
200
215
 
201
- const properties = parameters.reduce((prev: Record<string, SchemaObject>, current: RMOAS.ParameterObject) => {
202
- let schema: SchemaObject = {};
203
- if ('schema' in current) {
204
- const currentSchema: SchemaObject = current.schema ? cloneObject(current.schema) : {};
205
-
206
- if (current.example) {
207
- // `example` can be present outside of the `schema` block so if it's there we should pull it in so it can be
208
- // handled and returned if it's valid.
209
- currentSchema.example = current.example;
210
- } else if (current.examples) {
211
- // `examples` isn't actually supported here in OAS 3.0, but we might as well support it because `examples` is
212
- // JSON Schema and that's fully supported in OAS 3.1.
213
- currentSchema.examples = current.examples as unknown as unknown[];
214
- }
216
+ const properties = parameters.reduce((prev: Record<string, SchemaObject>, current: RMOAS.ParameterObject) => {
217
+ let schema: SchemaObject = {};
218
+ if ('schema' in current) {
219
+ const currentSchema: SchemaObject = current.schema ? cloneObject(current.schema) : {};
220
+
221
+ if (current.example) {
222
+ // `example` can be present outside of the `schema` block so if it's there we should pull it in so it can be
223
+ // handled and returned if it's valid.
224
+ currentSchema.example = current.example;
225
+ } else if (current.examples) {
226
+ // `examples` isn't actually supported here in OAS 3.0, but we might as well support it because `examples` is
227
+ // JSON Schema and that's fully supported in OAS 3.1.
228
+ currentSchema.examples = current.examples as unknown as unknown[];
229
+ }
215
230
 
216
- if (current.deprecated) currentSchema.deprecated = current.deprecated;
217
-
218
- schema = {
219
- ...toJSONSchema(currentSchema, {
220
- currentLocation: `/${current.name}`,
221
- globalDefaults,
222
- refLogger,
223
- }),
224
- // Note: this applies a $schema version to each field in the larger schema object. It's not really *correct*
225
- // but it's what we have to do because there's a chance that the end user has indicated the schemas are different
226
- $schema: getSchemaVersionString(currentSchema, api),
227
- };
228
- } else if ('content' in current && typeof current.content === 'object') {
229
- const contentKeys = Object.keys(current.content);
230
- if (contentKeys.length) {
231
- let contentType;
232
- if (contentKeys.length === 1) {
233
- contentType = contentKeys[0];
234
- } else {
235
- // We should always try to prioritize `application/json` over any other possible content that might be present
236
- // on this schema.
237
- const jsonLikeContentTypes = contentKeys.filter(k => isJSON(k));
238
- if (jsonLikeContentTypes.length) {
239
- contentType = jsonLikeContentTypes[0];
240
- } else {
231
+ if (current.deprecated) currentSchema.deprecated = current.deprecated;
232
+
233
+ schema = {
234
+ ...toJSONSchema(currentSchema, {
235
+ currentLocation: `/${current.name}`,
236
+ globalDefaults: opts.globalDefaults,
237
+ refLogger,
238
+ }),
239
+ // Note: this applies a $schema version to each field in the larger schema object. It's not really *correct*
240
+ // but it's what we have to do because there's a chance that the end user has indicated the schemas are different
241
+ $schema: getSchemaVersionString(currentSchema, api),
242
+ };
243
+ } else if ('content' in current && typeof current.content === 'object') {
244
+ const contentKeys = Object.keys(current.content);
245
+ if (contentKeys.length) {
246
+ let contentType;
247
+ if (contentKeys.length === 1) {
241
248
  contentType = contentKeys[0];
249
+ } else {
250
+ // We should always try to prioritize `application/json` over any other possible content that might be present
251
+ // on this schema.
252
+ const jsonLikeContentTypes = contentKeys.filter(k => isJSON(k));
253
+ if (jsonLikeContentTypes.length) {
254
+ contentType = jsonLikeContentTypes[0];
255
+ } else {
256
+ contentType = contentKeys[0];
257
+ }
242
258
  }
243
- }
244
259
 
245
- if (typeof current.content[contentType] === 'object' && 'schema' in current.content[contentType]) {
246
- const currentSchema: SchemaObject = current.content[contentType].schema
247
- ? cloneObject(current.content[contentType].schema)
248
- : {};
249
-
250
- if (current.example) {
251
- // `example` can be present outside of the `schema` block so if it's there we should pull it in so it can be
252
- // handled and returned if it's valid.
253
- currentSchema.example = current.example;
254
- } else if (current.examples) {
255
- // `examples` isn't actually supported here in OAS 3.0, but we might as well support it because `examples` is
256
- // JSON Schema and that's fully supported in OAS 3.1.
257
- currentSchema.examples = current.examples as unknown as unknown[];
260
+ if (typeof current.content[contentType] === 'object' && 'schema' in current.content[contentType]) {
261
+ const currentSchema: SchemaObject = current.content[contentType].schema
262
+ ? cloneObject(current.content[contentType].schema)
263
+ : {};
264
+
265
+ if (current.example) {
266
+ // `example` can be present outside of the `schema` block so if it's there we should pull it in so it can be
267
+ // handled and returned if it's valid.
268
+ currentSchema.example = current.example;
269
+ } else if (current.examples) {
270
+ // `examples` isn't actually supported here in OAS 3.0, but we might as well support it because `examples` is
271
+ // JSON Schema and that's fully supported in OAS 3.1.
272
+ currentSchema.examples = current.examples as unknown as unknown[];
273
+ }
274
+
275
+ if (current.deprecated) currentSchema.deprecated = current.deprecated;
276
+
277
+ schema = {
278
+ ...toJSONSchema(currentSchema, {
279
+ currentLocation: `/${current.name}`,
280
+ globalDefaults: opts.globalDefaults,
281
+ refLogger,
282
+ }),
283
+ // Note: this applies a $schema version to each field in the larger schema object. It's not really *correct*
284
+ // but it's what we have to do because there's a chance that the end user has indicated the schemas are different
285
+ $schema: getSchemaVersionString(currentSchema, api),
286
+ };
258
287
  }
259
-
260
- if (current.deprecated) currentSchema.deprecated = current.deprecated;
261
-
262
- schema = {
263
- ...toJSONSchema(currentSchema, {
264
- currentLocation: `/${current.name}`,
265
- globalDefaults,
266
- refLogger,
267
- }),
268
- // Note: this applies a $schema version to each field in the larger schema object. It's not really *correct*
269
- // but it's what we have to do because there's a chance that the end user has indicated the schemas are different
270
- $schema: getSchemaVersionString(currentSchema, api),
271
- };
272
288
  }
273
289
  }
274
- }
275
290
 
276
- // Parameter descriptions don't exist in `current.schema` so `constructSchema` will never have access to it.
277
- if (current.description) {
278
- schema.description = current.description;
279
- }
291
+ // Parameter descriptions don't exist in `current.schema` so `constructSchema` will never have access to it.
292
+ if (current.description) {
293
+ schema.description = current.description;
294
+ }
280
295
 
281
- prev[current.name] = schema;
296
+ prev[current.name] = schema;
282
297
 
283
- if (current.required) {
284
- required.push(current.name);
285
- }
298
+ if (current.required) {
299
+ required.push(current.name);
300
+ }
286
301
 
287
- return prev;
288
- }, {});
289
-
290
- // This typing is technically WRONG :( but it's the best we can do for now.
291
- const schema: OpenAPIV3_1.SchemaObject = {
292
- type: 'object',
293
- properties: properties as Record<string, OpenAPIV3_1.SchemaObject>,
294
- required,
295
- };
296
-
297
- return {
298
- type,
299
- label: types[type],
300
- schema,
301
- deprecatedProps: getDeprecated(schema, type),
302
- };
303
- });
302
+ return prev;
303
+ }, {});
304
+
305
+ // This typing is technically WRONG :( but it's the best we can do for now.
306
+ const schema: OpenAPIV3_1.SchemaObject = {
307
+ type: 'object',
308
+ properties: properties as Record<string, OpenAPIV3_1.SchemaObject>,
309
+ required,
310
+ };
311
+
312
+ return {
313
+ type,
314
+ label: types[type],
315
+ schema,
316
+ deprecatedProps: getDeprecated(schema, type),
317
+ };
318
+ })
319
+ .filter(Boolean);
320
+
321
+ if (!opts.mergeIntoBodyAndMetadata) {
322
+ return transformed;
323
+ }
324
+
325
+ // If we want to merge parameters into a single metadata entry then we need to pull all
326
+ // available schemas and `deprecatedProps` (if we don't want to retain them via the
327
+ // `retainDeprecatedProps` option) under one roof.
328
+ const deprecatedProps = transformed.map(r => r.deprecatedProps?.schema || null).filter(Boolean);
329
+ return [
330
+ {
331
+ type: 'metadata',
332
+ label: types.metadata,
333
+ schema: {
334
+ allOf: transformed.map(r => r.schema),
335
+ } as SchemaObject,
336
+ deprecatedProps: deprecatedProps.length
337
+ ? {
338
+ type: 'metadata',
339
+ schema: {
340
+ allOf: deprecatedProps,
341
+ } as SchemaObject,
342
+ }
343
+ : null,
344
+ },
345
+ ];
304
346
  }
305
347
 
306
348
  // If this operation neither has any parameters or a request body then we should return null because there won't be
package/src/operation.ts CHANGED
@@ -2,7 +2,6 @@ import type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
2
2
  import type { RequestBodyExamples } from './operation/get-requestbody-examples';
3
3
  import type { CallbackExamples } from './operation/get-callback-examples';
4
4
  import type { ResponseExamples } from './operation/get-response-examples';
5
- import type { SchemaWrapper } from './operation/get-parameters-as-json-schema';
6
5
 
7
6
  import * as RMOAS from './rmoas.types';
8
7
  import dedupeCommonParameters from './lib/dedupe-common-parameters';
@@ -66,11 +65,6 @@ export default class Operation {
66
65
  response: string[];
67
66
  };
68
67
 
69
- /**
70
- * All parameters and request bodies converted into JSON Schema.
71
- */
72
- parameterJsonSchema: SchemaWrapper[];
73
-
74
68
  constructor(api: RMOAS.OASDocument, path: string, method: RMOAS.HttpMethods, operation: RMOAS.OperationObject) {
75
69
  this.schema = operation;
76
70
  this.api = api;
@@ -439,15 +433,22 @@ export default class Operation {
439
433
  * Convert the operation into an array of JSON Schema schemas for each available type of parameter available on the
440
434
  * operation.
441
435
  *
442
- * @param globalDefaults Contains an object of user defined schema defaults.
443
- */
444
- getParametersAsJsonSchema(globalDefaults?: Record<string, unknown>) {
445
- if (this.parameterJsonSchema) {
446
- return this.parameterJsonSchema;
447
- }
448
-
449
- this.parameterJsonSchema = getParametersAsJsonSchema(this, this.api, globalDefaults);
450
- return this.parameterJsonSchema;
436
+ * @param opts
437
+ * @param opts.globalDefaults Contains an object of user defined schema defaults.
438
+ * @param opts.mergeIntoBodyAndMetadata If you want the output to be two objects: body (contains
439
+ * `body` and `formData` JSON Schema) and metadata (contains `path`, `query`, `cookie`, and
440
+ * `header`).
441
+ * @param opts.retainDeprecatedProperties If you wish to **not** split out deprecated properties
442
+ * into a separate `deprecatedProps` object.
443
+ */
444
+ getParametersAsJsonSchema(
445
+ opts: {
446
+ globalDefaults?: Record<string, unknown>;
447
+ mergeIntoBodyAndMetadata?: boolean;
448
+ retainDeprecatedProperties?: boolean;
449
+ } = {}
450
+ ) {
451
+ return getParametersAsJsonSchema(this, this.api, opts);
451
452
  }
452
453
 
453
454
  /**
@@ -153,6 +153,7 @@ export type SchemaObject = (
153
153
  | JSONSchema
154
154
  ) & {
155
155
  // TODO: We should split this into one type for v3 and one type for v3.1 to ensure type accuracy.
156
+ $schema?: string;
156
157
  deprecated?: boolean;
157
158
  readOnly?: boolean;
158
159
  writeOnly?: boolean;
package/src/utils.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import findSchemaDefinition from './lib/find-schema-definition';
2
- import getSchema from './lib/get-schema';
3
2
  import matchesMimeType from './lib/matches-mimetype';
4
3
  import { types as jsonSchemaTypes } from './operation/get-parameters-as-json-schema';
5
4
 
@@ -7,7 +6,6 @@ const supportedMethods = new Set(['get', 'put', 'post', 'delete', 'options', 'he
7
6
 
8
7
  export default {
9
8
  findSchemaDefinition,
10
- getSchema,
11
9
  jsonSchemaTypes,
12
10
  matchesMimeType,
13
11
  };
@@ -1,17 +0,0 @@
1
- import type * as RMOAS from '../rmoas.types';
2
- /**
3
- * Retrieves the schema of the first media type defined in the `content` of the path operation or returns the reference
4
- * if there's no Request Body Object.
5
- *
6
- * If the reference pointer looks like a `requestBodies` reference, then we also do a lookup for the actual schema.
7
- *
8
- * @deprecated
9
- * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#fixed-fields-8}
10
- * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#fixed-fields-8}
11
- * @param operation Operation to look for a primary requestBody schema in.
12
- * @param api The API definition that this operation exists within.
13
- */
14
- export default function getSchema(operation: RMOAS.OperationObject, api?: RMOAS.OASDocument | Record<string, Record<string, RMOAS.SchemaObject>>): {
15
- type: string;
16
- schema: any;
17
- };
@@ -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 `oas`, 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,45 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- exports.__esModule = true;
6
- var rmoas_types_1 = require("../rmoas.types");
7
- var find_schema_definition_1 = __importDefault(require("./find-schema-definition"));
8
- /**
9
- * Retrieves the schema of the first media type defined in the `content` of the path operation or returns the reference
10
- * if there's no Request Body Object.
11
- *
12
- * If the reference pointer looks like a `requestBodies` reference, then we also do a lookup for the actual schema.
13
- *
14
- * @deprecated
15
- * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#fixed-fields-8}
16
- * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#fixed-fields-8}
17
- * @param operation Operation to look for a primary requestBody schema in.
18
- * @param api The API definition that this operation exists within.
19
- */
20
- function getSchema(operation, api) {
21
- try {
22
- if ((0, rmoas_types_1.isRef)(operation.requestBody)) {
23
- if (operation.requestBody.$ref.match(/^#\/components\/requestBodies\/.*$/)) {
24
- return getSchema({
25
- requestBody: (0, find_schema_definition_1["default"])(operation.requestBody.$ref, api)
26
- });
27
- }
28
- }
29
- var requestBody = operation.requestBody;
30
- if (requestBody.content) {
31
- var type = Object.keys(requestBody.content)[0];
32
- return {
33
- type: type,
34
- schema: requestBody.content[type]
35
- };
36
- }
37
- return {
38
- type: 'application/json',
39
- schema: requestBody
40
- };
41
- }
42
- catch (e) { } // eslint-disable-line no-empty
43
- return undefined;
44
- }
45
- exports["default"] = getSchema;
@@ -1,50 +0,0 @@
1
- import type * as RMOAS from '../rmoas.types';
2
- import { isRef } from '../rmoas.types';
3
- import findSchemaDefinition from './find-schema-definition';
4
-
5
- /**
6
- * Retrieves the schema of the first media type defined in the `content` of the path operation or returns the reference
7
- * if there's no Request Body Object.
8
- *
9
- * If the reference pointer looks like a `requestBodies` reference, then we also do a lookup for the actual schema.
10
- *
11
- * @deprecated
12
- * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#fixed-fields-8}
13
- * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#fixed-fields-8}
14
- * @param operation Operation to look for a primary requestBody schema in.
15
- * @param api The API definition that this operation exists within.
16
- */
17
- export default function getSchema(
18
- operation: RMOAS.OperationObject,
19
- api?: RMOAS.OASDocument | Record<string /* schemaType */, Record<string, RMOAS.SchemaObject>>
20
- ): {
21
- type: string;
22
- schema: any; // @fixme give this a better type
23
- } {
24
- try {
25
- if (isRef(operation.requestBody)) {
26
- if (operation.requestBody.$ref.match(/^#\/components\/requestBodies\/.*$/)) {
27
- return getSchema({
28
- requestBody: findSchemaDefinition(operation.requestBody.$ref, api),
29
- } as RMOAS.OperationObject);
30
- }
31
- }
32
-
33
- const requestBody = operation.requestBody as RMOAS.RequestBodyObject;
34
- if (requestBody.content) {
35
- const type = Object.keys(requestBody.content)[0];
36
-
37
- return {
38
- type,
39
- schema: requestBody.content[type],
40
- };
41
- }
42
-
43
- return {
44
- type: 'application/json',
45
- schema: requestBody,
46
- };
47
- } catch (e) {} // eslint-disable-line no-empty
48
-
49
- return undefined;
50
- }