swagger2openapi
Advanced tools
Comparing version 2.1.0 to 2.2.0
@@ -5,4 +5,2 @@ 'use strict'; | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var util = require('util'); | ||
var url = require('url'); | ||
@@ -51,3 +49,3 @@ | ||
var newState = {}; | ||
newState.parent = object; | ||
newState.parent = object; | ||
newState.path = state.path; | ||
@@ -103,3 +101,3 @@ newState.depth = (state.depth ? state.depth++ : state.depth=1); | ||
function resolveInternal(root,pointer,options) { | ||
function resolveInternal(root,pointer) { | ||
return jptr.jptr(root,pointer)||false; | ||
@@ -106,0 +104,0 @@ } |
@@ -15,3 +15,3 @@ { | ||
"url": "https://github.com/mermade/swagger2openapi", | ||
"version": "2.0.4" | ||
"version": "2.1.0" | ||
} | ||
@@ -18,0 +18,0 @@ } |
@@ -16,2 +16,3 @@ # Options documentation | ||
laxurls|Boolean|Input|Flag to validation step to ignore empty URLs | ||
nopatch|Boolean|Input|Command-line flag by `testRunner` to unset `patch` | ||
openapi|Object|Output|The OpenApi 3.x definition returned from a conversion step | ||
@@ -18,0 +19,0 @@ origin|String|Input|The URL of the definition, set by convertUrl method |
129
index.js
'use strict'; | ||
var fs = require('fs'); | ||
var util = require('util'); | ||
@@ -17,2 +16,3 @@ var co = require('co'); | ||
const targetVersion = '3.0.0-RC1'; | ||
var componentNames; // initialised in main | ||
@@ -28,7 +28,7 @@ function throwError(message,options) { | ||
obj.oneOf = []; | ||
for (var type of obj[key]) { | ||
for (let type of obj[key]) { | ||
var schema = {}; | ||
schema.type = type; | ||
if (type == 'array') { | ||
for (var prop of common.arrayProperties) { | ||
for (let prop of common.arrayProperties) { | ||
if (typeof obj[prop] !== 'undefined') { | ||
@@ -67,5 +67,16 @@ schema[prop] = obj[prop]; | ||
if ((key == '$ref') && (typeof obj[key] === 'string')) { | ||
if (obj[key].indexOf('#/definitions/') == 0) { | ||
obj[key] = '#/components/schemas/'+common.sanitise(obj[key].replace('#/definitions/','')); | ||
if (obj[key].startsWith('#/definitions/')) { | ||
//only the first part of a schema component name must be sanitised | ||
let keys = obj[key].replace('#/definitions/','').split('/'); | ||
keys[0] = componentNames.schemas[keys[0]]; | ||
obj[key] = '#/components/schemas/'+keys.join('/'); | ||
} | ||
if (obj[key].startsWith('#/parameters/')) { | ||
// for extensions like Apigee's x-templates | ||
obj[key] = '#/components/parameters/'+common.sanitise(obj[key].replace('#/parameters/','')); | ||
} | ||
if (obj[key].startsWith('#/responses/')) { | ||
// for extensions like Apigee's x-templates | ||
obj[key] = '#/components/responses/'+common.sanitise(obj[key].replace('#/responses/','')); | ||
} | ||
Object.keys(obj).forEach(function(k){ | ||
@@ -76,3 +87,5 @@ if (k !== '$ref') delete obj[k]; | ||
if ((key == 'x-ms-odata') && (typeof obj[key] === 'string')) { | ||
obj[key] = '#/components/schemas/'+common.sanitise(obj[key].replace('#/definitions/','')); | ||
let keys = obj[key].replace('#/definitions/','').split('/'); | ||
keys[0] = componentNames.schemas[keys[0]]; | ||
obj[key] = '#/components/schemas/'+keys.join('/'); | ||
} | ||
@@ -82,4 +95,4 @@ } | ||
function processSecurity(securityObject) { | ||
for (var s in securityObject) { | ||
for (var k in securityObject[s]) { | ||
for (let s in securityObject) { | ||
for (let k in securityObject[s]) { | ||
var sname = common.sanitise(k); | ||
@@ -116,3 +129,3 @@ if (k != sname) { | ||
function deleteParameters(value, index, self) { | ||
function deleteParameters(value) { | ||
return !value["x-s2o-delete"]; | ||
@@ -131,3 +144,3 @@ } | ||
delete header.type; | ||
for (var prop of common.parameterTypeProperties) { | ||
for (let prop of common.parameterTypeProperties) { | ||
if (typeof header[prop] !== 'undefined') { | ||
@@ -151,3 +164,3 @@ header.schema[prop] = header[prop]; | ||
if (param.$ref) { | ||
if (param.$ref && (typeof param.$ref === 'string')) { | ||
// if we still have a ref here, it must be an internal one | ||
@@ -162,3 +175,3 @@ if (param.$ref.startsWith('#/parameters/')) { | ||
var rbody = false; | ||
var target = openapi.components.parameters[ptr]; // resolves a $ref, must have been sanitised already | ||
let target = openapi.components.parameters[ptr]; // resolves a $ref, must have been sanitised already | ||
@@ -212,3 +225,3 @@ if ((!target) || (target["x-s2o-delete"])) { | ||
if (param.collectionFormat == 'tsv') { | ||
throwError('collectionFormat:tsv is not supported', options); // not lossless | ||
throwError('collectionFormat:tsv is no longer supported', options); // not lossless | ||
} | ||
@@ -234,6 +247,6 @@ delete param.collectionFormat; | ||
delete obj[key]; // not lossless | ||
}; | ||
} | ||
}); | ||
} | ||
for (var prop of common.parameterTypeProperties) { | ||
for (let prop of common.parameterTypeProperties) { | ||
if (typeof param[prop] !== 'undefined') param.schema[prop] = param[prop]; | ||
@@ -279,7 +292,7 @@ delete param.prop; | ||
var schema = result.content[contentType].schema; | ||
var target = result.content[contentType].schema.properties[param.name]; | ||
let target = result.content[contentType].schema.properties[param.name]; | ||
if (param.description) result.description = param.description; | ||
if (param.type) target.type = param.type; | ||
for (var prop of common.parameterTypeProperties) { | ||
for (let prop of common.parameterTypeProperties) { | ||
if (typeof param[prop] !== 'undefined') target[prop] = param[prop]; | ||
@@ -322,3 +335,3 @@ } | ||
for (var mimetype of consumes) { | ||
for (let mimetype of consumes) { | ||
result.content[mimetype] = {}; | ||
@@ -365,3 +378,3 @@ if (param.description) result.content[mimetype].description = param.description; | ||
else if (path) { | ||
var uniqueName = index ? index.toCamelCase()+'RequestBodyBase' : param.name; | ||
let uniqueName = index ? index.toCamelCase()+'RequestBodyBase' : param.name; | ||
if (param.in == 'formData') { | ||
@@ -373,3 +386,3 @@ result["x-s2o-partial"] = true; | ||
else { | ||
var uniqueName = index ? index : param.name; | ||
let uniqueName = index ? index : param.name; | ||
if (param.in == 'formData') { | ||
@@ -384,3 +397,3 @@ result["x-s2o-partial"] = true; | ||
delete param.type; | ||
for (var prop of common.parameterTypeProperties) { | ||
for (let prop of common.parameterTypeProperties) { | ||
delete param[prop]; | ||
@@ -402,3 +415,3 @@ } | ||
function processResponse(response, op, openapi, options) { | ||
if (response.$ref) { | ||
if (response.$ref && (typeof response.$ref === 'string')) { | ||
if (typeof response.description !== 'undefined') { | ||
@@ -435,3 +448,3 @@ if (options.patch) { | ||
if (response.schema.$ref && response.schema.$ref.startsWith('#/responses/')) { | ||
if (response.schema.$ref && (typeof response.schema.$ref === 'string') && response.schema.$ref.startsWith('#/responses/')) { | ||
response.schema.$ref = '#/components/responses/' + common.sanitise(response.schema.$ref.replace('#/responses/', '')); | ||
@@ -443,3 +456,3 @@ } | ||
response.content = {}; | ||
for (var mimetype of produces) { | ||
for (let mimetype of produces) { | ||
response.content[mimetype] = {}; | ||
@@ -459,3 +472,3 @@ response.content[mimetype].schema = common.clone(response.schema); | ||
// examples for other types | ||
for (var mimetype in response.examples) { | ||
for (let mimetype in response.examples) { | ||
if (!response.content) response.content = {}; | ||
@@ -468,3 +481,3 @@ if (!response.content[mimetype]) response.content[mimetype] = {}; | ||
if (response.headers) { | ||
for (var h in response.headers) { | ||
for (let h in response.headers) { | ||
processHeader(response.headers[h]); | ||
@@ -477,3 +490,3 @@ } | ||
function processPaths(container, containerName, options, requestBodyCache, openapi) { | ||
for (var p in container) { | ||
for (let p in container) { | ||
var path = container[p]; | ||
@@ -497,3 +510,3 @@ // path.$ref is external only | ||
} | ||
for (var method in path) { | ||
for (let method in path) { | ||
if ((common.httpVerbs.indexOf(method) >= 0) || (method === 'x-amazon-apigateway-any-method')) { | ||
@@ -508,3 +521,3 @@ var op = path[method]; | ||
if (op.parameters && Array.isArray(op.parameters)) { | ||
for (var param of op.parameters) { | ||
for (let param of op.parameters) { | ||
processParameter(param, op, path, null, openapi, options); | ||
@@ -527,3 +540,3 @@ } | ||
} | ||
for (var r in op.responses) { | ||
for (let r in op.responses) { | ||
var response = op.responses[r]; | ||
@@ -561,3 +574,3 @@ processResponse(response,op,openapi,options); | ||
if (path.parameters) { | ||
for (var p2 in path.parameters) { | ||
for (let p2 in path.parameters) { | ||
var param = path.parameters[p2]; | ||
@@ -576,7 +589,8 @@ processParameter(param, null, path, p, openapi, options); // index here is the path string | ||
var requestBodyCache = {}; | ||
componentNames = {schemas:{}}; | ||
if (openapi.security) processSecurity(openapi.security); | ||
for (var s in openapi.components.securitySchemes) { | ||
var sname = common.sanitise(s); | ||
for (let s in openapi.components.securitySchemes) { | ||
let sname = common.sanitise(s); | ||
if (s != sname) { | ||
@@ -592,15 +606,17 @@ if (openapi.components.securitySchemes[sname]) { | ||
for (var s in openapi.components.schemas) { | ||
var sname = common.sanitise(s); | ||
for (let s in openapi.components.schemas) { | ||
let sname = common.sanitise(s); | ||
let suffix = ''; | ||
if (s != sname) { | ||
if (openapi.components.schemas[sname]) { | ||
throwError('Duplicate sanitised schema name '+sname,options); | ||
while (openapi.components.schemas[sname+suffix]) { | ||
suffix = (suffix ? ++suffix : 2); | ||
} | ||
openapi.components.schemas[sname] = openapi.components.schemas[s]; | ||
openapi.components.schemas[sname+suffix] = openapi.components.schemas[s]; | ||
delete openapi.components.schemas[s]; | ||
} | ||
componentNames.schemas[s] = sname+suffix; | ||
} | ||
for (var p in openapi.components.parameters) { | ||
var sname = common.sanitise(p); | ||
for (let p in openapi.components.parameters) { | ||
let sname = common.sanitise(p); | ||
if (p != sname) { | ||
@@ -618,4 +634,4 @@ if (openapi.components.parameters[sname]) { | ||
common.recurse(openapi.components.responses,{payload:{targetted:false}},fixupSchema); | ||
for (var r in openapi.components.responses) { | ||
var sname = common.sanitise(r); | ||
for (let r in openapi.components.responses) { | ||
let sname = common.sanitise(r); | ||
if (r != sname) { | ||
@@ -631,3 +647,3 @@ if (openapi.components.responses[sname]) { | ||
if (response.headers) { | ||
for (var h in response.headers) { | ||
for (let h in response.headers) { | ||
processHeader(response.headers[h]); | ||
@@ -638,7 +654,7 @@ } | ||
for (var r in openapi.components.requestBodies) { // converted ones | ||
for (let r in openapi.components.requestBodies) { // converted ones | ||
var rb = openapi.components.requestBodies[r]; | ||
var rbStr = JSON.stringify(rb); | ||
var rbSha256 = common.sha256(rbStr); | ||
var entry = {}; | ||
let entry = {}; | ||
entry.name = r; | ||
@@ -656,3 +672,3 @@ entry.body = rb; | ||
if (!options.debug) { | ||
for (var p in openapi.components.parameters) { | ||
for (let p in openapi.components.parameters) { | ||
param = openapi.components.parameters[p]; | ||
@@ -680,4 +696,4 @@ if (param["x-s2o-delete"]) { | ||
var counter = 1; | ||
for (var e in requestBodyCache) { | ||
var entry = requestBodyCache[e]; | ||
for (let e in requestBodyCache) { | ||
let entry = requestBodyCache[e]; | ||
if (entry.refs.length>1) { | ||
@@ -697,3 +713,3 @@ // create a shared requestBody | ||
openapi.components.requestBodies[entry.name] = entry.body; | ||
for (var r in entry.refs) { | ||
for (let r in entry.refs) { | ||
var address = entry.refs[r].split(' '); | ||
@@ -712,3 +728,3 @@ var ref = {}; | ||
return maybe(callback, new Promise(function(resolve, reject) { | ||
if ((swagger.openapi) && (swagger.openapi.startsWith('3.'))) { | ||
if (swagger.openapi && (typeof swagger.openapi === 'string') && swagger.openapi.startsWith('3.')) { | ||
options.openapi = swagger; | ||
@@ -743,6 +759,5 @@ return resolve(options); | ||
var server; | ||
if (swagger.host && swagger.schemes) { | ||
for (var s of swagger.schemes) { | ||
server = {}; | ||
for (let s of swagger.schemes) { | ||
let server = {}; | ||
server.url = s + '://' + swagger.host + (swagger.basePath ? swagger.basePath : '/'); | ||
@@ -761,3 +776,3 @@ server.url = server.url.split('{{').join('{'); | ||
else if (swagger.basePath) { | ||
server = {}; | ||
let server = {}; | ||
server.url = swagger.basePath; | ||
@@ -775,10 +790,10 @@ openapi.servers.push(server); | ||
// TODO APIMatic ? | ||
// TODO APIMatic extensions ? | ||
if (swagger['x-ms-parameterized-host']) { | ||
var xMsPHost = swagger['x-ms-parameterized-host']; | ||
var server = {}; | ||
let server = {}; | ||
server.url = xMsPHost.hostTemplate; | ||
server.parameters = xMsPHost.parameters; | ||
for (var param of server.parameters) { | ||
for (let param of server.parameters) { | ||
if (param.ref === false) param.required = true; // has a different meaning | ||
@@ -785,0 +800,0 @@ delete param.type; // all strings |
{ | ||
"name": "swagger2openapi", | ||
"version": "2.1.0", | ||
"version": "2.2.0", | ||
"description": "Convert Swagger 2.0 definitions to OpenApi 3.0", | ||
@@ -9,2 +9,14 @@ "main": "index.js", | ||
}, | ||
"browserify": { | ||
"transform": [ | ||
[ | ||
"babelify", | ||
{ | ||
"presets": [ | ||
"es2015" | ||
] | ||
} | ||
] | ||
] | ||
}, | ||
"repository": { | ||
@@ -39,4 +51,8 @@ "url": "https://github.com/Mermade/swagger2openapi.git", | ||
"devDependencies": { | ||
"webpack": "^2.4.1", | ||
"babel-core": "^6.24.1", | ||
"babel-loader": "^7.0.0", | ||
"babel-preset-es2015": "^6.24.1", | ||
"coveralls": "^2.12.0" | ||
} | ||
} |
@@ -132,2 +132,5 @@ { | ||
"description": "An object representing a Server.", | ||
"required": [ | ||
"url" | ||
], | ||
"patternProperties": { | ||
@@ -148,6 +151,3 @@ "^x-": { | ||
} | ||
}, | ||
"required": [ | ||
"url" | ||
] | ||
} | ||
}, | ||
@@ -181,3 +181,3 @@ "serverVariables": { | ||
"items": { | ||
"$ref": "#/definitions/primitive" | ||
"type": "string" | ||
}, | ||
@@ -187,3 +187,3 @@ "uniqueItems": true | ||
"default": { | ||
"$ref": "#/definitions/primitive" | ||
"type": "string" | ||
}, | ||
@@ -205,27 +205,27 @@ "description": { | ||
"schemas": { | ||
"$ref": "#/definitions/schemas" | ||
"$ref": "#/definitions/schemasOrReferences" | ||
}, | ||
"responses": { | ||
"$ref": "#/definitions/responses" | ||
"$ref": "#/definitions/responsesOrReferences" | ||
}, | ||
"parameters": { | ||
"$ref": "#/definitions/parameters" | ||
"$ref": "#/definitions/parametersOrReferences" | ||
}, | ||
"examples": { | ||
"$ref": "#/definitions/examples" | ||
"$ref": "#/definitions/examplesOrReferences" | ||
}, | ||
"requestBodies": { | ||
"$ref": "#/definitions/requestBodies" | ||
"$ref": "#/definitions/requestBodiesOrReferences" | ||
}, | ||
"headers": { | ||
"$ref": "#/definitions/headers" | ||
"$ref": "#/definitions/headersOrReferences" | ||
}, | ||
"securitySchemes": { | ||
"$ref": "#/definitions/securitySchemes" | ||
"$ref": "#/definitions/securitySchemesOrReferences" | ||
}, | ||
"links": { | ||
"$ref": "#/definitions/links" | ||
"$ref": "#/definitions/linksOrReferences" | ||
}, | ||
"callbacks": { | ||
"$ref": "#/definitions/callbacks" | ||
"$ref": "#/definitions/callbacksOrReferences" | ||
} | ||
@@ -289,3 +289,7 @@ } | ||
"servers": { | ||
"$ref": "#/definitions/server" | ||
"type": "array", | ||
"items": { | ||
"$ref": "#/definitions/server" | ||
}, | ||
"uniqueItems": true | ||
}, | ||
@@ -359,3 +363,7 @@ "parameters": { | ||
"servers": { | ||
"$ref": "#/definitions/server" | ||
"type": "array", | ||
"items": { | ||
"$ref": "#/definitions/server" | ||
}, | ||
"uniqueItems": true | ||
} | ||
@@ -427,12 +435,8 @@ } | ||
}, | ||
"example": { | ||
"$ref": "#/definitions/any" | ||
}, | ||
"examples": { | ||
"type": "array", | ||
"items": { | ||
"$ref": "#/definitions/exampleOrReference" | ||
}, | ||
"uniqueItems": true | ||
"$ref": "#/definitions/examplesOrReferences" | ||
}, | ||
"example": { | ||
"$ref": "#/definitions/exampleOrReference" | ||
}, | ||
"content": { | ||
@@ -446,2 +450,5 @@ "$ref": "#/definitions/content" | ||
"description": "Describes a single request body.", | ||
"required": [ | ||
"content" | ||
], | ||
"patternProperties": { | ||
@@ -452,3 +459,2 @@ "^x-": { | ||
}, | ||
"additionalProperties": false, | ||
"properties": { | ||
@@ -464,10 +470,7 @@ "description": { | ||
} | ||
}, | ||
"required": [ | ||
"content" | ||
] | ||
} | ||
}, | ||
"content": { | ||
"type": "object", | ||
"description": "Describes a set of supported media types. A Content Object can be used in Request Body Object, Parameter Objects, Header Objects, and Response Objects. Each key in the Content Object is the media type of the Media Type Object.", | ||
"description": "Describes a set of supported media types. A Content Object can be used in Request Body Object, Parameter Objects, Header Objects, and Response Objects.", | ||
"patternProperties": { | ||
@@ -491,12 +494,8 @@ "{media-type}": { | ||
}, | ||
"example": { | ||
"$ref": "#/definitions/any" | ||
}, | ||
"examples": { | ||
"type": "array", | ||
"items": { | ||
"$ref": "#/definitions/exampleOrReference" | ||
}, | ||
"uniqueItems": true | ||
"$ref": "#/definitions/examplesOrReferences" | ||
}, | ||
"example": { | ||
"$ref": "#/definitions/exampleOrReference" | ||
}, | ||
"encoding": { | ||
@@ -536,2 +535,5 @@ "$ref": "#/definitions/encoding" | ||
"type": "boolean" | ||
}, | ||
"allowReserved": { | ||
"type": "boolean" | ||
} | ||
@@ -542,3 +544,3 @@ } | ||
"type": "object", | ||
"description": "A container for the expected responses of an operation. The container maps a HTTP response code to the expected response. It is not expected from the documentation to necessarily cover all possible HTTP response codes, since they may not be known in advance. However, it is expected from the documentation to cover a successful operation response and any known errors. The `default` MAY be used as a default response object for all HTTP codes that are not covered individually by the specification. The `Responses Object` MUST contain at least one response code, and it SHOULD be the response for a successful operation call.", | ||
"description": "A container for the expected responses of an operation. The container maps a HTTP response code to the expected response. It is not expected for the documentation to necessarily cover all possible HTTP response codes, since they may not be known in advance. However, it is expected for the documentation to cover a successful operation response and any known errors. The `default` MAY be used as a default response object for all HTTP codes that are not covered individually by the specification. The `Responses Object` MUST contain at least one response code, and it SHOULD be the response for a successful operation call.", | ||
"patternProperties": { | ||
@@ -619,3 +621,22 @@ "^([0-9]{3})$": { | ||
"type": "object", | ||
"description": "Allows sharing examples for operation requests and responses. This object can either be a freeform object, array or primitive value. To represent examples of media types that cannot naturally represented in the OpenAPI definition, a string value can be used to contain the example with escaping where necessary." | ||
"description": "", | ||
"patternProperties": { | ||
"^x-": { | ||
"$ref": "#/definitions/specificationExtension" | ||
} | ||
}, | ||
"properties": { | ||
"summary": { | ||
"type": "string" | ||
}, | ||
"description": { | ||
"type": "string" | ||
}, | ||
"value": { | ||
"$ref": "#/definitions/any" | ||
}, | ||
"externalValue": { | ||
"type": "string" | ||
} | ||
} | ||
}, | ||
@@ -640,3 +661,3 @@ "links": { | ||
"properties": { | ||
"href": { | ||
"operationRef": { | ||
"type": "string" | ||
@@ -655,2 +676,5 @@ }, | ||
"type": "string" | ||
}, | ||
"server": { | ||
"$ref": "#/definitions/server" | ||
} | ||
@@ -702,12 +726,8 @@ } | ||
}, | ||
"example": { | ||
"$ref": "#/definitions/any" | ||
}, | ||
"examples": { | ||
"type": "array", | ||
"items": { | ||
"$ref": "#/definitions/exampleOrReference" | ||
}, | ||
"uniqueItems": true | ||
"$ref": "#/definitions/examplesOrReferences" | ||
}, | ||
"example": { | ||
"$ref": "#/definitions/exampleOrReference" | ||
}, | ||
"content": { | ||
@@ -760,2 +780,3 @@ "$ref": "#/definitions/content" | ||
"description": "The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is an extended subset of the JSON Schema Specification Wright Draft 00. Further information about the properties can be found in JSON Schema Core and JSON Schema Validation. Unless stated otherwise, the property definitions follow the JSON Schema specification as referenced here.", | ||
"additionalProperties": false, | ||
"patternProperties": { | ||
@@ -766,3 +787,2 @@ "^x-": { | ||
}, | ||
"additionalProperties": false, | ||
"properties": { | ||
@@ -790,5 +810,2 @@ "nullable": { | ||
}, | ||
"examples": { | ||
"$ref": "#/definitions/any" | ||
}, | ||
"deprecated": { | ||
@@ -893,10 +910,10 @@ "type": "boolean" | ||
"additionalProperties": { | ||
"oneOf": [ | ||
{ | ||
"$ref": "#/definitions/schemaOrReference" | ||
}, | ||
{ | ||
"type": "boolean" | ||
} | ||
] | ||
"oneOf": [ | ||
{ | ||
"$ref": "#/definitions/schemaOrReference" | ||
}, | ||
{ | ||
"type": "boolean" | ||
} | ||
] | ||
}, | ||
@@ -1139,24 +1156,64 @@ "default": { | ||
}, | ||
"parameters": { | ||
"securitySchemeOrReference": { | ||
"oneOf": [ | ||
{ | ||
"$ref": "#/definitions/securityScheme" | ||
}, | ||
{ | ||
"$ref": "#/definitions/reference" | ||
} | ||
] | ||
}, | ||
"callbacksOrReferences": { | ||
"type": "object", | ||
"additionalProperties": { | ||
"$ref": "#/definitions/parameter" | ||
"$ref": "#/definitions/callbackOrReference" | ||
} | ||
}, | ||
"requestBodies": { | ||
"examplesOrReferences": { | ||
"type": "object", | ||
"additionalProperties": { | ||
"$ref": "#/definitions/requestBody" | ||
"$ref": "#/definitions/exampleOrReference" | ||
} | ||
}, | ||
"schemas": { | ||
"headersOrReferences": { | ||
"type": "object", | ||
"additionalProperties": { | ||
"$ref": "#/definitions/headerOrReference" | ||
} | ||
}, | ||
"linksOrReferences": { | ||
"type": "object", | ||
"additionalProperties": { | ||
"$ref": "#/definitions/linkOrReference" | ||
} | ||
}, | ||
"parametersOrReferences": { | ||
"type": "object", | ||
"additionalProperties": { | ||
"$ref": "#/definitions/parameterOrReference" | ||
} | ||
}, | ||
"requestBodiesOrReferences": { | ||
"type": "object", | ||
"additionalProperties": { | ||
"$ref": "#/definitions/requestBodyOrReference" | ||
} | ||
}, | ||
"responsesOrReferences": { | ||
"type": "object", | ||
"additionalProperties": { | ||
"$ref": "#/definitions/responseOrReference" | ||
} | ||
}, | ||
"schemasOrReferences": { | ||
"type": "object", | ||
"additionalProperties": { | ||
"$ref": "#/definitions/schemaOrReference" | ||
} | ||
}, | ||
"securitySchemes": { | ||
"securitySchemesOrReferences": { | ||
"type": "object", | ||
"additionalProperties": { | ||
"$ref": "#/definitions/securityScheme" | ||
"$ref": "#/definitions/securitySchemeOrReference" | ||
} | ||
@@ -1166,13 +1223,10 @@ }, | ||
"type": "object", | ||
"additionalProperties": true, | ||
"additionalItems": true | ||
"additionalProperties": true | ||
}, | ||
"any": { | ||
"additionalProperties": true, | ||
"additionalItems": true | ||
"additionalProperties": true | ||
}, | ||
"expression": { | ||
"type": "object", | ||
"additionalProperties": true, | ||
"additionalItems": true | ||
"additionalProperties": true | ||
}, | ||
@@ -1223,18 +1277,4 @@ "specificationExtension": { | ||
] | ||
}, | ||
"primitive": { | ||
"oneOf": [ | ||
{ | ||
"type": "number" | ||
}, | ||
{ | ||
"type": "boolean" | ||
}, | ||
{ | ||
"type": "string" | ||
} | ||
] | ||
} | ||
} | ||
} | ||
@@ -61,13 +61,13 @@ #!/usr/bin/env node | ||
if (options.yaml) { | ||
s = options.debug ? yaml.dump(options.openapi) : yaml.safeDump(options.openapi); | ||
s = options.debug ? yaml.dump(options.openapi) : yaml.safeDump(options.openapi); | ||
} | ||
else { | ||
s = JSON.stringify(options.openapi, null, 2); | ||
s = JSON.stringify(options.openapi, null, 2); | ||
} | ||
if (argv.outfile) { | ||
fs.writeFileSync(options.outfile, s, options.encoding||'utf8'); | ||
fs.writeFileSync(options.outfile, s, options.encoding||'utf8'); | ||
} | ||
else { | ||
console.log(s); | ||
console.log(s); | ||
} | ||
@@ -74,0 +74,0 @@ |
@@ -5,2 +5,3 @@ 'use strict'; | ||
var path = require('path'); | ||
var util = require('util'); | ||
var readfiles = require('node-readfiles'); | ||
@@ -25,5 +26,5 @@ var yaml = require('js-yaml'); | ||
.describe('laxurls','lax checking of empty urls') | ||
.boolean('stop') | ||
.alias('s','stop') | ||
.describe('stop','stop on first error') | ||
.boolean('nopatch') | ||
.alias('n','nopatch') | ||
.describe('nopatch','do not patch minor errors in the source definition') | ||
.boolean('quiet') | ||
@@ -35,2 +36,5 @@ .alias('q','quiet') | ||
.describe('resolve','resolve external references') | ||
.boolean('stop') | ||
.alias('s','stop') | ||
.describe('stop','stop on first error') | ||
.count('verbose') | ||
@@ -60,3 +64,3 @@ .alias('v','verbose') | ||
var options = argv; | ||
options.patch = true; | ||
options.patch = !argv.nopatch; | ||
@@ -136,6 +140,6 @@ function handleResult(err, options) { | ||
try { | ||
src = yaml.safeLoad(srcStr,{json:true}); | ||
src = yaml.safeLoad(srcStr,{schema:yaml.JSON_SCHEMA,json:true}); | ||
} | ||
catch (ex) { | ||
var warning = 'Could not parse file '+file; | ||
var warning = 'Could not parse file '+file+'\n'+ex.message; | ||
console.log(red+warning); | ||
@@ -154,11 +158,11 @@ warnings.push(warning); | ||
try { | ||
swagger2openapi.convertObj(src, common.clone(options), handleResult); | ||
} | ||
catch (ex) { | ||
console.log(red+'Converter threw an error: '+ex.message); | ||
warnings.push('Converter failed '+options.source); | ||
try { | ||
swagger2openapi.convertObj(src, common.clone(options), handleResult); | ||
} | ||
catch (ex) { | ||
console.log(red+'Converter threw an error: '+ex.message); | ||
warnings.push('Converter failed '+options.source); | ||
genStackNext(); | ||
result = false; | ||
} | ||
result = false; | ||
} | ||
@@ -181,3 +185,4 @@ } | ||
else { | ||
readfiles(pathspec, {readContents: false, filenameFormat: readfiles.FULL_PATH}, function (err, filename, content) { | ||
readfiles(pathspec, {readContents: false, filenameFormat: readfiles.FULL_PATH}, function (err) { | ||
if (err) console.log(util.inspect(err)); | ||
}) | ||
@@ -206,3 +211,3 @@ .then(files => { | ||
} | ||
for (var pathspec of argv._) { | ||
for (let pathspec of argv._) { | ||
processPathSpec(pathspec,false); | ||
@@ -212,3 +217,3 @@ } | ||
if (!Array.isArray(argv.fail)) argv.fail = [argv.fail]; | ||
for (var pathspec of argv.fail) { | ||
for (let pathspec of argv.fail) { | ||
processPathSpec(pathspec,true); | ||
@@ -218,3 +223,3 @@ } | ||
process.on('exit', function(code) { | ||
process.on('exit', function() { | ||
if (warnings.length) { | ||
@@ -221,0 +226,0 @@ warnings.sort(); |
@@ -1,2 +0,3 @@ | ||
var path = require('path'); | ||
'use strict'; | ||
var url = require('url'); | ||
@@ -16,4 +17,4 @@ var URL = url.URL; | ||
var jsonSchema = require(path.join(__dirname,'/schemas/json_v5.json')); | ||
var openapi3Schema = require(path.join(__dirname,'/schemas/openapi-3.json')); | ||
var jsonSchema = require('./schemas/json_v5.json'); | ||
var openapi3Schema = require('./schemas/openapi-3.json'); | ||
var validateMetaSchema = ajv.compile(jsonSchema); | ||
@@ -56,3 +57,3 @@ var validateOpenAPI3 = ajv.compile(openapi3Schema); | ||
contextAppend(options,'content'); | ||
for (var ct in content) { | ||
for (let ct in content) { | ||
contextAppend(options,ct); | ||
@@ -75,7 +76,7 @@ var contentType = content[ct]; | ||
servers.should.be.an.Array(); | ||
for (var server of servers) { | ||
for (let server of servers) { | ||
server.should.have.property('url'); | ||
validateUrl(server.url,[],'server.url',options).should.not.throw(); | ||
if (server.variables) { | ||
for (var v in server.variables) { | ||
for (let v in server.variables) { | ||
server.variables[v].should.have.key('default'); | ||
@@ -86,3 +87,3 @@ server.variables[v].default.should.be.type('string'); | ||
should(server.variables[v].enum.length).not.be.exactly(0,'Server variables enum should not be empty'); | ||
for (var enumValue of server.variables[v].enum) { | ||
for (let enumValue of server.variables[v].enum) { | ||
enumValue.should.be.type('string'); | ||
@@ -106,3 +107,3 @@ } | ||
header.should.not.have.property('type'); | ||
for (var prop of common.parameterTypeProperties) { | ||
for (let prop of common.parameterTypeProperties) { | ||
header.should.not.have.property(prop); | ||
@@ -136,3 +137,3 @@ } | ||
contextAppend(options,'headers'); | ||
for (var h in response.headers) { | ||
for (let h in response.headers) { | ||
contextAppend(options,h); | ||
@@ -171,3 +172,3 @@ checkHeader(response.headers[h],openapi); | ||
param.should.not.have.property('type'); | ||
for (var prop of common.parameterTypeProperties) { | ||
for (let prop of common.parameterTypeProperties) { | ||
param.should.not.have.property(prop); | ||
@@ -202,7 +203,7 @@ } | ||
for (var o in pathItem) { | ||
for (let o in pathItem) { | ||
contextAppend(options,o); | ||
var op = pathItem[o]; | ||
if (o == 'parameters') { | ||
for (var p in pathItem.parameters) { | ||
for (let p in pathItem.parameters) { | ||
checkParam(pathItem.parameters[p],p,openapi,options); | ||
@@ -221,2 +222,3 @@ } | ||
else if (common.httpVerbs.indexOf(o)>=0) { | ||
op.should.not.be.empty(); | ||
op.should.not.have.property('consumes'); | ||
@@ -239,3 +241,3 @@ op.should.not.have.property('produces'); | ||
contextAppend(options,'responses'); | ||
for (var r in op.responses) { | ||
for (let r in op.responses) { | ||
contextAppend(options,r); | ||
@@ -250,3 +252,3 @@ var response = op.responses[r]; | ||
contextAppend(options,'parameters'); | ||
for (var p in op.parameters) { | ||
for (let p in op.parameters) { | ||
checkParam(op.parameters[p],p,openapi,options); | ||
@@ -280,2 +282,3 @@ } | ||
openapi.openapi.should.have.type('string'); | ||
should.ok(openapi.openapi.startsWith('3.0.'),'Must be an OpenAPI 3.0.x document'); | ||
openapi.should.not.have.key('host'); | ||
@@ -322,3 +325,4 @@ openapi.should.not.have.key('basePath'); | ||
if (openapi.tags) { | ||
for (var tag of openapi.tags) { | ||
contextAppend(options,'tags'); | ||
for (let tag of openapi.tags) { | ||
tag.should.have.property('name'); | ||
@@ -332,6 +336,7 @@ tag.name.should.have.type('string'); | ||
} | ||
options.context.pop(); | ||
} | ||
if (openapi.components && openapi.components.securitySchemes) { | ||
for (var s in openapi.components.securitySchemes) { | ||
for (let s in openapi.components.securitySchemes) { | ||
options.context.push('#/components/securitySchemes/'+s); | ||
@@ -369,3 +374,3 @@ validateComponentName(s).should.be.equal(true,'component name invalid'); | ||
scheme.should.have.property('flows'); | ||
for (var f in scheme.flows) { | ||
for (let f in scheme.flows) { | ||
var flow = scheme.flows[f]; | ||
@@ -410,10 +415,11 @@ if ((f == 'implicit') || (f == 'authorizationCode')) { | ||
should.ok(openapi.openapi.startsWith('3.0.'),'Must be an OpenAPI 3.0.x document'); | ||
common.recurse(openapi,null,function(obj,key,state){ | ||
if ((key === '$ref') && (typeof obj[key] === 'string')) { | ||
options.context.push(state.path); | ||
should(obj[key].indexOf('#/definitions/')).be.exactly(-1,'Reference to #/definitions'); | ||
obj[key].should.not.startWith('#/definitions/'); | ||
should(Object.keys(obj).length).be.exactly(1,'Reference object cannot be extended'); | ||
should(jptr.jptr(openapi,obj[key])).not.be.exactly(false,'Cannot resolve reference: '+obj[key]); | ||
var refUrl = url.parse(obj[key]); | ||
if (!refUrl.protocol && !refUrl.path) { | ||
should(jptr.jptr(openapi,obj[key])).not.be.exactly(false,'Cannot resolve reference: '+obj[key]); | ||
} | ||
options.context.pop(); | ||
@@ -425,3 +431,3 @@ } | ||
options.context.push('#/components/parameters/'); | ||
for (var p in openapi.components.parameters) { | ||
for (let p in openapi.components.parameters) { | ||
checkParam(openapi.components.parameters[p],p,openapi,options); | ||
@@ -434,10 +440,14 @@ contextAppend(options, p); | ||
} | ||
for (var p in openapi.paths) { | ||
for (let p in openapi.paths) { | ||
options.context.push('#/paths/'+jptr.jpescape(p)); | ||
checkPathItem(openapi.paths[p],openapi,options); | ||
if (!p.startsWith('x-')) { | ||
p.should.startWith('/'); | ||
checkPathItem(openapi.paths[p],openapi,options); | ||
} | ||
options.context.pop(); | ||
} | ||
if (openapi["x-ms-paths"]) { | ||
for (var p in openapi["x-ms-paths"]) { | ||
for (let p in openapi["x-ms-paths"]) { | ||
options.context.push('#/x-ms-paths/'+jptr.jpescape(p)); | ||
p.should.startWith('/'); | ||
checkPathItem(openapi["x-ms-paths"][p],openapi,options); | ||
@@ -449,3 +459,3 @@ options.context.pop(); | ||
if (openapi.components && openapi.components.schemas) { | ||
for (var s in openapi.components.schemas) { | ||
for (let s in openapi.components.schemas) { | ||
options.context.push('#/components/schemas/'+s); | ||
@@ -459,3 +469,3 @@ validateComponentName(s).should.be.equal(true,'component name invalid'); | ||
if (openapi.components && openapi.components.responses) { | ||
for (var r in openapi.components.responses) { | ||
for (let r in openapi.components.responses) { | ||
options.context.push('#/components/responses/'+r); | ||
@@ -469,3 +479,3 @@ validateComponentName(r).should.be.equal(true,'component name invalid'); | ||
if (openapi.components && openapi.components.headers) { | ||
for (var h in openapi.components.headers) { | ||
for (let h in openapi.components.headers) { | ||
options.context.push('#/components/headers/'+h); | ||
@@ -479,3 +489,3 @@ validateComponentName(h).should.be.equal(true,'component name invalid'); | ||
if (openapi.components && openapi.components.requestBodies) { | ||
for (var r in openapi.components.requestBodies) { | ||
for (let r in openapi.components.requestBodies) { | ||
options.context.push('#/components/requestBodies/'+r); | ||
@@ -491,7 +501,5 @@ validateComponentName(r).should.be.equal(true,'component name invalid'); | ||
validateOpenAPI3(openapi); | ||
validateOpenAPI3(openapi); | ||
var errors = validateOpenAPI3.errors; | ||
if (errors && errors.length) { | ||
throw(new Error('Failed OpenAPI3 schema validation: '+JSON.stringify(errors,null,2))); | ||
throw(new Error('Failed OpenAPI3 schema validation: '+JSON.stringify(errors,null,2))); | ||
} | ||
@@ -498,0 +506,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
257077
20
4274
8
5