Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

express-swagger-generator

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

express-swagger-generator - npm Package Compare versions

Comparing version 1.0.4 to 1.1.0

297

lib/swagger-helpers.js
'use strict';
// Dependencies.
var RecursiveIterator = require('recursive-iterator');
const RecursiveIterator = require('recursive-iterator');

@@ -16,16 +16,16 @@ /**

function _tagDuplicated(target, tag) {
// Check input is workable.
if (target && target.length && tag) {
for (var i = 0; i < target.length; i = i + 1) {
var targetTag = target[i];
// The name of the tag to include already exists in the taget.
// Therefore, it's not necessary to be added again.
if (targetTag.name === tag.name) {
return true;
}
}
}
// Check input is workable.
if (target && target.length && tag) {
for (let i = 0; i < target.length; i = i + 1) {
let targetTag = target[i];
// The name of the tag to include already exists in the taget.
// Therefore, it's not necessary to be added again.
if (targetTag.name === tag.name) {
return true;
}
}
}
// This will indicate that `tag` is not present in `target`.
return false;
// This will indicate that `tag` is not present in `target`.
return false;
}

@@ -39,22 +39,22 @@

function _attachTags(conf) {
var tag = conf.tag;
var swaggerObject = conf.swaggerObject;
var propertyName = conf.propertyName;
let tag = conf.tag;
let swaggerObject = conf.swaggerObject;
let propertyName = conf.propertyName;
// Correct deprecated property.
if (propertyName === 'tag') {
propertyName = 'tags';
}
// Correct deprecated property.
if (propertyName === 'tag') {
propertyName = 'tags';
}
if (Array.isArray(tag)) {
for (var i = 0; i < tag.length; i = i + 1) {
if (!_tagDuplicated(swaggerObject[propertyName], tag[i])) {
swaggerObject[propertyName].push(tag[i]);
}
}
} else {
if (!_tagDuplicated(swaggerObject[propertyName], tag)) {
swaggerObject[propertyName].push(tag);
}
}
if (Array.isArray(tag)) {
for (let i = 0; i < tag.length; i = i + 1) {
if (!_tagDuplicated(swaggerObject[propertyName], tag[i])) {
swaggerObject[propertyName].push(tag[i]);
}
}
} else {
if (!_tagDuplicated(swaggerObject[propertyName], tag)) {
swaggerObject[propertyName].push(tag);
}
}
}

@@ -70,14 +70,14 @@

function _objectMerge(obj1, obj2) {
var obj3 = {};
for (var attr in obj1) {
if (obj1.hasOwnProperty(attr)) {
obj3[attr] = obj1[attr];
}
}
for (var name in obj2) {
if (obj2.hasOwnProperty(name)) {
obj3[name] = obj2[name];
}
}
return obj3;
let obj3 = {};
for (let attr in obj1) {
if (obj1.hasOwnProperty(attr)) {
obj3[attr] = obj1[attr];
}
}
for (let name in obj2) {
if (obj2.hasOwnProperty(name)) {
obj3[name] = obj2[name];
}
}
return obj3;
}

@@ -93,10 +93,10 @@

function swaggerizeObj(swaggerObject) {
swaggerObject.swagger = '2.0';
swaggerObject.paths = swaggerObject.paths || {};
swaggerObject.definitions = swaggerObject.definitions || {};
swaggerObject.responses = swaggerObject.responses || {};
swaggerObject.parameters = swaggerObject.parameters || {};
swaggerObject.securityDefinitions = swaggerObject.securityDefinitions || {};
swaggerObject.tags = swaggerObject.tags || [];
return swaggerObject;
swaggerObject.swagger = '2.0';
swaggerObject.paths = swaggerObject.paths || {};
swaggerObject.definitions = swaggerObject.definitions || {};
swaggerObject.responses = swaggerObject.responses || {};
swaggerObject.parameters = swaggerObject.parameters || {};
swaggerObject.securityDefinitions = swaggerObject.securityDefinitions || {};
swaggerObject.tags = swaggerObject.tags || [];
return swaggerObject;
}

@@ -110,13 +110,13 @@

function _getSwaggerSchemaWrongProperties() {
return [
'consume',
'produce',
'path',
'tag',
'definition',
'securityDefinition',
'scheme',
'response',
'parameter',
];
return [
'consume',
'produce',
'path',
'tag',
'definition',
'securityDefinition',
'scheme',
'response',
'parameter',
];
}

@@ -131,8 +131,8 @@

function _correctSwaggerKey(propertyName) {
var wrong = _getSwaggerSchemaWrongProperties();
if (wrong.indexOf(propertyName) > 0) {
// Returns the corrected property name.
return propertyName + 's';
}
return propertyName;
let wrong = _getSwaggerSchemaWrongProperties();
if (wrong.indexOf(propertyName) > 0) {
// Returns the corrected property name.
return propertyName + 's';
}
return propertyName;
}

@@ -148,45 +148,54 @@

function _organizeSwaggerProperties(swaggerObject, pathObject, propertyName) {
var simpleProperties = [
'consume',
'consumes',
'produce',
'produces',
'path',
'paths',
'schema',
'schemas',
'securityDefinition',
'securityDefinitions',
'response',
'responses',
'parameter',
'parameters',
'definition',
'definitions',
];
let simpleProperties = [
'consume',
'consumes',
'produce',
'produces',
// 'path',
// 'paths',
'schema',
'schemas',
'securityDefinition',
'securityDefinitions',
'response',
'responses',
'parameter',
'parameters',
'definition',
'definitions',
];
// Common properties.
if (simpleProperties.indexOf(propertyName) !== -1) {
var keyName = _correctSwaggerKey(propertyName);
var definitionNames = Object
.getOwnPropertyNames(pathObject[propertyName]);
for (var k = 0; k < definitionNames.length; k = k + 1) {
var definitionName = definitionNames[k];
swaggerObject[keyName][definitionName] =
pathObject[propertyName][definitionName];
}
// Tags.
} else if (propertyName === 'tag' || propertyName === 'tags') {
var tag = pathObject[propertyName];
_attachTags({
tag: tag,
swaggerObject: swaggerObject,
propertyName: propertyName,
});
// Paths.
} else {
swaggerObject.paths[propertyName] = _objectMerge(
swaggerObject.paths[propertyName], pathObject[propertyName]
);
}
// Common properties.
if (simpleProperties.indexOf(propertyName) !== -1) {
let keyName = _correctSwaggerKey(propertyName);
let definitionNames = Object
.getOwnPropertyNames(pathObject[propertyName]);
for (let k = 0; k < definitionNames.length; k = k + 1) {
let definitionName = definitionNames[k];
swaggerObject[keyName][definitionName] =
pathObject[propertyName][definitionName];
}
// Tags.
} else if (propertyName === 'tag' || propertyName === 'tags') {
let tag = pathObject[propertyName];
_attachTags({
tag: tag,
swaggerObject: swaggerObject,
propertyName: propertyName,
});
// Paths.
} else {
let routes = Object
.getOwnPropertyNames(pathObject[propertyName]);
for (let k = 0; k < routes.length; k = k + 1) {
let route = routes[k];
if(!swaggerObject.paths){
swaggerObject.paths = {};
}
swaggerObject.paths[route] = _objectMerge(
swaggerObject.paths[route], pathObject[propertyName][route]
);
}
}
}

@@ -202,16 +211,16 @@

function addDataToSwaggerObject(swaggerObject, data) {
if (!swaggerObject || !data) {
throw new Error('swaggerObject and data are required!');
}
if (!swaggerObject || !data) {
throw new Error('swaggerObject and data are required!');
}
for (var i = 0; i < data.length; i = i + 1) {
var pathObject = data[i];
var propertyNames = Object.getOwnPropertyNames(pathObject);
// Iterating the properties of the a given pathObject.
for (var j = 0; j < propertyNames.length; j = j + 1) {
var propertyName = propertyNames[j];
// Do what's necessary to organize the end specification.
_organizeSwaggerProperties(swaggerObject, pathObject, propertyName);
}
}
for (let i = 0; i < data.length; i = i + 1) {
let pathObject = data[i];
let propertyNames = Object.getOwnPropertyNames(pathObject);
// Iterating the properties of the a given pathObject.
for (let j = 0; j < propertyNames.length; j = j + 1) {
let propertyName = propertyNames[j];
// Do what's necessary to organize the end specification.
_organizeSwaggerProperties(swaggerObject, pathObject, propertyName);
}
}
}

@@ -227,11 +236,11 @@

function seekWrong(list, wrongSet, problems) {
var iterator = new RecursiveIterator(list, 0, false);
for (var item = iterator.next(); !item.done; item = iterator.next()) {
var isDirectChildOfProperties =
item.value.path[item.value.path.length - 2] === 'properties';
let iterator = new RecursiveIterator(list, 0, false);
for (let item = iterator.next(); !item.done; item = iterator.next()) {
let isDirectChildOfProperties =
item.value.path[item.value.path.length - 2] === 'properties';
if (wrongSet.indexOf(item.value.key) > 0 && !isDirectChildOfProperties) {
problems.push(item.value.key);
}
}
if (wrongSet.indexOf(item.value.key) > 0 && !isDirectChildOfProperties) {
problems.push(item.value.key);
}
}
}

@@ -246,16 +255,16 @@

function findDeprecated(sources) {
var wrong = _getSwaggerSchemaWrongProperties();
// accumulate problems encountered
var problems = [];
sources.forEach(function(source) {
// Iterate through `source`, search for `wrong`, accumulate in `problems`.
seekWrong(source, wrong, problems);
});
return problems;
let wrong = _getSwaggerSchemaWrongProperties();
// accumulate problems encountered
let problems = [];
sources.forEach(function(source) {
// Iterate through `source`, search for `wrong`, accumulate in `problems`.
seekWrong(source, wrong, problems);
});
return problems;
}
module.exports = {
addDataToSwaggerObject: addDataToSwaggerObject,
swaggerizeObj: swaggerizeObj,
findDeprecated: findDeprecated,
};
addDataToSwaggerObject: addDataToSwaggerObject,
swaggerizeObj: swaggerizeObj,
findDeprecated: findDeprecated,
};

@@ -25,88 +25,136 @@ /**

function parseApiFile(file) {
const content = fs.readFileSync(file, 'utf-8');
const content = fs.readFileSync(file, 'utf-8');
let comments = doctrineFile.parseFileContent(content, {unwrap: true, sloppy: true});
return comments;
let comments = doctrineFile.parseFileContent(content, {unwrap: true, sloppy: true, tags: null, recoverable: true});
return comments;
}
function parseRoute(str) {
let split = str.split(" ")
let split = str.split(" ")
return {
method: split[0].toLowerCase() || 'get',
uri: split[1] || ''
}
return {
method: split[0].toLowerCase() || 'get',
uri: split[1] || ''
}
}
function parseField(str) {
let split = str.split(".")
return {
name: split[0],
parameter_type: split[1] || 'get',
required: split[2] && split[2] === 'required' || false
}
let split = str.split(".")
return {
name: split[0],
parameter_type: split[1] || 'get',
required: split[2] && split[2] === 'required' || false
}
}
function parseType(obj) {
return obj.name || 'string'
if(!obj) return undefined;
if(!obj.name) return 'string';
const spl = obj.name.split('.');
if(spl.length > 1 && spl[1] == 'model'){
return spl[0];
}
else return obj.name;
}
function parseSchema(obj){
if(!obj.name) return undefined;
const spl = obj.name.split('.');
if(spl.length > 1 && spl[1] == 'model'){
return { "$ref": "#/definitions/" + spl[0] };
}
else return undefined;
}
function parseReturn(tags) {
let rets = {}
for (let i in tags) {
if (tags[i]['title'] == 'returns' || tags[i]['title'] == 'return') {
let description = tags[i]['description'].split("-")
rets[description[0]] = {description: description[1]}
}
}
return rets
let rets = {}
for (let i in tags) {
if (tags[i]['title'] == 'returns' || tags[i]['title'] == 'return') {
let description = tags[i]['description'].split("-")
rets[description[0]] = {description: description[1]};
const type = parseType(tags[i].type);
if(type){
rets[description[0]].type = type;
rets[description[0]].schema = parseSchema(tags[i].type)
}
}
}
return rets
}
function parseDescription(obj) {
return obj.description || ''
return obj.description || ''
}
function parseTag(tags) {
for (var i in tags) {
if (tags[i]['title'] == 'group') {
return tags[i]['description'].split("-")
}
}
return ['default', '']
for (let i in tags) {
if (tags[i]['title'] == 'group') {
return tags[i]['description'].split("-")
}
}
return ['default', '']
}
function parseTypedef(tags){
const typeName = tags[0]['name'];
let details = {
required: [],
properties: {}
};
for(let i = 1; i < tags.length; i++){
if(tags[i].title == 'property'){
let propName = tags[i].name;
const required = propName.split('.')[1];
if(required && required == 'required'){
propName = propName.split('.')[0];
details.required.push(propName);
}
details.properties[propName] = {
type: parseType(tags[i].type),
schema: parseSchema(tags[i].type)
};
}
}
return {typeName, details};
}
function fileFormat(comments) {
let route, parameters = {}, params = [], tags = [];
for (let i in comments) {
let desc = parseDescription(comments);
if (i == 'tags') {
for (let j in comments[i]) {
let title = comments[i][j]['title']
if (title == 'route') {
route = parseRoute(comments[i][j]['description'])
let tag = parseTag(comments[i])
parameters[route.uri] = {}
parameters[route.uri][route.method] = {}
parameters[route.uri][route.method]['parameters'] = []
parameters[route.uri][route.method]['description'] = desc
parameters[route.uri][route.method]['tags'] = [tag[0]]
tags.push({
name: tag[0],
description: tag[1]
})
}
if (title == 'param') {
let field = parseField(comments[i][j]['name'])
params.push({
name: field.name,
in: field.parameter_type,
description: comments[i][j]['description'],
required: field.required,
type: parseType(comments[i][j]['type'])
})
}
}
parameters[route.uri][route.method]['parameters'] = params;
parameters[route.uri][route.method]['responses'] = parseReturn(comments[i]);
}
}
return {parameters: parameters, tags: tags}
let route, parameters = {}, params = [], tags = [], definitions = {};
for (let i in comments) {
let desc = parseDescription(comments);
if (i == 'tags') {
if(comments[i].length > 0 && comments[i][0]['title'] && comments[i][0]['title'] == 'typedef'){
const typedefParsed = parseTypedef(comments[i]);
definitions[typedefParsed.typeName] = typedefParsed.details;
continue;
}
for (let j in comments[i]) {
let title = comments[i][j]['title']
if (title == 'route') {
route = parseRoute(comments[i][j]['description'])
let tag = parseTag(comments[i])
parameters[route.uri] = parameters[route.uri] || {}
parameters[route.uri][route.method] = parameters[route.uri][route.method] || {}
parameters[route.uri][route.method]['parameters'] = []
parameters[route.uri][route.method]['description'] = desc
parameters[route.uri][route.method]['tags'] = [tag[0]]
tags.push({
name: tag[0],
description: tag[1]
})
}
if (title == 'param') {
let field = parseField(comments[i][j]['name'])
params.push({
name: field.name,
in: field.parameter_type,
description: comments[i][j]['description'],
required: field.required,
type: parseType(comments[i][j]['type']),
schema: parseSchema(comments[i][j]['type'])
})
}
parameters[route.uri][route.method]['parameters'] = params;
parameters[route.uri][route.method]['responses'] = parseReturn(comments[i]);
}
}
}
return {parameters: parameters, tags: tags, definitions: definitions}
}

@@ -122,5 +170,5 @@

function filterJsDocComments(jsDocComments) {
return jsDocComments.filter(function (item) {
return item.tags.length > 0
})
return jsDocComments.filter(function (item) {
return item.tags.length > 0
})
}

@@ -136,6 +184,6 @@

function convertGlobPaths(base, globs) {
return globs.reduce(function (acc, globString) {
var globFiles = glob.sync(path.resolve(base, globString));
return acc.concat(globFiles);
}, []);
return globs.reduce(function (acc, globString) {
let globFiles = glob.sync(path.resolve(base, globString));
return acc.concat(globFiles);
}, []);
}

@@ -152,40 +200,42 @@

return function (options) {
/* istanbul ignore if */
if (!options) {
throw new Error('\'options\' is required.');
} else /* istanbul ignore if */ if (!options.swaggerDefinition) {
throw new Error('\'swaggerDefinition\' is required.');
} else /* istanbul ignore if */ if (!options.files) {
throw new Error('\'files\' is required.');
}
return function (options) {
/* istanbul ignore if */
if (!options) {
throw new Error('\'options\' is required.');
} else /* istanbul ignore if */ if (!options.swaggerDefinition) {
throw new Error('\'swaggerDefinition\' is required.');
} else /* istanbul ignore if */ if (!options.files) {
throw new Error('\'files\' is required.');
}
// Build basic swagger json
var swaggerObject = swaggerHelpers.swaggerizeObj(options.swaggerDefinition);
var apiFiles = convertGlobPaths(options.basedir, options.files);
// Build basic swagger json
let swaggerObject = swaggerHelpers.swaggerizeObj(options.swaggerDefinition);
let apiFiles = convertGlobPaths(options.basedir, options.files);
// Parse the documentation in the APIs array.
for (var i = 0; i < apiFiles.length; i = i + 1) {
var comments = parseApiFile(apiFiles[i]);
var comments = filterJsDocComments(comments);
// Parse the documentation in the APIs array.
for (let i = 0; i < apiFiles.length; i = i + 1) {
let parsedFile = parseApiFile(apiFiles[i]);
//console.log(JSON.stringify(parsedFile))
let comments = filterJsDocComments(parsedFile);
for (let i in comments) {
var parsed = fileFormat(comments[i])
swaggerHelpers.addDataToSwaggerObject(swaggerObject, [{paths: parsed.parameters, tags: parsed.tags}]);
}
}
for (let j in comments) {
parser.parse(swaggerObject, function (err, api) {
if (!err) {
swaggerObject = api;
}
});
app.use('/api-docs.json', function (req, res) {
res.json(swaggerObject);
});
app.use('/api-docs', swaggerUi({
docs: '/api-docs.json' // from the express route above.
}));
return swaggerObject;
}
};
let parsed = fileFormat(comments[j])
swaggerHelpers.addDataToSwaggerObject(swaggerObject, [{paths: parsed.parameters, tags: parsed.tags, definitions: parsed.definitions}]);
}
}
parser.parse(swaggerObject, function (err, api) {
if (!err) {
swaggerObject = api;
}
});
app.use('/api-docs.json', function (req, res) {
res.json(swaggerObject);
});
app.use('/api-docs', swaggerUi({
docs: '/api-docs.json' // from the express route above.
}));
return swaggerObject;
}
};
{
"name": "express-swagger-generator",
"version": "1.0.4",
"version": "1.1.0",
"description": "Generates swagger doc & ui based on express existing routes.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -55,4 +55,23 @@ ### Express Swagger Generator

For model definitions:
```
/**
* @typedef Point
* @property {integer} x.required
* @property {integer} y.required
* @property {string} color
*/
// Now I can use it as below:
/**
* Insert a point
* @route POST /api/point
* @param {Point.model} point.body.required - the new point
*/
```
#### More
This module is based on [express-swaggerize-ui](https://github.com/pgroot/express-swaggerize-ui) and [Doctrine-File](https://github.com/researchgate/doctrine-file)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc