oas 17.8.0 → 18.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@types/lib/find-schema-definition.d.ts +1 -0
- package/@types/operation/get-parameters-as-json-schema.d.ts +5 -6
- package/@types/operation.d.ts +30 -6
- package/@types/rmoas.types.d.ts +1 -0
- package/@types/utils.d.ts +0 -2
- package/CHANGELOG.md +27 -0
- package/dist/lib/find-schema-definition.js +1 -0
- package/dist/operation/get-parameters-as-json-schema.js +48 -15
- package/dist/operation.js +62 -8
- package/dist/utils.js +0 -2
- package/package.json +5 -3
- package/src/cli/lib/utils.js +1 -1
- package/src/lib/find-schema-definition.ts +1 -0
- package/src/operation/get-parameters-as-json-schema.ts +152 -108
- package/src/operation.ts +76 -9
- package/src/rmoas.types.ts +1 -0
- package/src/utils.ts +0 -2
- package/@types/lib/get-schema.d.ts +0 -17
- package/CODE_OF_CONDUCT.md +0 -128
- package/SECURITY.md +0 -12
- package/dist/lib/get-schema.js +0 -45
- package/src/lib/get-schema.ts +0 -50
|
@@ -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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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[];
|
package/@types/operation.d.ts
CHANGED
|
@@ -84,11 +84,15 @@ export default class Operation {
|
|
|
84
84
|
*/
|
|
85
85
|
hasOperationId(): boolean;
|
|
86
86
|
/**
|
|
87
|
-
* Get an `operationId` for this operation. If one is not present (it's not required by the spec!)
|
|
88
|
-
* and method will be returned instead.
|
|
87
|
+
* Get an `operationId` for this operation. If one is not present (it's not required by the spec!)
|
|
88
|
+
* a hash of the path and method will be returned instead.
|
|
89
89
|
*
|
|
90
|
+
* @param opts
|
|
91
|
+
* @param opts.camelCase Generate a JS method-friendly operation ID when one isn't present.
|
|
90
92
|
*/
|
|
91
|
-
getOperationId(
|
|
93
|
+
getOperationId(opts?: {
|
|
94
|
+
camelCase: boolean;
|
|
95
|
+
}): string;
|
|
92
96
|
/**
|
|
93
97
|
* Return an array of all tags, and their metadata, that exist on this operation.
|
|
94
98
|
*
|
|
@@ -109,13 +113,28 @@ export default class Operation {
|
|
|
109
113
|
*
|
|
110
114
|
*/
|
|
111
115
|
getParameters(): RMOAS.ParameterObject[];
|
|
116
|
+
/**
|
|
117
|
+
* Determine if this operation has any required parameters.
|
|
118
|
+
*
|
|
119
|
+
*/
|
|
120
|
+
hasRequiredParameters(): boolean;
|
|
112
121
|
/**
|
|
113
122
|
* Convert the operation into an array of JSON Schema schemas for each available type of parameter available on the
|
|
114
123
|
* operation.
|
|
115
124
|
*
|
|
116
|
-
* @param
|
|
117
|
-
|
|
118
|
-
|
|
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[];
|
|
119
138
|
/**
|
|
120
139
|
* Get a single response for this status code, formatted as JSON schema.
|
|
121
140
|
*
|
|
@@ -144,6 +163,11 @@ export default class Operation {
|
|
|
144
163
|
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#mediaTypeObject}
|
|
145
164
|
*/
|
|
146
165
|
getRequestBodyMediaTypes(): string[];
|
|
166
|
+
/**
|
|
167
|
+
* Determine if this operation has a required request body.
|
|
168
|
+
*
|
|
169
|
+
*/
|
|
170
|
+
hasRequiredRequestBody(): boolean;
|
|
147
171
|
/**
|
|
148
172
|
* Retrieve a specific request body content schema off this operation.
|
|
149
173
|
*
|
package/@types/rmoas.types.d.ts
CHANGED
|
@@ -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,30 @@
|
|
|
1
|
+
## <small>18.0.1 (2022-03-10)</small>
|
|
2
|
+
|
|
3
|
+
* fix: don't create an empty metadata allOf is there's no metadata (#619) ([28a7752](https://github.com/readmeio/oas/commit/28a7752)), closes [#619](https://github.com/readmeio/oas/issues/619)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## 18.0.0 (2022-03-08)
|
|
8
|
+
|
|
9
|
+
> **BREAKING CHANGE**
|
|
10
|
+
>
|
|
11
|
+
> 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!
|
|
12
|
+
|
|
13
|
+
* chore(deps-dev): bumping dev deps ([08833bb](https://github.com/readmeio/oas/commit/08833bb))
|
|
14
|
+
* 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)
|
|
15
|
+
* feat: adding new options to `getParametersAsJsonSchema` (#617) ([7b17b9f](https://github.com/readmeio/oas/commit/7b17b9f)), closes [#617](https://github.com/readmeio/oas/issues/617)
|
|
16
|
+
* feat: removing getSchema, deprecating findSchemaDefinition (#600) ([161611f](https://github.com/readmeio/oas/commit/161611f)), closes [#600](https://github.com/readmeio/oas/issues/600)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## <small>17.8.1 (2022-03-04)</small>
|
|
21
|
+
|
|
22
|
+
* fix: typo in the `--pattern` option ([42db80a](https://github.com/readmeio/oas/commit/42db80a))
|
|
23
|
+
* feat: adding new accessors for determining if an operation has required params (#615) ([c081d92](https://github.com/readmeio/oas/commit/c081d92)), closes [#615](https://github.com/readmeio/oas/issues/615)
|
|
24
|
+
* feat: optionally generate friendlier operationIds (#602) ([6826164](https://github.com/readmeio/oas/commit/6826164)), closes [#602](https://github.com/readmeio/oas/issues/602)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
1
28
|
## 17.8.0 (2022-03-02)
|
|
2
29
|
|
|
3
30
|
* chore(deps-dev): bump @commitlint/cli from 16.1.0 to 16.2.1 (#612) ([e7364dd](https://github.com/readmeio/oas/commit/e7364dd)), closes [#612](https://github.com/readmeio/oas/issues/612)
|
|
@@ -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, {
|
|
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
|
-
|
|
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,35 @@ 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
|
+
else if (!transformed.length) {
|
|
300
|
+
return [];
|
|
301
|
+
}
|
|
302
|
+
// If we want to merge parameters into a single metadata entry then we need to pull all
|
|
303
|
+
// available schemas and `deprecatedProps` (if we don't want to retain them via the
|
|
304
|
+
// `retainDeprecatedProps` option) under one roof.
|
|
305
|
+
var deprecatedProps = transformed.map(function (r) { var _a; return ((_a = r.deprecatedProps) === null || _a === void 0 ? void 0 : _a.schema) || null; }).filter(Boolean);
|
|
306
|
+
return [
|
|
307
|
+
{
|
|
308
|
+
type: 'metadata',
|
|
309
|
+
label: exports.types.metadata,
|
|
310
|
+
schema: {
|
|
311
|
+
allOf: transformed.map(function (r) { return r.schema; })
|
|
312
|
+
},
|
|
313
|
+
deprecatedProps: deprecatedProps.length
|
|
314
|
+
? {
|
|
315
|
+
type: 'metadata',
|
|
316
|
+
schema: {
|
|
317
|
+
allOf: deprecatedProps
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
: null
|
|
321
|
+
},
|
|
322
|
+
];
|
|
290
323
|
}
|
|
291
324
|
// If this operation neither has any parameters or a request body then we should return null because there won't be
|
|
292
325
|
// any JSON Schema.
|
package/dist/operation.js
CHANGED
|
@@ -286,20 +286,33 @@ var Operation = /** @class */ (function () {
|
|
|
286
286
|
return 'operationId' in this.schema;
|
|
287
287
|
};
|
|
288
288
|
/**
|
|
289
|
-
* Get an `operationId` for this operation. If one is not present (it's not required by the spec!)
|
|
290
|
-
* and method will be returned instead.
|
|
289
|
+
* Get an `operationId` for this operation. If one is not present (it's not required by the spec!)
|
|
290
|
+
* a hash of the path and method will be returned instead.
|
|
291
291
|
*
|
|
292
|
+
* @param opts
|
|
293
|
+
* @param opts.camelCase Generate a JS method-friendly operation ID when one isn't present.
|
|
292
294
|
*/
|
|
293
|
-
Operation.prototype.getOperationId = function () {
|
|
295
|
+
Operation.prototype.getOperationId = function (opts) {
|
|
294
296
|
if ('operationId' in this.schema) {
|
|
295
297
|
return this.schema.operationId;
|
|
296
298
|
}
|
|
297
|
-
var
|
|
299
|
+
var method = this.method.toLowerCase();
|
|
300
|
+
var operationId = this.path
|
|
298
301
|
.replace(/[^a-zA-Z0-9]/g, '-') // Remove weird characters
|
|
299
302
|
.replace(/^-|-$/g, '') // Don't start or end with -
|
|
300
303
|
.replace(/--+/g, '-') // Remove double --'s
|
|
301
304
|
.toLowerCase();
|
|
302
|
-
|
|
305
|
+
if (opts === null || opts === void 0 ? void 0 : opts.camelCase) {
|
|
306
|
+
operationId = operationId.replace(/[^a-zA-Z0-9]+(.)/g, function (_, chr) { return chr.toUpperCase(); });
|
|
307
|
+
// If the generated operationId already starts with the method (eg. `getPets`) we don't want
|
|
308
|
+
// to double it up into `getGetPets`.
|
|
309
|
+
if (operationId.startsWith(method)) {
|
|
310
|
+
return operationId;
|
|
311
|
+
}
|
|
312
|
+
operationId = operationId.charAt(0).toUpperCase() + operationId.slice(1);
|
|
313
|
+
return "".concat(method).concat(operationId);
|
|
314
|
+
}
|
|
315
|
+
return "".concat(method, "_").concat(operationId);
|
|
303
316
|
};
|
|
304
317
|
/**
|
|
305
318
|
* Return an array of all tags, and their metadata, that exist on this operation.
|
|
@@ -358,14 +371,28 @@ var Operation = /** @class */ (function () {
|
|
|
358
371
|
}
|
|
359
372
|
return parameters;
|
|
360
373
|
};
|
|
374
|
+
/**
|
|
375
|
+
* Determine if this operation has any required parameters.
|
|
376
|
+
*
|
|
377
|
+
*/
|
|
378
|
+
Operation.prototype.hasRequiredParameters = function () {
|
|
379
|
+
return this.getParameters().some(function (param) { return 'required' in param && param.required; });
|
|
380
|
+
};
|
|
361
381
|
/**
|
|
362
382
|
* Convert the operation into an array of JSON Schema schemas for each available type of parameter available on the
|
|
363
383
|
* operation.
|
|
364
384
|
*
|
|
365
|
-
* @param
|
|
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.
|
|
366
392
|
*/
|
|
367
|
-
Operation.prototype.getParametersAsJsonSchema = function (
|
|
368
|
-
|
|
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);
|
|
369
396
|
};
|
|
370
397
|
/**
|
|
371
398
|
* Get a single response for this status code, formatted as JSON schema.
|
|
@@ -407,6 +434,33 @@ var Operation = /** @class */ (function () {
|
|
|
407
434
|
}
|
|
408
435
|
return Object.keys(requestBody.content);
|
|
409
436
|
};
|
|
437
|
+
/**
|
|
438
|
+
* Determine if this operation has a required request body.
|
|
439
|
+
*
|
|
440
|
+
*/
|
|
441
|
+
Operation.prototype.hasRequiredRequestBody = function () {
|
|
442
|
+
if (!this.hasRequestBody()) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
var requestBody = this.schema.requestBody;
|
|
446
|
+
if (RMOAS.isRef(requestBody)) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
if (requestBody.required) {
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
// The OpenAPI spec isn't clear on the differentiation between schema `required` and
|
|
453
|
+
// `requestBody.required` because you can have required top-level schema properties but a
|
|
454
|
+
// non-required requestBody that negates each other.
|
|
455
|
+
//
|
|
456
|
+
// To kind of work ourselves around this and present a better QOL for this accessor, if at this
|
|
457
|
+
// final point where we don't have a required request body, but the underlying Media Type Object
|
|
458
|
+
// schema says that it has required properties then we should ultimately recognize that this
|
|
459
|
+
// request body is required -- even as the request body description says otherwise.
|
|
460
|
+
return !!this.getParametersAsJsonSchema()
|
|
461
|
+
.filter(function (js) { return ['body', 'formData'].includes(js.type); })
|
|
462
|
+
.find(function (js) { return js.schema && Array.isArray(js.schema.required) && js.schema.required.length; });
|
|
463
|
+
};
|
|
410
464
|
/**
|
|
411
465
|
* Retrieve a specific request body content schema off this operation.
|
|
412
466
|
*
|
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": "
|
|
3
|
+
"version": "18.0.1",
|
|
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.
|
|
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",
|
package/src/cli/lib/utils.js
CHANGED
|
@@ -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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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, {
|
|
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,148 @@ export default function getParametersAsJsonSchema(operation: Operation, api: OAS
|
|
|
189
203
|
function transformParameters(): SchemaWrapper[] {
|
|
190
204
|
const operationParams = operation.getParameters();
|
|
191
205
|
|
|
192
|
-
|
|
193
|
-
|
|
206
|
+
const transformed = Object.keys(types)
|
|
207
|
+
.map(type => {
|
|
208
|
+
const required: string[] = [];
|
|
194
209
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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
|
-
|
|
296
|
+
prev[current.name] = schema;
|
|
282
297
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
298
|
+
if (current.required) {
|
|
299
|
+
required.push(current.name);
|
|
300
|
+
}
|
|
286
301
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
+
} else if (!transformed.length) {
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// If we want to merge parameters into a single metadata entry then we need to pull all
|
|
328
|
+
// available schemas and `deprecatedProps` (if we don't want to retain them via the
|
|
329
|
+
// `retainDeprecatedProps` option) under one roof.
|
|
330
|
+
const deprecatedProps = transformed.map(r => r.deprecatedProps?.schema || null).filter(Boolean);
|
|
331
|
+
return [
|
|
332
|
+
{
|
|
333
|
+
type: 'metadata',
|
|
334
|
+
label: types.metadata,
|
|
335
|
+
schema: {
|
|
336
|
+
allOf: transformed.map(r => r.schema),
|
|
337
|
+
} as SchemaObject,
|
|
338
|
+
deprecatedProps: deprecatedProps.length
|
|
339
|
+
? {
|
|
340
|
+
type: 'metadata',
|
|
341
|
+
schema: {
|
|
342
|
+
allOf: deprecatedProps,
|
|
343
|
+
} as SchemaObject,
|
|
344
|
+
}
|
|
345
|
+
: null,
|
|
346
|
+
},
|
|
347
|
+
];
|
|
304
348
|
}
|
|
305
349
|
|
|
306
350
|
// 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
|
@@ -323,22 +323,38 @@ export default class Operation {
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
/**
|
|
326
|
-
* Get an `operationId` for this operation. If one is not present (it's not required by the spec!)
|
|
327
|
-
* and method will be returned instead.
|
|
326
|
+
* Get an `operationId` for this operation. If one is not present (it's not required by the spec!)
|
|
327
|
+
* a hash of the path and method will be returned instead.
|
|
328
328
|
*
|
|
329
|
+
* @param opts
|
|
330
|
+
* @param opts.camelCase Generate a JS method-friendly operation ID when one isn't present.
|
|
329
331
|
*/
|
|
330
|
-
getOperationId(): string {
|
|
332
|
+
getOperationId(opts?: { camelCase: boolean }): string {
|
|
331
333
|
if ('operationId' in this.schema) {
|
|
332
334
|
return this.schema.operationId;
|
|
333
335
|
}
|
|
334
336
|
|
|
335
|
-
const
|
|
337
|
+
const method = this.method.toLowerCase();
|
|
338
|
+
let operationId = this.path
|
|
336
339
|
.replace(/[^a-zA-Z0-9]/g, '-') // Remove weird characters
|
|
337
340
|
.replace(/^-|-$/g, '') // Don't start or end with -
|
|
338
341
|
.replace(/--+/g, '-') // Remove double --'s
|
|
339
342
|
.toLowerCase();
|
|
340
343
|
|
|
341
|
-
|
|
344
|
+
if (opts?.camelCase) {
|
|
345
|
+
operationId = operationId.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase());
|
|
346
|
+
|
|
347
|
+
// If the generated operationId already starts with the method (eg. `getPets`) we don't want
|
|
348
|
+
// to double it up into `getGetPets`.
|
|
349
|
+
if (operationId.startsWith(method)) {
|
|
350
|
+
return operationId;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
operationId = operationId.charAt(0).toUpperCase() + operationId.slice(1);
|
|
354
|
+
return `${method}${operationId}`;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return `${method}_${operationId}`;
|
|
342
358
|
}
|
|
343
359
|
|
|
344
360
|
/**
|
|
@@ -405,14 +421,34 @@ export default class Operation {
|
|
|
405
421
|
return parameters;
|
|
406
422
|
}
|
|
407
423
|
|
|
424
|
+
/**
|
|
425
|
+
* Determine if this operation has any required parameters.
|
|
426
|
+
*
|
|
427
|
+
*/
|
|
428
|
+
hasRequiredParameters() {
|
|
429
|
+
return this.getParameters().some(param => 'required' in param && param.required);
|
|
430
|
+
}
|
|
431
|
+
|
|
408
432
|
/**
|
|
409
433
|
* Convert the operation into an array of JSON Schema schemas for each available type of parameter available on the
|
|
410
434
|
* operation.
|
|
411
435
|
*
|
|
412
|
-
* @param
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
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);
|
|
416
452
|
}
|
|
417
453
|
|
|
418
454
|
/**
|
|
@@ -461,6 +497,37 @@ export default class Operation {
|
|
|
461
497
|
return Object.keys(requestBody.content);
|
|
462
498
|
}
|
|
463
499
|
|
|
500
|
+
/**
|
|
501
|
+
* Determine if this operation has a required request body.
|
|
502
|
+
*
|
|
503
|
+
*/
|
|
504
|
+
hasRequiredRequestBody() {
|
|
505
|
+
if (!this.hasRequestBody()) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const requestBody = this.schema.requestBody;
|
|
510
|
+
if (RMOAS.isRef(requestBody)) {
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (requestBody.required) {
|
|
515
|
+
return true;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// The OpenAPI spec isn't clear on the differentiation between schema `required` and
|
|
519
|
+
// `requestBody.required` because you can have required top-level schema properties but a
|
|
520
|
+
// non-required requestBody that negates each other.
|
|
521
|
+
//
|
|
522
|
+
// To kind of work ourselves around this and present a better QOL for this accessor, if at this
|
|
523
|
+
// final point where we don't have a required request body, but the underlying Media Type Object
|
|
524
|
+
// schema says that it has required properties then we should ultimately recognize that this
|
|
525
|
+
// request body is required -- even as the request body description says otherwise.
|
|
526
|
+
return !!this.getParametersAsJsonSchema()
|
|
527
|
+
.filter(js => ['body', 'formData'].includes(js.type))
|
|
528
|
+
.find(js => js.schema && Array.isArray(js.schema.required) && js.schema.required.length);
|
|
529
|
+
}
|
|
530
|
+
|
|
464
531
|
/**
|
|
465
532
|
* Retrieve a specific request body content schema off this operation.
|
|
466
533
|
*
|
package/src/rmoas.types.ts
CHANGED
|
@@ -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
|
-
};
|
package/CODE_OF_CONDUCT.md
DELETED
|
@@ -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.
|
package/dist/lib/get-schema.js
DELETED
|
@@ -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;
|
package/src/lib/get-schema.ts
DELETED
|
@@ -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
|
-
}
|