Skip to content

Commit 803ff45

Browse files
authored
Merge pull request #225 from kibertoad/fix/ts-and-imports
Fix support for newer TypeScript and named imports
2 parents 534bb3f + be3f009 commit 803ff45

File tree

4 files changed

+162
-167
lines changed

4 files changed

+162
-167
lines changed

lib/index.js

+146-157
Original file line numberDiff line numberDiff line change
@@ -11,191 +11,180 @@ const { ono } = require("@jsdevtools/ono");
1111
const $RefParser = require("@apidevtools/json-schema-ref-parser");
1212
const dereference = require("@apidevtools/json-schema-ref-parser/lib/dereference");
1313

14-
module.exports = SwaggerParser;
15-
1614
/**
1715
* This class parses a Swagger 2.0 or 3.0 API, resolves its JSON references and their resolved values,
1816
* and provides methods for traversing, dereferencing, and validating the API.
1917
*
2018
* @class
2119
* @augments $RefParser
2220
*/
23-
function SwaggerParser () {
24-
$RefParser.apply(this, arguments);
25-
}
26-
27-
util.inherits(SwaggerParser, $RefParser);
28-
SwaggerParser.parse = $RefParser.parse;
29-
SwaggerParser.resolve = $RefParser.resolve;
30-
SwaggerParser.bundle = $RefParser.bundle;
31-
SwaggerParser.dereference = $RefParser.dereference;
32-
33-
/**
34-
* Alias {@link $RefParser#schema} as {@link SwaggerParser#api}
35-
*/
36-
Object.defineProperty(SwaggerParser.prototype, "api", {
37-
configurable: true,
38-
enumerable: true,
39-
get () {
40-
return this.schema;
41-
}
42-
});
43-
44-
/**
45-
* Parses the given Swagger API.
46-
* This method does not resolve any JSON references.
47-
* It just reads a single file in JSON or YAML format, and parse it as a JavaScript object.
48-
*
49-
* @param {string} [path] - The file path or URL of the JSON schema
50-
* @param {object} [api] - The Swagger API object. This object will be used instead of reading from `path`.
51-
* @param {ParserOptions} [options] - Options that determine how the API is parsed
52-
* @param {Function} [callback] - An error-first callback. The second parameter is the parsed API object.
53-
* @returns {Promise} - The returned promise resolves with the parsed API object.
54-
*/
55-
SwaggerParser.prototype.parse = async function (path, api, options, callback) {
56-
let args = normalizeArgs(arguments);
57-
args.options = new Options(args.options);
58-
59-
try {
60-
let schema = await $RefParser.prototype.parse.call(this, args.path, args.schema, args.options);
61-
62-
if (schema.swagger) {
63-
// Verify that the parsed object is a Swagger API
64-
if (schema.swagger === undefined || schema.info === undefined || schema.paths === undefined) {
65-
throw ono.syntax(`${args.path || args.schema} is not a valid Swagger API definition`);
66-
}
67-
else if (typeof schema.swagger === "number") {
68-
// This is a very common mistake, so give a helpful error message
69-
throw ono.syntax('Swagger version number must be a string (e.g. "2.0") not a number.');
70-
}
71-
else if (typeof schema.info.version === "number") {
72-
// This is a very common mistake, so give a helpful error message
73-
throw ono.syntax('API version number must be a string (e.g. "1.0.0") not a number.');
74-
}
75-
else if (schema.swagger !== "2.0") {
76-
throw ono.syntax(`Unrecognized Swagger version: ${schema.swagger}. Expected 2.0`);
21+
class SwaggerParser extends $RefParser {
22+
23+
/**
24+
* Parses the given Swagger API.
25+
* This method does not resolve any JSON references.
26+
* It just reads a single file in JSON or YAML format, and parse it as a JavaScript object.
27+
*
28+
* @param {string} [path] - The file path or URL of the JSON schema
29+
* @param {object} [api] - The Swagger API object. This object will be used instead of reading from `path`.
30+
* @param {ParserOptions} [options] - Options that determine how the API is parsed
31+
* @param {Function} [callback] - An error-first callback. The second parameter is the parsed API object.
32+
* @returns {Promise} - The returned promise resolves with the parsed API object.
33+
*/
34+
async parse (path, api, options, callback) {
35+
let args = normalizeArgs(arguments);
36+
args.options = new Options(args.options);
37+
38+
try {
39+
let schema = await super.parse(args.path, args.schema, args.options);
40+
41+
if (schema.swagger) {
42+
// Verify that the parsed object is a Swagger API
43+
if (schema.swagger === undefined || schema.info === undefined || schema.paths === undefined) {
44+
throw ono.syntax(`${args.path || args.schema} is not a valid Swagger API definition`);
45+
}
46+
else if (typeof schema.swagger === "number") {
47+
// This is a very common mistake, so give a helpful error message
48+
throw ono.syntax('Swagger version number must be a string (e.g. "2.0") not a number.');
49+
}
50+
else if (typeof schema.info.version === "number") {
51+
// This is a very common mistake, so give a helpful error message
52+
throw ono.syntax('API version number must be a string (e.g. "1.0.0") not a number.');
53+
}
54+
else if (schema.swagger !== "2.0") {
55+
throw ono.syntax(`Unrecognized Swagger version: ${schema.swagger}. Expected 2.0`);
56+
}
7757
}
78-
}
79-
else {
80-
let supportedVersions = ["3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.1.0"];
58+
else {
59+
let supportedVersions = ["3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.1.0"];
8160

82-
// Verify that the parsed object is a Openapi API
83-
if (schema.openapi === undefined || schema.info === undefined) {
84-
throw ono.syntax(`${args.path || args.schema} is not a valid Openapi API definition`);
85-
}
86-
else if (schema.paths === undefined) {
87-
if (schema.openapi === "3.1.0") {
88-
if (schema.webhooks === undefined) {
61+
// Verify that the parsed object is a Openapi API
62+
if (schema.openapi === undefined || schema.info === undefined) {
63+
throw ono.syntax(`${args.path || args.schema} is not a valid Openapi API definition`);
64+
}
65+
else if (schema.paths === undefined) {
66+
if (schema.openapi === "3.1.0") {
67+
if (schema.webhooks === undefined) {
68+
throw ono.syntax(`${args.path || args.schema} is not a valid Openapi API definition`);
69+
}
70+
}
71+
else {
8972
throw ono.syntax(`${args.path || args.schema} is not a valid Openapi API definition`);
9073
}
9174
}
92-
else {
93-
throw ono.syntax(`${args.path || args.schema} is not a valid Openapi API definition`);
75+
else if (typeof schema.openapi === "number") {
76+
// This is a very common mistake, so give a helpful error message
77+
throw ono.syntax('Openapi version number must be a string (e.g. "3.0.0") not a number.');
9478
}
95-
}
96-
else if (typeof schema.openapi === "number") {
97-
// This is a very common mistake, so give a helpful error message
98-
throw ono.syntax('Openapi version number must be a string (e.g. "3.0.0") not a number.');
99-
}
100-
else if (typeof schema.info.version === "number") {
101-
// This is a very common mistake, so give a helpful error message
102-
throw ono.syntax('API version number must be a string (e.g. "1.0.0") not a number.');
103-
}
104-
else if (supportedVersions.indexOf(schema.openapi) === -1) {
105-
throw ono.syntax(
106-
`Unsupported OpenAPI version: ${schema.openapi}. ` +
107-
`Swagger Parser only supports versions ${supportedVersions.join(", ")}`
108-
);
79+
else if (typeof schema.info.version === "number") {
80+
// This is a very common mistake, so give a helpful error message
81+
throw ono.syntax('API version number must be a string (e.g. "1.0.0") not a number.');
82+
}
83+
else if (supportedVersions.indexOf(schema.openapi) === -1) {
84+
throw ono.syntax(
85+
`Unsupported OpenAPI version: ${schema.openapi}. ` +
86+
`Swagger Parser only supports versions ${supportedVersions.join(", ")}`
87+
);
88+
}
89+
90+
// This is an OpenAPI v3 schema, check if the "servers" have any relative paths and
91+
// fix them if the content was pulled from a web resource
92+
util.fixOasRelativeServers(schema, args.path);
10993
}
11094

111-
// This is an OpenAPI v3 schema, check if the "servers" have any relative paths and
112-
// fix them if the content was pulled from a web resource
113-
util.fixOasRelativeServers(schema, args.path);
95+
// Looks good!
96+
return maybe(args.callback, Promise.resolve(schema));
97+
}
98+
catch (err) {
99+
return maybe(args.callback, Promise.reject(err));
114100
}
115-
116-
// Looks good!
117-
return maybe(args.callback, Promise.resolve(schema));
118-
}
119-
catch (err) {
120-
return maybe(args.callback, Promise.reject(err));
121101
}
122-
};
123-
124-
/**
125-
* Parses, dereferences, and validates the given Swagger API.
126-
* Depending on the options, validation can include JSON Schema validation and/or Swagger Spec validation.
127-
*
128-
* @param {string} [path] - The file path or URL of the JSON schema
129-
* @param {object} [api] - The Swagger API object. This object will be used instead of reading from `path`.
130-
* @param {ParserOptions} [options] - Options that determine how the API is parsed, dereferenced, and validated
131-
* @param {Function} [callback] - An error-first callback. The second parameter is the parsed API object.
132-
* @returns {Promise} - The returned promise resolves with the parsed API object.
133-
*/
134-
SwaggerParser.validate = function (path, api, options, callback) {
135-
let Class = this; // eslint-disable-line consistent-this
136-
let instance = new Class();
137-
return instance.validate.apply(instance, arguments);
138-
};
139102

140-
/**
141-
* Parses, dereferences, and validates the given Swagger API.
142-
* Depending on the options, validation can include JSON Schema validation and/or Swagger Spec validation.
143-
*
144-
* @param {string} [path] - The file path or URL of the JSON schema
145-
* @param {object} [api] - The Swagger API object. This object will be used instead of reading from `path`.
146-
* @param {ParserOptions} [options] - Options that determine how the API is parsed, dereferenced, and validated
147-
* @param {Function} [callback] - An error-first callback. The second parameter is the parsed API object.
148-
* @returns {Promise} - The returned promise resolves with the parsed API object.
149-
*/
150-
SwaggerParser.prototype.validate = async function (path, api, options, callback) {
151-
let me = this;
152-
let args = normalizeArgs(arguments);
153-
args.options = new Options(args.options);
154-
155-
// ZSchema doesn't support circular objects, so don't dereference circular $refs yet
156-
// (see https://github.com/zaggino/z-schema/issues/137)
157-
let circular$RefOption = args.options.dereference.circular;
158-
args.options.validate.schema && (args.options.dereference.circular = "ignore");
159-
160-
try {
161-
await this.dereference(args.path, args.schema, args.options);
162-
163-
// Restore the original options, now that we're done dereferencing
164-
args.options.dereference.circular = circular$RefOption;
165-
166-
if (args.options.validate.schema) {
167-
// Validate the API against the Swagger schema
168-
// NOTE: This is safe to do, because we haven't dereferenced circular $refs yet
169-
validateSchema(me.api);
170-
171-
if (me.$refs.circular) {
172-
if (circular$RefOption === true) {
173-
// The API has circular references,
174-
// so we need to do a second-pass to fully-dereference it
175-
dereference(me, args.options);
176-
}
177-
else if (circular$RefOption === false) {
178-
// The API has circular references, and they're not allowed, so throw an error
179-
throw ono.reference("The API contains circular references");
103+
/**
104+
* Parses, dereferences, and validates the given Swagger API.
105+
* Depending on the options, validation can include JSON Schema validation and/or Swagger Spec validation.
106+
*
107+
* @param {string} [path] - The file path or URL of the JSON schema
108+
* @param {object} [api] - The Swagger API object. This object will be used instead of reading from `path`.
109+
* @param {ParserOptions} [options] - Options that determine how the API is parsed, dereferenced, and validated
110+
* @param {Function} [callback] - An error-first callback. The second parameter is the parsed API object.
111+
* @returns {Promise} - The returned promise resolves with the parsed API object.
112+
*/
113+
async validate (path, api, options, callback) {
114+
let me = this;
115+
let args = normalizeArgs(arguments);
116+
args.options = new Options(args.options);
117+
118+
// ZSchema doesn't support circular objects, so don't dereference circular $refs yet
119+
// (see https://github.com/zaggino/z-schema/issues/137)
120+
let circular$RefOption = args.options.dereference.circular;
121+
args.options.validate.schema && (args.options.dereference.circular = "ignore");
122+
123+
try {
124+
await this.dereference(args.path, args.schema, args.options);
125+
126+
// Restore the original options, now that we're done dereferencing
127+
args.options.dereference.circular = circular$RefOption;
128+
129+
if (args.options.validate.schema) {
130+
// Validate the API against the Swagger schema
131+
// NOTE: This is safe to do, because we haven't dereferenced circular $refs yet
132+
validateSchema(me.api);
133+
134+
if (me.$refs.circular) {
135+
if (circular$RefOption === true) {
136+
// The API has circular references,
137+
// so we need to do a second-pass to fully-dereference it
138+
dereference(me, args.options);
139+
}
140+
else if (circular$RefOption === false) {
141+
// The API has circular references, and they're not allowed, so throw an error
142+
throw ono.reference("The API contains circular references");
143+
}
180144
}
181145
}
182-
}
183146

184-
if (args.options.validate.spec) {
185-
// Validate the API against the Swagger spec
186-
validateSpec(me.api);
187-
}
147+
if (args.options.validate.spec) {
148+
// Validate the API against the Swagger spec
149+
validateSpec(me.api);
150+
}
188151

189-
return maybe(args.callback, Promise.resolve(me.schema));
152+
return maybe(args.callback, Promise.resolve(me.schema));
153+
}
154+
catch (err) {
155+
return maybe(args.callback, Promise.reject(err));
156+
}
190157
}
191-
catch (err) {
192-
return maybe(args.callback, Promise.reject(err));
158+
}
159+
160+
161+
/**
162+
* Alias {@link $RefParser#schema} as {@link SwaggerParser#api}
163+
*/
164+
Object.defineProperty(SwaggerParser.prototype, "api", {
165+
configurable: true,
166+
enumerable: true,
167+
get () {
168+
return this.schema;
193169
}
194-
};
170+
});
195171

196172
/**
197173
* The Swagger object
198174
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#swagger-object
199175
*
200176
* @typedef {{swagger: string, info: {}, paths: {}}} SwaggerObject
201177
*/
178+
179+
const defaultInstance = new SwaggerParser();
180+
const defaultExport = SwaggerParser;
181+
182+
defaultExport.validate = (...args) => { return defaultInstance.validate(...args); };
183+
defaultExport.dereference = (...args) => { return defaultInstance.dereference(...args); };
184+
defaultExport.bundle = (...args) => { return defaultInstance.bundle(...args); };
185+
defaultExport.parse = (...args) => { return defaultInstance.parse(...args); };
186+
defaultExport.resolve = (...args) => { return defaultInstance.resolve(...args); };
187+
defaultExport.default = defaultExport;
188+
defaultExport.SwaggerParser = defaultExport;
189+
190+
module.exports = defaultExport;

package-lock.json

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"@types/node": "^14.6.4",
6262
"chai": "^4.2.0",
6363
"eslint": "^7.8.1",
64-
"js-yaml": "^3.14.0",
64+
"js-yaml": "^3.14.1",
6565
"karma": "^6.3.19",
6666
"karma-cli": "^2.0.0",
6767
"mocha": "^8.1.3",
@@ -73,7 +73,7 @@
7373
"shx": "^0.3.2",
7474
"simplifyify": "^7.0.7",
7575
"sinon": "^11.1.2",
76-
"typescript": "^4.0.2"
76+
"typescript": "^4.7.4"
7777
},
7878
"dependencies": {
7979
"@apidevtools/json-schema-ref-parser": "9.0.6",

0 commit comments

Comments
 (0)