From 817cf56080428abc42daaffe1dd0a4ecb26f791f Mon Sep 17 00:00:00 2001 From: Gregory Koberger Date: Thu, 21 Jul 2016 01:53:41 +0700 Subject: [PATCH] First pass at framework for new version --- .gitignore | 3 + LICENSE | 1 + api.js | 109 +--- bin/api.js | 106 ---- config/config.json | 5 + config/test.json | 6 + index.js | 8 + lib/generate.js | 3 + lib/host.js | 19 + lib/serve.js | 86 +++ lib/test.js | 3 + node_modules/confdir/.foo/test.js | 8 - node_modules/confdir/LICENSE.mkd | 18 - node_modules/confdir/README.mkd | 46 -- node_modules/confdir/confdir.js | 34 -- node_modules/confdir/package.json | 30 - node_modules/confdir/test.js | 16 - node_modules/ejs/.gitmodules | 0 node_modules/ejs/.npmignore | 4 - node_modules/ejs/History.md | 88 --- node_modules/ejs/Makefile | 21 - node_modules/ejs/Readme.md | 150 ----- node_modules/ejs/benchmark.js | 14 - node_modules/ejs/ejs.js | 565 ------------------ node_modules/ejs/ejs.min.js | 2 - node_modules/ejs/examples/client.html | 24 - node_modules/ejs/examples/list.ejs | 7 - node_modules/ejs/examples/list.js | 14 - node_modules/ejs/index.js | 2 - node_modules/ejs/lib/ejs.js | 288 --------- node_modules/ejs/lib/filters.js | 198 ------ node_modules/ejs/lib/utils.js | 23 - node_modules/ejs/package.json | 11 - node_modules/ejs/support/compile.js | 173 ------ node_modules/ejs/test/ejs.test.js | 290 --------- node_modules/ejs/test/fixtures/user.ejs | 1 - node_modules/stoopid/index.js | 150 ----- .../node_modules/colors/MIT-LICENSE.txt | 22 - .../stoopid/node_modules/colors/ReadMe.md | 77 --- .../stoopid/node_modules/colors/colors.js | 269 --------- .../stoopid/node_modules/colors/example.html | 74 --- .../stoopid/node_modules/colors/example.js | 65 -- .../stoopid/node_modules/colors/package.json | 14 - .../stoopid/node_modules/colors/test.js | 65 -- node_modules/stoopid/package.json | 13 - node_modules/stoopid/test.js | 7 - package.json | 40 +- test.js | 38 -- test/fixtures/json/swagger.json | 1 + test/fixtures/json/wrongfile.json | 3 + test/fixtures/json/wrongfile.yaml | 1 + test/fixtures/yaml/NotTheFile.yaml | 1 + test/fixtures/yaml/PetStore.yaml | 345 +++++++++++ test/fixtures/yaml/index.html | 200 +++++++ test/fixtures/yaml/notthefile.json | 1 + test/test.js | 83 +++ utils.js | 55 ++ 57 files changed, 880 insertions(+), 3020 deletions(-) create mode 100644 .gitignore mode change 100755 => 100644 api.js delete mode 100644 bin/api.js create mode 100644 config/config.json create mode 100644 config/test.json create mode 100644 index.js create mode 100644 lib/generate.js create mode 100644 lib/host.js create mode 100644 lib/serve.js create mode 100644 lib/test.js delete mode 100644 node_modules/confdir/.foo/test.js delete mode 100644 node_modules/confdir/LICENSE.mkd delete mode 100644 node_modules/confdir/README.mkd delete mode 100644 node_modules/confdir/confdir.js delete mode 100644 node_modules/confdir/package.json delete mode 100644 node_modules/confdir/test.js delete mode 100644 node_modules/ejs/.gitmodules delete mode 100644 node_modules/ejs/.npmignore delete mode 100644 node_modules/ejs/History.md delete mode 100644 node_modules/ejs/Makefile delete mode 100644 node_modules/ejs/Readme.md delete mode 100644 node_modules/ejs/benchmark.js delete mode 100644 node_modules/ejs/ejs.js delete mode 100644 node_modules/ejs/ejs.min.js delete mode 100644 node_modules/ejs/examples/client.html delete mode 100644 node_modules/ejs/examples/list.ejs delete mode 100644 node_modules/ejs/examples/list.js delete mode 100644 node_modules/ejs/index.js delete mode 100644 node_modules/ejs/lib/ejs.js delete mode 100644 node_modules/ejs/lib/filters.js delete mode 100644 node_modules/ejs/lib/utils.js delete mode 100644 node_modules/ejs/package.json delete mode 100644 node_modules/ejs/support/compile.js delete mode 100644 node_modules/ejs/test/ejs.test.js delete mode 100644 node_modules/ejs/test/fixtures/user.ejs delete mode 100644 node_modules/stoopid/index.js delete mode 100644 node_modules/stoopid/node_modules/colors/MIT-LICENSE.txt delete mode 100644 node_modules/stoopid/node_modules/colors/ReadMe.md delete mode 100644 node_modules/stoopid/node_modules/colors/colors.js delete mode 100644 node_modules/stoopid/node_modules/colors/example.html delete mode 100644 node_modules/stoopid/node_modules/colors/example.js delete mode 100644 node_modules/stoopid/node_modules/colors/package.json delete mode 100644 node_modules/stoopid/node_modules/colors/test.js delete mode 100644 node_modules/stoopid/package.json delete mode 100644 node_modules/stoopid/test.js mode change 100755 => 100644 package.json delete mode 100644 test.js create mode 100644 test/fixtures/json/swagger.json create mode 100644 test/fixtures/json/wrongfile.json create mode 100644 test/fixtures/json/wrongfile.yaml create mode 100644 test/fixtures/yaml/NotTheFile.yaml create mode 100644 test/fixtures/yaml/PetStore.yaml create mode 100644 test/fixtures/yaml/index.html create mode 100644 test/fixtures/yaml/notthefile.json create mode 100644 test/test.js create mode 100644 utils.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..e2be5243b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +_test +TODO.md +node_modules diff --git a/LICENSE b/LICENSE index b797b5635..b573887a9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,4 @@ +Copyright © 2016 ReadMe.io Copyright © 2011-2012 Paul Vorbach Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/api.js b/api.js old mode 100755 new mode 100644 index efded6dbe..293e37f24 --- a/api.js +++ b/api.js @@ -1,88 +1,45 @@ -module.exports = function(version) { +var fs = require('fs'); +var path = require('path'); -if (version !== 'http' && version !== 'https') - throw new Error(version + ' not supported.'); +var utils = require('./utils'); -var util = require('util'); -var http = require(version); -var url = require('url'); -var api = {}; - -// API Server extends EventEmitter -function Server () { - if (!(this instanceof Server)) - return new Server(); - - http.Server.call(this); - - // An array that contains the listeners for the different methods - this.methods = []; - - // Listen for any request and map the request to it's own event. - // 'regularRequest' is emitted, when there are no listeners for the event. - this.addListener('request', function(req, resp) { - var method; - var path; - - req.urlParsed = url.parse(req.url, true, true); - path = req.urlParsed.pathname; - - if (this.listeners(path).length > 0) - this.emit(path, req, resp); - else { - // check if method is defined - if (method = this.methods[req.method]) { - // for each listener of method - for (var listener in method) { - var match; - var p = method[listener].pattern; - - // match it - if ((match = p.exec(req.url)) != null) { - // add to resp - resp.match = match; - // callback - method[listener].callback(req, resp); - return; - } - } - } - this.emit('regularRequest', req, resp); - } - }); - - this.extend('GET'); - this.extend('POST'); - this.extend('PUT'); - this.extend('DELETE'); - this.extend('HEAD'); +exports.actions = { + 'test': {swagger: true}, + 'host': {swagger: true}, + 'generate': {swagger: true}, }; -// Inherit from native http.Server -util.inherits(Server, http.Server); +exports.api = function(args, opts) { + opts = opts || {}; -// extend server with a new request method -Server.prototype.extend = function (method, override) { - var fn = method.toLowerCase(); // the methods will be lowercase + var action = args[0]; + var config = utils.config(opts.env); - if (this[fn] && !override) - return new Error('The property '+fn - +' already exists. Please use another name or set override to true.'); + if(!(action in exports.actions)) { + console.log('Action not found'); + return; + } - this.methods[method] = []; + if(exports.actions[action].swagger) { + utils.findSwagger(function(err, swagger) { + if(err) { + console.error(err); + return; + } - this[fn] = function (p, cb) { - this.methods[method].push({ pattern: Server.util.regExp(p), callback: cb }); - }; -}; + if(!swagger) { + console.log("We couldn't find a Swagger file. Let's set one up!"); + // TODO: Help them set it up + return; // TODO: This is wrong + } -Server.util = {}; -Server.util.regExp = function(path) { - return new RegExp(path.replace(/\//g, '\\/')); + exports.load(action)(config, swagger); + }); + } else { + exports.load(action)(config); + } }; -api.Server = Server; - -return api; - +exports.load = function(action) { + return require(path.join(__dirname, 'lib', `${action}.js`)).run; }; diff --git a/bin/api.js b/bin/api.js deleted file mode 100644 index 0cec6fafa..000000000 --- a/bin/api.js +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env node - -var confdir = require('confdir'); -var fs = require('fs'); -var path = require('path'); -var ejs = require('ejs'); -var logger = require('stoopid'); - -// get the configuration directory of from CWD -confdir(process.cwd(), 'conf', function (err, confdir) { - if (err) - throw err; - - // read '.conf/api.json' - fs.readFile(path.resolve(confdir, 'api.json'), 'utf8', - function (err, conf) { - if (err) - throw err; - - conf = JSON.parse(conf); - - conf.root = path.resolve(confdir, '..'); - - // the log file - logger.addHandler('file', conf.logFile); - - // new API server - var app = new require('api')(conf.protocol).Server(); - - process.on('TERM', die); // die on 'TERM'ination ;) - - // die() is: shut down the server and exit the process - function die(err) { - try { - app.on('close', function () { - process.exit(); - }); - app.close(); - } finally { - if (err) - throw err; - } - } - - // error handling - app.error = function error(code, req, resp) { - logger.warn('error: '+code+' '+req.url); // log errors - - resp.writeHead(code, { 'Content-Type': 'text/html' }); - var tplFile = path.resolve(conf.root, conf.directories.templates, - 'error.tpl'); - fs.readFile(tplFile, 'uft8', function (err, tpl) { - if (err) - return logger.error('Could not read template "'+tplFile+'".'); - resp.end(ejs.render(tpl, { locals: { code: code, request: req } })); - }); - }; - - // for every registered module - conf.modules.forEach(function (mod) { - var module = require(path.resolve(conf.root, conf.directories.modules, - mod+'.js')); - - - // read module specific configuration file - var confFile = path.resolve(confdir, mod+'.json'); - fs.readFile(confFile, 'utf8', function (err, data) { - if (err) - return logger.error('Could not read configuration "'+confFile+'".'); - - var modConf = JSON.parse(data); - - logger.info('Starting module "'+mod+'".'); - // hook module into app - module(app, logger.logger(mod), modConf, conf, function (err) { - if (err) - return logger.error('Could not start module "'+mod+'".'); - - logger.info('Module "'+mod+'" up and running.'); - }); - }); - }); - - if (conf.connection.port) - if (conf.connection.hostname) - app.listen(conf.connection.port, conf.connection.hostname, listen); - else - app.listen(conf.connection.port, listen); - else - app.listen(conf.connection.path, listen); - - function listen() { - if (conf.connection.path) - fs.chmod(conf.connection.path, conf.connection.permissions, listening); - else - listening(); - - function listening(err) { - if (err) - return die(err); - - logger.info('Server up and running.'); - } - } - }); -}); diff --git a/config/config.json b/config/config.json new file mode 100644 index 000000000..29ad2c5ac --- /dev/null +++ b/config/config.json @@ -0,0 +1,5 @@ +{ + "host": { + "url": "http://apis.host" + } +} diff --git a/config/test.json b/config/test.json new file mode 100644 index 000000000..53d95050c --- /dev/null +++ b/config/test.json @@ -0,0 +1,6 @@ +{ + "env": "test", + "host": { + "url": "http://apis.host" + } +} diff --git a/index.js b/index.js new file mode 100644 index 000000000..907cc2033 --- /dev/null +++ b/index.js @@ -0,0 +1,8 @@ +var _ = require('lodash'); + +var parseArgs = require('minimist')(process.argv.slice(2)) +var args = parseArgs._; +var opts = _.clone(parseArgs); +delete opts['_']; + +require('./api').api(args, opts); diff --git a/lib/generate.js b/lib/generate.js new file mode 100644 index 000000000..e387081e5 --- /dev/null +++ b/lib/generate.js @@ -0,0 +1,3 @@ +exports.run = function(config, swagger) { + console.log(swagger); +}; diff --git a/lib/host.js b/lib/host.js new file mode 100644 index 000000000..b0d8e28ae --- /dev/null +++ b/lib/host.js @@ -0,0 +1,19 @@ +var request = require('request'); + +/* + * This will completely change 100%, and all files + * uploaded to apis.host will be removed! It's just + * a placeholder to kinda have something that works. + */ + +exports.run = function(config, swagger) { + console.log('Uploading Swagger file...'); + + request.post(config.host.url + '/save.php', { + 'form': { + 'swagger': JSON.stringify(swagger), + } + }, function(err, res, data) { + console.log(data); + }); +}; diff --git a/lib/serve.js b/lib/serve.js new file mode 100644 index 000000000..d5bd30d4d --- /dev/null +++ b/lib/serve.js @@ -0,0 +1,86 @@ +exports.run = function(config, swagger) { + if (version !== 'http' && version !== 'https') + throw new Error(version + ' not supported.'); + + var util = require('util'); + var http = require(version); + var url = require('url'); + var api = {}; + + // API Server extends EventEmitter + function Server () { + if (!(this instanceof Server)) + return new Server(); + + http.Server.call(this); + + // An array that contains the listeners for the different methods + this.methods = []; + + // Listen for any request and map the request to it's own event. + // 'regularRequest' is emitted, when there are no listeners for the event. + this.addListener('request', function(req, resp) { + var method; + var path; + + req.urlParsed = url.parse(req.url, true, true); + path = req.urlParsed.pathname; + + if (this.listeners(path).length > 0) + this.emit(path, req, resp); + else { + // check if method is defined + if (method = this.methods[req.method]) { + // for each listener of method + for (var listener in method) { + var match; + var p = method[listener].pattern; + + // match it + if ((match = p.exec(req.url)) != null) { + // add to resp + resp.match = match; + // callback + method[listener].callback(req, resp); + return; + } + } + } + this.emit('regularRequest', req, resp); + } + }); + + this.extend('GET'); + this.extend('POST'); + this.extend('PUT'); + this.extend('DELETE'); + this.extend('HEAD'); + }; + + // Inherit from native http.Server + util.inherits(Server, http.Server); + + // extend server with a new request method + Server.prototype.extend = function (method, override) { + var fn = method.toLowerCase(); // the methods will be lowercase + + if (this[fn] && !override) + return new Error('The property '+fn + +' already exists. Please use another name or set override to true.'); + + this.methods[method] = []; + + this[fn] = function (p, cb) { + this.methods[method].push({ pattern: Server.util.regExp(p), callback: cb }); + }; + }; + + Server.util = {}; + Server.util.regExp = function(path) { + return new RegExp(path.replace(/\//g, '\\/')); + }; + + api.Server = Server; + + return api; +}; diff --git a/lib/test.js b/lib/test.js new file mode 100644 index 000000000..59207acb6 --- /dev/null +++ b/lib/test.js @@ -0,0 +1,3 @@ +exports.run = function(config, swagger) { + console.log('SWAGGER', swagger); +}; diff --git a/node_modules/confdir/.foo/test.js b/node_modules/confdir/.foo/test.js deleted file mode 100644 index 4933c63b8..000000000 --- a/node_modules/confdir/.foo/test.js +++ /dev/null @@ -1,8 +0,0 @@ -var assert = require('assert'); -var path = require('path'); -var confdir = require('../'); - -confdir(__dirname, 'foo', function callback(err, dir) { - assert(dir === __dirname, 'Paths do not match.'); - console.log('passed test.'); -}); diff --git a/node_modules/confdir/LICENSE.mkd b/node_modules/confdir/LICENSE.mkd deleted file mode 100644 index 9252d00cd..000000000 --- a/node_modules/confdir/LICENSE.mkd +++ /dev/null @@ -1,18 +0,0 @@ -Copyright © 2011 Paul Vorbach - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the “Software”), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/confdir/README.mkd b/node_modules/confdir/README.mkd deleted file mode 100644 index 7193cf43a..000000000 --- a/node_modules/confdir/README.mkd +++ /dev/null @@ -1,46 +0,0 @@ -# confdir -handle module specific configurations in their own directory - -## Installation - -`npm install confdir` or `npm install -g confdir` - -## Usage - -For example anywhere in a Git repository you could get a reference to the `.git` -directory: - -``` js -var confdir = require('confdir'); - -confdir(__dirname, 'git', function (err, dir) { - if (err) - console.log(err); - else - console.log("The Git files are in " + dir); -}); -``` - -This would print an absolute reference to the `.git` directory. - ---- - -**confdir** is only one method: - -`confdir(dir, name, callback)` - -where - -* `dir` is a reference to a directory, that will be walked up, -* `name` is the name of the configuration directory (without the dot) and -* `callback` is a callback function that takes two arguments `(err, dir)`. - -## Bugs and Issues - -If you encounter any bugs or issues, feel free to open an issue at -[github](//github.com/pvorb/node-confdir/issues). - -## License - -This package is licensed under the -[MIT license](http://vorb.de/license/mit.html). diff --git a/node_modules/confdir/confdir.js b/node_modules/confdir/confdir.js deleted file mode 100644 index bfc7db3b9..000000000 --- a/node_modules/confdir/confdir.js +++ /dev/null @@ -1,34 +0,0 @@ -// confDir -;(function() { - var fs = require('fs'); - var path = require('path'); - - exports = module.exports = function getConfDir(dir, mod, callback) { - if (typeof mod != 'string' || /\//.test(mod)) { - callback(new Error("Illegal argument 'modname'.")); - return; - } - - var dirmod = '.' + mod; - - var lastResult = ''; - // find dirname by recursively walking up the path hierarchy - function findDirRec(dir, callback) { - var result = path.resolve(dir, dirmod); - fs.stat(result, function stat(err, stat) { - if (err || !stat.isDirectory()) { - if (lastResult == result) { - callback(new Error('No configuration directory found.')); - return; - } - lastResult = result; - findDirRec(path.resolve(dir, '..'), callback); - } else { - callback(null, result); - } - }); - } - - findDirRec(dir, callback); - }; -}).call(this); diff --git a/node_modules/confdir/package.json b/node_modules/confdir/package.json deleted file mode 100644 index bc3eef6da..000000000 --- a/node_modules/confdir/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "author": "Paul Vorbach (http://vorb.de/)", - "name": "confdir", - "description": "manage module specific configuration files in their own directory", - "tags": [ - "configuration", - "fs", - "directory" - ], - "version": "0.0.2", - "repository": { - "type": "git", - "url": "git://github.com/pvorb/node-confdir.git" - }, - "bugs": { - "url": "https://github.com/pvorb/node-confdir/issues" - }, - "main": "./confdir.js", - "engines": { - "node": ">=0.6.0" - }, - "dependencies": {}, - "licenses": [ - { - "type": "MIT", - "url": "http://vorb.de/license/mit.html" - } - ], - "devDependencies": {} -} \ No newline at end of file diff --git a/node_modules/confdir/test.js b/node_modules/confdir/test.js deleted file mode 100644 index 558fd316d..000000000 --- a/node_modules/confdir/test.js +++ /dev/null @@ -1,16 +0,0 @@ -var assert = require('assert'); -var path = require('path'); -var confdir = require('./'); - -confdir(__dirname, 'foo', function callback(err, dir) { - assert(path.resolve(__dirname, '.foo') === dir, 'Paths do not match.'); - console.log('passed test.'); -}); - -confdir(__dirname, 'bar', function callback(err, dir) { - assert(err instanceof Error, 'Expected to receive an error.'); - console.log('passed test.'); -}); - -require('./.foo/test'); - diff --git a/node_modules/ejs/.gitmodules b/node_modules/ejs/.gitmodules deleted file mode 100644 index e69de29bb..000000000 diff --git a/node_modules/ejs/.npmignore b/node_modules/ejs/.npmignore deleted file mode 100644 index 020ddac2c..000000000 --- a/node_modules/ejs/.npmignore +++ /dev/null @@ -1,4 +0,0 @@ -# ignore any vim files: -*.sw[a-z] -vim/.netrwhist -node_modules diff --git a/node_modules/ejs/History.md b/node_modules/ejs/History.md deleted file mode 100644 index 6277f53c1..000000000 --- a/node_modules/ejs/History.md +++ /dev/null @@ -1,88 +0,0 @@ - -0.6.1 / 2011-12-09 -================== - - * Fixed `ejs.renderFile()` - -0.6.0 / 2011-12-09 -================== - - * Changed: you no longer need `{ locals: {} }` - -0.5.0 / 2011-11-20 -================== - - * Added express 3.x support - * Added ejs.renderFile() - * Added 'json' filter - * Fixed tests for 0.5.x - -0.4.3 / 2011-06-20 -================== - - * Fixed stacktraces line number when used multiline js expressions [Octave] - -0.4.2 / 2011-05-11 -================== - - * Added client side support - -0.4.1 / 2011-04-21 -================== - - * Fixed error context - -0.4.0 / 2011-04-21 -================== - - * Added; ported jade's error reporting to ejs. [slaskis] - -0.3.1 / 2011-02-23 -================== - - * Fixed optional `compile()` options - -0.3.0 / 2011-02-14 -================== - - * Added 'json' filter [Yuriy Bogdanov] - * Use exported version of parse function to allow monkey-patching [Anatoliy Chakkaev] - -0.2.1 / 2010-10-07 -================== - - * Added filter support - * Fixed _cache_ option. ~4x performance increase - -0.2.0 / 2010-08-05 -================== - - * Added support for global tag config - * Added custom tag support. Closes #5 - * Fixed whitespace bug. Closes #4 - -0.1.0 / 2010-08-04 -================== - - * Faster implementation [ashleydev] - -0.0.4 / 2010-08-02 -================== - - * Fixed single quotes for content outside of template tags. [aniero] - * Changed; `exports.compile()` now expects only "locals" - -0.0.3 / 2010-07-15 -================== - - * Fixed single quotes - -0.0.2 / 2010-07-09 -================== - - * Fixed newline preservation - -0.0.1 / 2010-07-09 -================== - - * Initial release diff --git a/node_modules/ejs/Makefile b/node_modules/ejs/Makefile deleted file mode 100644 index 34936a248..000000000 --- a/node_modules/ejs/Makefile +++ /dev/null @@ -1,21 +0,0 @@ - -SRC = $(shell find lib -name "*.js" -type f) -UGLIFY_FLAGS = --no-mangle - -test: - @./node_modules/.bin/mocha \ - --ui exports - -ejs.js: $(SRC) - @node support/compile.js $^ - -ejs.min.js: ejs.js - @uglifyjs $(UGLIFY_FLAGS) $< > $@ \ - && du ejs.min.js \ - && du ejs.js - -clean: - rm -f ejs.js - rm -f ejs.min.js - -.PHONY: test \ No newline at end of file diff --git a/node_modules/ejs/Readme.md b/node_modules/ejs/Readme.md deleted file mode 100644 index b14d1f67c..000000000 --- a/node_modules/ejs/Readme.md +++ /dev/null @@ -1,150 +0,0 @@ - -# EJS - -Embedded JavaScript templates. - -## Installation - - $ npm install ejs - -## Features - - * Complies with the [Express](http://expressjs.com) view system - * Static caching of intermediate JavaScript - * Unbuffered code for conditionals etc `<% code %>` - * Escapes html by default with `<%= code %>` - * Unescaped buffering with `<%- code %>` - * Supports tag customization - * Filter support for designer-friendly templates - * Client-side support - -## Example - - <% if (user) { %> -

<%= user.name %>

- <% } %> - -## Usage - - ejs.compile(str, options); - // => Function - - ejs.render(str, options); - // => str - -## Options - - - `cache` Compiled functions are cached, requires `filename` - - `filename` Used by `cache` to key caches - - `scope` Function execution context - - `debug` Output generated function body - - `open` Open tag, defaulting to "<%" - - `close` Closing tag, defaulting to "%>" - - * All others are template-local variables - -## Custom tags - -Custom tags can also be applied globally: - - var ejs = require('ejs'); - ejs.open = '{{'; - ejs.close = '}}'; - -Which would make the following a valid template: - -

{{= title }}

- -## Filters - -EJS conditionally supports the concept of "filters". A "filter chain" -is a designer friendly api for manipulating data, without writing JavaScript. - -Filters can be applied by supplying the _:_ modifier, so for example if we wish to take the array `[{ name: 'tj' }, { name: 'mape' }, { name: 'guillermo' }]` and output a list of names we can do this simply with filters: - -Template: - -

<%=: users | map:'name' | join %>

- -Output: - -

Tj, Mape, Guillermo

- -Render call: - - ejs.render(str, { - users: [ - { name: 'tj' }, - { name: 'mape' }, - { name: 'guillermo' } - ] - }); - -Or perhaps capitalize the first user's name for display: - -

<%=: users | first | capitalize %>

- -## Filter list - -Currently these filters are available: - - - first - - last - - capitalize - - downcase - - upcase - - sort - - sort_by:'prop' - - size - - length - - plus:n - - minus:n - - times:n - - divided_by:n - - join:'val' - - truncate:n - - truncate_words:n - - replace:pattern,substitution - - prepend:val - - append:val - - map:'prop' - - reverse - - get:'prop' - -## Adding filters - - To add a filter simply add a method to the `.filters` object: - -```js -ejs.filters.last = function(obj) { - return obj[obj.length - 1]; -}; -``` - -## client-side support - - include `./ejs.js` or `./ejs.min.js` and `require("ejs").compile(str)`. - -## License - -(The MIT License) - -Copyright (c) 2009-2010 TJ Holowaychuk <tj@vision-media.ca> - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/ejs/benchmark.js b/node_modules/ejs/benchmark.js deleted file mode 100644 index 7b267e160..000000000 --- a/node_modules/ejs/benchmark.js +++ /dev/null @@ -1,14 +0,0 @@ - - -var ejs = require('./lib/ejs'), - str = '<% if (foo) { %>

<%= foo %>

<% } %>', - times = 50000; - -console.log('rendering ' + times + ' times'); - -var start = new Date; -while (times--) { - ejs.render(str, { cache: true, filename: 'test', locals: { foo: 'bar' }}); -} - -console.log('took ' + (new Date - start) + 'ms'); \ No newline at end of file diff --git a/node_modules/ejs/ejs.js b/node_modules/ejs/ejs.js deleted file mode 100644 index 26c31f90a..000000000 --- a/node_modules/ejs/ejs.js +++ /dev/null @@ -1,565 +0,0 @@ - -// CommonJS require() - -function require(p){ - var path = require.resolve(p) - , mod = require.modules[path]; - if (!mod) throw new Error('failed to require "' + p + '"'); - if (!mod.exports) { - mod.exports = {}; - mod.call(mod.exports, mod, mod.exports, require.relative(path)); - } - return mod.exports; - } - -require.modules = {}; - -require.resolve = function (path){ - var orig = path - , reg = path + '.js' - , index = path + '/index.js'; - return require.modules[reg] && reg - || require.modules[index] && index - || orig; - }; - -require.register = function (path, fn){ - require.modules[path] = fn; - }; - -require.relative = function (parent) { - return function(p){ - if ('.' != p.substr(0, 1)) return require(p); - - var path = parent.split('/') - , segs = p.split('/'); - path.pop(); - - for (var i = 0; i < segs.length; i++) { - var seg = segs[i]; - if ('..' == seg) path.pop(); - else if ('.' != seg) path.push(seg); - } - - return require(path.join('/')); - }; - }; - - -require.register("ejs.js", function(module, exports, require){ - -/*! - * EJS - * Copyright(c) 2010 TJ Holowaychuk - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var utils = require('./utils'); - -/** - * Library version. - */ - -exports.version = '0.5.0'; - -/** - * Filters. - * - * @type Object - */ - -var filters = exports.filters = require('./filters'); - -/** - * Intermediate js cache. - * - * @type Object - */ - -var cache = {}; - -/** - * Clear intermediate js cache. - * - * @api public - */ - -exports.clearCache = function(){ - cache = {}; -}; - -/** - * Translate filtered code into function calls. - * - * @param {String} js - * @return {String} - * @api private - */ - -function filtered(js) { - return js.substr(1).split('|').reduce(function(js, filter){ - var parts = filter.split(':') - , name = parts.shift() - , args = parts.shift() || ''; - if (args) args = ', ' + args; - return 'filters.' + name + '(' + js + args + ')'; - }); -}; - -/** - * Re-throw the given `err` in context to the - * `str` of ejs, `filename`, and `lineno`. - * - * @param {Error} err - * @param {String} str - * @param {String} filename - * @param {String} lineno - * @api private - */ - -function rethrow(err, str, filename, lineno){ - var lines = str.split('\n') - , start = Math.max(lineno - 3, 0) - , end = Math.min(lines.length, lineno + 3); - - // Error context - var context = lines.slice(start, end).map(function(line, i){ - var curr = i + start + 1; - return (curr == lineno ? ' >> ' : ' ') - + curr - + '| ' - + line; - }).join('\n'); - - // Alter exception message - err.path = filename; - err.message = (filename || 'ejs') + ':' - + lineno + '\n' - + context + '\n\n' - + err.message; - - throw err; -} - -/** - * Parse the given `str` of ejs, returning the function body. - * - * @param {String} str - * @return {String} - * @api public - */ - -var parse = exports.parse = function(str, options){ - var options = options || {} - , open = options.open || exports.open || '<%' - , close = options.close || exports.close || '%>'; - - var buf = [ - "var buf = [];" - , "\nwith (locals) {" - , "\n buf.push('" - ]; - - var lineno = 1; - - for (var i = 0, len = str.length; i < len; ++i) { - if (str.slice(i, open.length + i) == open) { - i += open.length - - var prefix, postfix, line = '__stack.lineno=' + lineno; - switch (str.substr(i, 1)) { - case '=': - prefix = "', escape((" + line + ', '; - postfix = ")), '"; - ++i; - break; - case '-': - prefix = "', (" + line + ', '; - postfix = "), '"; - ++i; - break; - default: - prefix = "');" + line + ';'; - postfix = "; buf.push('"; - } - - var end = str.indexOf(close, i) - , js = str.substring(i, end) - , start = i - , n = 0; - - while (~(n = js.indexOf("\n", n))) n++, lineno++; - if (js.substr(0, 1) == ':') js = filtered(js); - buf.push(prefix, js, postfix); - i += end - start + close.length - 1; - - } else if (str.substr(i, 1) == "\\") { - buf.push("\\\\"); - } else if (str.substr(i, 1) == "'") { - buf.push("\\'"); - } else if (str.substr(i, 1) == "\r") { - buf.push(" "); - } else if (str.substr(i, 1) == "\n") { - buf.push("\\n"); - lineno++; - } else { - buf.push(str.substr(i, 1)); - } - } - - buf.push("');\n}\nreturn buf.join('');"); - return buf.join(''); -}; - -/** - * Compile the given `str` of ejs into a `Function`. - * - * @param {String} str - * @param {Object} options - * @return {Function} - * @api public - */ - -var compile = exports.compile = function(str, options){ - options = options || {}; - - var input = JSON.stringify(str) - , filename = options.filename - ? JSON.stringify(options.filename) - : 'undefined'; - - // Adds the fancy stack trace meta info - str = [ - 'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };', - rethrow.toString(), - 'try {', - exports.parse(str, options), - '} catch (err) {', - ' rethrow(err, __stack.input, __stack.filename, __stack.lineno);', - '}' - ].join("\n"); - - if (options.debug) console.log(str); - var fn = new Function('locals, filters, escape', str); - return function(locals){ - return fn.call(this, locals, filters, utils.escape); - } -}; - -/** - * Render the given `str` of ejs. - * - * Options: - * - * - `locals` Local variables object - * - `cache` Compiled functions are cached, requires `filename` - * - `filename` Used by `cache` to key caches - * - `scope` Function execution context - * - `debug` Output generated function body - * - `open` Open tag, defaulting to "<%" - * - `close` Closing tag, defaulting to "%>" - * - * @param {String} str - * @param {Object} options - * @return {String} - * @api public - */ - -exports.render = function(str, options){ - var fn - , options = options || {}; - - if (options.cache) { - if (options.filename) { - fn = cache[options.filename] || (cache[options.filename] = compile(str, options)); - } else { - throw new Error('"cache" option requires "filename".'); - } - } else { - fn = compile(str, options); - } - - options.__proto__ = options.locals; - return fn.call(options.scope, options); -}; - -/** - * Render an EJS file at the given `path` and callback `fn(err, str)`. - * - * @param {String} path - * @param {Object|Function} options or callback - * @param {Function} fn - * @api public - */ - -exports.renderFile = function(path, options, fn){ - var key = path + ':string'; - - if ('function' == typeof options) { - fn = options, options = {}; - } - - options.filename = path; - - try { - var str = options.cache - ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8')) - : fs.readFileSync(path, 'utf8'); - - fn(null, exports.render(str, options)); - } catch (err) { - fn(err); - } -}; - -// express support - -exports.__express = exports.renderFile; - -/** - * Expose to require(). - */ - -if (require.extensions) { - require.extensions['.ejs'] = function(module, filename) { - source = require('fs').readFileSync(filename, 'utf-8'); - module._compile(compile(source, {}), filename); - }; -} else if (require.registerExtension) { - require.registerExtension('.ejs', function(src) { - return compile(src, {}); - }); -} - -}); // module: ejs.js - -require.register("filters.js", function(module, exports, require){ - -/*! - * EJS - Filters - * Copyright(c) 2010 TJ Holowaychuk - * MIT Licensed - */ - -/** - * First element of the target `obj`. - */ - -exports.first = function(obj) { - return obj[0]; -}; - -/** - * Last element of the target `obj`. - */ - -exports.last = function(obj) { - return obj[obj.length - 1]; -}; - -/** - * Capitalize the first letter of the target `str`. - */ - -exports.capitalize = function(str){ - str = String(str); - return str[0].toUpperCase() + str.substr(1, str.length); -}; - -/** - * Downcase the target `str`. - */ - -exports.downcase = function(str){ - return String(str).toLowerCase(); -}; - -/** - * Uppercase the target `str`. - */ - -exports.upcase = function(str){ - return String(str).toUpperCase(); -}; - -/** - * Sort the target `obj`. - */ - -exports.sort = function(obj){ - return Object.create(obj).sort(); -}; - -/** - * Sort the target `obj` by the given `prop` ascending. - */ - -exports.sort_by = function(obj, prop){ - return Object.create(obj).sort(function(a, b){ - a = a[prop], b = b[prop]; - if (a > b) return 1; - if (a < b) return -1; - return 0; - }); -}; - -/** - * Size or length of the target `obj`. - */ - -exports.size = exports.length = function(obj) { - return obj.length; -}; - -/** - * Add `a` and `b`. - */ - -exports.plus = function(a, b){ - return Number(a) + Number(b); -}; - -/** - * Subtract `b` from `a`. - */ - -exports.minus = function(a, b){ - return Number(a) - Number(b); -}; - -/** - * Multiply `a` by `b`. - */ - -exports.times = function(a, b){ - return Number(a) * Number(b); -}; - -/** - * Divide `a` by `b`. - */ - -exports.divided_by = function(a, b){ - return Number(a) / Number(b); -}; - -/** - * Join `obj` with the given `str`. - */ - -exports.join = function(obj, str){ - return obj.join(str || ', '); -}; - -/** - * Truncate `str` to `len`. - */ - -exports.truncate = function(str, len){ - str = String(str); - return str.substr(0, len); -}; - -/** - * Truncate `str` to `n` words. - */ - -exports.truncate_words = function(str, n){ - var str = String(str) - , words = str.split(/ +/); - return words.slice(0, n).join(' '); -}; - -/** - * Replace `pattern` with `substitution` in `str`. - */ - -exports.replace = function(str, pattern, substitution){ - return String(str).replace(pattern, substitution || ''); -}; - -/** - * Prepend `val` to `obj`. - */ - -exports.prepend = function(obj, val){ - return Array.isArray(obj) - ? [val].concat(obj) - : val + obj; -}; - -/** - * Append `val` to `obj`. - */ - -exports.append = function(obj, val){ - return Array.isArray(obj) - ? obj.concat(val) - : obj + val; -}; - -/** - * Map the given `prop`. - */ - -exports.map = function(arr, prop){ - return arr.map(function(obj){ - return obj[prop]; - }); -}; - -/** - * Reverse the given `obj`. - */ - -exports.reverse = function(obj){ - return Array.isArray(obj) - ? obj.reverse() - : String(obj).split('').reverse().join(''); -}; - -/** - * Get `prop` of the given `obj`. - */ - -exports.get = function(obj, prop){ - return obj[prop]; -}; - -/** - * Packs the given `obj` into json string - */ -exports.json = function(obj){ - return JSON.stringify(obj); -}; -}); // module: filters.js - -require.register("utils.js", function(module, exports, require){ - -/*! - * EJS - * Copyright(c) 2010 TJ Holowaychuk - * MIT Licensed - */ - -/** - * Escape the given string of `html`. - * - * @param {String} html - * @return {String} - * @api private - */ - -exports.escape = function(html){ - return String(html) - .replace(/&(?!\w+;)/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); -}; - -}); // module: utils.js diff --git a/node_modules/ejs/ejs.min.js b/node_modules/ejs/ejs.min.js deleted file mode 100644 index 250ba8833..000000000 --- a/node_modules/ejs/ejs.min.js +++ /dev/null @@ -1,2 +0,0 @@ -// CommonJS require() -function require(p){var path=require.resolve(p),mod=require.modules[path];if(!mod)throw new Error('failed to require "'+p+'"');mod.exports||(mod.exports={},mod.call(mod.exports,mod,mod.exports,require.relative(path)));return mod.exports}require.modules={},require.resolve=function(path){var orig=path,reg=path+".js",index=path+"/index.js";return require.modules[reg]&®||require.modules[index]&&index||orig},require.register=function(path,fn){require.modules[path]=fn},require.relative=function(parent){return function(p){if("."!=p.substr(0,1))return require(p);var path=parent.split("/"),segs=p.split("/");path.pop();for(var i=0;i> ":" ")+curr+"| "+line}).join("\n");err.path=filename,err.message=(filename||"ejs")+":"+lineno+"\n"+context+"\n\n"+err.message;throw err}var parse=exports.parse=function(str,options){var options=options||{},open=options.open||exports.open||"<%",close=options.close||exports.close||"%>",buf=["var buf = [];","\nwith (locals) {","\n buf.push('"],lineno=1;for(var i=0,len=str.length;ib)return 1;if(a/g,">").replace(/"/g,""")}}) \ No newline at end of file diff --git a/node_modules/ejs/examples/client.html b/node_modules/ejs/examples/client.html deleted file mode 100644 index 51ce0b4ce..000000000 --- a/node_modules/ejs/examples/client.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/node_modules/ejs/examples/list.ejs b/node_modules/ejs/examples/list.ejs deleted file mode 100644 index d571330ae..000000000 --- a/node_modules/ejs/examples/list.ejs +++ /dev/null @@ -1,7 +0,0 @@ -<% if (names.length) { %> -
    - <% names.forEach(function(name){ %> -
  • <%= name %>
  • - <% }) %> -
-<% } %> \ No newline at end of file diff --git a/node_modules/ejs/examples/list.js b/node_modules/ejs/examples/list.js deleted file mode 100644 index ec614ed62..000000000 --- a/node_modules/ejs/examples/list.js +++ /dev/null @@ -1,14 +0,0 @@ - -/** - * Module dependencies. - */ - -var ejs = require('../') - , fs = require('fs') - , str = fs.readFileSync(__dirname + '/list.ejs', 'utf8'); - -var ret = ejs.render(str, { - names: ['foo', 'bar', 'baz'] -}); - -console.log(ret); \ No newline at end of file diff --git a/node_modules/ejs/index.js b/node_modules/ejs/index.js deleted file mode 100644 index 20bf71a3f..000000000 --- a/node_modules/ejs/index.js +++ /dev/null @@ -1,2 +0,0 @@ - -module.exports = require('./lib/ejs'); \ No newline at end of file diff --git a/node_modules/ejs/lib/ejs.js b/node_modules/ejs/lib/ejs.js deleted file mode 100644 index 2eeb458f7..000000000 --- a/node_modules/ejs/lib/ejs.js +++ /dev/null @@ -1,288 +0,0 @@ - -/*! - * EJS - * Copyright(c) 2010 TJ Holowaychuk - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var utils = require('./utils') - , fs = require('fs'); - -/** - * Library version. - */ - -exports.version = '0.6.1'; - -/** - * Filters. - * - * @type Object - */ - -var filters = exports.filters = require('./filters'); - -/** - * Intermediate js cache. - * - * @type Object - */ - -var cache = {}; - -/** - * Clear intermediate js cache. - * - * @api public - */ - -exports.clearCache = function(){ - cache = {}; -}; - -/** - * Translate filtered code into function calls. - * - * @param {String} js - * @return {String} - * @api private - */ - -function filtered(js) { - return js.substr(1).split('|').reduce(function(js, filter){ - var parts = filter.split(':') - , name = parts.shift() - , args = parts.shift() || ''; - if (args) args = ', ' + args; - return 'filters.' + name + '(' + js + args + ')'; - }); -}; - -/** - * Re-throw the given `err` in context to the - * `str` of ejs, `filename`, and `lineno`. - * - * @param {Error} err - * @param {String} str - * @param {String} filename - * @param {String} lineno - * @api private - */ - -function rethrow(err, str, filename, lineno){ - var lines = str.split('\n') - , start = Math.max(lineno - 3, 0) - , end = Math.min(lines.length, lineno + 3); - - // Error context - var context = lines.slice(start, end).map(function(line, i){ - var curr = i + start + 1; - return (curr == lineno ? ' >> ' : ' ') - + curr - + '| ' - + line; - }).join('\n'); - - // Alter exception message - err.path = filename; - err.message = (filename || 'ejs') + ':' - + lineno + '\n' - + context + '\n\n' - + err.message; - - throw err; -} - -/** - * Parse the given `str` of ejs, returning the function body. - * - * @param {String} str - * @return {String} - * @api public - */ - -var parse = exports.parse = function(str, options){ - var options = options || {} - , open = options.open || exports.open || '<%' - , close = options.close || exports.close || '%>'; - - var buf = [ - "var buf = [];" - , "\nwith (locals) {" - , "\n buf.push('" - ]; - - var lineno = 1; - - for (var i = 0, len = str.length; i < len; ++i) { - if (str.slice(i, open.length + i) == open) { - i += open.length - - var prefix, postfix, line = '__stack.lineno=' + lineno; - switch (str.substr(i, 1)) { - case '=': - prefix = "', escape((" + line + ', '; - postfix = ")), '"; - ++i; - break; - case '-': - prefix = "', (" + line + ', '; - postfix = "), '"; - ++i; - break; - default: - prefix = "');" + line + ';'; - postfix = "; buf.push('"; - } - - var end = str.indexOf(close, i) - , js = str.substring(i, end) - , start = i - , n = 0; - - while (~(n = js.indexOf("\n", n))) n++, lineno++; - if (js.substr(0, 1) == ':') js = filtered(js); - buf.push(prefix, js, postfix); - i += end - start + close.length - 1; - - } else if (str.substr(i, 1) == "\\") { - buf.push("\\\\"); - } else if (str.substr(i, 1) == "'") { - buf.push("\\'"); - } else if (str.substr(i, 1) == "\r") { - buf.push(" "); - } else if (str.substr(i, 1) == "\n") { - buf.push("\\n"); - lineno++; - } else { - buf.push(str.substr(i, 1)); - } - } - - buf.push("');\n}\nreturn buf.join('');"); - return buf.join(''); -}; - -/** - * Compile the given `str` of ejs into a `Function`. - * - * @param {String} str - * @param {Object} options - * @return {Function} - * @api public - */ - -var compile = exports.compile = function(str, options){ - options = options || {}; - - var input = JSON.stringify(str) - , filename = options.filename - ? JSON.stringify(options.filename) - : 'undefined'; - - // Adds the fancy stack trace meta info - str = [ - 'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };', - rethrow.toString(), - 'try {', - exports.parse(str, options), - '} catch (err) {', - ' rethrow(err, __stack.input, __stack.filename, __stack.lineno);', - '}' - ].join("\n"); - - if (options.debug) console.log(str); - var fn = new Function('locals, filters, escape', str); - return function(locals){ - return fn.call(this, locals, filters, utils.escape); - } -}; - -/** - * Render the given `str` of ejs. - * - * Options: - * - * - `locals` Local variables object - * - `cache` Compiled functions are cached, requires `filename` - * - `filename` Used by `cache` to key caches - * - `scope` Function execution context - * - `debug` Output generated function body - * - `open` Open tag, defaulting to "<%" - * - `close` Closing tag, defaulting to "%>" - * - * @param {String} str - * @param {Object} options - * @return {String} - * @api public - */ - -exports.render = function(str, options){ - var fn - , options = options || {}; - - if (options.cache) { - if (options.filename) { - fn = cache[options.filename] || (cache[options.filename] = compile(str, options)); - } else { - throw new Error('"cache" option requires "filename".'); - } - } else { - fn = compile(str, options); - } - - options.__proto__ = options.locals; - return fn.call(options.scope, options); -}; - -/** - * Render an EJS file at the given `path` and callback `fn(err, str)`. - * - * @param {String} path - * @param {Object|Function} options or callback - * @param {Function} fn - * @api public - */ - -exports.renderFile = function(path, options, fn){ - var key = path + ':string'; - - if ('function' == typeof options) { - fn = options, options = {}; - } - - options.filename = path; - - try { - var str = options.cache - ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8')) - : fs.readFileSync(path, 'utf8'); - - fn(null, exports.render(str, options)); - } catch (err) { - fn(err); - } -}; - -// express support - -exports.__express = exports.renderFile; - -/** - * Expose to require(). - */ - -if (require.extensions) { - require.extensions['.ejs'] = function(module, filename) { - source = require('fs').readFileSync(filename, 'utf-8'); - module._compile(compile(source, {}), filename); - }; -} else if (require.registerExtension) { - require.registerExtension('.ejs', function(src) { - return compile(src, {}); - }); -} diff --git a/node_modules/ejs/lib/filters.js b/node_modules/ejs/lib/filters.js deleted file mode 100644 index d425c8d89..000000000 --- a/node_modules/ejs/lib/filters.js +++ /dev/null @@ -1,198 +0,0 @@ - -/*! - * EJS - Filters - * Copyright(c) 2010 TJ Holowaychuk - * MIT Licensed - */ - -/** - * First element of the target `obj`. - */ - -exports.first = function(obj) { - return obj[0]; -}; - -/** - * Last element of the target `obj`. - */ - -exports.last = function(obj) { - return obj[obj.length - 1]; -}; - -/** - * Capitalize the first letter of the target `str`. - */ - -exports.capitalize = function(str){ - str = String(str); - return str[0].toUpperCase() + str.substr(1, str.length); -}; - -/** - * Downcase the target `str`. - */ - -exports.downcase = function(str){ - return String(str).toLowerCase(); -}; - -/** - * Uppercase the target `str`. - */ - -exports.upcase = function(str){ - return String(str).toUpperCase(); -}; - -/** - * Sort the target `obj`. - */ - -exports.sort = function(obj){ - return Object.create(obj).sort(); -}; - -/** - * Sort the target `obj` by the given `prop` ascending. - */ - -exports.sort_by = function(obj, prop){ - return Object.create(obj).sort(function(a, b){ - a = a[prop], b = b[prop]; - if (a > b) return 1; - if (a < b) return -1; - return 0; - }); -}; - -/** - * Size or length of the target `obj`. - */ - -exports.size = exports.length = function(obj) { - return obj.length; -}; - -/** - * Add `a` and `b`. - */ - -exports.plus = function(a, b){ - return Number(a) + Number(b); -}; - -/** - * Subtract `b` from `a`. - */ - -exports.minus = function(a, b){ - return Number(a) - Number(b); -}; - -/** - * Multiply `a` by `b`. - */ - -exports.times = function(a, b){ - return Number(a) * Number(b); -}; - -/** - * Divide `a` by `b`. - */ - -exports.divided_by = function(a, b){ - return Number(a) / Number(b); -}; - -/** - * Join `obj` with the given `str`. - */ - -exports.join = function(obj, str){ - return obj.join(str || ', '); -}; - -/** - * Truncate `str` to `len`. - */ - -exports.truncate = function(str, len){ - str = String(str); - return str.substr(0, len); -}; - -/** - * Truncate `str` to `n` words. - */ - -exports.truncate_words = function(str, n){ - var str = String(str) - , words = str.split(/ +/); - return words.slice(0, n).join(' '); -}; - -/** - * Replace `pattern` with `substitution` in `str`. - */ - -exports.replace = function(str, pattern, substitution){ - return String(str).replace(pattern, substitution || ''); -}; - -/** - * Prepend `val` to `obj`. - */ - -exports.prepend = function(obj, val){ - return Array.isArray(obj) - ? [val].concat(obj) - : val + obj; -}; - -/** - * Append `val` to `obj`. - */ - -exports.append = function(obj, val){ - return Array.isArray(obj) - ? obj.concat(val) - : obj + val; -}; - -/** - * Map the given `prop`. - */ - -exports.map = function(arr, prop){ - return arr.map(function(obj){ - return obj[prop]; - }); -}; - -/** - * Reverse the given `obj`. - */ - -exports.reverse = function(obj){ - return Array.isArray(obj) - ? obj.reverse() - : String(obj).split('').reverse().join(''); -}; - -/** - * Get `prop` of the given `obj`. - */ - -exports.get = function(obj, prop){ - return obj[prop]; -}; - -/** - * Packs the given `obj` into json string - */ -exports.json = function(obj){ - return JSON.stringify(obj); -}; \ No newline at end of file diff --git a/node_modules/ejs/lib/utils.js b/node_modules/ejs/lib/utils.js deleted file mode 100644 index 8d569d6f2..000000000 --- a/node_modules/ejs/lib/utils.js +++ /dev/null @@ -1,23 +0,0 @@ - -/*! - * EJS - * Copyright(c) 2010 TJ Holowaychuk - * MIT Licensed - */ - -/** - * Escape the given string of `html`. - * - * @param {String} html - * @return {String} - * @api private - */ - -exports.escape = function(html){ - return String(html) - .replace(/&(?!\w+;)/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); -}; - \ No newline at end of file diff --git a/node_modules/ejs/package.json b/node_modules/ejs/package.json deleted file mode 100644 index 9b43d0d40..000000000 --- a/node_modules/ejs/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "ejs", - "description": "Embedded JavaScript templates", - "version": "0.6.1", - "author": "TJ Holowaychuk ", - "keywords": ["template", "engine", "ejs"], - "devDependencies": { - "mocha": "*" - }, - "main": "./lib/ejs.js" -} \ No newline at end of file diff --git a/node_modules/ejs/support/compile.js b/node_modules/ejs/support/compile.js deleted file mode 100644 index edd381584..000000000 --- a/node_modules/ejs/support/compile.js +++ /dev/null @@ -1,173 +0,0 @@ - -/** - * Module dependencies. - */ - -var fs = require('fs'); - -/** - * Arguments. - */ - -var args = process.argv.slice(2) - , pending = args.length - , files = {}; - -console.log(''); - -// parse arguments - -args.forEach(function(file){ - var mod = file.replace('lib/', ''); - fs.readFile(file, 'utf8', function(err, js){ - if (err) throw err; - console.log(' \033[90mcompile : \033[0m\033[36m%s\033[0m', file); - files[file] = parse(js); - --pending || compile(); - }); -}); - -/** - * Parse the given `js`. - */ - -function parse(js) { - return parseInheritance(parseConditionals(js)); -} - -/** - * Parse __proto__. - */ - -function parseInheritance(js) { - return js - .replace(/^ *(\w+)\.prototype\.__proto__ * = *(\w+)\.prototype *;?/gm, function(_, child, parent){ - return child + '.prototype = new ' + parent + ';\n' - + child + '.prototype.constructor = '+ child + ';\n'; - }); -} - -/** - * Parse the given `js`, currently supporting: - * - * 'if' ['node' | 'browser'] - * 'end' - * - */ - -function parseConditionals(js) { - var lines = js.split('\n') - , len = lines.length - , buffer = true - , browser = false - , buf = [] - , line - , cond; - - for (var i = 0; i < len; ++i) { - line = lines[i]; - if (/^ *\/\/ *if *(node|browser)/gm.exec(line)) { - cond = RegExp.$1; - buffer = browser = 'browser' == cond; - } else if (/^ *\/\/ *end/.test(line)) { - buffer = true; - browser = false; - } else if (browser) { - buf.push(line.replace(/^( *)\/\//, '$1')); - } else if (buffer) { - buf.push(line); - } - } - - return buf.join('\n'); -} - -/** - * Compile the files. - */ - -function compile() { - var buf = ''; - buf += '\n// CommonJS require()\n\n'; - buf += browser.require + '\n\n'; - buf += 'require.modules = {};\n\n'; - buf += 'require.resolve = ' + browser.resolve + ';\n\n'; - buf += 'require.register = ' + browser.register + ';\n\n'; - buf += 'require.relative = ' + browser.relative + ';\n\n'; - args.forEach(function(file){ - var js = files[file]; - file = file.replace('lib/', ''); - buf += '\nrequire.register("' + file + '", function(module, exports, require){\n'; - buf += js; - buf += '\n}); // module: ' + file + '\n'; - }); - fs.writeFile('ejs.js', buf, function(err){ - if (err) throw err; - console.log(' \033[90m create : \033[0m\033[36m%s\033[0m', 'ejs.js'); - console.log(); - }); -} - -// refactored version of weepy's -// https://github.com/weepy/brequire/blob/master/browser/brequire.js - -var browser = { - - /** - * Require a module. - */ - - require: function require(p){ - var path = require.resolve(p) - , mod = require.modules[path]; - if (!mod) throw new Error('failed to require "' + p + '"'); - if (!mod.exports) { - mod.exports = {}; - mod.call(mod.exports, mod, mod.exports, require.relative(path)); - } - return mod.exports; - }, - - /** - * Resolve module path. - */ - - resolve: function(path){ - var orig = path - , reg = path + '.js' - , index = path + '/index.js'; - return require.modules[reg] && reg - || require.modules[index] && index - || orig; - }, - - /** - * Return relative require(). - */ - - relative: function(parent) { - return function(p){ - if ('.' != p.substr(0, 1)) return require(p); - - var path = parent.split('/') - , segs = p.split('/'); - path.pop(); - - for (var i = 0; i < segs.length; i++) { - var seg = segs[i]; - if ('..' == seg) path.pop(); - else if ('.' != seg) path.push(seg); - } - - return require(path.join('/')); - }; - }, - - /** - * Register a module. - */ - - register: function(path, fn){ - require.modules[path] = fn; - } -}; \ No newline at end of file diff --git a/node_modules/ejs/test/ejs.test.js b/node_modules/ejs/test/ejs.test.js deleted file mode 100644 index 1c47adff7..000000000 --- a/node_modules/ejs/test/ejs.test.js +++ /dev/null @@ -1,290 +0,0 @@ - -/** - * Module dependencies. - */ - -var ejs = require('../') - , assert = require('assert'); - -module.exports = { - 'test .version': function(){ - assert.ok(/^\d+\.\d+\.\d+$/.test(ejs.version), 'Test .version format'); - }, - - 'test html': function(){ - assert.equal('

yay

', ejs.render('

yay

')); - }, - - 'test renderFile': function(){ - var html = '

tj

', - str = '

<%= name %>

', - options = { name: 'tj', open: '{', close: '}' }; - - ejs.renderFile(__dirname + '/fixtures/user.ejs', options, function(err, res){ - assert.ok(!err); - assert.equal(res, html); - }) - }, - - 'test buffered code': function(){ - var html = '

tj

', - str = '

<%= name %>

', - locals = { name: 'tj' }; - assert.equal(html, ejs.render(str, { locals: locals })); - }, - - 'test unbuffered code': function(){ - var html = '

tj

', - str = '<% if (name) { %>

<%= name %>

<% } %>', - locals = { name: 'tj' }; - assert.equal(html, ejs.render(str, { locals: locals })); - }, - - 'test `scope` option': function(){ - var html = '

tj

', - str = '

<%= this %>

'; - assert.equal(html, ejs.render(str, { scope: 'tj' })); - }, - - 'test escaping': function(){ - assert.equal('<script>', ejs.render('<%= " - - - - - \ No newline at end of file diff --git a/node_modules/stoopid/node_modules/colors/example.js b/node_modules/stoopid/node_modules/colors/example.js deleted file mode 100644 index 3da298644..000000000 --- a/node_modules/stoopid/node_modules/colors/example.js +++ /dev/null @@ -1,65 +0,0 @@ -var colors = require('./colors'); - -//colors.mode = "browser"; - -var test = colors.red("hopefully colorless output"); -console.log('Rainbows are fun!'.rainbow); -console.log('So '.italic + 'are'.underline + ' styles! '.bold + 'inverse'.inverse); // styles not widely supported -console.log('Chains are also cool.'.bold.italic.underline.red); // styles not widely supported -//console.log('zalgo time!'.zalgo); -console.log(test.stripColors); -console.log("a".grey + " b".black); - -console.log("Zebras are so fun!".zebra); - -console.log(colors.rainbow('Rainbows are fun!')); -console.log(colors.italic('So ') + colors.underline('are') + colors.bold(' styles! ') + colors.inverse('inverse')); // styles not widely supported -console.log(colors.bold(colors.italic(colors.underline(colors.red('Chains are also cool.'))))); // styles not widely supported -//console.log(colors.zalgo('zalgo time!')); -console.log(colors.stripColors(test)); -console.log(colors.grey("a") + colors.black(" b")); - -colors.addSequencer("america", function(letter, i, exploded) { - if(letter === " ") return letter; - switch(i%3) { - case 0: return letter.red; - case 1: return letter.white; - case 2: return letter.blue; - } -}); - -colors.addSequencer("random", (function() { - var available = ['bold', 'underline', 'italic', 'inverse', 'grey', 'yellow', 'red', 'green', 'blue', 'white', 'cyan', 'magenta']; - - return function(letter, i, exploded) { - return letter === " " ? letter : letter[available[Math.round(Math.random() * (available.length - 1))]]; - }; -})()); - -console.log("AMERICA! F--K YEAH!".america); -console.log("So apparently I've been to Mars, with all the little green men. But you know, I don't recall.".random); - -// -// Custom themes -// - -colors.setTheme({ - silly: 'rainbow', - input: 'grey', - verbose: 'cyan', - prompt: 'grey', - info: 'green', - data: 'grey', - help: 'cyan', - warn: 'yellow', - debug: 'blue', - error: 'red' -}); - -// outputs red text -console.log("this is an error".error); - -// outputs yellow text -console.log("this is a warning".warn); - - diff --git a/node_modules/stoopid/node_modules/colors/package.json b/node_modules/stoopid/node_modules/colors/package.json deleted file mode 100644 index 3a53d62b2..000000000 --- a/node_modules/stoopid/node_modules/colors/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "colors", - "description": "get colors in your node.js console like what", - "version": "0.6.0-1", - "author": "Marak Squires", - "repository": { - "type": "git", - "url": "http://github.com/Marak/colors.js.git" - }, - "engines": { - "node": ">=0.1.90" - }, - "main": "colors" -} diff --git a/node_modules/stoopid/node_modules/colors/test.js b/node_modules/stoopid/node_modules/colors/test.js deleted file mode 100644 index 1c03d658b..000000000 --- a/node_modules/stoopid/node_modules/colors/test.js +++ /dev/null @@ -1,65 +0,0 @@ -var assert = require('assert'), - colors = require('./colors'); - -// -// This is a pretty nice example on how tests shouldn't be written. However, -// it's more about API stability than about really testing it (although it's -// a pretty complete test suite). -// - -var s = 'string'; - -function a(s, code) { - return '\033[' + code.toString() + 'm' + s + '\033[39m'; -} - -function aE(s, color, code) { - assert.equal(s[color], a(s, code)); - assert.equal(colors[color](s), a(s, code)); - assert.equal(s[color], colors[color](s)); - assert.equal(s[color].stripColors, s); - assert.equal(s[color].stripColors, colors.stripColors(s)); -} - -function h(s, color) { - return '' + s + ''; - // that's pretty dumb approach to testing it -} - -var stylesColors = ['white', 'grey', 'black', 'blue', 'cyan', 'green', 'magenta', 'red', 'yellow']; -var stylesAll = stylesColors.concat(['bold', 'italic', 'underline', 'inverse', 'rainbow']); - -colors.mode = 'console'; -assert.equal(s.bold, '\033[1m' + s + '\033[22m'); -assert.equal(s.italic, '\033[3m' + s + '\033[23m'); -assert.equal(s.underline, '\033[4m' + s + '\033[24m'); -assert.equal(s.inverse, '\033[7m' + s + '\033[27m'); -assert.ok(s.rainbow); -aE(s, 'white', 37); -aE(s, 'grey', 90); -aE(s, 'black', 30); -aE(s, 'blue', 34); -aE(s, 'cyan', 36); -aE(s, 'green', 32); -aE(s, 'magenta', 35); -aE(s, 'red', 31); -aE(s, 'yellow', 33); -assert.equal(s, 'string'); - -colors.mode = 'browser'; -assert.equal(s.bold, '' + s + ''); -assert.equal(s.italic, '' + s + ''); -assert.equal(s.underline, '' + s + ''); -assert.equal(s.inverse, '' + s + ''); -assert.ok(s.rainbow); -stylesColors.forEach(function (color) { - assert.equal(s[color], h(s, color)); - assert.equal(colors[color](s), h(s, color)); -}); - -colors.mode = 'none'; -stylesAll.forEach(function (style) { - assert.equal(s[style], s); - assert.equal(colors[style](s), s); -}); - diff --git a/node_modules/stoopid/package.json b/node_modules/stoopid/package.json deleted file mode 100644 index cea9e68a2..000000000 --- a/node_modules/stoopid/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "author": "Mikeal Rogers (http://www.mikealrogers.com)", - "name": "stoopid", - "description": "Loggers are stupid and I'm resentful that I had to write this.", - "version": "0.0.0", - "repository": { - "type": "git", - "url": "git://github.com/mikeal/stoopid.git" - }, - "main": "index.js", - "dependencies": {"colors":"*"}, - "devDependencies": {} -} diff --git a/node_modules/stoopid/test.js b/node_modules/stoopid/test.js deleted file mode 100644 index 39609eb88..000000000 --- a/node_modules/stoopid/test.js +++ /dev/null @@ -1,7 +0,0 @@ -var stoopid = require('./index') - -stoopid.info('info') -stoopid.warn('warn') -stoopid.error('error') -stoopid.log('log') -stoopid.trace('trace') \ No newline at end of file diff --git a/package.json b/package.json old mode 100755 new mode 100644 index bb8ca43a4..d41b48d7d --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "tags": [ "api", "apis", + "swagger", + "open api initiative", + "apidoc", "microservice" ], "version": "0.4.0", @@ -15,24 +18,27 @@ "bugs": { "url": "https://github.com/readmeio/api/issues" }, - "main": "./api.js", - "bin": { - "api": "./bin/api.js" + "main": "index.js", + "dependencies": { + "colors": "^1.1.2", + "git-utils": "^4.1.2", + "lodash": "^4.13.1", + "minimist": "^1.2.0", + "readline-sync": "^1.4.4", + "request": "^2.73.0", + "sinon-chai": "^2.8.0", + "swagger-parser": "^3.4.1", + "yamljs": "^0.2.8" }, - "engines": { - "node": ">=0.4.0" + "devDependencies": { + "chai": "^3.5.0", + "chai-string": "^1.2.0", + "mocha": "^2.5.3", + "mocha-sinon": "^1.1.5", + "sinon": "^1.17.4" }, - "dependencies": { - "confdir": ">=0.0.2", - "ejs": ">=0.6.1", - "stoopid": ">=0.0.0" + "scripts": { + "test": "mocha" }, - "licenses": [ - { - "type": "MIT", - "url": "http://vorb.de/license/mit.html" - } - ], - "devDependencies": {}, - "optionalDependencies": {} + "license": "see LICENSE file" } diff --git a/test.js b/test.js deleted file mode 100644 index 3df943960..000000000 --- a/test.js +++ /dev/null @@ -1,38 +0,0 @@ -var api = require('./')('http'), - msg = 'Hello World!'; - -var server = new api.Server(); -server.listen(1337, '127.0.0.1'); - -function error404(res) { - res.writeHead(404); - res.end('Not found.\n'); -}; - -// Listen for regular requests and end with an 404 error. -server.on('regularRequest', function(req, res) { - error404(res); -}); - -// Listen for requests to /hello-world. -server.on('/hello-world', function(req, res) { - if (req.method == 'GET') { - res.writeHead(200); - res.end(msg+'\n'); - } else if (req.method == 'POST') { - res.writeHead(200); - msg = ''; - - // Update the message - req.on('data', function(chunk) { - msg += chunk; - }); - - // After the POST request has ended, end with the message. - req.on('end', function() { - res.end('Successfully changed message to "'+msg+'".\n'); - }); - } else { - error404(res); - } -}); diff --git a/test/fixtures/json/swagger.json b/test/fixtures/json/swagger.json new file mode 100644 index 000000000..816847f31 --- /dev/null +++ b/test/fixtures/json/swagger.json @@ -0,0 +1 @@ +{"swagger":"2.0","info":{"description":"This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.","version":"1.0.0","title":"Swagger Petstore","termsOfService":"http://swagger.io/terms/","contact":{"email":"apiteam@swagger.io"},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0.html"}},"host":"petstore.swagger.io","basePath":"/v2","tags":[{"name":"pet","description":"Everything about your Pets","externalDocs":{"description":"Find out more","url":"http://swagger.io"}},{"name":"store","description":"Access to Petstore orders"},{"name":"user","description":"Operations about user","externalDocs":{"description":"Find out more about our store","url":"http://swagger.io"}}],"schemes":["http"],"paths":{"/pet":{"post":{"tags":["pet"],"summary":"Add a new pet to the store","description":"","operationId":"addPet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"put":{"tags":["pet"],"summary":"Update an existing pet","description":"","operationId":"updatePet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"},"405":{"description":"Validation exception"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByStatus":{"get":{"tags":["pet"],"summary":"Finds Pets by status","description":"Multiple status values can be provided with comma separated strings","operationId":"findPetsByStatus","produces":["application/xml","application/json"],"parameters":[{"name":"status","in":"query","description":"Status values that need to be considered for filter","required":true,"type":"array","items":{"type":"string","enum":["available","pending","sold"],"default":"available"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid status value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByTags":{"get":{"tags":["pet"],"summary":"Finds Pets by tags","description":"Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.","operationId":"findPetsByTags","produces":["application/xml","application/json"],"parameters":[{"name":"tags","in":"query","description":"Tags to filter by","required":true,"type":"array","items":{"type":"string"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid tag value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}],"deprecated":true}},"/pet/{petId}":{"get":{"tags":["pet"],"summary":"Find pet by ID","description":"Returns a single pet","operationId":"getPetById","produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to return","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Pet"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"api_key":[]}]},"post":{"tags":["pet"],"summary":"Updates a pet in the store with form data","description":"","operationId":"updatePetWithForm","consumes":["application/x-www-form-urlencoded"],"produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet that needs to be updated","required":true,"type":"integer","format":"int64"},{"name":"name","in":"formData","description":"Updated name of the pet","required":false,"type":"string"},{"name":"status","in":"formData","description":"Updated status of the pet","required":false,"type":"string"}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"delete":{"tags":["pet"],"summary":"Deletes a pet","description":"","operationId":"deletePet","produces":["application/xml","application/json"],"parameters":[{"name":"api_key","in":"header","required":false,"type":"string"},{"name":"petId","in":"path","description":"Pet id to delete","required":true,"type":"integer","format":"int64"}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/{petId}/uploadImage":{"post":{"tags":["pet"],"summary":"uploads an image","description":"","operationId":"uploadFile","consumes":["multipart/form-data"],"produces":["application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to update","required":true,"type":"integer","format":"int64"},{"name":"additionalMetadata","in":"formData","description":"Additional data to pass to server","required":false,"type":"string"},{"name":"file","in":"formData","description":"file to upload","required":false,"type":"file"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/ApiResponse"}}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/store/inventory":{"get":{"tags":["store"],"summary":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","operationId":"getInventory","produces":["application/json"],"parameters":[],"responses":{"200":{"description":"successful operation","schema":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}}},"security":[{"api_key":[]}]}},"/store/order":{"post":{"tags":["store"],"summary":"Place an order for a pet","description":"","operationId":"placeOrder","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"order placed for purchasing the pet","required":true,"schema":{"$ref":"#/definitions/Order"}}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid Order"}}}},"/store/order/{orderId}":{"get":{"tags":["store"],"summary":"Find purchase order by ID","description":"For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions","operationId":"getOrderById","produces":["application/xml","application/json"],"parameters":[{"name":"orderId","in":"path","description":"ID of pet that needs to be fetched","required":true,"type":"integer","maximum":10.0,"minimum":1.0,"format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}},"delete":{"tags":["store"],"summary":"Delete purchase order by ID","description":"For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors","operationId":"deleteOrder","produces":["application/xml","application/json"],"parameters":[{"name":"orderId","in":"path","description":"ID of the order that needs to be deleted","required":true,"type":"integer","minimum":1.0,"format":"int64"}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}}},"/user":{"post":{"tags":["user"],"summary":"Create user","description":"This can only be done by the logged in user.","operationId":"createUser","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Created user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithArray":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithArrayInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithList":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithListInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/login":{"get":{"tags":["user"],"summary":"Logs user into the system","description":"","operationId":"loginUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"query","description":"The user name for login","required":true,"type":"string"},{"name":"password","in":"query","description":"The password for login in clear text","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"type":"string"},"headers":{"X-Rate-Limit":{"type":"integer","format":"int32","description":"calls per hour allowed by the user"},"X-Expires-After":{"type":"string","format":"date-time","description":"date in UTC when token expires"}}},"400":{"description":"Invalid username/password supplied"}}}},"/user/logout":{"get":{"tags":["user"],"summary":"Logs out current logged in user session","description":"","operationId":"logoutUser","produces":["application/xml","application/json"],"parameters":[],"responses":{"default":{"description":"successful operation"}}}},"/user/{username}":{"get":{"tags":["user"],"summary":"Get user by user name","description":"","operationId":"getUserByName","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be fetched. Use user1 for testing. ","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/User"}},"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}},"put":{"tags":["user"],"summary":"Updated user","description":"This can only be done by the logged in user.","operationId":"updateUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"name that need to be updated","required":true,"type":"string"},{"in":"body","name":"body","description":"Updated user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"400":{"description":"Invalid user supplied"},"404":{"description":"User not found"}}},"delete":{"tags":["user"],"summary":"Delete user","description":"This can only be done by the logged in user.","operationId":"deleteUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be deleted","required":true,"type":"string"}],"responses":{"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}}}},"securityDefinitions":{"petstore_auth":{"type":"oauth2","authorizationUrl":"http://petstore.swagger.io/oauth/dialog","flow":"implicit","scopes":{"write:pets":"modify pets in your account","read:pets":"read your pets"}},"api_key":{"type":"apiKey","name":"api_key","in":"header"}},"definitions":{"Order":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"petId":{"type":"integer","format":"int64"},"quantity":{"type":"integer","format":"int32"},"shipDate":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Order Status","enum":["placed","approved","delivered"]},"complete":{"type":"boolean","default":false}},"xml":{"name":"Order"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Category"}},"User":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"integer","format":"int32","description":"User Status"}},"xml":{"name":"User"}},"Tag":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Tag"}},"Pet":{"type":"object","required":["name","photoUrls"],"properties":{"id":{"type":"integer","format":"int64"},"category":{"$ref":"#/definitions/Category"},"name":{"type":"string","example":"doggie"},"photoUrls":{"type":"array","xml":{"name":"photoUrl","wrapped":true},"items":{"type":"string"}},"tags":{"type":"array","xml":{"name":"tag","wrapped":true},"items":{"$ref":"#/definitions/Tag"}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"xml":{"name":"Pet"}},"ApiResponse":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"type":{"type":"string"},"message":{"type":"string"}}}},"externalDocs":{"description":"Find out more about Swagger","url":"http://swagger.io"}} \ No newline at end of file diff --git a/test/fixtures/json/wrongfile.json b/test/fixtures/json/wrongfile.json new file mode 100644 index 000000000..b4b62ea8e --- /dev/null +++ b/test/fixtures/json/wrongfile.json @@ -0,0 +1,3 @@ +{ + 'test': 1 +} diff --git a/test/fixtures/json/wrongfile.yaml b/test/fixtures/json/wrongfile.yaml new file mode 100644 index 000000000..820d2ec13 --- /dev/null +++ b/test/fixtures/json/wrongfile.yaml @@ -0,0 +1 @@ +test: hi diff --git a/test/fixtures/yaml/NotTheFile.yaml b/test/fixtures/yaml/NotTheFile.yaml new file mode 100644 index 000000000..d951fcf3b --- /dev/null +++ b/test/fixtures/yaml/NotTheFile.yaml @@ -0,0 +1 @@ +hi: 1 diff --git a/test/fixtures/yaml/PetStore.yaml b/test/fixtures/yaml/PetStore.yaml new file mode 100644 index 000000000..3088e2b92 --- /dev/null +++ b/test/fixtures/yaml/PetStore.yaml @@ -0,0 +1,345 @@ +swagger: "2.0" +info: + version: 1.0.0 + title: Swagger petstore + description: A sample API that demonstrates Swagger-Express-Middleware features + +consumes: + - application/json +produces: + - application/json + +definitions: + pet: + required: + - name + - type + properties: + name: + type: string + minLength: 4 + pattern: "^[a-zA-Z0-9- ]+$" + age: + type: integer + dob: + type: string + format: 'date' + type: + type: string + enum: [cat, dog, bird] + address: + $ref: "#/definitions/address" + vet: + $ref: "#/definitions/veterinarian" + tags: + type: array + uniqueItems: true + items: + type: string + minLength: 1 + + veterinarian: + required: + - name + properties: + name: + type: string + minLength: 1 + address: + $ref: "#/definitions/address" + + address: + properties: + street: + type: string + minLength: 1 + city: + type: string + minLength: 1 + state: + type: string + minLength: 2 + maxLength: 2 + pattern: "^[A-Z]+$" + zipcode: + type: integer + minimum: 10000 + maximum: 99999 + +parameters: + petName: + name: petName + in: path + description: Name of the pet + required: true + type: string + +paths: + /pets: + get: + description: Returns all pets, optionally filtered by one or more criteria + operationId: findPets + parameters: &petFilters + - name: tags + in: query + description: Filters pets by one or more tags + required: false + type: array + items: + type: string + uniqueItems: true + collectionFormat: csv + - name: type + in: query + description: Filters pets by type (dog, cat, or bird) + required: false + type: string + enum: [cat, dog, bird] + - name: age + in: query + description: Filters pets by age + required: false + type: integer + - name: dob + in: query + description: Filters pets by date of birth + required: false + type: string + format: date + - name: address.city + in: query + description: Filters pets by city + required: false + type: string + - name: address.state + in: query + description: Filters pets by state + required: false + type: string + - name: address.zipcode + in: query + description: Filters pets by zip code + required: false + type: integer + - name: vet.name + in: query + description: Filters pets by veterinarian name + required: false + type: string + - name: vet.address.city + in: query + description: Filters pets by veterinarian city + required: false + type: string + - name: vet.address.state + in: query + description: Filters pets by veterinarian state + required: false + type: string + - name: vet.address.zipcode + in: query + description: Filters pets by veterinarian zip code + required: false + type: integer + responses: + default: + description: Returns the matching pets + schema: + type: array + items: + $ref: "#/definitions/pet" + headers: + last-modified: + type: string + description: The date/time that a pet was last modified + + delete: + description: Deletes all pets, optionally filtered by one or more criteria + operationId: deletePets + parameters: *petFilters + responses: + default: + description: Returns the pets that were deleted + schema: + type: array + items: + $ref: "#/definitions/pet" + + post: + description: Creates a new pet in the store + operationId: addPet + parameters: + - name: pet + in: body + description: The pet to add to the store + required: true + schema: + $ref: "#/definitions/pet" + responses: + 201: + description: Returns the newly-added pet + schema: + $ref: "#/definitions/pet" + headers: + Location: + type: string + description: The URL of the newly-added pet + + /pets/{petName}: + parameters: + - $ref: "#/parameters/petName" + + get: + description: Returns a pet by name + operationId: findPetByName + responses: + default: + description: Returns the pet data + schema: + $ref: "#/definitions/pet" + headers: + last-modified: + type: string + description: The date/time that the pet was last modified + + delete: + description: Deletes a single pet based on the name supplied + operationId: deletePet + responses: + default: + description: Returns the pet that was deleted + schema: + $ref: "#/definitions/pet" + + patch: + description: Updates a pet by name + parameters: + - name: pet + in: body + description: The updated pet info + required: true + schema: + $ref: "#/definitions/pet" + responses: + default: + description: Returns the updated pet data + schema: + $ref: "#/definitions/pet" + + /pets/{petName}/photos: + parameters: + - $ref: "#/parameters/petName" + + post: + description: Upload a new pet photo + operationId: addPetPhoto + consumes: + - multipart/form-data + parameters: + - name: id + in: formData + description: The photo ID (generated automatically) + type: integer + format: int32 + minimum: 1 + - name: label + in: formData + description: A label for the photo + required: true + type: string + minLength: 1 + - name: description + in: formData + description: An optional description of the photo + type: string + - name: photo + in: formData + description: The pet photo + required: true + type: file + minLength: 1 + maxLength: 5000000 # ~5MB + responses: + default: + description: Returns the photo information + schema: + properties: + id: + type: integer + format: int32 + description: The auto-generated photo ID + label: + type: string + description: + type: string + photo: + type: object + description: Information about the photo (size, file name, etc.) + headers: + Location: + type: string + description: The URL of the newly-added photo + + get: + description: Get a list of the photos for a pet + responses: + 200: + description: Returns the list of photos + schema: + type: array + items: + properties: + id: + type: integer + format: int32 + description: The auto-generated photo ID + label: + type: string + description: + type: string + photo: + type: object + description: Information about the photo (size, file name, etc.) + + /pets/{petName}/photos/{id}: + parameters: + - $ref: "#/parameters/petName" + - name: id + in: path + description: The ID of the photo + required: true + type: integer + format: int32 + + get: + description: Gets a pet photo + operationId: getPetPhoto + produces: + - image/jpeg + - image/gif + - image/png + - image/bmp + responses: + default: + description: Returns the pet photo + schema: + type: file + + delete: + description: Deletes a pet photo + operationId: deletePetPhoto + responses: + default: + description: The photo was deleted successfully + + /: + get: + produces: + - text/html + responses: + default: + description: The Swagger Pet Store homepage :) + schema: + type: file + default: + $ref: "index.html" diff --git a/test/fixtures/yaml/index.html b/test/fixtures/yaml/index.html new file mode 100644 index 000000000..2894bd45c --- /dev/null +++ b/test/fixtures/yaml/index.html @@ -0,0 +1,200 @@ + + + + + + Swagger Pet Store + + + + + + + +
+
+

Swagger Pet Store

+ +

+ This sample API is powered by the Swagger Express Middleware mock + in an otherwise empty Express application. There's no extra configuration, custom code, or third-party-middleware. +

+

+ Read the Walkthroughs +

+
+ +
+
+ Add/Edit a Pet + +

+ Use a tool like Postman or curl + to perform more advanced operations. See the full Swagger API + for all the operations available. And be sure to try + a few + queries. +

+ +
+
+ +
+
+

+ + +   + + + +   + + + + + All Pets + + +

+
+
+ +
+
+ Add Photos + +

+ You can also delete or view individual photos by their ID. + See the full Swagger API for all the operations available. +

+ +
+
+ +
+
+
+ +
+
+
+ +
+
+

+ + +   + + + + + Fido's Photos + + +

+
+
+
+ + + + + + + + diff --git a/test/fixtures/yaml/notthefile.json b/test/fixtures/yaml/notthefile.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/fixtures/yaml/notthefile.json @@ -0,0 +1 @@ +{} diff --git a/test/test.js b/test/test.js new file mode 100644 index 000000000..51081401f --- /dev/null +++ b/test/test.js @@ -0,0 +1,83 @@ +var chai = require('chai'); +var assert = chai.assert; +var expect = chai.expect; +chai.use(require('chai-string')); +chai.use(require('sinon-chai')); +require('sinon'); +require('mocha-sinon'); + +var path = require('path'); + +describe('utils.js', function() { + var utils = require('../utils'); + describe('#findSwagger()', function() { + + it('find a YAML file', function(done) { + utils.findSwagger(function(err, swagger, file) { + if(err) return done(err); + expect(file).to.endsWith('PetStore.yaml'); + assert.equal('2.0', swagger.swagger); + done(); + }, { + dir: path.join(__dirname, 'fixtures', 'yaml') + }); + }); + + it('find a JSON file', function(done) { + utils.findSwagger(function(err, swagger, file) { + if(err) return done(err); + expect(file).to.endsWith('swagger.json'); + assert.equal('2.0', swagger.swagger); + done(); + }, { + dir: path.join(__dirname, 'fixtures', 'json') + }); + }); + + it('loads main config', function() { + var config = utils.config('config'); + expect(Object.keys(config).length > 0).to.be.true; + assert.notEqual(config, 'test'); + }); + + it('loads test config', function() { + var config = utils.config('test'); + expect(Object.keys(config).length > 0).to.be.true; + assert.equal(config.env, 'test'); + }); + + }); + + describe('#isSwagger()', function() { + it('yaml file is swagger', function() { + expect(utils.isSwagger(path.join(__dirname, 'fixtures', 'yaml', 'PetStore.yaml'))).to.be.true; + }); + + it('json file is swagger', function() { + expect(utils.isSwagger(path.join(__dirname, 'fixtures', 'json', 'swagger.json'))).to.be.true; + }); + + it('bad json file is not swagger', function() { + expect(utils.isSwagger(path.join(__dirname, 'fixtures', 'yaml', 'notthefile.json'))).to.be.false; + }); + + it('bad yaml file is not swagger', function() { + expect(utils.isSwagger(path.join(__dirname, 'fixtures', 'json', 'wrongfile.yaml'))).to.be.false; + }); + + }); + +}); + +describe('api.js', function() { + var api = require('../api'); + beforeEach(function() { + this.sinon.stub(console, 'log'); + }); + describe('#api()', function() { + it('action not found', function() { + api.api('notARealAction'); + expect(console.log).to.have.been.calledWithMatch('not found'); + }); + }); +}); diff --git a/utils.js b/utils.js new file mode 100644 index 000000000..a57a199b3 --- /dev/null +++ b/utils.js @@ -0,0 +1,55 @@ +var fs = require('fs'); +var path = require('path'); + +var _ = require('lodash'); +var git = require('git-utils'); +var swagger = require('swagger-parser'); +var yaml = require('yamljs'); + +exports.config = function(env) { + return require('./config/' + (env || 'config')); +} + +exports.findSwagger = function(cb, opts) { + opts = opts || {}; + + var dir = opts.dir || process.cwd(); + /* + // TODO: Maybe use the git root? + if(!dir) { + var repository = git.open(__dirname) + dir = repository.getWorkingDirectory(); + } + */ + + var files = fs.readdirSync(dir).filter((file) => { + if(!file.match(/\.(json|yaml)$/)) return false; + return exports.isSwagger(path.join(dir, file)); + }); + + // TODO: Give people an option if there's more than one Swagger file + if(files[0]) { + var file = path.join(dir, files[0]); + swagger.bundle(file, function(err, api) { + cb(err, api, file); + }); + } else { + cb(); + } +}; + +exports.isSwagger = function(file) { + var fileType = file.split('.').slice(-1)[0]; + if(fileType == 'json') { + try { + var content = require(file); + return content.swagger === "2.0"; + } catch(e) {} + } + + if(fileType == 'yaml') { + return yaml.load(file).swagger === "2.0"; + } + + return false; +}