Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
}
else if (obj[key].startsWith('#/definitions/')) {
//only the first part of a schema component name must be sanitised
let keys = obj[key].replace('#/definitions/', '').split('/');
let newKey = componentNames.schemas[decodeURIComponent(keys[0])]; // lookup, resolves a $ref
if (newKey) {
keys[0] = newKey;
}
else {
throwOrWarn('Could not resolve reference '+obj[key],obj,options);
}
obj[key] = '#/components/schemas/' + keys.join('/');
}
else if (obj[key].startsWith('#/parameters/')) {
// for extensions like Apigee's x-templates
obj[key] = '#/components/parameters/' + common.sanitise(obj[key].replace('#/parameters/', ''));
}
else if (obj[key].startsWith('#/responses/')) {
// for extensions like Apigee's x-templates
obj[key] = '#/components/responses/' + common.sanitise(obj[key].replace('#/responses/', ''));
}
else if (obj[key].startsWith('#')) {
// fixes up direct $refs or those created by resolvers
let target = clone(jptr.jptr(options.openapi,obj[key]));
if (target === false) throwOrWarn('direct $ref not found '+obj[key],obj,options)
else if (options.refmap[obj[key]]) {
obj[key] = options.refmap[obj[key]];
}
else {
// we use a heuristic to determine what kind of thing is being referenced
let oldRef = obj[key];
oldRef = oldRef.replace('/properties/headers/','');
&& result.content["application/x-www-form-urlencoded"] && result.content["application/x-www-form-urlencoded"].schema && result.content["application/x-www-form-urlencoded"].schema.properties) {
op.requestBody.content["application/x-www-form-urlencoded"].schema.properties =
Object.assign(op.requestBody.content["application/x-www-form-urlencoded"].schema.properties, result.content["application/x-www-form-urlencoded"].schema.properties);
op.requestBody.content["application/x-www-form-urlencoded"].schema.required = (op.requestBody.content["application/x-www-form-urlencoded"].schema.required || []).concat(result.content["application/x-www-form-urlencoded"].schema.required||[]);
if (!op.requestBody.content["application/x-www-form-urlencoded"].schema.required.length) {
delete op.requestBody.content["application/x-www-form-urlencoded"].schema.required;
}
}
else {
op.requestBody = Object.assign(op.requestBody, result);
if (!op.requestBody['x-s2o-name']) {
if (op.requestBody.schema && op.requestBody.schema.$ref) {
op.requestBody['x-s2o-name'] = decodeURIComponent(op.requestBody.schema.$ref.replace('#/components/schemas/', '')).split('/').join('');
}
else if (op.operationId) {
op.requestBody['x-s2o-name'] = common.sanitiseAll(op.operationId);
}
}
}
}
}
}
// tidy up
if (param && !param['x-s2o-delete']) {
delete param.type;
for (let prop of common.parameterTypeProperties) {
delete param[prop];
}
if ((param.in === 'path') && ((typeof param.required === 'undefined') || (param.required !== true))) {
if (options.patch) {
function finalise(err, options) {
if (!argv.quiet || err) {
console.warn(common.colour.normal + options.file);
}
if (err) {
console.warn(common.colour.red + options.context.pop() + '\n' + err.message);
if (err.name.indexOf('ERR_INVALID_URL')>=0) {
// nop
}
else if (err.message.indexOf('schema validation')>=0) {
if (options.validateSchema !== 'first') {
warnings.push('Schema fallback '+options.file);
}
}
else if (err.stack && err.name !== 'AssertionError' && err.name !== 'CLIError') {
console.warn(err.stack);
warnings.push(err.name+' '+options.file);
}
if (options.lintRule && options.lintRule.description !== err.message) {
console.warn(options.lintRule.description);
}
options.valid = (!!options.expectFailure || options.allowFailure);
recurse(obj, {identityDetection:true}, function (obj, key, state) {
if (isRef(obj, key)) {
if (obj[key].startsWith('#')) {
if (!seen[obj[key]] && !obj.$fixed) {
let target = clone(jptr(context, obj[key]));
if (options.verbose>1) console.warn((target === false ? common.colour.red : common.colour.green)+'Fragment resolution', obj[key], common.colour.normal);
/*
ResolutionCase:A is where there is a local reference in an externally
referenced document, and we have not seen it before. The reference
is replaced by a copy of the data pointed to, which may be outside this fragment
but within the context of the external document
*/
if (target === false) {
state.parent[state.pkey] = {}; /* case:A(2) where the resolution fails */
if (options.fatal) {
let ex = new Error('Fragment $ref resolution failed '+obj[key]);
if (options.promise) options.promise.reject(ex)
else throw(ex);
}
}
else {
changes++;
}
else if (o === 'parameters') {
// checked above
}
else if (o === 'servers') {
contextAppend(options, 'servers');
checkServers(op, options); // won't be here in converted definitions
options.context.pop();
}
else if (o === 'summary') {
should(pathItem.summary).have.type('string');
}
else if (o === 'description') {
should(pathItem.description).have.type('string');
}
else if (common.httpMethods.indexOf(o) >= 0) {
should(op).be.an.Object();
should(op).not.be.an.Array();
should(op).not.have.property('consumes');
should(op).not.have.property('produces');
should(op).not.have.property('schemes');
should(op).have.property('responses');
should(op.responses).not.be.undefined();
should(op.responses).be.an.Object();
should(op.responses).not.be.an.Array();
should(op.responses).not.be.empty();
if (typeof op.summary !== 'undefined') should(op.summary).have.type('string');
if (typeof op.description !== 'undefined') should(op.description).be.a.String();
if (typeof op.operationId !== 'undefined') {
should(op.operationId).be.a.String();
should(options.operationIds.indexOf(op.operationId)).be.exactly(-1,'operationIds must be unique ['+op.operationId+']');
options.operationIds.push(op.operationId);
should(param.name).have.type('string');
should(param).have.property('in');
should(param.in).have.type('string');
should(param.in).equalOneOf('query', 'header', 'path', 'cookie');
if (param.in === 'path') {
should(param).have.property('required');
should(param.required).be.exactly(true, 'Path parameters must have an explicit required:true');
if (path) { // if we're not looking at a param from #/components (checked when used)
should(path.indexOf('{'+param.name+'}')).be.greaterThan(-1,'path parameters must appear in the path');
}
}
if (typeof param.required !== 'undefined') should(param.required).have.type('boolean');
should(param).not.have.property('items');
should(param).not.have.property('collectionFormat');
should(param).not.have.property('type');
for (let prop of common.parameterTypeProperties) {
should(param).not.have.property(prop);
}
should(param.in).not.be.exactly('body', 'Parameter type body is no-longer valid');
should(param.in).not.be.exactly('formData', 'Parameter type formData is no-longer valid');
if (param.description) {
should(param.description).have.type('string');
}
if (typeof param.deprecated !== 'undefined') {
should(param.deprecated).be.a.Boolean();
}
if (typeof param.schema !== 'undefined') {
should(param).not.have.property('content');
if (typeof param.style !== 'undefined') {
should(param.style).be.type('string');
if (param.in === 'path') {
should(param.style).not.be.exactly('form');
}
if (typeof schema.uniqueItems !== 'undefined') {
should(schema.uniqueItems).be.type('boolean','uniqueItems must be a boolean');
}
if (typeof schema.maxProperties !== 'undefined') {
should(schema.maxProperties).be.type('number','maxProperties must be a number');
should(schema.maxProperties).be.greaterThan(-1);
}
if (typeof schema.minProperties !== 'undefined') {
should(schema.minProperties).be.type('number','minProperties must be a number');
should(schema.minProperties).be.greaterThan(-1);
}
if (typeof schema.required !== 'undefined') {
should(schema.required).be.an.Array();
should(schema.required).not.be.empty();
should(common.hasDuplicates(schema.required)).be.exactly(false,'required items must be unique: '+common.firstDupe(schema.required));
// nb: required array can include (for example) specific properties which match patternProperties and which aren't listed in properties
}
if (schema.properties) {
should(schema.properties).be.an.Object();
should(schema.properties).not.be.an.Array();
}
should(schema).not.have.property('patternProperties');
/*if (schema.patternProperties) {
should(schema.patternProperties).be.an.Object();
for (let prop in schema.patternProperties) {
try {
let regex = new RegExp(prop);
}
catch (ex) {
should.fail(false,true,'patternProperty '+prop+' does not conform to ECMA-262');
}
function main(openapi, options) {
let requestBodyCache = {};
componentNames = { schemas: {} };
if (openapi.security) processSecurity(openapi.security);
for (let s in openapi.components.securitySchemes) {
let sname = common.sanitise(s);
if (s != sname) {
if (openapi.components.securitySchemes[sname]) {
throwError('Duplicate sanitised securityScheme name ' + sname, options);
}
openapi.components.securitySchemes[sname] = openapi.components.securitySchemes[s];
delete openapi.components.securitySchemes[s];
}
processSecurityScheme(openapi.components.securitySchemes[sname], options);
}
for (let s in openapi.components.schemas) {
let sname = common.sanitiseAll(s);
let suffix = '';
if (s != sname) {
while (openapi.components.schemas[sname + suffix]) {
// @ts-ignore
suffix = (suffix ? ++suffix : 2);
}
openapi.components.schemas[sname + suffix] = openapi.components.schemas[s];
delete openapi.components.schemas[s];
}
componentNames.schemas[s] = sname + suffix;
fixUpSchema(openapi.components.schemas[sname+suffix],options)
}
// fix all $refs to their new locations (and potentially new names)
options.refmap = {};
recurse(openapi, { payload: { options: options } }, fixupRefs);
dedupeRefs(openapi,options);
for (let p in openapi.components.parameters) {
let sname = common.sanitise(p);
if (p != sname) {
if (openapi.components.parameters[sname]) {
throwError('Duplicate sanitised parameter name ' + sname, options);
}
openapi.components.parameters[sname] = openapi.components.parameters[p];
delete openapi.components.parameters[p];
}
let param = openapi.components.parameters[sname];
processParameter(param, null, null, null, sname, openapi, options);
}
for (let r in openapi.components.responses) {
let sname = common.sanitise(r);
if (r != sname) {
if (openapi.components.responses[sname]) {
throwError('Duplicate sanitised response name ' + sname, options);
|| ((response.description === '') && options.patch)) {
if (options.patch) {
if ((typeof response === 'object') && (!Array.isArray(response))) {
response.description = (statusCodes[response] || '');
}
}
else {
throwError('(Patchable) response.description is mandatory', options);
}
}
if (typeof response.schema !== 'undefined') {
fixUpSchema(response.schema,options);
if (response.schema.$ref && (typeof response.schema.$ref === 'string') && response.schema.$ref.startsWith('#/responses/')) {
response.schema.$ref = '#/components/responses/' + common.sanitise(decodeURIComponent(response.schema.$ref.replace('#/responses/', '')));
}
if (op && op.produces && (typeof op.produces === 'string')) {
if (options.patch) {
op.produces = [op.produces];
}
else {
return throwError('(Patchable) operation.produces must be an array', options);
}
}
if (openapi.produces && !Array.isArray(openapi.produces)) delete openapi.produces;
let produces = ((op ? op.produces : null) || (openapi.produces || [])).filter(common.uniqueOnly);
if (!produces.length) produces.push('*/*'); // TODO verify default
response.content = {};