From fd16962d7f1c0bf075ab77b0ca2519ca747be923 Mon Sep 17 00:00:00 2001 From: Kalin Chernev Date: Sat, 31 Dec 2016 16:13:42 +0000 Subject: [PATCH] Include watch task in cli tool. --- README.md | 7 +-- bin/swagger-jsdoc.js | 111 +++++++++++++++++++++++++++++++------------ package.json | 3 +- test/cli-test.js | 10 ++-- 4 files changed, 91 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 184101d8..594c0313 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ app.post('/login', function(req, res) { A model may be the same for multiple endpoints (Ex. User POST,PUT responses). In place of writing (or copy and pasting) the same code into multiple locations, -which can be error prone when adding a new field to the schema. You can define +which can be error prone when adding a new field to the schema. You can define a model and re-use it across multiple endpoints. You can also reference another model and add fields. ```javascript @@ -130,7 +130,7 @@ model and add fields. * description: users * schema: * type: array - * items: + * items: * $ref: '#/definitions/User' */ app.get('/users', function(req, res) { @@ -171,7 +171,7 @@ model and add fields. }); ``` -### Load external definitions +### Load external definitions You can load external definitions or paths after ``swaggerJSDoc()`` function. ```javascript @@ -213,3 +213,4 @@ Common usage: - Specify a swagger definition file: `./bin/swagger-jsdoc -d example/swaggerDef.js` - could be any .js or .json file which will be `require()`-ed and parsed/validated as JSON. - Specify files with documentation: `./bin/swagger-jsdoc example/routes.js example/routes2.js` - free form input, can be before or after definition - Specify output file (optional): `./bin/swagger-jsdoc -o output.json` - swaggerSpec.json will be created if this is not set. +- Watch for changes: `./bin/swagger-jsdoc -d example/swaggerDef.js example/routes.js example/routes2.js -w` - this will add the definition file swaggerDef.js and its arguments routes.js and routes2.js in a watch process, re-generating swagger spec on changes. diff --git a/bin/swagger-jsdoc.js b/bin/swagger-jsdoc.js index 10a67d9a..967c42f9 100755 --- a/bin/swagger-jsdoc.js +++ b/bin/swagger-jsdoc.js @@ -5,21 +5,80 @@ /** * Module dependencies. */ + var program = require('commander'); var fs = require('fs'); var path = require('path'); var swaggerJSDoc = require('../'); var pkg = require('../package.json'); +var watcher = require('chokidar'); // Useful input. var input = process.argv.slice(2); -var output = 'swaggerSpec.json'; +// The spec, following a convention. +var output = 'swagger.json'; + +/** + * Creates a swagger.json file from a definition and a set of files. + * @function + * @param {object} swaggerDefinition - The swagger definition object. + * @param {array} files - List of files with jsdoc comments. + */ +function createSpecification(swaggerDefinition, files) { + // Aggregate information about APIs. + var apis = []; + files.forEach(function(argument) { + // Try to resolve the argument: + var result = fs.lstatSync(path.resolve(argument)); + if (result) { + if (result.isFile()) { + apis.push(argument); + } + } + }); + + // Options for the swagger docs + var options = { + // Import swaggerDefinitions + swaggerDefinition: swaggerDefinition, + // Path to the API docs + apis: apis, + }; + + // Initialize swagger-jsdoc -> returns validated swagger spec in json format + var swSpec = swaggerJSDoc(options); + + // Delete existing files and recreate. + fs.exists(output, function(exists) { + if (exists) { + fs.unlink(output, function fileDeleted() { + console.log('Spec file to be updated'); + // Create the output file with swagger specification. + fs.writeFile(output, JSON.stringify(swSpec, null, 2), function(err) { + if (err) { + throw err; + } + console.log('swagger.json updated.'); + }); + }); + } else { + // Create the output file with swagger specification. + fs.writeFile(output, JSON.stringify(swSpec, null, 2), function(err) { + if (err) { + throw err; + } + console.log('swagger.json updated.'); + }); + } + }); +} program .version(pkg.version) .usage('[options] ') .option('-d, --definition ', 'Input swagger definition.') .option('-o, --output [swaggerSpec.json]', 'Output swagger specification.') + .option('-w, --watch', 'Whether or not to listen for continous changes.') .parse(process.argv); // If no arguments provided, display help menu. @@ -76,35 +135,25 @@ fs.readFile(program.definition, 'utf-8', function(err, data) { if (!program.args.length) { return console.log('You must provide arguments for reading APIs.'); } - // Aggregate information about APIs. - var apis = []; - program.args.forEach(function(argument) { - // Try to resolve the argument: - var result = fs.lstatSync(path.resolve(argument)); - if (result) { - if (result.isFile()) { - apis.push(argument); - } - } - }); - - // Options for the swagger docs - var options = { - // Import swaggerDefinitions - swaggerDefinition: swaggerDefinition, - // Path to the API docs - apis: apis, - }; - - // Initialize swagger-jsdoc -> returns validated swagger spec in json format - var swaggerSpec = swaggerJSDoc(options); - - // Create the output file with swagger specification. - fs.writeFile(output, JSON.stringify(swaggerSpec, null, 2), function(err) { - if (err) { - throw err; - } - console.log('Swagger specification created successfully.'); - }); + // If watch flag is turned on, listen for changes. + if (program.watch) { + watcher.watch([program.definition, program.args]) + .on('ready', function startMessage() { + console.log('Listening for changes in definition and documentation.'); + }) + .on('error', function catchErr(err) { + console.error(err); + }) + .on('add', function fileAdded(path) { + console.log('File added ' + path); + }) + .on('all', function regenerateSpec() { + createSpecification(swaggerDefinition, program.args); + }); + } + // Just create the specification. + else { + createSpecification(swaggerDefinition, program.args); + } }); diff --git a/package.json b/package.json index c5df3547..9c971601 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "devDependencies": { "body-parser": "^1.15.0", "chai": "^3.5.0", + "chokidar": "^1.6.1", "express": "^4.13.4", "istanbul": "^0.4.2", "jscs": "^3.0.0", @@ -48,4 +49,4 @@ "mocha-jshint": "^2.3.1", "supertest": "^2.0.1" } -} \ No newline at end of file +} diff --git a/test/cli-test.js b/test/cli-test.js index 2f4f6802..ea27d79f 100644 --- a/test/cli-test.js +++ b/test/cli-test.js @@ -85,15 +85,15 @@ describe('command line interface', function () { }); }); - it('should create swaggerSpec.json by default when the API input is good', function (done) { + it('should create swagger.json by default when the API input is good', function (done) { var goodInput = process.env.PWD + '/bin/swagger-jsdoc.js -d example/swaggerDef.js example/routes.js'; exec(goodInput, function (error, stdout, stderr) { if (error) { throw new Error(error, stderr); } - expect(stdout).to.contain('Swagger specification created successfully.'); + expect(stdout).to.contain('swagger.json updated.'); expect(stderr).to.not.contain('You are using properties to be deprecated'); - var specification = fs.statSync('swaggerSpec.json'); + var specification = fs.statSync('swagger.json'); // Check that the physical file was created. expect(specification.nlink).to.be.above(0); done(); @@ -106,7 +106,7 @@ describe('command line interface', function () { if (error) { throw new Error(error, stderr); } - expect(stdout).to.contain('Swagger specification created successfully.'); + expect(stdout).to.contain('swagger.json updated.'); var specification = fs.statSync('customSpec.json'); // Check that the physical file was created. expect(specification.nlink).to.be.above(0); @@ -116,7 +116,7 @@ describe('command line interface', function () { // Cleanup test files if any. after(function() { - var defaultSpecification = process.env.PWD + '/swaggerSpec.json'; + var defaultSpecification = process.env.PWD + '/swagger.json'; var customSpecification = process.env.PWD + '/customSpec.json'; fs.unlinkSync(defaultSpecification); fs.unlinkSync(customSpecification);