oas-normalize 7.1.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -39
- package/dist/index.d.ts +12 -11
- package/dist/index.js +64 -37
- package/dist/lib/utils.d.ts +33 -7
- package/dist/lib/utils.js +71 -23
- package/docs/github_logo_raw.png +0 -0
- package/docs/github_logo_small.png +0 -0
- package/docs/logo.png +0 -0
- package/package.json +15 -14
- package/src/index.ts +53 -27
- package/src/lib/utils.ts +69 -24
package/README.md
CHANGED
|
@@ -1,26 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://npm.im/oas-normalize">
|
|
3
|
+
<img src="https://user-images.githubusercontent.com/33762/200434622-23946869-1965-46f8-8deb-f284b8d0b92c.png" alt="oas-normalize" />
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
Tooling for converting, valiating, and parsing OpenAPI, Swagger, and Postman API definitions
|
|
9
|
+
</p>
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://npm.im/oas-normalize"><img src="https://img.shields.io/npm/v/oas-normalize.svg?style=for-the-badge" alt="NPM Version"></a>
|
|
13
|
+
<a href="https://npm.im/oas-normalize"><img src="https://img.shields.io/node/v/oas-normalize.svg?style=for-the-badge" alt="Node Version"></a>
|
|
14
|
+
<a href="https://npm.im/oas-normalize"><img src="https://img.shields.io/npm/l/oas-normalize.svg?style=for-the-badge" alt="MIT License"></a>
|
|
15
|
+
<a href="https://github.com/readmeio/oas-normalize"><img src="https://img.shields.io/github/workflow/status/readmeio/oas-normalize/CI.svg?style=for-the-badge" alt="Build status"></a>
|
|
16
|
+
</p>
|
|
6
17
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# Install
|
|
18
|
+
## Installation
|
|
10
19
|
|
|
11
20
|
```bash
|
|
12
|
-
npm install oas-normalize
|
|
21
|
+
npm install oas-normalize
|
|
13
22
|
```
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
## Usage
|
|
16
25
|
|
|
17
26
|
```javascript
|
|
18
27
|
import OASNormalize from 'oas-normalize';
|
|
19
28
|
// const { default: OASNormalize } = require('oas-normalize'); // If you're using CJS.
|
|
20
29
|
|
|
21
30
|
const oas = new OASNormalize(
|
|
22
|
-
// Or a string, pathname, JSON blob, whatever
|
|
23
31
|
'https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v3.0/petstore-expanded.yaml'
|
|
32
|
+
// ...or a string, path, JSON blob, whatever you've got.
|
|
24
33
|
);
|
|
25
34
|
|
|
26
35
|
oas
|
|
@@ -34,7 +43,55 @@ oas
|
|
|
34
43
|
});
|
|
35
44
|
```
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
### `#bundle()`
|
|
47
|
+
|
|
48
|
+
> **Note**
|
|
49
|
+
>
|
|
50
|
+
> Because Postman collections don't support `$ref` pointers, this method will automatically upconvert a Postman collection to OpenAPI if supplied one.
|
|
51
|
+
|
|
52
|
+
Bundle up the given API definition, resolving any external `$ref` pointers in the process.
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
await oas.bundle().then(definition => {
|
|
56
|
+
console.log(definition);
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### `#deref()`
|
|
61
|
+
|
|
62
|
+
> **Note**
|
|
63
|
+
>
|
|
64
|
+
> Because Postman collections don't support `$ref` pointers, this method will automatically upconvert a Postman collection to OpenAPI if supplied one.
|
|
65
|
+
|
|
66
|
+
Dereference the given API definition, resolving all `$ref` pointers in the process.
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
await oas.deref().then(definition => {
|
|
70
|
+
console.log(definition);
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### `#validate({ convertToLatest?: boolean })`
|
|
75
|
+
|
|
76
|
+
Validate and optionally convert to OpenAPI, a given API definition. This supports Swagger 2.0, OpenAPI 3.x API definitions as well as Postman 2.x collections.
|
|
77
|
+
|
|
78
|
+
Please note that if you've supplied a Postman collection to the library it will **always** be converted to OpenAPI, using [postman-to-openapi](https://github.com/joolfe/postman-to-openapi), and we will only validate resulting OpenAPI definition.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
await oas.validate().then(definition => {
|
|
82
|
+
console.log(definition);
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Options
|
|
87
|
+
|
|
88
|
+
<!-- prettier-ignore-start -->
|
|
89
|
+
| Option | Type | Description |
|
|
90
|
+
| :--- | :--- | :--- |
|
|
91
|
+
| `convertToLatest` | Boolean | By default `#validate` will not upconvert Swagger API definitions to OpenAPI so if you wish for this to happen, supply `true`. |
|
|
92
|
+
<!-- prettier-ignore-end -->
|
|
93
|
+
|
|
94
|
+
#### Error Handling
|
|
38
95
|
|
|
39
96
|
For validation errors, when available, you'll get back an object:
|
|
40
97
|
|
|
@@ -55,35 +112,9 @@ For validation errors, when available, you'll get back an object:
|
|
|
55
112
|
|
|
56
113
|
`message` is almost always there, but `path` is less dependable.
|
|
57
114
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
> **Note:** All of these functions are promise-driven.
|
|
61
|
-
|
|
62
|
-
If you want some more functionality, you can do anything here:
|
|
63
|
-
|
|
64
|
-
<!--
|
|
65
|
-
Prettier's table formatting sucks, hence the ignore block below.
|
|
66
|
-
-->
|
|
67
|
-
<!-- prettier-ignore-start -->
|
|
68
|
-
| Function | What it does |
|
|
69
|
-
| :--- | :--- |
|
|
70
|
-
| `.load()` | Just load the file, valid or not, as JSON |
|
|
71
|
-
| `.bundle()` | Bring together all files into one JSON blob (but retain `$ref` pointers) |
|
|
72
|
-
| `.deref()` | Resolve `$ref` pointers |
|
|
73
|
-
| `.validate([convertToLatest?])` | Validate the whole thing! |
|
|
74
|
-
<!-- prettier-ignore-end -->
|
|
75
|
-
|
|
76
|
-
# Other Little Features
|
|
77
|
-
|
|
78
|
-
### Always Return OpenAPI 3.x
|
|
79
|
-
|
|
80
|
-
If you want `.validate()` to always return an OpenAPI 3.x definition, supply `true` as its argument:
|
|
81
|
-
|
|
82
|
-
```js
|
|
83
|
-
OASNormalize.validate(true).then(...);
|
|
84
|
-
```
|
|
115
|
+
### Options
|
|
85
116
|
|
|
86
|
-
|
|
117
|
+
##### Enable local paths
|
|
87
118
|
|
|
88
119
|
For security reasons, you need to opt into allowing fetching by a local path. To enable it supply the `enablePaths` option to the class instance:
|
|
89
120
|
|
|
@@ -91,7 +122,7 @@ For security reasons, you need to opt into allowing fetching by a local path. To
|
|
|
91
122
|
const oas = new OASNormalize('./petstore.json', { enablePaths: true });
|
|
92
123
|
```
|
|
93
124
|
|
|
94
|
-
|
|
125
|
+
##### Colorized errors
|
|
95
126
|
|
|
96
127
|
If you wish errors from `.validate()` to be styled and colorized, supply `colorizeErrors: true` to your instance of `OASNormalize`:
|
|
97
128
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { OpenAPI } from 'openapi-types';
|
|
2
|
+
import * as utils from './lib/utils';
|
|
2
3
|
export declare type Options = {
|
|
3
4
|
colorizeErrors?: boolean;
|
|
4
5
|
enablePaths?: boolean;
|
|
5
6
|
};
|
|
7
|
+
export declare const isAPIDefinition: typeof utils.isAPIDefinition;
|
|
8
|
+
export declare const getAPIDefinitionType: typeof utils.getAPIDefinitionType;
|
|
6
9
|
export default class OASNormalize {
|
|
7
10
|
cache: {
|
|
8
11
|
bundle?: false | OpenAPI.Document;
|
|
@@ -13,10 +16,12 @@ export default class OASNormalize {
|
|
|
13
16
|
opts: Options;
|
|
14
17
|
type: boolean | string;
|
|
15
18
|
constructor(file: any, opts?: Options);
|
|
19
|
+
/**
|
|
20
|
+
* @private
|
|
21
|
+
*/
|
|
16
22
|
load(): Promise<any>;
|
|
17
23
|
/**
|
|
18
|
-
* Bundle up the given
|
|
19
|
-
* the process.
|
|
24
|
+
* Bundle up the given API definition, resolving any external `$ref` pointers in the process.
|
|
20
25
|
*
|
|
21
26
|
*/
|
|
22
27
|
bundle(): Promise<import("openapi-types").OpenAPIV2.Document<{}> | import("openapi-types").OpenAPIV3.Document<{}> | (Omit<Omit<import("openapi-types").OpenAPIV3.Document<{}>, "paths" | "components">, "paths" | "components" | "info" | "servers" | "webhooks" | "jsonSchemaDialect"> & {
|
|
@@ -57,7 +62,7 @@ export default class OASNormalize {
|
|
|
57
62
|
components: import("openapi-types").OpenAPIV3_1.ComponentsObject;
|
|
58
63
|
}>, "components">)>;
|
|
59
64
|
/**
|
|
60
|
-
* Dereference the given
|
|
65
|
+
* Dereference the given API definition.
|
|
61
66
|
*
|
|
62
67
|
*/
|
|
63
68
|
deref(): Promise<import("openapi-types").OpenAPIV2.Document<{}> | import("openapi-types").OpenAPIV3.Document<{}> | (Omit<Omit<import("openapi-types").OpenAPIV3.Document<{}>, "paths" | "components">, "paths" | "components" | "info" | "servers" | "webhooks" | "jsonSchemaDialect"> & {
|
|
@@ -98,14 +103,10 @@ export default class OASNormalize {
|
|
|
98
103
|
components: import("openapi-types").OpenAPIV3_1.ComponentsObject;
|
|
99
104
|
}>, "components">)>;
|
|
100
105
|
/**
|
|
101
|
-
* Validate
|
|
102
|
-
* OpenAPI in the process if you wish.
|
|
103
|
-
*
|
|
104
|
-
*/
|
|
105
|
-
validate(convertToLatest?: boolean): Promise<any>;
|
|
106
|
-
/**
|
|
107
|
-
* Retrieve the OpenAPI or Swagger version of the current API definition.
|
|
106
|
+
* Validate, and potentially convert to OpenAPI, a given API definition.
|
|
108
107
|
*
|
|
109
108
|
*/
|
|
110
|
-
|
|
109
|
+
validate(opts?: {
|
|
110
|
+
convertToLatest?: boolean;
|
|
111
|
+
}): Promise<any>;
|
|
111
112
|
}
|
package/dist/index.js
CHANGED
|
@@ -73,11 +73,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
73
73
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
74
74
|
};
|
|
75
75
|
exports.__esModule = true;
|
|
76
|
+
exports.getAPIDefinitionType = exports.isAPIDefinition = void 0;
|
|
76
77
|
var fs_1 = __importDefault(require("fs"));
|
|
77
78
|
var openapi_parser_1 = __importDefault(require("@readme/openapi-parser"));
|
|
78
79
|
var node_fetch_1 = __importDefault(require("node-fetch"));
|
|
80
|
+
var postman_to_openapi_1 = __importDefault(require("postman-to-openapi"));
|
|
79
81
|
var swagger2openapi_1 = __importDefault(require("swagger2openapi"));
|
|
80
82
|
var utils = __importStar(require("./lib/utils"));
|
|
83
|
+
exports.isAPIDefinition = utils.isAPIDefinition;
|
|
84
|
+
exports.getAPIDefinitionType = utils.getAPIDefinitionType;
|
|
81
85
|
var OASNormalize = /** @class */ (function () {
|
|
82
86
|
function OASNormalize(file, opts) {
|
|
83
87
|
this.file = file;
|
|
@@ -89,7 +93,9 @@ var OASNormalize = /** @class */ (function () {
|
|
|
89
93
|
deref: false
|
|
90
94
|
};
|
|
91
95
|
}
|
|
92
|
-
|
|
96
|
+
/**
|
|
97
|
+
* @private
|
|
98
|
+
*/
|
|
93
99
|
OASNormalize.prototype.load = function () {
|
|
94
100
|
return __awaiter(this, void 0, void 0, function () {
|
|
95
101
|
var resolve, _a, resp, contents;
|
|
@@ -133,8 +139,7 @@ var OASNormalize = /** @class */ (function () {
|
|
|
133
139
|
});
|
|
134
140
|
};
|
|
135
141
|
/**
|
|
136
|
-
* Bundle up the given
|
|
137
|
-
* the process.
|
|
142
|
+
* Bundle up the given API definition, resolving any external `$ref` pointers in the process.
|
|
138
143
|
*
|
|
139
144
|
*/
|
|
140
145
|
OASNormalize.prototype.bundle = function () {
|
|
@@ -144,6 +149,15 @@ var OASNormalize = /** @class */ (function () {
|
|
|
144
149
|
if (this.cache.bundle)
|
|
145
150
|
return [2 /*return*/, Promise.resolve(this.cache.bundle)];
|
|
146
151
|
return [2 /*return*/, this.load()
|
|
152
|
+
.then(function (schema) {
|
|
153
|
+
// Though Postman collections don't support `$ref` pointers for us to bundle we'll still
|
|
154
|
+
// upconvert it to an OpenAPI definition file so our returned dataset is always one of
|
|
155
|
+
// those for a Postman dataset.
|
|
156
|
+
if (utils.isPostman(schema)) {
|
|
157
|
+
return (0, postman_to_openapi_1["default"])(JSON.stringify(schema), null, { outputFormat: 'json' }).then(JSON.parse);
|
|
158
|
+
}
|
|
159
|
+
return schema;
|
|
160
|
+
})
|
|
147
161
|
.then(function (schema) { return openapi_parser_1["default"].bundle(schema); })
|
|
148
162
|
.then(function (bundle) {
|
|
149
163
|
_this.cache.bundle = bundle;
|
|
@@ -153,7 +167,7 @@ var OASNormalize = /** @class */ (function () {
|
|
|
153
167
|
});
|
|
154
168
|
};
|
|
155
169
|
/**
|
|
156
|
-
* Dereference the given
|
|
170
|
+
* Dereference the given API definition.
|
|
157
171
|
*
|
|
158
172
|
*/
|
|
159
173
|
OASNormalize.prototype.deref = function () {
|
|
@@ -163,6 +177,15 @@ var OASNormalize = /** @class */ (function () {
|
|
|
163
177
|
if (this.cache.deref)
|
|
164
178
|
return [2 /*return*/, Promise.resolve(this.cache.deref)];
|
|
165
179
|
return [2 /*return*/, this.load()
|
|
180
|
+
.then(function (schema) {
|
|
181
|
+
// Though Postman collections don't support `$ref` pointers for us to dereference we'll
|
|
182
|
+
// still upconvert it to an OpenAPI definition file so our returned dataset is always one
|
|
183
|
+
// of those for a Postman dataset.
|
|
184
|
+
if (utils.isPostman(schema)) {
|
|
185
|
+
return (0, postman_to_openapi_1["default"])(JSON.stringify(schema), null, { outputFormat: 'json' }).then(JSON.parse);
|
|
186
|
+
}
|
|
187
|
+
return schema;
|
|
188
|
+
})
|
|
166
189
|
.then(function (schema) { return openapi_parser_1["default"].dereference(schema); })
|
|
167
190
|
.then(function (dereferenced) {
|
|
168
191
|
_this.cache.deref = dereferenced;
|
|
@@ -172,54 +195,58 @@ var OASNormalize = /** @class */ (function () {
|
|
|
172
195
|
});
|
|
173
196
|
};
|
|
174
197
|
/**
|
|
175
|
-
* Validate
|
|
176
|
-
* OpenAPI in the process if you wish.
|
|
198
|
+
* Validate, and potentially convert to OpenAPI, a given API definition.
|
|
177
199
|
*
|
|
178
200
|
*/
|
|
179
|
-
OASNormalize.prototype.validate = function (
|
|
180
|
-
if (
|
|
201
|
+
OASNormalize.prototype.validate = function (opts) {
|
|
202
|
+
if (opts === void 0) { opts = { convertToLatest: false }; }
|
|
181
203
|
return __awaiter(this, void 0, void 0, function () {
|
|
182
|
-
var colorizeErrors;
|
|
204
|
+
var convertToLatest, colorizeErrors;
|
|
183
205
|
var _this = this;
|
|
184
206
|
return __generator(this, function (_a) {
|
|
207
|
+
convertToLatest = opts.convertToLatest;
|
|
185
208
|
colorizeErrors = this.opts.colorizeErrors;
|
|
186
|
-
return [2 /*return*/, this.load()
|
|
209
|
+
return [2 /*return*/, this.load()
|
|
210
|
+
.then(function (schema) { return __awaiter(_this, void 0, void 0, function () {
|
|
211
|
+
return __generator(this, function (_a) {
|
|
212
|
+
if (!utils.isPostman(schema)) {
|
|
213
|
+
return [2 /*return*/, schema];
|
|
214
|
+
}
|
|
215
|
+
return [2 /*return*/, (0, postman_to_openapi_1["default"])(JSON.stringify(schema), null, { outputFormat: 'json' }).then(JSON.parse)];
|
|
216
|
+
});
|
|
217
|
+
}); })
|
|
218
|
+
.then(function (schema) { return __awaiter(_this, void 0, void 0, function () {
|
|
187
219
|
var baseVersion, clonedSchema;
|
|
188
220
|
return __generator(this, function (_a) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return [2 /*return*/, Promise.reject(new Error('Swagger v1.2 is unsupported.'))];
|
|
221
|
+
if (!utils.isSwagger(schema) && !utils.isOpenAPI(schema)) {
|
|
222
|
+
return [2 /*return*/, Promise.reject(new Error('The supplied API definition is unsupported.'))];
|
|
192
223
|
}
|
|
193
|
-
else if (
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
colorizeErrors: colorizeErrors
|
|
199
|
-
}
|
|
200
|
-
})
|
|
201
|
-
.then(function () {
|
|
202
|
-
if (!convertToLatest) {
|
|
203
|
-
return schema;
|
|
204
|
-
}
|
|
205
|
-
return swagger2openapi_1["default"].convertObj(schema, { anchors: true }).then(function (options) {
|
|
206
|
-
return options.openapi;
|
|
207
|
-
});
|
|
208
|
-
})["catch"](function (err) { return Promise.reject(err); })];
|
|
224
|
+
else if (utils.isSwagger(schema)) {
|
|
225
|
+
baseVersion = parseInt(schema.swagger, 10);
|
|
226
|
+
if (baseVersion === 1) {
|
|
227
|
+
return [2 /*return*/, Promise.reject(new Error('Swagger v1.2 is unsupported.'))];
|
|
228
|
+
}
|
|
209
229
|
}
|
|
210
|
-
|
|
230
|
+
clonedSchema = JSON.parse(JSON.stringify(schema));
|
|
231
|
+
return [2 /*return*/, openapi_parser_1["default"]
|
|
232
|
+
.validate(clonedSchema, {
|
|
233
|
+
validate: {
|
|
234
|
+
colorizeErrors: colorizeErrors
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
.then(function () {
|
|
238
|
+
if (!convertToLatest) {
|
|
239
|
+
return schema;
|
|
240
|
+
}
|
|
241
|
+
return swagger2openapi_1["default"]
|
|
242
|
+
.convertObj(schema, { anchors: true })
|
|
243
|
+
.then(function (options) { return options.openapi; });
|
|
244
|
+
})["catch"](function (err) { return Promise.reject(err); })];
|
|
211
245
|
});
|
|
212
246
|
}); })];
|
|
213
247
|
});
|
|
214
248
|
});
|
|
215
249
|
};
|
|
216
|
-
/**
|
|
217
|
-
* Retrieve the OpenAPI or Swagger version of the current API definition.
|
|
218
|
-
*
|
|
219
|
-
*/
|
|
220
|
-
OASNormalize.prototype.version = function () {
|
|
221
|
-
return this.load().then(function (schema) { return utils.version(schema); });
|
|
222
|
-
};
|
|
223
250
|
return OASNormalize;
|
|
224
251
|
}());
|
|
225
252
|
exports["default"] = OASNormalize;
|
package/dist/lib/utils.d.ts
CHANGED
|
@@ -1,21 +1,47 @@
|
|
|
1
|
-
import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
2
|
+
* Determine if a given variable is a `Buffer`.
|
|
4
3
|
*
|
|
5
4
|
*/
|
|
6
|
-
export declare function
|
|
5
|
+
export declare function isBuffer(obj: any): any;
|
|
7
6
|
/**
|
|
8
|
-
* Determine
|
|
7
|
+
* Determine the type of a given variable. Returns `false` if unrecognized.
|
|
9
8
|
*
|
|
10
9
|
*/
|
|
11
|
-
export declare function
|
|
10
|
+
export declare function getType(obj: any): false | "path" | "json" | "buffer" | "string-json" | "string-yaml" | "url";
|
|
11
|
+
/**
|
|
12
|
+
* Determine if a given schema if an OpenAPI definition.
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
export declare function isOpenAPI(schema: Record<string, unknown>): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Determine if a given schema is a Postman collection.
|
|
18
|
+
*
|
|
19
|
+
* Unfortunately the Postman schema spec doesn't have anything like `openapi` or `swagger` for us
|
|
20
|
+
* to look at but it does require that `info` and `item` be present and as `item` doesn't exist in
|
|
21
|
+
* OpenAPI or Swagger we can use the combination of those two properties to determine if what we
|
|
22
|
+
* have is a Postman collection.
|
|
23
|
+
*
|
|
24
|
+
* @see {@link https://schema.postman.com/json/collection/v2.0.0/collection.json}
|
|
25
|
+
* @see {@link https://schema.postman.com/json/collection/v2.1.0/collection.json}
|
|
26
|
+
*/
|
|
27
|
+
export declare function isPostman(schema: Record<string, unknown>): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Determine if a given schema if an Swagger definition.
|
|
30
|
+
*
|
|
31
|
+
*/
|
|
32
|
+
export declare function isSwagger(schema: Record<string, unknown>): boolean;
|
|
12
33
|
/**
|
|
13
34
|
* Convert a YAML blob or stringified JSON object into a JSON object.
|
|
14
35
|
*
|
|
15
36
|
*/
|
|
16
37
|
export declare function stringToJSON(string: string | Record<string, unknown>): any;
|
|
17
38
|
/**
|
|
18
|
-
* Determine
|
|
39
|
+
* Determine if a given schema is an API definition that we can support.
|
|
19
40
|
*
|
|
20
41
|
*/
|
|
21
|
-
export declare function
|
|
42
|
+
export declare function isAPIDefinition(schema: Record<string, unknown>): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Retrieve the type of API definition that a given schema is.
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
export declare function getAPIDefinitionType(schema: Record<string, unknown>): "unknown" | "openapi" | "postman" | "swagger";
|
package/dist/lib/utils.js
CHANGED
|
@@ -3,16 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
exports.__esModule = true;
|
|
6
|
-
exports.
|
|
6
|
+
exports.getAPIDefinitionType = exports.isAPIDefinition = exports.stringToJSON = exports.isSwagger = exports.isPostman = exports.isOpenAPI = exports.getType = exports.isBuffer = void 0;
|
|
7
7
|
var js_yaml_1 = __importDefault(require("js-yaml"));
|
|
8
|
-
/**
|
|
9
|
-
* Retrieve the Swagger or OpenAPI version that a given Swagger or OpenAPI definition are targeting.
|
|
10
|
-
*
|
|
11
|
-
*/
|
|
12
|
-
function version(schema) {
|
|
13
|
-
return schema.swagger || schema.openapi;
|
|
14
|
-
}
|
|
15
|
-
exports.version = version;
|
|
16
8
|
/**
|
|
17
9
|
* Determine if a given variable is a `Buffer`.
|
|
18
10
|
*
|
|
@@ -24,20 +16,6 @@ function isBuffer(obj) {
|
|
|
24
16
|
obj.constructor.isBuffer(obj));
|
|
25
17
|
}
|
|
26
18
|
exports.isBuffer = isBuffer;
|
|
27
|
-
/**
|
|
28
|
-
* Convert a YAML blob or stringified JSON object into a JSON object.
|
|
29
|
-
*
|
|
30
|
-
*/
|
|
31
|
-
function stringToJSON(string) {
|
|
32
|
-
if (typeof string === 'object') {
|
|
33
|
-
return string;
|
|
34
|
-
}
|
|
35
|
-
else if (string.match(/^\s*{/)) {
|
|
36
|
-
return JSON.parse(string);
|
|
37
|
-
}
|
|
38
|
-
return js_yaml_1["default"].load(string);
|
|
39
|
-
}
|
|
40
|
-
exports.stringToJSON = stringToJSON;
|
|
41
19
|
/**
|
|
42
20
|
* Determine the type of a given variable. Returns `false` if unrecognized.
|
|
43
21
|
*
|
|
@@ -65,3 +43,73 @@ function getType(obj) {
|
|
|
65
43
|
return false;
|
|
66
44
|
}
|
|
67
45
|
exports.getType = getType;
|
|
46
|
+
/**
|
|
47
|
+
* Determine if a given schema if an OpenAPI definition.
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
function isOpenAPI(schema) {
|
|
51
|
+
return !!schema.openapi;
|
|
52
|
+
}
|
|
53
|
+
exports.isOpenAPI = isOpenAPI;
|
|
54
|
+
/**
|
|
55
|
+
* Determine if a given schema is a Postman collection.
|
|
56
|
+
*
|
|
57
|
+
* Unfortunately the Postman schema spec doesn't have anything like `openapi` or `swagger` for us
|
|
58
|
+
* to look at but it does require that `info` and `item` be present and as `item` doesn't exist in
|
|
59
|
+
* OpenAPI or Swagger we can use the combination of those two properties to determine if what we
|
|
60
|
+
* have is a Postman collection.
|
|
61
|
+
*
|
|
62
|
+
* @see {@link https://schema.postman.com/json/collection/v2.0.0/collection.json}
|
|
63
|
+
* @see {@link https://schema.postman.com/json/collection/v2.1.0/collection.json}
|
|
64
|
+
*/
|
|
65
|
+
function isPostman(schema) {
|
|
66
|
+
return !!schema.info && !!schema.item;
|
|
67
|
+
}
|
|
68
|
+
exports.isPostman = isPostman;
|
|
69
|
+
/**
|
|
70
|
+
* Determine if a given schema if an Swagger definition.
|
|
71
|
+
*
|
|
72
|
+
*/
|
|
73
|
+
function isSwagger(schema) {
|
|
74
|
+
return !!schema.swagger;
|
|
75
|
+
}
|
|
76
|
+
exports.isSwagger = isSwagger;
|
|
77
|
+
/**
|
|
78
|
+
* Convert a YAML blob or stringified JSON object into a JSON object.
|
|
79
|
+
*
|
|
80
|
+
*/
|
|
81
|
+
function stringToJSON(string) {
|
|
82
|
+
if (typeof string === 'object') {
|
|
83
|
+
return string;
|
|
84
|
+
}
|
|
85
|
+
else if (string.match(/^\s*{/)) {
|
|
86
|
+
return JSON.parse(string);
|
|
87
|
+
}
|
|
88
|
+
return js_yaml_1["default"].load(string);
|
|
89
|
+
}
|
|
90
|
+
exports.stringToJSON = stringToJSON;
|
|
91
|
+
/**
|
|
92
|
+
* Determine if a given schema is an API definition that we can support.
|
|
93
|
+
*
|
|
94
|
+
*/
|
|
95
|
+
function isAPIDefinition(schema) {
|
|
96
|
+
return isOpenAPI(schema) || isPostman(schema) || isSwagger(schema);
|
|
97
|
+
}
|
|
98
|
+
exports.isAPIDefinition = isAPIDefinition;
|
|
99
|
+
/**
|
|
100
|
+
* Retrieve the type of API definition that a given schema is.
|
|
101
|
+
*
|
|
102
|
+
*/
|
|
103
|
+
function getAPIDefinitionType(schema) {
|
|
104
|
+
if (isOpenAPI(schema)) {
|
|
105
|
+
return 'openapi';
|
|
106
|
+
}
|
|
107
|
+
else if (isPostman(schema)) {
|
|
108
|
+
return 'postman';
|
|
109
|
+
}
|
|
110
|
+
else if (isSwagger(schema)) {
|
|
111
|
+
return 'swagger';
|
|
112
|
+
}
|
|
113
|
+
return 'unknown';
|
|
114
|
+
}
|
|
115
|
+
exports.getAPIDefinitionType = getAPIDefinitionType;
|
|
Binary file
|
|
Binary file
|
package/docs/logo.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oas-normalize",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
|
+
"description": "Tooling for converting, valiating, and parsing OpenAPI, Swagger, and Postman API definitions",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=14"
|
|
9
9
|
},
|
|
10
|
-
"
|
|
10
|
+
"keywords": [
|
|
11
11
|
"api",
|
|
12
|
+
"apidoc",
|
|
12
13
|
"apis",
|
|
14
|
+
"documentation",
|
|
15
|
+
"microservice",
|
|
16
|
+
"postman",
|
|
17
|
+
"oai",
|
|
18
|
+
"oas",
|
|
13
19
|
"openapi",
|
|
14
|
-
"
|
|
20
|
+
"openapi document",
|
|
15
21
|
"openapi initiative",
|
|
16
|
-
"openapi specification",
|
|
17
22
|
"openapi spec",
|
|
18
|
-
"openapi
|
|
19
|
-
"
|
|
20
|
-
"oas",
|
|
21
|
-
"apidoc",
|
|
22
|
-
"microservice",
|
|
23
|
-
"documentation"
|
|
23
|
+
"openapi specification",
|
|
24
|
+
"swagger"
|
|
24
25
|
],
|
|
25
26
|
"repository": {
|
|
26
27
|
"type": "git",
|
|
@@ -45,17 +46,17 @@
|
|
|
45
46
|
"js-yaml": "^4.1.0",
|
|
46
47
|
"node-fetch": "^2.6.1",
|
|
47
48
|
"openapi-types": "^12.0.0",
|
|
49
|
+
"postman-to-openapi": "^2.7.1",
|
|
48
50
|
"swagger2openapi": "^7.0.8"
|
|
49
51
|
},
|
|
50
52
|
"devDependencies": {
|
|
51
|
-
"@readme/eslint-config": "^10.
|
|
52
|
-
"@readme/oas-examples": "^5.
|
|
53
|
+
"@readme/eslint-config": "^10.1.3",
|
|
54
|
+
"@readme/oas-examples": "^5.8.1",
|
|
53
55
|
"@types/jest": "^28.1.6",
|
|
54
56
|
"@types/js-yaml": "^4.0.5",
|
|
55
57
|
"@types/node-fetch": "^2.6.2",
|
|
56
58
|
"eslint": "^8.21.0",
|
|
57
59
|
"jest": "^28.0.3",
|
|
58
|
-
"jet": "^0.8.1",
|
|
59
60
|
"nock": "^13.2.4",
|
|
60
61
|
"prettier": "^2.7.1",
|
|
61
62
|
"ts-jest": "^28.0.7",
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import fs from 'fs';
|
|
|
4
4
|
|
|
5
5
|
import openapiParser from '@readme/openapi-parser';
|
|
6
6
|
import fetch from 'node-fetch';
|
|
7
|
+
import postmanToOpenAPI from 'postman-to-openapi';
|
|
7
8
|
|
|
8
9
|
import converter from 'swagger2openapi';
|
|
9
10
|
|
|
@@ -14,6 +15,9 @@ export type Options = {
|
|
|
14
15
|
enablePaths?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
18
|
+
export const isAPIDefinition = utils.isAPIDefinition;
|
|
19
|
+
export const getAPIDefinitionType = utils.getAPIDefinitionType;
|
|
20
|
+
|
|
17
21
|
export default class OASNormalize {
|
|
18
22
|
cache: {
|
|
19
23
|
bundle?: false | OpenAPI.Document;
|
|
@@ -44,7 +48,9 @@ export default class OASNormalize {
|
|
|
44
48
|
};
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
/**
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
48
54
|
async load() {
|
|
49
55
|
if (this.cache.load) return Promise.resolve(this.cache.load);
|
|
50
56
|
|
|
@@ -82,14 +88,23 @@ export default class OASNormalize {
|
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
/**
|
|
85
|
-
* Bundle up the given
|
|
86
|
-
* the process.
|
|
91
|
+
* Bundle up the given API definition, resolving any external `$ref` pointers in the process.
|
|
87
92
|
*
|
|
88
93
|
*/
|
|
89
94
|
async bundle() {
|
|
90
95
|
if (this.cache.bundle) return Promise.resolve(this.cache.bundle);
|
|
91
96
|
|
|
92
97
|
return this.load()
|
|
98
|
+
.then(schema => {
|
|
99
|
+
// Though Postman collections don't support `$ref` pointers for us to bundle we'll still
|
|
100
|
+
// upconvert it to an OpenAPI definition file so our returned dataset is always one of
|
|
101
|
+
// those for a Postman dataset.
|
|
102
|
+
if (utils.isPostman(schema)) {
|
|
103
|
+
return postmanToOpenAPI(JSON.stringify(schema), null, { outputFormat: 'json' }).then(JSON.parse);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return schema;
|
|
107
|
+
})
|
|
93
108
|
.then(schema => openapiParser.bundle(schema))
|
|
94
109
|
.then(bundle => {
|
|
95
110
|
this.cache.bundle = bundle;
|
|
@@ -98,13 +113,23 @@ export default class OASNormalize {
|
|
|
98
113
|
}
|
|
99
114
|
|
|
100
115
|
/**
|
|
101
|
-
* Dereference the given
|
|
116
|
+
* Dereference the given API definition.
|
|
102
117
|
*
|
|
103
118
|
*/
|
|
104
119
|
async deref() {
|
|
105
120
|
if (this.cache.deref) return Promise.resolve(this.cache.deref);
|
|
106
121
|
|
|
107
122
|
return this.load()
|
|
123
|
+
.then(schema => {
|
|
124
|
+
// Though Postman collections don't support `$ref` pointers for us to dereference we'll
|
|
125
|
+
// still upconvert it to an OpenAPI definition file so our returned dataset is always one
|
|
126
|
+
// of those for a Postman dataset.
|
|
127
|
+
if (utils.isPostman(schema)) {
|
|
128
|
+
return postmanToOpenAPI(JSON.stringify(schema), null, { outputFormat: 'json' }).then(JSON.parse);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return schema;
|
|
132
|
+
})
|
|
108
133
|
.then(schema => openapiParser.dereference(schema))
|
|
109
134
|
.then(dereferenced => {
|
|
110
135
|
this.cache.deref = dereferenced;
|
|
@@ -113,19 +138,31 @@ export default class OASNormalize {
|
|
|
113
138
|
}
|
|
114
139
|
|
|
115
140
|
/**
|
|
116
|
-
* Validate
|
|
117
|
-
* OpenAPI in the process if you wish.
|
|
141
|
+
* Validate, and potentially convert to OpenAPI, a given API definition.
|
|
118
142
|
*
|
|
119
143
|
*/
|
|
120
|
-
async validate(convertToLatest = false) {
|
|
144
|
+
async validate(opts: { convertToLatest?: boolean } = { convertToLatest: false }) {
|
|
145
|
+
const convertToLatest = opts.convertToLatest;
|
|
121
146
|
const colorizeErrors = this.opts.colorizeErrors;
|
|
122
147
|
|
|
123
|
-
return this.load()
|
|
124
|
-
|
|
148
|
+
return this.load()
|
|
149
|
+
.then(async schema => {
|
|
150
|
+
if (!utils.isPostman(schema)) {
|
|
151
|
+
return schema;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return postmanToOpenAPI(JSON.stringify(schema), null, { outputFormat: 'json' }).then(JSON.parse);
|
|
155
|
+
})
|
|
156
|
+
.then(async schema => {
|
|
157
|
+
if (!utils.isSwagger(schema) && !utils.isOpenAPI(schema)) {
|
|
158
|
+
return Promise.reject(new Error('The supplied API definition is unsupported.'));
|
|
159
|
+
} else if (utils.isSwagger(schema)) {
|
|
160
|
+
const baseVersion = parseInt(schema.swagger, 10);
|
|
161
|
+
if (baseVersion === 1) {
|
|
162
|
+
return Promise.reject(new Error('Swagger v1.2 is unsupported.'));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
125
165
|
|
|
126
|
-
if (baseVersion === 1) {
|
|
127
|
-
return Promise.reject(new Error('Swagger v1.2 is unsupported.'));
|
|
128
|
-
} else if (baseVersion === 2 || baseVersion === 3) {
|
|
129
166
|
/**
|
|
130
167
|
* `openapiParser.validate()` dereferences schemas at the same time as validation and does
|
|
131
168
|
* not give us an option to disable this. Since all we already have a dereferencing method
|
|
@@ -146,22 +183,11 @@ export default class OASNormalize {
|
|
|
146
183
|
return schema;
|
|
147
184
|
}
|
|
148
185
|
|
|
149
|
-
return converter
|
|
150
|
-
|
|
151
|
-
|
|
186
|
+
return converter
|
|
187
|
+
.convertObj(schema, { anchors: true })
|
|
188
|
+
.then((options: { openapi: OpenAPI.Document }) => options.openapi);
|
|
152
189
|
})
|
|
153
190
|
.catch(err => Promise.reject(err));
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return Promise.reject(new Error('The supplied API definition is unsupported.'));
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Retrieve the OpenAPI or Swagger version of the current API definition.
|
|
162
|
-
*
|
|
163
|
-
*/
|
|
164
|
-
version() {
|
|
165
|
-
return this.load().then(schema => utils.version(schema));
|
|
191
|
+
});
|
|
166
192
|
}
|
|
167
193
|
}
|
package/src/lib/utils.ts
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
|
|
2
|
-
|
|
3
1
|
import YAML from 'js-yaml';
|
|
4
2
|
|
|
5
|
-
/**
|
|
6
|
-
* Retrieve the Swagger or OpenAPI version that a given Swagger or OpenAPI definition are targeting.
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
export function version(schema: OpenAPIV2.Document & OpenAPIV3.Document & OpenAPIV3_1.Document) {
|
|
10
|
-
return schema.swagger || schema.openapi;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
3
|
/**
|
|
14
4
|
* Determine if a given variable is a `Buffer`.
|
|
15
5
|
*
|
|
@@ -23,20 +13,6 @@ export function isBuffer(obj: any) {
|
|
|
23
13
|
);
|
|
24
14
|
}
|
|
25
15
|
|
|
26
|
-
/**
|
|
27
|
-
* Convert a YAML blob or stringified JSON object into a JSON object.
|
|
28
|
-
*
|
|
29
|
-
*/
|
|
30
|
-
export function stringToJSON(string: string | Record<string, unknown>) {
|
|
31
|
-
if (typeof string === 'object') {
|
|
32
|
-
return string;
|
|
33
|
-
} else if (string.match(/^\s*{/)) {
|
|
34
|
-
return JSON.parse(string);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return YAML.load(string);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
16
|
/**
|
|
41
17
|
* Determine the type of a given variable. Returns `false` if unrecognized.
|
|
42
18
|
*
|
|
@@ -61,3 +37,72 @@ export function getType(obj: any) {
|
|
|
61
37
|
|
|
62
38
|
return false;
|
|
63
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Determine if a given schema if an OpenAPI definition.
|
|
43
|
+
*
|
|
44
|
+
*/
|
|
45
|
+
export function isOpenAPI(schema: Record<string, unknown>) {
|
|
46
|
+
return !!schema.openapi;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Determine if a given schema is a Postman collection.
|
|
51
|
+
*
|
|
52
|
+
* Unfortunately the Postman schema spec doesn't have anything like `openapi` or `swagger` for us
|
|
53
|
+
* to look at but it does require that `info` and `item` be present and as `item` doesn't exist in
|
|
54
|
+
* OpenAPI or Swagger we can use the combination of those two properties to determine if what we
|
|
55
|
+
* have is a Postman collection.
|
|
56
|
+
*
|
|
57
|
+
* @see {@link https://schema.postman.com/json/collection/v2.0.0/collection.json}
|
|
58
|
+
* @see {@link https://schema.postman.com/json/collection/v2.1.0/collection.json}
|
|
59
|
+
*/
|
|
60
|
+
export function isPostman(schema: Record<string, unknown>): boolean {
|
|
61
|
+
return !!schema.info && !!schema.item;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Determine if a given schema if an Swagger definition.
|
|
66
|
+
*
|
|
67
|
+
*/
|
|
68
|
+
export function isSwagger(schema: Record<string, unknown>) {
|
|
69
|
+
return !!schema.swagger;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Convert a YAML blob or stringified JSON object into a JSON object.
|
|
74
|
+
*
|
|
75
|
+
*/
|
|
76
|
+
export function stringToJSON(string: string | Record<string, unknown>) {
|
|
77
|
+
if (typeof string === 'object') {
|
|
78
|
+
return string;
|
|
79
|
+
} else if (string.match(/^\s*{/)) {
|
|
80
|
+
return JSON.parse(string);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return YAML.load(string);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Determine if a given schema is an API definition that we can support.
|
|
88
|
+
*
|
|
89
|
+
*/
|
|
90
|
+
export function isAPIDefinition(schema: Record<string, unknown>) {
|
|
91
|
+
return isOpenAPI(schema) || isPostman(schema) || isSwagger(schema);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Retrieve the type of API definition that a given schema is.
|
|
96
|
+
*
|
|
97
|
+
*/
|
|
98
|
+
export function getAPIDefinitionType(schema: Record<string, unknown>) {
|
|
99
|
+
if (isOpenAPI(schema)) {
|
|
100
|
+
return 'openapi';
|
|
101
|
+
} else if (isPostman(schema)) {
|
|
102
|
+
return 'postman';
|
|
103
|
+
} else if (isSwagger(schema)) {
|
|
104
|
+
return 'swagger';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return 'unknown';
|
|
108
|
+
}
|