swaggerize-routes
Advanced tools
Comparing version
@@ -0,1 +1,7 @@ | ||
### 1.0.12 | ||
- Update to node v10, add `package-lock.json` file | ||
- Update for following dependencies: `enjoi` and `tape` | ||
- Use of `eslint` instead of `jshint` as linter tool. Use of `nyc` instead of `istambul` as a code coverage tool. | ||
### 1.0.11 | ||
@@ -2,0 +8,0 @@ |
@@ -1,10 +0,8 @@ | ||
'use strict'; | ||
const thing = require('core-util-is'); | ||
const path = require('path'); | ||
const assert = require('assert'); | ||
const utils = require('./utils'); | ||
const validation = require('./validator'); | ||
const readhandlers = require('./readhandlers'); | ||
var utils = require('./utils'), | ||
validation = require('./validator'), | ||
readhandlers = require('./readhandlers'), | ||
thing = require('core-util-is'), | ||
path = require('path'), | ||
assert = require('assert'); | ||
/** | ||
@@ -16,77 +14,78 @@ * Convert definition of api to something we can work with. | ||
function buildroutes(options) { | ||
var api, routes, handlers, defaulthandler, validator; | ||
const { api } = options; | ||
const handlers = readhandlers(options.handlers); | ||
const { defaulthandler } = options; | ||
const validator = validation(options); | ||
const routes = []; | ||
api = options.api; | ||
handlers = readhandlers(options.handlers); | ||
defaulthandler = options.defaulthandler; | ||
validator = validation(options); | ||
routes = []; | ||
// eslint-disable-next-line no-shadow | ||
Object.keys(api.paths).forEach((path) => { | ||
const def = options.api.paths[path]; | ||
Object.keys(api.paths).forEach(function (path) { | ||
var def = options.api.paths[path]; | ||
utils.verbs.forEach((verb) => { | ||
const pathnames = []; | ||
utils.verbs.forEach(function (verb) { | ||
var route, pathnames, operation, validators; | ||
const operation = def[verb]; | ||
operation = def[verb]; | ||
if (!operation) { | ||
return; | ||
} | ||
if (!operation) { | ||
return; | ||
} | ||
const route = { | ||
path, | ||
name: operation.operationId, | ||
description: operation.description, | ||
method: verb, | ||
// eslint-disable-next-line max-len, no-use-before-define | ||
security: buildSecurity(options, api.securityDefinitions, operation.security || def.security || api.security), | ||
validators: [], | ||
handler: defaulthandler || undefined, | ||
consumes: operation.consumes || api.consumes, | ||
produces: operation.produces || api.produces, | ||
json: operation.json || api.json, | ||
cache: operation.cache || api.cache, | ||
config: operation.config || api.config, | ||
jsonp: operation.jsonp || api.jsonp, | ||
}; | ||
route = { | ||
path: path, | ||
name: operation.operationId, | ||
description: operation.description, | ||
method: verb, | ||
security: buildSecurity(options, api.securityDefinitions, operation.security || def.security || api.security), | ||
validators: [], | ||
handler : defaulthandler || undefined, | ||
consumes: operation.consumes || api.consumes, | ||
produces: operation.produces || api.produces, | ||
json: operation.json || api.json, | ||
cache: operation.cache || api.cache, | ||
config: operation.config || api.config, | ||
jsonp: operation.jsonp || api.jsonp | ||
}; | ||
const validators = {}; | ||
validators = {}; | ||
if (def.parameters) { | ||
def.parameters.forEach((parameter) => { | ||
validators[parameter.in + parameter.name] = parameter; | ||
}); | ||
} | ||
if (def.parameters) { | ||
def.parameters.forEach(function (parameter) { | ||
validators[parameter.in + parameter.name] = parameter; | ||
}); | ||
} | ||
if (operation.parameters) { | ||
operation.parameters.forEach((parameter) => { | ||
validators[parameter.in + parameter.name] = parameter; | ||
}); | ||
} | ||
if (operation.parameters) { | ||
operation.parameters.forEach(function (parameter) { | ||
validators[parameter.in + parameter.name] = parameter; | ||
}); | ||
} | ||
route.validators = validator.makeAll(validators, route); | ||
route.validators = validator.makeAll(validators, route); | ||
// Figure out the names from the params. | ||
path.split('/').forEach((element) => { | ||
if (element) { | ||
pathnames.push(element); | ||
} | ||
}); | ||
pathnames = []; | ||
if (!route.handler) { | ||
// eslint-disable-next-line no-use-before-define | ||
route.handler = handlers && (pathnames[0] ? matchpath(`$${verb}`, pathnames, handlers[pathnames[0]]) : handlers[`$${verb}`]); | ||
} | ||
//Figure out the names from the params. | ||
path.split('/').forEach(function (element) { | ||
if (element) { | ||
pathnames.push(element); | ||
} | ||
}); | ||
if (!route.handler) { | ||
route.handler = operation['x-handler'] || def['x-handler']; | ||
// eslint-disable-next-line no-use-before-define | ||
route.handler = route.handler && resolve(options.basedir, route.handler, verb); | ||
} | ||
if (!route.handler) { | ||
route.handler = handlers && (pathnames[0] ? matchpath('$' + verb, pathnames, handlers[pathnames[0]]) : handlers['$' + verb]); | ||
} | ||
if (!route.handler) { | ||
route.handler = operation['x-handler'] || def['x-handler']; | ||
route.handler = route.handler && resolve(options.basedir, route.handler, verb); | ||
} | ||
route.handler && routes.push(route); | ||
}); | ||
// eslint-disable-next-line no-unused-expressions | ||
route.handler && routes.push(route); | ||
}); | ||
}); | ||
return routes; | ||
return routes; | ||
} | ||
@@ -102,11 +101,11 @@ | ||
function matchpath(method, pathnames, handlers) { | ||
if (!handlers) { | ||
return null; | ||
} | ||
if (pathnames.length > 1) { | ||
pathnames.shift(); | ||
return matchpath(method, pathnames, handlers[pathnames[0]]); | ||
} | ||
if (!handlers) { | ||
return null; | ||
} | ||
if (pathnames.length > 1) { | ||
pathnames.shift(); | ||
return matchpath(method, pathnames, handlers[pathnames[0]]); | ||
} | ||
return handlers[pathnames[0]] ? handlers[pathnames[0]] : handlers[method]; | ||
return handlers[pathnames[0]] ? handlers[pathnames[0]] : handlers[method]; | ||
} | ||
@@ -122,34 +121,37 @@ | ||
function buildSecurity(options, securityDefinitions, routeSecurity) { | ||
var security = {}; | ||
var basedir = options.basedir; | ||
const security = {}; | ||
const { basedir } = options; | ||
if (!securityDefinitions || !routeSecurity || !thing.isArray(routeSecurity)) { | ||
return undefined; | ||
} | ||
if (!securityDefinitions || !routeSecurity || !thing.isArray(routeSecurity)) { | ||
return undefined; | ||
} | ||
routeSecurity.forEach(function (definition) { | ||
Object.keys(definition).forEach(function (defName) { | ||
assert.ok(securityDefinitions[defName], 'Unrecognized security definition (' + defName + ')'); | ||
routeSecurity.forEach((definition) => { | ||
Object.keys(definition).forEach((defName) => { | ||
assert.ok(securityDefinitions[defName], `Unrecognized security definition (${defName})`); | ||
security[defName] = {}; | ||
//The value of security scheme is a list of scope names required for the execution | ||
security[defName].scopes = definition[defName]; | ||
security[defName] = {}; | ||
// The value of security scheme is a list of scope names required for the execution | ||
security[defName].scopes = definition[defName]; | ||
security[defName].scopes.forEach(function (scope) { | ||
assert.ok(thing.isString(scope) && Object.keys(securityDefinitions[defName].scopes).indexOf(scope) > -1, 'Unrecognized scope (' + scope + ').'); | ||
}); | ||
security[defName].scopes.forEach((scope) => { | ||
assert.ok(thing.isString(scope) && Object.keys(securityDefinitions[defName].scopes).indexOf(scope) > -1, `Unrecognized scope (${scope}).`); | ||
}); | ||
if (options.security) { | ||
//Security options found | ||
//Resolve the security authorize handler path - basedir + options.security + securityDefinition name | ||
security[defName].authorize = resolve(basedir, path.join(options.security, defName + '.js')); | ||
} | ||
//'x-authorize' can override the 'security' options and default handlers. | ||
if (securityDefinitions[defName]['x-authorize']) { | ||
security[defName].authorize = resolve(basedir, securityDefinitions[defName]['x-authorize']); | ||
} | ||
}); | ||
if (options.security) { | ||
// Security options found | ||
// eslint-disable-next-line max-len | ||
// Resolve the security authorize handler path - basedir + options.security + securityDefinition name | ||
// eslint-disable-next-line no-use-before-define | ||
security[defName].authorize = resolve(basedir, path.join(options.security, `${defName}.js`)); | ||
} | ||
// 'x-authorize' can override the 'security' options and default handlers. | ||
if (securityDefinitions[defName]['x-authorize']) { | ||
// eslint-disable-next-line no-use-before-define | ||
security[defName].authorize = resolve(basedir, securityDefinitions[defName]['x-authorize']); | ||
} | ||
}); | ||
}); | ||
return security; | ||
return security; | ||
} | ||
@@ -164,28 +166,29 @@ | ||
*/ | ||
// eslint-disable-next-line consistent-return | ||
function resolve(basedir, pathname, method) { | ||
var handler; | ||
try { | ||
//If the pathname is already a resolved function, return it. | ||
//In the case of x-handler and x-authorize, users can define | ||
//external handler/authorize modules and functions OR override | ||
//existing x-authorize functions. | ||
if (thing.isFunction(pathname)) { | ||
return pathname; | ||
} | ||
let handler; | ||
try { | ||
// If the pathname is already a resolved function, return it. | ||
// In the case of x-handler and x-authorize, users can define | ||
// external handler/authorize modules and functions OR override | ||
// existing x-authorize functions. | ||
if (thing.isFunction(pathname)) { | ||
return pathname; | ||
} | ||
pathname = path.resolve(basedir, pathname); | ||
handler = require(pathname); | ||
// eslint-disable-next-line no-param-reassign | ||
pathname = path.resolve(basedir, pathname); | ||
// eslint-disable-next-line import/no-dynamic-require, global-require | ||
handler = require(pathname); | ||
if (thing.isFunction(handler)) { | ||
return handler; | ||
} | ||
if (thing.isFunction(handler)) { | ||
return handler; | ||
} | ||
return method && handler[method]; | ||
} | ||
catch (error) { | ||
utils.debuglog('Could not find %s.', pathname); | ||
return; | ||
} | ||
return method && handler[method]; | ||
} catch (error) { | ||
utils.debuglog('Could not find %s.', pathname); | ||
} | ||
} | ||
module.exports = buildroutes; |
110
lib/index.js
@@ -1,71 +0,75 @@ | ||
'use strict'; | ||
const assert = require('assert'); | ||
const enjoi = require('enjoi'); | ||
const thing = require('core-util-is'); | ||
const path = require('path'); | ||
const caller = require('caller'); | ||
const swaggerSchema = require('swagger-schema-official/schema'); | ||
const buildroutes = require('./buildroutes'); | ||
var assert = require('assert'), | ||
enjoi = require('enjoi'), | ||
thing = require('core-util-is'), | ||
path = require('path'), | ||
caller = require('caller'), | ||
utils = require('./utils'), | ||
buildroutes = require('./buildroutes'), | ||
swaggerSchema = require('swagger-schema-official/schema'); | ||
function swaggerize(options) { | ||
var schemas; | ||
const schemas = { | ||
'#': swaggerSchema, | ||
}; | ||
assert.ok(thing.isObject(options), 'Expected options to be an object.'); | ||
assert.ok(thing.isObject(options.api), 'Expected an api definition.'); | ||
assert.ok(thing.isObject(options), 'Expected options to be an object.'); | ||
assert.ok(thing.isObject(options.api), 'Expected an api definition.'); | ||
if ('basedir' in options) { | ||
assert.ok(thing.isString(options.basedir), 'Expected basedir to be a string.'); | ||
assert.ok(options.basedir.length, 'Expected basedir to be a non-empty string.'); | ||
} | ||
if ('basedir' in options) { | ||
assert.ok(thing.isString(options.basedir), 'Expected basedir to be a string.'); | ||
assert.ok(options.basedir.length, 'Expected basedir to be a non-empty string.'); | ||
} | ||
if ('schemas' in options) { | ||
assert.ok(thing.isArray(options.schemas), 'Expected schemas option to be an array.'); | ||
} | ||
if ('schemas' in options) { | ||
assert.ok(thing.isArray(options.schemas), 'Expected schemas option to be an array.'); | ||
} | ||
if ('handlers' in options) { | ||
assert.ok(thing.isString(options.handlers) || thing.isObject(options.handlers), 'Expected handlers to be a string or an object.'); | ||
assert.ok(!thing.isString(options.handlers) || options.handlers.length, 'Expected handlers to be a non-empty string.'); | ||
} | ||
if ('handlers' in options) { | ||
assert.ok(thing.isString(options.handlers) || thing.isObject(options.handlers), 'Expected handlers to be a string or an object.'); | ||
assert.ok(!thing.isString(options.handlers) || options.handlers.length, 'Expected handlers to be a non-empty string.'); | ||
} | ||
options.basedir = options.basedir || path.dirname(caller()); | ||
// eslint-disable-next-line no-param-reassign | ||
options.basedir = options.basedir || path.dirname(caller()); | ||
schemas = { | ||
'#': swaggerSchema | ||
}; | ||
// Map and validate API against schemas | ||
if (thing.isArray(options.schemas)) { | ||
options.schemas.forEach((schema) => { | ||
assert.ok(thing.isObject(schema), 'Expected schema option to be an object.'); | ||
assert.ok(thing.isString(schema.name), 'Expected schema name to be a string.'); | ||
assert.ok(schema.name && schema.name !== '#', 'Schema name can not be base schema.'); | ||
assert.ok(thing.isString(schema.schema) || thing.isObject(schema.schema), 'Expected schema to to an object.'); | ||
// Map and validate API against schemas | ||
if (thing.isArray(options.schemas)) { | ||
options.schemas.forEach(function (schema) { | ||
assert.ok(thing.isObject(schema), 'Expected schema option to be an object.'); | ||
assert.ok(thing.isString(schema.name), 'Expected schema name to be a string.'); | ||
assert.ok(schema.name && schema.name !== '#', 'Schema name can not be base schema.'); | ||
assert.ok(thing.isString(schema.schema) || thing.isObject(schema.schema), 'Expected schema to to an object.'); | ||
if (thing.isString(schema.schema)) { | ||
// eslint-disable-next-line global-require, no-param-reassign,import/no-dynamic-require | ||
schema.schema = require(path.resolve(options.basedir, schema.schema)); | ||
} | ||
if (thing.isString(schema.schema)) { | ||
schema.schema = require(path.resolve(options.basedir, schema.schema)); | ||
} | ||
schemas[schema.name] = schema.schema; | ||
}); | ||
} | ||
schemas[schema.name] = schema.schema; | ||
}); | ||
} | ||
const result = enjoi.schema({ | ||
type: 'object', | ||
schema: swaggerSchema, | ||
}, { | ||
subSchemas: schemas, | ||
}).validate(options.api); | ||
enjoi(swaggerSchema, schemas).validate(options.api, function (error) { | ||
assert.ifError(error); | ||
}); | ||
if (result && result.error) { | ||
assert.ifError(result.error); | ||
} | ||
// Resolve path to handlers | ||
options.handlers = options.handlers || './handlers'; | ||
// Resolve path to handlers | ||
// eslint-disable-next-line no-param-reassign | ||
options.handlers = options.handlers || './handlers'; | ||
if (thing.isString(options.handlers) && path.resolve(options.handlers) !== options.handlers) { | ||
// Relative path, so resolve to basedir | ||
options.handlers = path.join(options.basedir, options.handlers); | ||
} | ||
if (thing.isString(options.handlers) && path.resolve(options.handlers) !== options.handlers) { | ||
// Relative path, so resolve to basedir | ||
// eslint-disable-next-line no-param-reassign | ||
options.handlers = path.join(options.basedir, options.handlers); | ||
} | ||
return buildroutes(options); | ||
return buildroutes(options); | ||
} | ||
module.exports = swaggerize; |
@@ -1,7 +0,25 @@ | ||
'use strict'; | ||
const assert = require('assert'); | ||
const thing = require('core-util-is'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
var assert = require('assert'), | ||
thing = require('core-util-is'), | ||
path = require('path'), | ||
fs = require('fs'); | ||
/** | ||
* Determines if the given method is a supported HTTP method. | ||
* @param method | ||
* @returns {boolean} | ||
*/ | ||
function isHttpMethod(method) { | ||
return (typeof method === 'string') && { | ||
get: 'GET', | ||
post: 'POST', | ||
put: 'PUT', | ||
delete: 'DELETE', | ||
head: 'HEAD', | ||
options: 'OPTIONS', | ||
trace: 'TRACE', | ||
connect: 'CONNECT', | ||
patch: 'PATCH', | ||
// eslint-disable-next-line no-prototype-builtins | ||
}.hasOwnProperty(method.toLowerCase()); | ||
} | ||
@@ -14,59 +32,40 @@ /** | ||
function read(dir) { | ||
var handlers, obj; | ||
let handlers; let | ||
obj; | ||
if (thing.isString(dir)) { | ||
assert.ok(fs.existsSync(dir), 'Specified or default \'handlers\' directory does not exist.'); | ||
if (thing.isString(dir)) { | ||
assert.ok(fs.existsSync(dir), 'Specified or default \'handlers\' directory does not exist.'); | ||
handlers = {}; | ||
handlers = {}; | ||
fs.readdirSync(dir).forEach(function (name) { | ||
var abspath, key, stat; | ||
fs.readdirSync(dir).forEach((name) => { | ||
const abspath = path.join(dir, name); | ||
const stat = fs.statSync(abspath); | ||
const key = name.replace(/\.js/, ''); | ||
abspath = path.join(dir, name); | ||
stat = fs.statSync(abspath); | ||
key = name.replace(/\.js/, ''); | ||
if (stat.isFile()) { | ||
if (name.match(/^.*\.(js)$/)) { | ||
// eslint-disable-next-line import/no-dynamic-require, global-require | ||
obj = require(abspath); | ||
if (stat.isFile()) { | ||
if (name.match(/^.*\.(js)$/)) { | ||
obj = require(abspath); | ||
if (!handlers[key]) { | ||
handlers[key] = {}; | ||
} | ||
if (!handlers[key]) { | ||
handlers[key] = {}; | ||
} | ||
Object.keys(obj).forEach((k) => { | ||
handlers[key][isHttpMethod(k) ? `$${k.toLowerCase()}` : k] = obj[k]; | ||
}); | ||
} | ||
} | ||
if (stat.isDirectory()) { | ||
handlers[key] = read(abspath); | ||
} | ||
}); | ||
Object.keys(obj).forEach(function (k) { | ||
handlers[key][isHttpMethod(k) ? '$' + k.toLowerCase() : k] = obj[k]; | ||
}); | ||
} | ||
} | ||
if (stat.isDirectory()) { | ||
handlers[key] = read(abspath); | ||
} | ||
}); | ||
return handlers; | ||
} | ||
return handlers; | ||
} | ||
return dir; | ||
return dir; | ||
} | ||
/** | ||
* Determines if the given method is a supported HTTP method. | ||
* @param method | ||
* @returns {boolean} | ||
*/ | ||
function isHttpMethod(method) { | ||
return (typeof method === 'string') && { | ||
get: 'GET', | ||
post: 'POST', | ||
put: 'PUT', | ||
delete: 'DELETE', | ||
head: 'HEAD', | ||
options: 'OPTIONS', | ||
trace: 'TRACE', | ||
connect: 'CONNECT', | ||
patch: 'PATCH' | ||
}.hasOwnProperty(method.toLowerCase()); | ||
} | ||
module.exports = read; |
112
lib/utils.js
@@ -1,71 +0,71 @@ | ||
'use strict'; | ||
/* eslint-disable no-param-reassign */ | ||
const pkg = require('../package.json'); | ||
var pkg = require('../package.json'); | ||
module.exports = { | ||
debuglog: require('debuglog')(pkg.name), | ||
// eslint-disable-next-line global-require | ||
debuglog: require('debuglog')(pkg.name), | ||
verbs: [ | ||
'get', | ||
'post', | ||
'put', | ||
'delete', | ||
'head', | ||
'options', | ||
'trace', | ||
'connect', | ||
'patch' | ||
], | ||
verbs: [ | ||
'get', | ||
'post', | ||
'put', | ||
'delete', | ||
'head', | ||
'options', | ||
'trace', | ||
'connect', | ||
'patch', | ||
], | ||
endsWith: function (haystack, needle) { | ||
if (!haystack || !needle) { | ||
return false; | ||
} | ||
endsWith(haystack, needle) { | ||
if (!haystack || !needle) { | ||
return false; | ||
} | ||
if (needle.length === 1) { | ||
return haystack[haystack.length - 1] === needle; | ||
} | ||
if (needle.length === 1) { | ||
return haystack[haystack.length - 1] === needle; | ||
} | ||
return haystack.slice(haystack.length - needle.length) === needle; | ||
}, | ||
return haystack.slice(haystack.length - needle.length) === needle; | ||
}, | ||
prefix: function (str, pre) { | ||
str = str || ''; | ||
if (str.indexOf(pre) === 0) { | ||
return str; | ||
} | ||
prefix(str, pre) { | ||
str = str || ''; | ||
if (str.indexOf(pre) === 0) { | ||
return str; | ||
} | ||
str = pre + str; | ||
return str; | ||
}, | ||
str = pre + str; | ||
return str; | ||
}, | ||
unprefix: function (str, pre) { | ||
str = str || ''; | ||
if (str.indexOf(pre) === 0) { | ||
str = str.substr(pre.length); | ||
return str; | ||
} | ||
unprefix(str, pre) { | ||
str = str || ''; | ||
if (str.indexOf(pre) === 0) { | ||
str = str.substr(pre.length); | ||
return str; | ||
} | ||
return str; | ||
}, | ||
return str; | ||
}, | ||
suffix: function (str, suff) { | ||
str = str || ''; | ||
if (this.endsWith(str, suff)) { | ||
return str; | ||
} | ||
suffix(str, suff) { | ||
str = str || ''; | ||
if (this.endsWith(str, suff)) { | ||
return str; | ||
} | ||
str = str + suff; | ||
return str; | ||
}, | ||
str += suff; | ||
return str; | ||
}, | ||
unsuffix: function (str, suff) { | ||
str = str || ''; | ||
if (this.endsWith(str, suff)) { | ||
str = str.substr(0, str.length - suff.length); | ||
return str; | ||
} | ||
unsuffix(str, suff) { | ||
str = str || ''; | ||
if (this.endsWith(str, suff)) { | ||
str = str.substr(0, str.length - suff.length); | ||
return str; | ||
} | ||
return str; | ||
} | ||
return str; | ||
}, | ||
}; |
@@ -1,47 +0,32 @@ | ||
'use strict'; | ||
const assert = require('assert'); | ||
const thing = require('core-util-is'); | ||
const Joi = require('joi'); | ||
const enjoi = require('enjoi'); | ||
const utils = require('./utils'); | ||
var assert = require('assert'), | ||
thing = require('core-util-is'), | ||
enjoi = require('enjoi'), | ||
utils = require('./utils'); | ||
const extensions = [ | ||
{ | ||
type: 'file', | ||
base: Joi.object({ | ||
value: Joi.binary().required(true), | ||
consumes: Joi.array().items( | ||
Joi.string().regex(/multipart\/form-data|application\/x-www-form-urlencoded/), | ||
).required(true), | ||
in: Joi.string().regex(/formData/).required(true), | ||
}), | ||
}, | ||
]; | ||
module.exports = function validator(options) { | ||
var schemas, types; | ||
const schemas = {}; | ||
schemas = {}; | ||
types = { | ||
file: enjoi({ | ||
type: 'object', | ||
properties: { | ||
value: { | ||
type: 'string', | ||
minLength: 0, | ||
required: true | ||
}, | ||
consumes: { | ||
type: 'array', | ||
items: { | ||
type: 'string', | ||
pattern: /multipart\/form-data|application\/x-www-form-urlencoded/, | ||
}, | ||
required: true | ||
}, | ||
in: { | ||
type: 'string', | ||
pattern: /formData/, | ||
required: true | ||
} | ||
} | ||
}) | ||
}; | ||
schemas['#'] = options.api; | ||
schemas['#'] = options.api; | ||
// eslint-disable-next-line no-unused-expressions | ||
options.schemas && Object.keys(options.schemas).forEach((key) => { | ||
schemas[key] = options.schemas[key]; | ||
}); | ||
options.schemas && Object.keys(options.schemas).forEach(function (key) { | ||
schemas[key] = options.schemas[key]; | ||
}); | ||
return { | ||
/** | ||
return { | ||
/** | ||
* Creates a parameter validator. | ||
@@ -51,13 +36,13 @@ * @param parameter | ||
*/ | ||
makeAll: function (validators, route) { | ||
var self = this; | ||
makeAll(validators, route) { | ||
const self = this; | ||
return Object.keys(validators).map(function (k) { | ||
var parameter = validators[k]; | ||
return Object.keys(validators).map((k) => { | ||
const parameter = validators[k]; | ||
return self.make(parameter, route.consumes); | ||
}); | ||
}, | ||
return self.make(parameter, route.consumes); | ||
}); | ||
}, | ||
/** | ||
/** | ||
* Creates a parameter validator. | ||
@@ -67,79 +52,85 @@ * @param parameter | ||
*/ | ||
make: function (parameter, consumes) { | ||
var schema, coerce, template; | ||
make(parameter, consumes, stripUnknownProperties = false) { | ||
let schema; | ||
if (parameter.$ref) { | ||
parameter = refresolver(schemas, parameter.$ref); | ||
} | ||
if (parameter.$ref) { | ||
// eslint-disable-next-line no-use-before-define, no-param-reassign | ||
parameter = refresolver(schemas, parameter.$ref); | ||
} | ||
coerce = coercion(parameter, consumes); | ||
// eslint-disable-next-line no-use-before-define | ||
const coerce = coercion(parameter, consumes); | ||
template = { | ||
required: parameter.required, | ||
enum: parameter.enum, | ||
type: normalizetype(parameter.type), | ||
schema: parameter.schema, | ||
items: parameter.items, | ||
properties: parameter.properties, | ||
pattern: parameter.pattern, | ||
format: parameter.format, | ||
allowEmptyValue: parameter.allowEmptyValue, | ||
collectionFormat: parameter.collectionFormat, | ||
default: parameter.default, | ||
maximum: parameter.maximum, | ||
minimum: parameter.minimum, | ||
maxLength: parameter.maxLength, | ||
minLength: parameter.minLength, | ||
maxItems: parameter.maxItems, | ||
minItems: parameter.minItems, | ||
uniqueItems: parameter.uniqueItems, | ||
multipleOf: parameter.multipleOf | ||
}; | ||
const template = { | ||
required: parameter.required, | ||
enum: parameter.enum, | ||
// eslint-disable-next-line no-use-before-define | ||
type: normalizetype(parameter.type), | ||
schema: parameter.schema, | ||
items: parameter.items, | ||
properties: parameter.properties, | ||
pattern: parameter.pattern, | ||
format: parameter.format, | ||
allowEmptyValue: parameter.allowEmptyValue, | ||
collectionFormat: parameter.collectionFormat, | ||
default: parameter.default, | ||
maximum: parameter.maximum, | ||
minimum: parameter.minimum, | ||
maxLength: parameter.maxLength, | ||
minLength: parameter.minLength, | ||
maxItems: parameter.maxItems, | ||
minItems: parameter.minItems, | ||
uniqueItems: parameter.uniqueItems, | ||
multipleOf: parameter.multipleOf, | ||
}; | ||
if ((parameter.in === 'body' || parameter.in === 'formData') && template.schema) { | ||
schema = enjoi(template.schema, { | ||
subSchemas: schemas, | ||
types: types | ||
}); | ||
} | ||
else { | ||
schema = enjoi(template, { | ||
subSchemas: schemas, | ||
types: types | ||
}); | ||
} | ||
if ((parameter.in === 'body' || parameter.in === 'formData') && template.schema) { | ||
schema = enjoi.schema(template.schema, { | ||
subSchemas: schemas, | ||
extensions, | ||
}); | ||
} else { | ||
schema = enjoi.schema(template, { | ||
subSchemas: schemas, | ||
extensions, | ||
}); | ||
} | ||
if (parameter.required) { | ||
schema = schema.required(); | ||
} | ||
if (parameter.required) { | ||
schema = schema.required(); | ||
} | ||
if (parameter.in !== 'body' && parameter.allowEmptyValue){ | ||
schema = schema.allow('').optional(); | ||
} | ||
if (parameter.in !== 'body' && parameter.allowEmptyValue) { | ||
schema = schema.allow('').optional(); | ||
} | ||
return { | ||
parameter: parameter, | ||
schema: schema, | ||
validate: function validateParameter(data, callback) { | ||
coerce && data && (data = coerce(data)); | ||
schema.validate(data, function (error, result) { | ||
if (error) { | ||
error.message = error.message.replace('value', parameter.name); | ||
if (stripUnknownProperties) { | ||
schema = schema.unknown(false); | ||
} | ||
error.details.forEach(function (detail) { | ||
detail.message = detail.message.replace('value', parameter.name); | ||
detail.path = parameter.name; | ||
}); | ||
return { | ||
parameter, | ||
schema, | ||
validate: function validateParameter(value, callback) { | ||
// eslint-disable-next-line no-unused-expressions, no-param-reassign | ||
coerce && value && (value = coerce(value)); | ||
const result = schema.validate(value, { stripUnknown: stripUnknownProperties }); | ||
if (result && result.error) { | ||
result.error.message = result.error.message.replace('value', parameter.name); | ||
utils.debuglog('%s', error.message); | ||
callback(error); | ||
return; | ||
} | ||
result.error.details.forEach((detail) => { | ||
// eslint-disable-next-line no-param-reassign | ||
detail.message = detail.message.replace('value', parameter.name); | ||
// eslint-disable-next-line no-param-reassign | ||
detail.path = [parameter.name]; | ||
}); | ||
utils.debuglog('%s', result.error.message); | ||
return callback(result.error); | ||
} | ||
callback(null, result || data); | ||
}); | ||
} | ||
}; | ||
} | ||
}; | ||
return callback(null, result.value); | ||
}, | ||
}; | ||
}, | ||
}; | ||
}; | ||
@@ -154,24 +145,27 @@ | ||
function refresolver(schemas, value) { | ||
var id, refschema, path, fragment, paths; | ||
let id; let refschema; let path; let fragment; let | ||
paths; | ||
id = value.substr(0, value.indexOf('#') + 1); | ||
path = value.substr(value.indexOf('#') + 1); | ||
// eslint-disable-next-line prefer-const | ||
id = value.substr(0, value.indexOf('#') + 1); | ||
// eslint-disable-next-line prefer-const | ||
path = value.substr(value.indexOf('#') + 1); | ||
if (id) { | ||
refschema = schemas[id] || schemas[id.substr(0, id.length - 1)]; | ||
} | ||
else { | ||
refschema = schemas['#']; | ||
} | ||
if (id) { | ||
refschema = schemas[id] || schemas[id.substr(0, id.length - 1)]; | ||
} else { | ||
refschema = schemas['#']; | ||
} | ||
assert.ok(refschema, 'Can not find schema reference: ' + value + '.'); | ||
assert.ok(refschema, `Can not find schema reference: ${value}.`); | ||
fragment = refschema; | ||
paths = Array.isArray(path) ? path : path.split('/'); | ||
fragment = refschema; | ||
// eslint-disable-next-line prefer-const | ||
paths = Array.isArray(path) ? path : path.split('/'); | ||
for (var i = 1; i < paths.length && fragment; i++) { | ||
fragment = typeof fragment === 'object' && fragment[paths[i]]; | ||
} | ||
for (let i = 1; i < paths.length && fragment; i += 1) { | ||
fragment = typeof fragment === 'object' && fragment[paths[i]]; | ||
} | ||
return fragment; | ||
return fragment; | ||
} | ||
@@ -181,102 +175,103 @@ | ||
* Returns a function that coerces a type. | ||
* Coercion of doubles and longs are not supported in Javascript and strings should be used instead for 64bit numbers. | ||
* Coercion of doubles and longs are not supported in Javascript and strings should be used | ||
* instead for 64bit numbers. | ||
* @param type | ||
*/ | ||
function coercion(parameter, consumes) { | ||
var fn; | ||
let fn; | ||
switch (parameter.type) { | ||
case 'array' : | ||
fn = function (data) { | ||
var sep; | ||
// eslint-disable-next-line default-case | ||
switch (parameter.type) { | ||
case 'array': | ||
fn = (data) => { | ||
let sep; | ||
if (Array.isArray(data)) { | ||
return data; | ||
} | ||
if (Array.isArray(data)) { | ||
return data; | ||
} | ||
sep = pathsep(parameter.collectionFormat || 'csv'); | ||
return data.split(sep); | ||
}; | ||
break; | ||
case 'integer': | ||
case 'float': | ||
case 'long': | ||
case 'double': | ||
fn = function (data) { | ||
if (isNaN(data)) { | ||
return data; | ||
} | ||
return Number(data); | ||
}; | ||
break; | ||
case 'string': | ||
fn = String; | ||
break; | ||
case 'byte': | ||
fn = function (data) { | ||
return isNaN(data) ? new Buffer(data)[0] : Number(data); | ||
}; | ||
break; | ||
case 'boolean': | ||
fn = function(data) { | ||
return (data === 'true') || (data === '1') || (data === true); | ||
}; | ||
break; | ||
case 'date': | ||
case 'dateTime': | ||
fn = Date.parse; | ||
break; | ||
case 'file': { | ||
fn = function (data) { | ||
return { | ||
value: data, | ||
consumes: consumes, | ||
in: parameter.in | ||
}; | ||
}; | ||
break; | ||
// eslint-disable-next-line no-use-before-define, prefer-const | ||
sep = pathsep(parameter.collectionFormat || 'csv'); | ||
return data.split(sep); | ||
}; | ||
break; | ||
case 'integer': | ||
case 'float': | ||
case 'long': | ||
case 'double': | ||
fn = (data) => { | ||
// eslint-disable-next-line no-restricted-globals | ||
if (isNaN(data)) { | ||
return data; | ||
} | ||
return Number(data); | ||
}; | ||
break; | ||
case 'string': | ||
fn = String; | ||
break; | ||
case 'byte': | ||
// eslint-disable-next-line no-restricted-globals | ||
fn = (data) => (isNaN(data) ? Buffer.from(data)[0] : Number(data)); | ||
break; | ||
case 'boolean': | ||
fn = (data) => (data === 'true') || (data === '1') || (data === true); | ||
break; | ||
case 'date': | ||
case 'dateTime': | ||
fn = Date.parse; | ||
break; | ||
case 'file': { | ||
fn = (data) => ({ | ||
value: data, | ||
consumes, | ||
in: parameter.in, | ||
}); | ||
break; | ||
} | ||
} | ||
if (!fn && parameter.schema) { | ||
fn = function (data) { | ||
if (thing.isObject(data) && !Object.keys(data).length) { | ||
return undefined; | ||
} | ||
return data; | ||
}; | ||
} | ||
if (!fn && parameter.schema) { | ||
fn = (data) => { | ||
if (thing.isObject(data) && !Object.keys(data).length) { | ||
return undefined; | ||
} | ||
return data; | ||
}; | ||
} | ||
return fn; | ||
return fn; | ||
} | ||
function normalizetype(type) { | ||
switch (type) { | ||
case 'long': | ||
case 'byte': | ||
return 'integer'; | ||
case 'float': | ||
case 'double': | ||
return 'number'; | ||
case 'date': | ||
case 'dateTime': | ||
return 'string'; | ||
default: | ||
return type; | ||
} | ||
switch (type) { | ||
case 'long': | ||
case 'byte': | ||
return 'integer'; | ||
case 'float': | ||
case 'double': | ||
return 'number'; | ||
case 'date': | ||
case 'dateTime': | ||
return 'string'; | ||
default: | ||
return type; | ||
} | ||
} | ||
// eslint-disable-next-line consistent-return | ||
function pathsep(format) { | ||
switch (format) { | ||
case 'csv': | ||
return ','; | ||
case 'ssv': | ||
return ' '; | ||
case 'tsv': | ||
return '\t'; | ||
case 'pipes': | ||
return '|'; | ||
case 'multi': | ||
return '&'; | ||
} | ||
// eslint-disable-next-line default-case | ||
switch (format) { | ||
case 'csv': | ||
return ','; | ||
case 'ssv': | ||
return ' '; | ||
case 'tsv': | ||
return '\t'; | ||
case 'pipes': | ||
return '|'; | ||
case 'multi': | ||
return '&'; | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
Copyright 2015 PayPal | ||
Copyright 2017 PayPal | ||
@@ -13,2 +13,2 @@ Licensed under the Apache License, Version 2.0 (the "License"); | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
limitations under the License. |
{ | ||
"name": "swaggerize-routes", | ||
"version": "1.0.11", | ||
"version": "2.0.0-alpha.1", | ||
"author": "Trevor Livingston <trlivingston@paypal.com>", | ||
@@ -20,3 +20,3 @@ "contributors": [ | ||
"engines": { | ||
"node": "<=4.x" | ||
"node": ">=12" | ||
}, | ||
@@ -27,16 +27,20 @@ "dependencies": { | ||
"debuglog": "^1.0.1", | ||
"enjoi": "^1.0.0", | ||
"swagger-schema-official": "^2.0.0-" | ||
"joi": "^17.4.0", | ||
"enjoi": "^9.0.0", | ||
"swagger-schema-official": "^2.0.0-bab6bed" | ||
}, | ||
"devDependencies": { | ||
"tape": "^4.2.2", | ||
"istanbul": "^0.4.0", | ||
"jshint": "^2.4.1" | ||
"eslint": "^7.21.0", | ||
"eslint-config-airbnb-base": "^14.2.1", | ||
"eslint-plugin-import": "^2.22.1", | ||
"nyc": "^15.1.0", | ||
"tape": "^5.2.2" | ||
}, | ||
"scripts": { | ||
"test": "tape test/*.js", | ||
"cover": "istanbul cover tape -- test/*.js", | ||
"lint": "jshint -c .jshintrc lib/*.js" | ||
"cover": "nyc tape -- test/*.js", | ||
"lint": "eslint .", | ||
"lint:fix": "eslint . --fix" | ||
}, | ||
"license": "Apache-2.0" | ||
} |
@@ -1,6 +0,3 @@ | ||
swaggerize-routes (formerly swaggerize-builder) | ||
================== | ||
# swaggerize-routes (formerly swaggerize-builder) | ||
Lead Maintainer: [Trevor Livingston](https://github.com/tlivings/) | ||
[](https://travis-ci.org/krakenjs/swaggerize-routes) | ||
@@ -7,0 +4,0 @@ [](http://badge.fury.io/js/swaggerize-routes) |
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
593
4.77%29585
-7.01%6
20%5
66.67%2
100%270
-1.1%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated