├── .gitignore ├── README.md ├── example ├── controllers │ ├── posts.js │ └── users.js └── server.js ├── lib ├── build-options.js ├── build-router.js ├── parse-controller.js ├── parse-controllers.js ├── remount-router.js └── watch-files.js ├── nuxt.js ├── package.json ├── tests ├── build-options-test.js ├── build-router-test.js ├── parse-controller-fixture-invalid1.js ├── parse-controller-fixture-invalid2.js ├── parse-controller-fixture-invalid3.js ├── parse-controller-fixture-invalid4.js ├── parse-controller-fixture-valid.js ├── parse-controller-test.js ├── parse-controllers-test.js └── watch-files-test.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | temp 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # remount-router 2 | 3 | A simple file-based router for [Express.js](https://expressjs.com) with 4 | automatic routes remounting on file changes without the need to restart the 5 | server. 6 | 7 | ![Quick Demo](https://i.imgur.com/84AzFCR.gif) 8 | 9 | 10 | ## Installation 11 | 12 | ```bash 13 | npm install remount-router --save 14 | ``` 15 | 16 | or 17 | 18 | ```bash 19 | yarn add remount-router 20 | ``` 21 | 22 | 23 | ## Initialization 24 | 25 | The `remount-router` comes as middleware and takes a couple of options. Take 26 | this example server for instance: 27 | 28 | ```javascript 29 | const path = require('path') 30 | const express = require('express') 31 | const remountRouter = require('remount-router') 32 | 33 | const app = express() 34 | 35 | app.use(remountRouter({ 36 | expressAppInstance: app, 37 | apiEndpoint: '/api', 38 | controllersPath: path.join(__dirname, 'controllers') 39 | })) 40 | 41 | app.listen(17777) 42 | ``` 43 | 44 | This will parse all `*.js` files in the `./controllers` directory and mounts it 45 | to the `/api` endpoint. 46 | 47 | 48 | ## Controllers 49 | 50 | The name of a controller file will be used as the parent route. Controllers must 51 | export an `Object`, the keys define the HTTP verb and the route. Each verb/route 52 | can have one `Function` or an `Array` of `Function`s. 53 | 54 | Let's take the controller file `./controllers/users.js` for example: 55 | 56 | ```javascript 57 | module.exports = { 58 | 'GET /' (req, res) { 59 | res.json({ action: 'find all users' }) 60 | }, 61 | 62 | 'POST /admin/:id': [ 63 | (req, res, next) => { 64 | // middleware to be executed before the route function 65 | next() 66 | }, 67 | 68 | (req, res) => { 69 | res.json({ action: 'save a new user' }) 70 | } 71 | ] 72 | } 73 | ``` 74 | 75 | This will result in two routes: `GET /api/users` and 76 | `POST /api/users/admin/:id`. Note that you can use middleware if you pass an 77 | `Array` to the verb/route key. 78 | 79 | The verb (`GET`, `POST`, `PUT`, etc.) can be any 80 | [routing method](https://expressjs.com/en/4x/api.html#app.METHOD) offered by 81 | Express.js (`app.get()`, `app.post()`, `app.put()`, etc.). 82 | 83 | 84 | ## Automatic Route Remounting 85 | 86 | If the option `isDev` is `true`, all matching controller files will be watched 87 | for changes (adding/removing files, editing files). If a change is detected, a 88 | new router is generated and remounted to the `apiEndpoint`. 89 | 90 | 91 | ## Options 92 | 93 | Options are passed to `remount-router` as an `Object` (as seen in the 94 | initialization example). 95 | 96 | ```javascript 97 | const defaults = { 98 | expressAppInstance: null, 99 | controllersPath: path.join(process.cwd(), 'controllers'), 100 | controllersGlob: '*.js', 101 | apiEndpoint: '/api', 102 | isDev: !(process.env.NODE_ENV === 'production') 103 | } 104 | ``` 105 | 106 | ### `expressAppInstance` (required) 107 | 108 | The instance of your main app created with `express()`. This is used to 109 | initially mount the router. But more importantly, it is used to remount the 110 | router (there is no other way than passing it as an option). 111 | 112 | ### `controllersPath` 113 | 114 | Where to find controller files to parse. Note that the default is pointing to 115 | the `controllers` directory in the current working directory. This is convenient 116 | to quickly get started, but the `process.cwd()` might change when you deploy to 117 | another system. Therefor it is advised to overwrite this option with an absolute 118 | path (as seen in the initialization example). 119 | 120 | ### `controllersGlob` 121 | 122 | This defaults to `*.js` and is consumed by the 123 | [Glob](https://github.com/isaacs/node-glob) 124 | module. Set this option if you do not have controllers only in the controllers 125 | directory. You might have `*.test.js` files along the controllers, then you 126 | would exclude them by overwriting this option with `*!(.test).js`. 127 | 128 | ### `apiEndpoint` 129 | 130 | This defaults to `/api` and is the endpoint where the router is mounted and all 131 | sub-routes parsed from the controllers will be mounted on. Remember, a 132 | controller named `./controllers/posts.js` with a route key `GET /all` will 133 | result in the `GET` route `/api/posts/all`. 134 | 135 | ### `isDev` 136 | 137 | This defaults to `true` if the `NODE_ENV` environment variable is not 138 | `production`, otherwise it is `false`. File watching and route remounting will 139 | only happen if this option is `true`. 140 | 141 | 142 | ## Using it with Nuxt.js 143 | 144 | Implementing `remount-router` in [Nuxt.js](https://nuxtjs.org/) is super simple. 145 | After you've installed the module (`yarn add remount-router`), add it to your 146 | `nuxt.config.js` as a module like so: 147 | 148 | ```javascript 149 | module.exports = { 150 | modules: [ 151 | 'remount-router/nuxt' 152 | ] 153 | } 154 | ``` 155 | 156 | Notice that we don't pass any options: the `expressAppInstance` is created for 157 | you, and the `controllersPath` is set to `/controllers` inside Nuxt's `srcDir`. 158 | The `isDev` option equals to Nuxt's `dev` option. 159 | 160 | However, you can pass custom options like so: 161 | 162 | ```javascript 163 | module.exports = { 164 | modules: [ 165 | ['remount-router/nuxt', { 166 | controllersGlob: '*!(.test).js', 167 | apiEndpoint: '/api/v1' 168 | }] 169 | ] 170 | } 171 | ``` 172 | 173 | 174 | ## Development 175 | 176 | ```bash 177 | yarn 178 | yarn test 179 | ``` 180 | 181 | 182 | ## Changelog 183 | 184 | - 2017-08-29: Add Nuxt.js module wrapper 185 | - 2017-08-25: Initial release 186 | 187 | 188 | ## License 189 | 190 | Copyright 2017 Sebastian Senf ([enkrateia.me](https://enkrateia.me)) 191 | 192 | 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: 193 | 194 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 195 | 196 | 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. 197 | -------------------------------------------------------------------------------- /example/controllers/posts.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'GET /' (req, res) { 3 | res.json({ action: 'find all posts' }) 4 | }, 5 | 6 | 'POST /:id' (req, res) { 7 | res.json({ action: 'save a new post' }) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/controllers/users.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'GET /' (req, res) { 3 | res.json({ action: 'find all users' }) 4 | }, 5 | 6 | 'POST /admin/:id': [ 7 | (req, res, next) => { 8 | // middleware to be executed before the route function 9 | next() 10 | }, 11 | 12 | (req, res) => { 13 | res.json({ action: 'save a new user' }) 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /example/server.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const express = require('express') 3 | const remountRouter = require('..') 4 | 5 | const app = express() 6 | 7 | app.use(remountRouter({ 8 | expressAppInstance: app, 9 | apiEndpoint: '/api', 10 | isDev: true, 11 | controllersPath: path.join(__dirname, 'controllers') 12 | })) 13 | 14 | app.listen(17777) 15 | -------------------------------------------------------------------------------- /lib/build-options.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = (options = {}) => { 4 | const defaults = { 5 | expressAppInstance: null, 6 | controllersPath: path.join(process.cwd(), 'controllers'), 7 | controllersGlob: '*.js', 8 | apiEndpoint: '/api', 9 | isDev: !(process.env.NODE_ENV === 'production') 10 | } 11 | 12 | return Object.assign({}, defaults, options) 13 | } 14 | -------------------------------------------------------------------------------- /lib/build-router.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | 3 | module.exports = controllers => { 4 | const router = express.Router() 5 | 6 | controllers.forEach(controller => { 7 | controller.routes.forEach(route => { 8 | const routerFunc = router[route.verb.toLowerCase()] 9 | const url = `/${controller.resourceName}${route.route}` 10 | 11 | routerFunc.apply(router, [url, ...route.handlers]) 12 | }) 13 | }) 14 | 15 | return router 16 | } 17 | -------------------------------------------------------------------------------- /lib/parse-controller.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const importFresh = require('import-fresh') 3 | const express = require('express') 4 | 5 | const router = express.Router() 6 | 7 | module.exports = filePath => { 8 | return new Promise((resolve, reject) => { 9 | const resourceName = path.basename(filePath, '.js') 10 | const controllerObj = importFresh(filePath) 11 | const routes = Object.keys(controllerObj).map(fullRoute => { 12 | let [verb, route] = fullRoute.split(' ') 13 | const routerFunc = router[verb.toLowerCase()] 14 | 15 | if (typeof routerFunc === 'undefined') { 16 | return reject({ 17 | filePath, 18 | fullRoute, 19 | message: `Unknown verb '${verb}'` 20 | }) 21 | } 22 | 23 | if (!route || route.length === 0) { 24 | return reject({ 25 | filePath, 26 | fullRoute, 27 | message: `Missing route for verb '${verb}'` 28 | }) 29 | } 30 | 31 | if (route.substr(0, 1) !== '/') { 32 | return reject({ 33 | filePath, 34 | fullRoute, 35 | message: `Route '${route}' must start with an /` 36 | }) 37 | } 38 | 39 | let handlers = controllerObj[fullRoute] 40 | 41 | if (typeof handlers !== 'function' && !Array.isArray(handlers)) { 42 | return reject({ 43 | filePath, 44 | fullRoute, 45 | message: 'Handlers must be either a single function or an array of functions' 46 | }) 47 | } 48 | 49 | if (typeof handlers === 'function') { 50 | handlers = [handlers] 51 | } 52 | 53 | return { verb, route, handlers } 54 | }) 55 | 56 | resolve({ filePath, resourceName, routes }) 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /lib/parse-controllers.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const glob = require('glob') 3 | const parseController = require('./parse-controller') 4 | 5 | module.exports = options => { 6 | return new Promise((resolve, reject) => { 7 | const pathGlob = path.join(options.controllersPath, options.controllersGlob) 8 | 9 | glob(pathGlob, (err, files) => { 10 | if (err) { 11 | return reject(err) 12 | } 13 | 14 | const promises = files.map(filePath => parseController(filePath)) 15 | 16 | Promise.all(promises) 17 | .then(controllers => resolve(controllers)) 18 | .catch(err => reject(err)) 19 | }) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /lib/remount-router.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const colors = require('colors') 3 | const buildOptions = require('./build-options') 4 | const parseControllers = require('./parse-controllers') 5 | const buildRouter = require('./build-router') 6 | const watchFiles = require('./watch-files') 7 | 8 | const shortFilePath = filePath => { 9 | return filePath.replace(process.cwd(), '.') 10 | } 11 | 12 | const log = message => { 13 | console.log(colors.grey('[remount-router]'), message) 14 | } 15 | 16 | const logError = err => { 17 | if (err.filePath) { 18 | const filePath = colors.red(shortFilePath(err.filePath)) 19 | 20 | if (err.eventName) { 21 | log(`${colors.blue(`[${err.eventName}]`)} ${filePath}`) 22 | } else { 23 | log(filePath) 24 | } 25 | 26 | log(colors.yellow(`-> ${err.message}`)) 27 | } else { 28 | log(colors.red(err)) 29 | } 30 | } 31 | 32 | const logController = (options, controller) => { 33 | const filePath = colors.green(shortFilePath(controller.filePath)) 34 | 35 | if (controller.eventName) { 36 | log(`${colors.blue(`[${controller.eventName}]`)} ${filePath}`) 37 | } else { 38 | log(filePath) 39 | } 40 | 41 | controller.routes.forEach(route => { 42 | const url = `${options.apiEndpoint}/${controller.resourceName}${route.route}` 43 | log(colors.yellow(`-> ${route.verb} ${url}`)) 44 | }) 45 | } 46 | 47 | module.exports = customOptions => { 48 | const middleware = (res, req, next) => { next() } 49 | const options = buildOptions(customOptions) 50 | 51 | if (!fs.existsSync(options.controllersPath)) { 52 | logError(`controllersPath: '${options.controllersPath}' does not exist`) 53 | return middleware 54 | } 55 | 56 | if (options.expressAppInstance === null) { 57 | logError(`expressAppInstance: 'express()' app instance must be passed`) 58 | return middleware 59 | } 60 | 61 | parseControllers(options) 62 | .then(controllers => { 63 | const router = buildRouter(controllers) 64 | 65 | options.expressAppInstance.use(options.apiEndpoint, router) 66 | controllers.forEach(controller => logController(options, controller)) 67 | }) 68 | .catch(err => logError(err)) 69 | 70 | if (options.isDev) { 71 | watchFiles(options, (err, controller) => { 72 | if (err) { 73 | logError(err) 74 | } else { 75 | logController(options, controller) 76 | } 77 | }) 78 | } 79 | 80 | return middleware 81 | } 82 | -------------------------------------------------------------------------------- /lib/watch-files.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const chokidar = require('chokidar') 3 | const parseControllers = require('./parse-controllers') 4 | const buildRouter = require('./build-router') 5 | 6 | module.exports = (options, cb = () => {}) => { 7 | const pathGlob = path.join(options.controllersPath, options.controllersGlob) 8 | const watcher = chokidar.watch(pathGlob, { ignoreInitial: true }) 9 | 10 | watcher.on('all', (eventName, filePath) => { 11 | options.expressAppInstance._router.stack.forEach(route => { 12 | if (route.name === 'router' && route.regexp.test(options.apiEndpoint)) { 13 | parseControllers(options) 14 | .then(controllers => { 15 | route.handle = buildRouter(controllers) 16 | 17 | const controller = controllers 18 | .filter(c => c.filePath === filePath) 19 | .map(c => Object.assign(c, { eventName })) 20 | 21 | cb(null, controller[0]) 22 | }) 23 | .catch(err => { 24 | err.eventName = eventName 25 | cb(err) 26 | }) 27 | } 28 | }) 29 | }) 30 | 31 | return watcher 32 | } 33 | -------------------------------------------------------------------------------- /nuxt.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const express = require('express') 3 | const remountRouter = require('./lib/remount-router') 4 | 5 | module.exports = function (moduleOptions) { 6 | if (typeof this.nuxt === 'undefined') { 7 | throw new Error('Seems like this is not initialized as a Nuxt.js module') 8 | } 9 | 10 | const app = express() 11 | const options = Object.assign({}, { 12 | expressAppInstance: app, 13 | isDev: this.options.dev, 14 | cobtrollersPath: path.join(this.options.srcDir, 'controllers') 15 | }, moduleOptions) 16 | 17 | app.use(remountRouter(options)) 18 | this.addServerMiddleware({ path: '/', handler: app._router }) 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remount-router", 3 | "version": "0.2.1", 4 | "description": "A simple file-based router for Express.js with automatic routes remounting on file changes without the need to restart the server.", 5 | "license": "MIT", 6 | "author": "Sebastian Senf (http://mustardamus.com)", 7 | "main": "lib/remount-router.js", 8 | "homepage": "https://github.com/mustardamus/remount-router", 9 | "bugs": "https://github.com/mustardamus/remount-router/issues", 10 | "repository" : { 11 | "type" : "git", 12 | "url" : "https://github.com/mustardamus/remount-router.git" 13 | }, 14 | "keywords": [ 15 | "express", 16 | "express.js", 17 | "router", 18 | "file-router", 19 | "reload", 20 | "hot-reload", 21 | "development", 22 | "api", 23 | "nuxt", 24 | "nuxt.js" 25 | ], 26 | "scripts": { 27 | "test": "tape tests/**/*-test.js | tap-summary" 28 | }, 29 | "dependencies": { 30 | "chokidar": "^1.7.0", 31 | "colors": "^1.1.2", 32 | "express": "^4.15.4", 33 | "glob": "^7.1.2", 34 | "import-fresh": "^2.0.0" 35 | }, 36 | "devDependencies": { 37 | "fs-extra": "^4.0.1", 38 | "supertest": "^3.0.0", 39 | "tap-summary": "^3.0.2", 40 | "tape": "^4.8.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/build-options-test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const test = require('tape') 3 | const buildOptions = require('../lib/build-options') 4 | 5 | test('build-options', t => { 6 | const defaults = { 7 | isDev: true, 8 | controllersPath: path.join(process.cwd(), 'controllers'), 9 | controllersGlob: '*.js', 10 | apiEndpoint: '/api', 11 | expressAppInstance: null 12 | } 13 | 14 | t.deepEqual(buildOptions(), defaults) 15 | 16 | const custom = buildOptions({ 17 | isDev: false, 18 | controllersPath: '/' 19 | }) 20 | 21 | t.equal(custom.isDev, false) 22 | t.equal(custom.controllersPath, '/') 23 | t.equal(custom.apiEndpoint, '/api') 24 | 25 | process.env.NODE_ENV = 'production' 26 | t.equal(buildOptions().isDev, false) 27 | process.env.NODE_ENV = 'test' 28 | 29 | t.end() 30 | }) 31 | -------------------------------------------------------------------------------- /tests/build-router-test.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const express = require('express') 3 | const request = require('supertest') 4 | const buildOptions = require('../lib/build-options') 5 | const parseControllers = require('../lib/parse-controllers') 6 | const buildRouter = require('../lib/build-router') 7 | 8 | test('parse-controllers', t => { 9 | parseControllers(buildOptions({ 10 | controllersPath: __dirname, 11 | controllersGlob: '*-fixture-valid.js' 12 | })).then(controllers => { 13 | t.ok(controllers) 14 | 15 | const router = buildRouter(controllers) 16 | 17 | t.equal(typeof router, 'function') 18 | t.equal(typeof router.get, 'function') 19 | 20 | const app = express() 21 | 22 | app.use('/api', router) 23 | 24 | request(app) 25 | .get('/api/parse-controller-fixture-valid') 26 | .expect(200) 27 | .end((err, res) => { 28 | t.notOk(err) 29 | t.deepEqual(res.body, { works: true }) 30 | 31 | request(app) 32 | .patch('/api/parse-controller-fixture-valid/posts/1') 33 | .expect(200) 34 | .end((err, res) => { 35 | t.notOk(err) 36 | t.deepEqual(res.body, { works: true }) 37 | 38 | t.end() 39 | }) 40 | }) 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /tests/parse-controller-fixture-invalid1.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'NOVALIDVERB /' (req, res) { 3 | return true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/parse-controller-fixture-invalid2.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'GET' (req, res) { 3 | return true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/parse-controller-fixture-invalid3.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'GET posts' (req, res) { 3 | return true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/parse-controller-fixture-invalid4.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'GET /posts': { 3 | valid: false 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/parse-controller-fixture-valid.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'GET /' (req, res) { 3 | res && res.status(200).json({ works: true }) 4 | return true 5 | }, 6 | 7 | 'POST /post' (req, res) { 8 | res && res.status(200).json({ works: true }) 9 | return true 10 | }, 11 | 12 | 'PATCH /posts/:id': [ 13 | (req, res, next) => { 14 | next && next() 15 | return 'middleware' 16 | }, 17 | 18 | (req, res) => { 19 | res && res.status(200).json({ works: true }) 20 | return true 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /tests/parse-controller-test.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const test = require('tape') 3 | const parseController = require('../lib/parse-controller') 4 | 5 | test('parse-controller', t => { 6 | const filePathValid = path.join(__dirname, 'parse-controller-fixture-valid.js') 7 | const filePathInvalid1 = path.join(__dirname, 'parse-controller-fixture-invalid1.js') 8 | const filePathInvalid2 = path.join(__dirname, 'parse-controller-fixture-invalid2.js') 9 | const filePathInvalid3 = path.join(__dirname, 'parse-controller-fixture-invalid3.js') 10 | const filePathInvalid4 = path.join(__dirname, 'parse-controller-fixture-invalid4.js') 11 | 12 | parseController(filePathValid).then(controller => { 13 | t.ok(controller) 14 | t.equal(controller.filePath, filePathValid) 15 | t.equal(controller.resourceName, 'parse-controller-fixture-valid') 16 | t.ok(Array.isArray(controller.routes)) 17 | t.equal(controller.routes.length, 3) 18 | 19 | t.equal(controller.routes[0].verb, 'GET') 20 | t.equal(controller.routes[0].route, '/') 21 | t.ok(Array.isArray(controller.routes[0].handlers)) 22 | t.equal(controller.routes[0].handlers.length, 1) 23 | t.ok(controller.routes[0].handlers[0]()) 24 | 25 | t.equal(controller.routes[2].verb, 'PATCH') 26 | t.equal(controller.routes[2].route, '/posts/:id') 27 | t.ok(Array.isArray(controller.routes[2].handlers)) 28 | t.equal(controller.routes[2].handlers.length, 2) 29 | t.equal(controller.routes[2].handlers[0](), 'middleware') 30 | t.ok(controller.routes[2].handlers[1]()) 31 | }) 32 | 33 | parseController(filePathInvalid1).catch(err => { 34 | t.ok(err) 35 | t.equal(err.filePath, filePathInvalid1) 36 | t.equal(err.fullRoute, 'NOVALIDVERB /') 37 | t.equal(err.message, `Unknown verb 'NOVALIDVERB'`) 38 | }) 39 | 40 | parseController(filePathInvalid2).catch(err => { 41 | t.ok(err) 42 | t.equal(err.message, `Missing route for verb 'GET'`) 43 | }) 44 | 45 | parseController(filePathInvalid3).catch(err => { 46 | t.ok(err) 47 | t.equal(err.message, `Route 'posts' must start with an /`) 48 | }) 49 | 50 | parseController(filePathInvalid4).catch(err => { 51 | t.ok(err) 52 | t.equal(err.message, 'Handlers must be either a single function or an array of functions') 53 | }) 54 | 55 | t.end() 56 | }) 57 | -------------------------------------------------------------------------------- /tests/parse-controllers-test.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const buildOptions = require('../lib/build-options') 3 | const parseControllers = require('../lib/parse-controllers') 4 | 5 | test('parse-controllers', t => { 6 | parseControllers(buildOptions({ 7 | controllersPath: __dirname, 8 | controllersGlob: '*-fixture-valid.js' 9 | })).then(controllers => { 10 | t.ok(Array.isArray(controllers)) 11 | t.equal(controllers.length, 1) 12 | t.equal(controllers[0].resourceName, 'parse-controller-fixture-valid') 13 | }) 14 | 15 | parseControllers(buildOptions({ 16 | controllersPath: __dirname, 17 | controllersGlob: '*-fixture-invalid*.js' 18 | })).catch(err => { 19 | t.ok(err) 20 | }) 21 | 22 | t.end() 23 | }) 24 | -------------------------------------------------------------------------------- /tests/watch-files-test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const path = require('path') 3 | const test = require('tape') 4 | const express = require('express') 5 | const request = require('supertest') 6 | const buildOptions = require('../lib/build-options') 7 | const watchFiles = require('../lib/watch-files') 8 | 9 | const tempPath = path.join(__dirname, '../temp') 10 | const controller1Path = path.join(tempPath, 'posts.js') 11 | const controller2Path = path.join(tempPath, 'users.js') 12 | const app = express() 13 | const router = express.Router() 14 | let watcher = null 15 | 16 | const controller1 = ` 17 | module.exports = { 18 | 'GET /' (req, res) { 19 | res.json({ works: true }) 20 | } 21 | }` 22 | 23 | const controller2 = ` 24 | module.exports = { 25 | 'GET /' (req, res) { 26 | res.json({ works: 'yes' }) 27 | }, 28 | 29 | 'POST /' (req, res) { 30 | res.json({ works: true }) 31 | } 32 | }` 33 | 34 | app.use('/api', router) 35 | 36 | test.onFinish(() => { 37 | watcher.close() 38 | fs.removeSync(tempPath) 39 | }) 40 | 41 | test('watch-files', t => { 42 | fs.ensureDirSync(tempPath) 43 | t.ok(fs.pathExistsSync(tempPath)) 44 | fs.writeFileSync(controller1Path, controller1, 'utf8') 45 | t.ok(fs.existsSync(controller1Path)) 46 | 47 | const options = buildOptions({ 48 | controllersPath: tempPath, 49 | expressAppInstance: app, 50 | isDev: true, 51 | apiEndpoint: '/api' 52 | }) 53 | 54 | watcher = watchFiles(options) 55 | t.ok(watcher) 56 | 57 | request(app) 58 | .get('/api/posts') 59 | .expect(200) 60 | .end((err, res) => { 61 | t.ok(err, 'initial added controllers are not mounted') 62 | 63 | fs.writeFileSync(controller2Path, controller1, 'utf8') 64 | 65 | setTimeout(() => { 66 | t.ok(fs.existsSync(controller2Path)) 67 | 68 | request(app) 69 | .get('/api/users') 70 | .expect(200) 71 | .end((err, res) => { 72 | t.notOk(err) 73 | 74 | request(app) 75 | .post('/api/users') 76 | .expect(200) 77 | .end((err, res) => { 78 | t.ok(err) 79 | 80 | fs.writeFileSync(controller2Path, controller2, 'utf8') 81 | 82 | setTimeout(() => { 83 | request(app) 84 | .post('/api/users') 85 | .expect(200) 86 | .end((err, res) => { 87 | t.notOk(err) 88 | t.deepEqual(res.body, { works: true }) 89 | t.end() 90 | }) 91 | }, 500) 92 | }) 93 | }) 94 | }, 500) 95 | }) 96 | }) 97 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | abbrev@1: 6 | version "1.1.0" 7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" 8 | 9 | accepts@~1.3.3: 10 | version "1.3.3" 11 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" 12 | dependencies: 13 | mime-types "~2.1.11" 14 | negotiator "0.6.1" 15 | 16 | ajv@^4.9.1: 17 | version "4.11.8" 18 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" 19 | dependencies: 20 | co "^4.6.0" 21 | json-stable-stringify "^1.0.1" 22 | 23 | ansi-escape@^1.0.1: 24 | version "1.1.0" 25 | resolved "https://registry.yarnpkg.com/ansi-escape/-/ansi-escape-1.1.0.tgz#8ad859e84a69e0ff91779694793a92e4e8c05e99" 26 | 27 | ansi-regex@^2.0.0: 28 | version "2.1.1" 29 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 30 | 31 | anymatch@^1.3.0: 32 | version "1.3.2" 33 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" 34 | dependencies: 35 | micromatch "^2.1.5" 36 | normalize-path "^2.0.0" 37 | 38 | aproba@^1.0.3: 39 | version "1.1.2" 40 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" 41 | 42 | are-we-there-yet@~1.1.2: 43 | version "1.1.4" 44 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" 45 | dependencies: 46 | delegates "^1.0.0" 47 | readable-stream "^2.0.6" 48 | 49 | arr-diff@^2.0.0: 50 | version "2.0.0" 51 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" 52 | dependencies: 53 | arr-flatten "^1.0.1" 54 | 55 | arr-flatten@^1.0.1: 56 | version "1.1.0" 57 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" 58 | 59 | array-flatten@1.1.1: 60 | version "1.1.1" 61 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 62 | 63 | array-unique@^0.2.1: 64 | version "0.2.1" 65 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" 66 | 67 | asn1@~0.2.3: 68 | version "0.2.3" 69 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" 70 | 71 | assert-plus@1.0.0, assert-plus@^1.0.0: 72 | version "1.0.0" 73 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 74 | 75 | assert-plus@^0.2.0: 76 | version "0.2.0" 77 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" 78 | 79 | async-each@^1.0.0: 80 | version "1.0.1" 81 | resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" 82 | 83 | asynckit@^0.4.0: 84 | version "0.4.0" 85 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 86 | 87 | aws-sign2@~0.6.0: 88 | version "0.6.0" 89 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" 90 | 91 | aws4@^1.2.1: 92 | version "1.6.0" 93 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" 94 | 95 | balanced-match@^1.0.0: 96 | version "1.0.0" 97 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 98 | 99 | bcrypt-pbkdf@^1.0.0: 100 | version "1.0.1" 101 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" 102 | dependencies: 103 | tweetnacl "^0.14.3" 104 | 105 | binary-extensions@^1.0.0: 106 | version "1.10.0" 107 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" 108 | 109 | block-stream@*: 110 | version "0.0.9" 111 | resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" 112 | dependencies: 113 | inherits "~2.0.0" 114 | 115 | boom@2.x.x: 116 | version "2.10.1" 117 | resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" 118 | dependencies: 119 | hoek "2.x.x" 120 | 121 | brace-expansion@^1.1.7: 122 | version "1.1.8" 123 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" 124 | dependencies: 125 | balanced-match "^1.0.0" 126 | concat-map "0.0.1" 127 | 128 | braces@^1.8.2: 129 | version "1.8.5" 130 | resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" 131 | dependencies: 132 | expand-range "^1.8.1" 133 | preserve "^0.2.0" 134 | repeat-element "^1.1.2" 135 | 136 | caller-callsite@^2.0.0: 137 | version "2.0.0" 138 | resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" 139 | dependencies: 140 | callsites "^2.0.0" 141 | 142 | caller-path@^2.0.0: 143 | version "2.0.0" 144 | resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" 145 | dependencies: 146 | caller-callsite "^2.0.0" 147 | 148 | callsites@^2.0.0: 149 | version "2.0.0" 150 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" 151 | 152 | caseless@~0.12.0: 153 | version "0.12.0" 154 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 155 | 156 | chokidar@^1.7.0: 157 | version "1.7.0" 158 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" 159 | dependencies: 160 | anymatch "^1.3.0" 161 | async-each "^1.0.0" 162 | glob-parent "^2.0.0" 163 | inherits "^2.0.1" 164 | is-binary-path "^1.0.0" 165 | is-glob "^2.0.0" 166 | path-is-absolute "^1.0.0" 167 | readdirp "^2.0.0" 168 | optionalDependencies: 169 | fsevents "^1.0.0" 170 | 171 | co@^4.6.0: 172 | version "4.6.0" 173 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 174 | 175 | code-point-at@^1.0.0: 176 | version "1.1.0" 177 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 178 | 179 | colors@^1.1.2: 180 | version "1.1.2" 181 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" 182 | 183 | combined-stream@^1.0.5, combined-stream@~1.0.5: 184 | version "1.0.5" 185 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" 186 | dependencies: 187 | delayed-stream "~1.0.0" 188 | 189 | commander@^2.9.0: 190 | version "2.11.0" 191 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" 192 | 193 | component-emitter@^1.2.0: 194 | version "1.2.1" 195 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" 196 | 197 | concat-map@0.0.1: 198 | version "0.0.1" 199 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 200 | 201 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 202 | version "1.1.0" 203 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 204 | 205 | content-disposition@0.5.2: 206 | version "0.5.2" 207 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 208 | 209 | content-type@~1.0.2: 210 | version "1.0.2" 211 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" 212 | 213 | cookie-signature@1.0.6: 214 | version "1.0.6" 215 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 216 | 217 | cookie@0.3.1: 218 | version "0.3.1" 219 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 220 | 221 | cookiejar@^2.0.6: 222 | version "2.1.1" 223 | resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.1.tgz#41ad57b1b555951ec171412a81942b1e8200d34a" 224 | 225 | core-util-is@1.0.2, core-util-is@~1.0.0: 226 | version "1.0.2" 227 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 228 | 229 | cryptiles@2.x.x: 230 | version "2.0.5" 231 | resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" 232 | dependencies: 233 | boom "2.x.x" 234 | 235 | dashdash@^1.12.0: 236 | version "1.14.1" 237 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 238 | dependencies: 239 | assert-plus "^1.0.0" 240 | 241 | debug@2.6.8, debug@^2.2.0: 242 | version "2.6.8" 243 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" 244 | dependencies: 245 | ms "2.0.0" 246 | 247 | deep-equal@~1.0.1: 248 | version "1.0.1" 249 | resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" 250 | 251 | deep-extend@~0.4.0: 252 | version "0.4.2" 253 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" 254 | 255 | define-properties@^1.1.2: 256 | version "1.1.2" 257 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" 258 | dependencies: 259 | foreach "^2.0.5" 260 | object-keys "^1.0.8" 261 | 262 | defined@~1.0.0: 263 | version "1.0.0" 264 | resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" 265 | 266 | delayed-stream@~1.0.0: 267 | version "1.0.0" 268 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 269 | 270 | delegates@^1.0.0: 271 | version "1.0.0" 272 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 273 | 274 | depd@1.1.1, depd@~1.1.1: 275 | version "1.1.1" 276 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" 277 | 278 | destroy@~1.0.4: 279 | version "1.0.4" 280 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 281 | 282 | ecc-jsbn@~0.1.1: 283 | version "0.1.1" 284 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" 285 | dependencies: 286 | jsbn "~0.1.0" 287 | 288 | ee-first@1.1.1: 289 | version "1.1.1" 290 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 291 | 292 | encodeurl@~1.0.1: 293 | version "1.0.1" 294 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" 295 | 296 | es-abstract@^1.5.0: 297 | version "1.8.0" 298 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.8.0.tgz#3b00385e85729932beffa9163bbea1234e932914" 299 | dependencies: 300 | es-to-primitive "^1.1.1" 301 | function-bind "^1.1.0" 302 | has "^1.0.1" 303 | is-callable "^1.1.3" 304 | is-regex "^1.0.4" 305 | 306 | es-to-primitive@^1.1.1: 307 | version "1.1.1" 308 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" 309 | dependencies: 310 | is-callable "^1.1.1" 311 | is-date-object "^1.0.1" 312 | is-symbol "^1.0.1" 313 | 314 | escape-html@~1.0.3: 315 | version "1.0.3" 316 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 317 | 318 | escape-string-regexp@^1.0.5: 319 | version "1.0.5" 320 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 321 | 322 | etag@~1.8.0: 323 | version "1.8.0" 324 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" 325 | 326 | expand-brackets@^0.1.4: 327 | version "0.1.5" 328 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" 329 | dependencies: 330 | is-posix-bracket "^0.1.0" 331 | 332 | expand-range@^1.8.1: 333 | version "1.8.2" 334 | resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" 335 | dependencies: 336 | fill-range "^2.1.0" 337 | 338 | express@^4.15.4: 339 | version "4.15.4" 340 | resolved "https://registry.yarnpkg.com/express/-/express-4.15.4.tgz#032e2253489cf8fce02666beca3d11ed7a2daed1" 341 | dependencies: 342 | accepts "~1.3.3" 343 | array-flatten "1.1.1" 344 | content-disposition "0.5.2" 345 | content-type "~1.0.2" 346 | cookie "0.3.1" 347 | cookie-signature "1.0.6" 348 | debug "2.6.8" 349 | depd "~1.1.1" 350 | encodeurl "~1.0.1" 351 | escape-html "~1.0.3" 352 | etag "~1.8.0" 353 | finalhandler "~1.0.4" 354 | fresh "0.5.0" 355 | merge-descriptors "1.0.1" 356 | methods "~1.1.2" 357 | on-finished "~2.3.0" 358 | parseurl "~1.3.1" 359 | path-to-regexp "0.1.7" 360 | proxy-addr "~1.1.5" 361 | qs "6.5.0" 362 | range-parser "~1.2.0" 363 | send "0.15.4" 364 | serve-static "1.12.4" 365 | setprototypeof "1.0.3" 366 | statuses "~1.3.1" 367 | type-is "~1.6.15" 368 | utils-merge "1.0.0" 369 | vary "~1.1.1" 370 | 371 | extend@^3.0.0, extend@~3.0.0: 372 | version "3.0.1" 373 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" 374 | 375 | extglob@^0.3.1: 376 | version "0.3.2" 377 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" 378 | dependencies: 379 | is-extglob "^1.0.0" 380 | 381 | extsprintf@1.3.0, extsprintf@^1.2.0: 382 | version "1.3.0" 383 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 384 | 385 | figures@^1.4.0: 386 | version "1.7.0" 387 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" 388 | dependencies: 389 | escape-string-regexp "^1.0.5" 390 | object-assign "^4.1.0" 391 | 392 | filename-regex@^2.0.0: 393 | version "2.0.1" 394 | resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" 395 | 396 | fill-range@^2.1.0: 397 | version "2.2.3" 398 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" 399 | dependencies: 400 | is-number "^2.1.0" 401 | isobject "^2.0.0" 402 | randomatic "^1.1.3" 403 | repeat-element "^1.1.2" 404 | repeat-string "^1.5.2" 405 | 406 | finalhandler@~1.0.4: 407 | version "1.0.4" 408 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.4.tgz#18574f2e7c4b98b8ae3b230c21f201f31bdb3fb7" 409 | dependencies: 410 | debug "2.6.8" 411 | encodeurl "~1.0.1" 412 | escape-html "~1.0.3" 413 | on-finished "~2.3.0" 414 | parseurl "~1.3.1" 415 | statuses "~1.3.1" 416 | unpipe "~1.0.0" 417 | 418 | for-each@~0.3.2: 419 | version "0.3.2" 420 | resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" 421 | dependencies: 422 | is-function "~1.0.0" 423 | 424 | for-in@^1.0.1: 425 | version "1.0.2" 426 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 427 | 428 | for-own@^0.1.4: 429 | version "0.1.5" 430 | resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" 431 | dependencies: 432 | for-in "^1.0.1" 433 | 434 | foreach@^2.0.5: 435 | version "2.0.5" 436 | resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" 437 | 438 | forever-agent@~0.6.1: 439 | version "0.6.1" 440 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 441 | 442 | form-data@^2.1.1: 443 | version "2.2.0" 444 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.2.0.tgz#9a5e3b9295f980b2623cf64fa238b14cebca707b" 445 | dependencies: 446 | asynckit "^0.4.0" 447 | combined-stream "^1.0.5" 448 | mime-types "^2.1.12" 449 | 450 | form-data@~2.1.1: 451 | version "2.1.4" 452 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" 453 | dependencies: 454 | asynckit "^0.4.0" 455 | combined-stream "^1.0.5" 456 | mime-types "^2.1.12" 457 | 458 | formidable@^1.1.1: 459 | version "1.1.1" 460 | resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.1.1.tgz#96b8886f7c3c3508b932d6bd70c4d3a88f35f1a9" 461 | 462 | forwarded@~0.1.0: 463 | version "0.1.0" 464 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" 465 | 466 | fresh@0.5.0: 467 | version "0.5.0" 468 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" 469 | 470 | fs-extra@^4.0.1: 471 | version "4.0.1" 472 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.1.tgz#7fc0c6c8957f983f57f306a24e5b9ddd8d0dd880" 473 | dependencies: 474 | graceful-fs "^4.1.2" 475 | jsonfile "^3.0.0" 476 | universalify "^0.1.0" 477 | 478 | fs.realpath@^1.0.0: 479 | version "1.0.0" 480 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 481 | 482 | fsevents@^1.0.0: 483 | version "1.1.2" 484 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" 485 | dependencies: 486 | nan "^2.3.0" 487 | node-pre-gyp "^0.6.36" 488 | 489 | fstream-ignore@^1.0.5: 490 | version "1.0.5" 491 | resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" 492 | dependencies: 493 | fstream "^1.0.0" 494 | inherits "2" 495 | minimatch "^3.0.0" 496 | 497 | fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: 498 | version "1.0.11" 499 | resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" 500 | dependencies: 501 | graceful-fs "^4.1.2" 502 | inherits "~2.0.0" 503 | mkdirp ">=0.5 0" 504 | rimraf "2" 505 | 506 | function-bind@^1.0.2, function-bind@^1.1.0, function-bind@~1.1.0: 507 | version "1.1.0" 508 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" 509 | 510 | gauge@~2.7.3: 511 | version "2.7.4" 512 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 513 | dependencies: 514 | aproba "^1.0.3" 515 | console-control-strings "^1.0.0" 516 | has-unicode "^2.0.0" 517 | object-assign "^4.1.0" 518 | signal-exit "^3.0.0" 519 | string-width "^1.0.1" 520 | strip-ansi "^3.0.1" 521 | wide-align "^1.1.0" 522 | 523 | getpass@^0.1.1: 524 | version "0.1.7" 525 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 526 | dependencies: 527 | assert-plus "^1.0.0" 528 | 529 | glob-base@^0.3.0: 530 | version "0.3.0" 531 | resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" 532 | dependencies: 533 | glob-parent "^2.0.0" 534 | is-glob "^2.0.0" 535 | 536 | glob-parent@^2.0.0: 537 | version "2.0.0" 538 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" 539 | dependencies: 540 | is-glob "^2.0.0" 541 | 542 | glob@^7.0.5, glob@^7.1.2, glob@~7.1.2: 543 | version "7.1.2" 544 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 545 | dependencies: 546 | fs.realpath "^1.0.0" 547 | inflight "^1.0.4" 548 | inherits "2" 549 | minimatch "^3.0.4" 550 | once "^1.3.0" 551 | path-is-absolute "^1.0.0" 552 | 553 | graceful-fs@^4.1.2, graceful-fs@^4.1.6: 554 | version "4.1.11" 555 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 556 | 557 | har-schema@^1.0.5: 558 | version "1.0.5" 559 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" 560 | 561 | har-validator@~4.2.1: 562 | version "4.2.1" 563 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" 564 | dependencies: 565 | ajv "^4.9.1" 566 | har-schema "^1.0.5" 567 | 568 | has-unicode@^2.0.0: 569 | version "2.0.1" 570 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 571 | 572 | has@^1.0.1, has@~1.0.1: 573 | version "1.0.1" 574 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" 575 | dependencies: 576 | function-bind "^1.0.2" 577 | 578 | hawk@~3.1.3: 579 | version "3.1.3" 580 | resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" 581 | dependencies: 582 | boom "2.x.x" 583 | cryptiles "2.x.x" 584 | hoek "2.x.x" 585 | sntp "1.x.x" 586 | 587 | hoek@2.x.x: 588 | version "2.16.3" 589 | resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" 590 | 591 | http-errors@~1.6.2: 592 | version "1.6.2" 593 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" 594 | dependencies: 595 | depd "1.1.1" 596 | inherits "2.0.3" 597 | setprototypeof "1.0.3" 598 | statuses ">= 1.3.1 < 2" 599 | 600 | http-signature@~1.1.0: 601 | version "1.1.1" 602 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" 603 | dependencies: 604 | assert-plus "^0.2.0" 605 | jsprim "^1.2.2" 606 | sshpk "^1.7.0" 607 | 608 | import-fresh@^2.0.0: 609 | version "2.0.0" 610 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" 611 | dependencies: 612 | caller-path "^2.0.0" 613 | resolve-from "^3.0.0" 614 | 615 | inflight@^1.0.4: 616 | version "1.0.6" 617 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 618 | dependencies: 619 | once "^1.3.0" 620 | wrappy "1" 621 | 622 | inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.3: 623 | version "2.0.3" 624 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 625 | 626 | ini@~1.3.0: 627 | version "1.3.4" 628 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" 629 | 630 | ipaddr.js@1.4.0: 631 | version "1.4.0" 632 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0" 633 | 634 | is-binary-path@^1.0.0: 635 | version "1.0.1" 636 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" 637 | dependencies: 638 | binary-extensions "^1.0.0" 639 | 640 | is-buffer@^1.1.5: 641 | version "1.1.5" 642 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" 643 | 644 | is-callable@^1.1.1, is-callable@^1.1.3: 645 | version "1.1.3" 646 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" 647 | 648 | is-date-object@^1.0.1: 649 | version "1.0.1" 650 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" 651 | 652 | is-dotfile@^1.0.0: 653 | version "1.0.3" 654 | resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" 655 | 656 | is-equal-shallow@^0.1.3: 657 | version "0.1.3" 658 | resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" 659 | dependencies: 660 | is-primitive "^2.0.0" 661 | 662 | is-extendable@^0.1.1: 663 | version "0.1.1" 664 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 665 | 666 | is-extglob@^1.0.0: 667 | version "1.0.0" 668 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" 669 | 670 | is-finite@^1.0.1: 671 | version "1.0.2" 672 | resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" 673 | dependencies: 674 | number-is-nan "^1.0.0" 675 | 676 | is-fullwidth-code-point@^1.0.0: 677 | version "1.0.0" 678 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 679 | dependencies: 680 | number-is-nan "^1.0.0" 681 | 682 | is-function@~1.0.0: 683 | version "1.0.1" 684 | resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" 685 | 686 | is-glob@^2.0.0, is-glob@^2.0.1: 687 | version "2.0.1" 688 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" 689 | dependencies: 690 | is-extglob "^1.0.0" 691 | 692 | is-number@^2.1.0: 693 | version "2.1.0" 694 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" 695 | dependencies: 696 | kind-of "^3.0.2" 697 | 698 | is-number@^3.0.0: 699 | version "3.0.0" 700 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" 701 | dependencies: 702 | kind-of "^3.0.2" 703 | 704 | is-posix-bracket@^0.1.0: 705 | version "0.1.1" 706 | resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" 707 | 708 | is-primitive@^2.0.0: 709 | version "2.0.0" 710 | resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" 711 | 712 | is-regex@^1.0.4: 713 | version "1.0.4" 714 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" 715 | dependencies: 716 | has "^1.0.1" 717 | 718 | is-symbol@^1.0.1: 719 | version "1.0.1" 720 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" 721 | 722 | is-typedarray@~1.0.0: 723 | version "1.0.0" 724 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 725 | 726 | isarray@1.0.0, isarray@~1.0.0: 727 | version "1.0.0" 728 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 729 | 730 | isobject@^2.0.0: 731 | version "2.1.0" 732 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 733 | dependencies: 734 | isarray "1.0.0" 735 | 736 | isstream@~0.1.2: 737 | version "0.1.2" 738 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 739 | 740 | jsbn@~0.1.0: 741 | version "0.1.1" 742 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 743 | 744 | json-schema@0.2.3: 745 | version "0.2.3" 746 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 747 | 748 | json-stable-stringify@^1.0.1: 749 | version "1.0.1" 750 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 751 | dependencies: 752 | jsonify "~0.0.0" 753 | 754 | json-stringify-safe@~5.0.1: 755 | version "5.0.1" 756 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 757 | 758 | jsonfile@^3.0.0: 759 | version "3.0.1" 760 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" 761 | optionalDependencies: 762 | graceful-fs "^4.1.6" 763 | 764 | jsonify@~0.0.0: 765 | version "0.0.0" 766 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 767 | 768 | jsprim@^1.2.2: 769 | version "1.4.1" 770 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" 771 | dependencies: 772 | assert-plus "1.0.0" 773 | extsprintf "1.3.0" 774 | json-schema "0.2.3" 775 | verror "1.10.0" 776 | 777 | kind-of@^3.0.2: 778 | version "3.2.2" 779 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 780 | dependencies: 781 | is-buffer "^1.1.5" 782 | 783 | kind-of@^4.0.0: 784 | version "4.0.0" 785 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" 786 | dependencies: 787 | is-buffer "^1.1.5" 788 | 789 | media-typer@0.3.0: 790 | version "0.3.0" 791 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 792 | 793 | merge-descriptors@1.0.1: 794 | version "1.0.1" 795 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 796 | 797 | methods@^1.1.1, methods@~1.1.2: 798 | version "1.1.2" 799 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 800 | 801 | micromatch@^2.1.5: 802 | version "2.3.11" 803 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" 804 | dependencies: 805 | arr-diff "^2.0.0" 806 | array-unique "^0.2.1" 807 | braces "^1.8.2" 808 | expand-brackets "^0.1.4" 809 | extglob "^0.3.1" 810 | filename-regex "^2.0.0" 811 | is-extglob "^1.0.0" 812 | is-glob "^2.0.1" 813 | kind-of "^3.0.2" 814 | normalize-path "^2.0.1" 815 | object.omit "^2.0.0" 816 | parse-glob "^3.0.4" 817 | regex-cache "^0.4.2" 818 | 819 | mime-db@~1.29.0: 820 | version "1.29.0" 821 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.29.0.tgz#48d26d235589651704ac5916ca06001914266878" 822 | 823 | mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: 824 | version "2.1.16" 825 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.16.tgz#2b858a52e5ecd516db897ac2be87487830698e23" 826 | dependencies: 827 | mime-db "~1.29.0" 828 | 829 | mime@1.3.4: 830 | version "1.3.4" 831 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" 832 | 833 | mime@^1.3.4: 834 | version "1.3.6" 835 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" 836 | 837 | minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: 838 | version "3.0.4" 839 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 840 | dependencies: 841 | brace-expansion "^1.1.7" 842 | 843 | minimist@0.0.8: 844 | version "0.0.8" 845 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 846 | 847 | minimist@^1.2.0, minimist@~1.2.0: 848 | version "1.2.0" 849 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 850 | 851 | "mkdirp@>=0.5 0", mkdirp@^0.5.1: 852 | version "0.5.1" 853 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 854 | dependencies: 855 | minimist "0.0.8" 856 | 857 | ms@2.0.0: 858 | version "2.0.0" 859 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 860 | 861 | nan@^2.3.0: 862 | version "2.6.2" 863 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" 864 | 865 | negotiator@0.6.1: 866 | version "0.6.1" 867 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 868 | 869 | node-pre-gyp@^0.6.36: 870 | version "0.6.36" 871 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786" 872 | dependencies: 873 | mkdirp "^0.5.1" 874 | nopt "^4.0.1" 875 | npmlog "^4.0.2" 876 | rc "^1.1.7" 877 | request "^2.81.0" 878 | rimraf "^2.6.1" 879 | semver "^5.3.0" 880 | tar "^2.2.1" 881 | tar-pack "^3.4.0" 882 | 883 | nopt@^4.0.1: 884 | version "4.0.1" 885 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" 886 | dependencies: 887 | abbrev "1" 888 | osenv "^0.1.4" 889 | 890 | normalize-path@^2.0.0, normalize-path@^2.0.1: 891 | version "2.1.1" 892 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" 893 | dependencies: 894 | remove-trailing-separator "^1.0.1" 895 | 896 | npmlog@^4.0.2: 897 | version "4.1.2" 898 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" 899 | dependencies: 900 | are-we-there-yet "~1.1.2" 901 | console-control-strings "~1.1.0" 902 | gauge "~2.7.3" 903 | set-blocking "~2.0.0" 904 | 905 | number-is-nan@^1.0.0: 906 | version "1.0.1" 907 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 908 | 909 | oauth-sign@~0.8.1: 910 | version "0.8.2" 911 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" 912 | 913 | object-assign@^4.1.0: 914 | version "4.1.1" 915 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 916 | 917 | object-inspect@~1.3.0: 918 | version "1.3.0" 919 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.3.0.tgz#5b1eb8e6742e2ee83342a637034d844928ba2f6d" 920 | 921 | object-keys@^1.0.8: 922 | version "1.0.11" 923 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" 924 | 925 | object.omit@^2.0.0: 926 | version "2.0.1" 927 | resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" 928 | dependencies: 929 | for-own "^0.1.4" 930 | is-extendable "^0.1.1" 931 | 932 | on-finished@~2.3.0: 933 | version "2.3.0" 934 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 935 | dependencies: 936 | ee-first "1.1.1" 937 | 938 | once@^1.3.0, once@^1.3.3: 939 | version "1.4.0" 940 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 941 | dependencies: 942 | wrappy "1" 943 | 944 | os-homedir@^1.0.0: 945 | version "1.0.2" 946 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 947 | 948 | os-tmpdir@^1.0.0: 949 | version "1.0.2" 950 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 951 | 952 | osenv@^0.1.4: 953 | version "0.1.4" 954 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" 955 | dependencies: 956 | os-homedir "^1.0.0" 957 | os-tmpdir "^1.0.0" 958 | 959 | parse-glob@^3.0.4: 960 | version "3.0.4" 961 | resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" 962 | dependencies: 963 | glob-base "^0.3.0" 964 | is-dotfile "^1.0.0" 965 | is-extglob "^1.0.0" 966 | is-glob "^2.0.0" 967 | 968 | parse-ms@^1.0.0: 969 | version "1.0.1" 970 | resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" 971 | 972 | parseurl@~1.3.1: 973 | version "1.3.1" 974 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" 975 | 976 | path-is-absolute@^1.0.0: 977 | version "1.0.1" 978 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 979 | 980 | path-parse@^1.0.5: 981 | version "1.0.5" 982 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" 983 | 984 | path-to-regexp@0.1.7: 985 | version "0.1.7" 986 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 987 | 988 | performance-now@^0.2.0: 989 | version "0.2.0" 990 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" 991 | 992 | plur@^1.0.0: 993 | version "1.0.0" 994 | resolved "https://registry.yarnpkg.com/plur/-/plur-1.0.0.tgz#db85c6814f5e5e5a3b49efc28d604fec62975156" 995 | 996 | preserve@^0.2.0: 997 | version "0.2.0" 998 | resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" 999 | 1000 | pretty-ms@^2.1.0: 1001 | version "2.1.0" 1002 | resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-2.1.0.tgz#4257c256df3fb0b451d6affaab021884126981dc" 1003 | dependencies: 1004 | is-finite "^1.0.1" 1005 | parse-ms "^1.0.0" 1006 | plur "^1.0.0" 1007 | 1008 | process-nextick-args@~1.0.6: 1009 | version "1.0.7" 1010 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 1011 | 1012 | proxy-addr@~1.1.5: 1013 | version "1.1.5" 1014 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918" 1015 | dependencies: 1016 | forwarded "~0.1.0" 1017 | ipaddr.js "1.4.0" 1018 | 1019 | punycode@^1.4.1: 1020 | version "1.4.1" 1021 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 1022 | 1023 | qs@6.5.0, qs@^6.1.0: 1024 | version "6.5.0" 1025 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49" 1026 | 1027 | qs@~6.4.0: 1028 | version "6.4.0" 1029 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" 1030 | 1031 | randomatic@^1.1.3: 1032 | version "1.1.7" 1033 | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" 1034 | dependencies: 1035 | is-number "^3.0.0" 1036 | kind-of "^4.0.0" 1037 | 1038 | range-parser@~1.2.0: 1039 | version "1.2.0" 1040 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 1041 | 1042 | rc@^1.1.7: 1043 | version "1.2.1" 1044 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" 1045 | dependencies: 1046 | deep-extend "~0.4.0" 1047 | ini "~1.3.0" 1048 | minimist "^1.2.0" 1049 | strip-json-comments "~2.0.1" 1050 | 1051 | re-emitter@^1.0.0: 1052 | version "1.1.3" 1053 | resolved "https://registry.yarnpkg.com/re-emitter/-/re-emitter-1.1.3.tgz#fa9e319ffdeeeb35b27296ef0f3d374dac2f52a7" 1054 | 1055 | readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4: 1056 | version "2.3.3" 1057 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" 1058 | dependencies: 1059 | core-util-is "~1.0.0" 1060 | inherits "~2.0.3" 1061 | isarray "~1.0.0" 1062 | process-nextick-args "~1.0.6" 1063 | safe-buffer "~5.1.1" 1064 | string_decoder "~1.0.3" 1065 | util-deprecate "~1.0.1" 1066 | 1067 | readdirp@^2.0.0: 1068 | version "2.1.0" 1069 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" 1070 | dependencies: 1071 | graceful-fs "^4.1.2" 1072 | minimatch "^3.0.2" 1073 | readable-stream "^2.0.2" 1074 | set-immediate-shim "^1.0.1" 1075 | 1076 | regex-cache@^0.4.2: 1077 | version "0.4.3" 1078 | resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" 1079 | dependencies: 1080 | is-equal-shallow "^0.1.3" 1081 | is-primitive "^2.0.0" 1082 | 1083 | remove-trailing-separator@^1.0.1: 1084 | version "1.1.0" 1085 | resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" 1086 | 1087 | repeat-element@^1.1.2: 1088 | version "1.1.2" 1089 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" 1090 | 1091 | repeat-string@^1.5.2: 1092 | version "1.6.1" 1093 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 1094 | 1095 | request@^2.81.0: 1096 | version "2.81.0" 1097 | resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" 1098 | dependencies: 1099 | aws-sign2 "~0.6.0" 1100 | aws4 "^1.2.1" 1101 | caseless "~0.12.0" 1102 | combined-stream "~1.0.5" 1103 | extend "~3.0.0" 1104 | forever-agent "~0.6.1" 1105 | form-data "~2.1.1" 1106 | har-validator "~4.2.1" 1107 | hawk "~3.1.3" 1108 | http-signature "~1.1.0" 1109 | is-typedarray "~1.0.0" 1110 | isstream "~0.1.2" 1111 | json-stringify-safe "~5.0.1" 1112 | mime-types "~2.1.7" 1113 | oauth-sign "~0.8.1" 1114 | performance-now "^0.2.0" 1115 | qs "~6.4.0" 1116 | safe-buffer "^5.0.1" 1117 | stringstream "~0.0.4" 1118 | tough-cookie "~2.3.0" 1119 | tunnel-agent "^0.6.0" 1120 | uuid "^3.0.0" 1121 | 1122 | resolve-from@^3.0.0: 1123 | version "3.0.0" 1124 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" 1125 | 1126 | resolve@~1.4.0: 1127 | version "1.4.0" 1128 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" 1129 | dependencies: 1130 | path-parse "^1.0.5" 1131 | 1132 | resumer@~0.0.0: 1133 | version "0.0.0" 1134 | resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" 1135 | dependencies: 1136 | through "~2.3.4" 1137 | 1138 | rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: 1139 | version "2.6.1" 1140 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" 1141 | dependencies: 1142 | glob "^7.0.5" 1143 | 1144 | safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1145 | version "5.1.1" 1146 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" 1147 | 1148 | semver@^5.3.0: 1149 | version "5.4.1" 1150 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" 1151 | 1152 | send@0.15.4: 1153 | version "0.15.4" 1154 | resolved "https://registry.yarnpkg.com/send/-/send-0.15.4.tgz#985faa3e284b0273c793364a35c6737bd93905b9" 1155 | dependencies: 1156 | debug "2.6.8" 1157 | depd "~1.1.1" 1158 | destroy "~1.0.4" 1159 | encodeurl "~1.0.1" 1160 | escape-html "~1.0.3" 1161 | etag "~1.8.0" 1162 | fresh "0.5.0" 1163 | http-errors "~1.6.2" 1164 | mime "1.3.4" 1165 | ms "2.0.0" 1166 | on-finished "~2.3.0" 1167 | range-parser "~1.2.0" 1168 | statuses "~1.3.1" 1169 | 1170 | serve-static@1.12.4: 1171 | version "1.12.4" 1172 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.4.tgz#9b6aa98eeb7253c4eedc4c1f6fdbca609901a961" 1173 | dependencies: 1174 | encodeurl "~1.0.1" 1175 | escape-html "~1.0.3" 1176 | parseurl "~1.3.1" 1177 | send "0.15.4" 1178 | 1179 | set-blocking@~2.0.0: 1180 | version "2.0.0" 1181 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1182 | 1183 | set-immediate-shim@^1.0.1: 1184 | version "1.0.1" 1185 | resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" 1186 | 1187 | setprototypeof@1.0.3: 1188 | version "1.0.3" 1189 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 1190 | 1191 | signal-exit@^3.0.0: 1192 | version "3.0.2" 1193 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 1194 | 1195 | sntp@1.x.x: 1196 | version "1.0.9" 1197 | resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" 1198 | dependencies: 1199 | hoek "2.x.x" 1200 | 1201 | split@^1.0.0: 1202 | version "1.0.1" 1203 | resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" 1204 | dependencies: 1205 | through "2" 1206 | 1207 | sshpk@^1.7.0: 1208 | version "1.13.1" 1209 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" 1210 | dependencies: 1211 | asn1 "~0.2.3" 1212 | assert-plus "^1.0.0" 1213 | dashdash "^1.12.0" 1214 | getpass "^0.1.1" 1215 | optionalDependencies: 1216 | bcrypt-pbkdf "^1.0.0" 1217 | ecc-jsbn "~0.1.1" 1218 | jsbn "~0.1.0" 1219 | tweetnacl "~0.14.0" 1220 | 1221 | "statuses@>= 1.3.1 < 2", statuses@~1.3.1: 1222 | version "1.3.1" 1223 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 1224 | 1225 | string-width@^1.0.1, string-width@^1.0.2: 1226 | version "1.0.2" 1227 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1228 | dependencies: 1229 | code-point-at "^1.0.0" 1230 | is-fullwidth-code-point "^1.0.0" 1231 | strip-ansi "^3.0.0" 1232 | 1233 | string.prototype.trim@~1.1.2: 1234 | version "1.1.2" 1235 | resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" 1236 | dependencies: 1237 | define-properties "^1.1.2" 1238 | es-abstract "^1.5.0" 1239 | function-bind "^1.0.2" 1240 | 1241 | string_decoder@~1.0.3: 1242 | version "1.0.3" 1243 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" 1244 | dependencies: 1245 | safe-buffer "~5.1.0" 1246 | 1247 | stringstream@~0.0.4: 1248 | version "0.0.5" 1249 | resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" 1250 | 1251 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 1252 | version "3.0.1" 1253 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1254 | dependencies: 1255 | ansi-regex "^2.0.0" 1256 | 1257 | strip-json-comments@~2.0.1: 1258 | version "2.0.1" 1259 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1260 | 1261 | superagent@^3.0.0: 1262 | version "3.5.2" 1263 | resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.5.2.tgz#3361a3971567504c351063abeaae0faa23dbf3f8" 1264 | dependencies: 1265 | component-emitter "^1.2.0" 1266 | cookiejar "^2.0.6" 1267 | debug "^2.2.0" 1268 | extend "^3.0.0" 1269 | form-data "^2.1.1" 1270 | formidable "^1.1.1" 1271 | methods "^1.1.1" 1272 | mime "^1.3.4" 1273 | qs "^6.1.0" 1274 | readable-stream "^2.0.5" 1275 | 1276 | supertest@^3.0.0: 1277 | version "3.0.0" 1278 | resolved "https://registry.yarnpkg.com/supertest/-/supertest-3.0.0.tgz#8d4bb68fd1830ee07033b1c5a5a9a4021c965296" 1279 | dependencies: 1280 | methods "~1.1.2" 1281 | superagent "^3.0.0" 1282 | 1283 | tap-out@^1.4.1: 1284 | version "1.4.2" 1285 | resolved "https://registry.yarnpkg.com/tap-out/-/tap-out-1.4.2.tgz#c907ec1bf9405111d088263e92f5608b88cbb37a" 1286 | dependencies: 1287 | re-emitter "^1.0.0" 1288 | readable-stream "^2.0.0" 1289 | split "^1.0.0" 1290 | trim "0.0.1" 1291 | 1292 | tap-summary@^3.0.2: 1293 | version "3.0.2" 1294 | resolved "https://registry.yarnpkg.com/tap-summary/-/tap-summary-3.0.2.tgz#669d3a38546293feac9d2d5fc1c45f6e4a811c99" 1295 | dependencies: 1296 | ansi-escape "^1.0.1" 1297 | commander "^2.9.0" 1298 | figures "^1.4.0" 1299 | pretty-ms "^2.1.0" 1300 | tap-out "^1.4.1" 1301 | 1302 | tape@^4.8.0: 1303 | version "4.8.0" 1304 | resolved "https://registry.yarnpkg.com/tape/-/tape-4.8.0.tgz#f6a9fec41cc50a1de50fa33603ab580991f6068e" 1305 | dependencies: 1306 | deep-equal "~1.0.1" 1307 | defined "~1.0.0" 1308 | for-each "~0.3.2" 1309 | function-bind "~1.1.0" 1310 | glob "~7.1.2" 1311 | has "~1.0.1" 1312 | inherits "~2.0.3" 1313 | minimist "~1.2.0" 1314 | object-inspect "~1.3.0" 1315 | resolve "~1.4.0" 1316 | resumer "~0.0.0" 1317 | string.prototype.trim "~1.1.2" 1318 | through "~2.3.8" 1319 | 1320 | tar-pack@^3.4.0: 1321 | version "3.4.0" 1322 | resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" 1323 | dependencies: 1324 | debug "^2.2.0" 1325 | fstream "^1.0.10" 1326 | fstream-ignore "^1.0.5" 1327 | once "^1.3.3" 1328 | readable-stream "^2.1.4" 1329 | rimraf "^2.5.1" 1330 | tar "^2.2.1" 1331 | uid-number "^0.0.6" 1332 | 1333 | tar@^2.2.1: 1334 | version "2.2.1" 1335 | resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" 1336 | dependencies: 1337 | block-stream "*" 1338 | fstream "^1.0.2" 1339 | inherits "2" 1340 | 1341 | through@2, through@~2.3.4, through@~2.3.8: 1342 | version "2.3.8" 1343 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1344 | 1345 | tough-cookie@~2.3.0: 1346 | version "2.3.2" 1347 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" 1348 | dependencies: 1349 | punycode "^1.4.1" 1350 | 1351 | trim@0.0.1: 1352 | version "0.0.1" 1353 | resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" 1354 | 1355 | tunnel-agent@^0.6.0: 1356 | version "0.6.0" 1357 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 1358 | dependencies: 1359 | safe-buffer "^5.0.1" 1360 | 1361 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 1362 | version "0.14.5" 1363 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 1364 | 1365 | type-is@~1.6.15: 1366 | version "1.6.15" 1367 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" 1368 | dependencies: 1369 | media-typer "0.3.0" 1370 | mime-types "~2.1.15" 1371 | 1372 | uid-number@^0.0.6: 1373 | version "0.0.6" 1374 | resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" 1375 | 1376 | universalify@^0.1.0: 1377 | version "0.1.1" 1378 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" 1379 | 1380 | unpipe@~1.0.0: 1381 | version "1.0.0" 1382 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1383 | 1384 | util-deprecate@~1.0.1: 1385 | version "1.0.2" 1386 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1387 | 1388 | utils-merge@1.0.0: 1389 | version "1.0.0" 1390 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" 1391 | 1392 | uuid@^3.0.0: 1393 | version "3.1.0" 1394 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" 1395 | 1396 | vary@~1.1.1: 1397 | version "1.1.1" 1398 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" 1399 | 1400 | verror@1.10.0: 1401 | version "1.10.0" 1402 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" 1403 | dependencies: 1404 | assert-plus "^1.0.0" 1405 | core-util-is "1.0.2" 1406 | extsprintf "^1.2.0" 1407 | 1408 | wide-align@^1.1.0: 1409 | version "1.1.2" 1410 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" 1411 | dependencies: 1412 | string-width "^1.0.2" 1413 | 1414 | wrappy@1: 1415 | version "1.0.2" 1416 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1417 | --------------------------------------------------------------------------------