diff --git a/.prettierrc b/.prettierrc index f914884..e74ed9f 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { "trailingComma": "es5", "tabWidth": 4, - "semi": true, + "semi": false, "singleQuote": true } diff --git a/README.md b/README.md index 84caf33..4f7f409 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,23 @@ A minimal file tree based api router for building rest api's with node. -### Motivation +### About -I'm one of the many people who use [Next.js(Vercel)](https://github.com/vercel/next.js) and while the whole framework is great, I'm a huge fan of the API routes mechanism and thought I'd implement my own version of it so I can continue having seperate backend and frontend code while having the ease of writing api routes also, wanted to learn how this stuff works. (I'm curious like that). +RouteX started as a clone of the Next.js' Api Routes implmentation and is now on it's path to compete with other frameworks as the simplest way to setup API routes. There's been numerous posts on why using the folder tree makes it atomic and easier to handle the separation between logic. While you cannot bundle code with routex since each file is independent of the other and doesn't need the others for its execution. -### Roadmap (as of now) +The Idea and Inspiration for the creation remains to be Vercel's Next.js -- [x] Start of simple with something that can handle static routes.(Master and Canary) -- [x] Add CLI tool to be used with it (Master and Canary) -- [x] Add Dynamic paths and parameter parsing. (Canary Only) -- [x] Add minimal request and response helpers. -- [ ] Add more features to CLI (reloading, watchers, etc, etc) +### Changes (6/Jul/2020) -That's all I want the `routex` to do for now. +- Removed the `.route` folder for storing the compiled routes +- Root Folder routes are now accessible, you don't need to specifically use an `api` folder anymore, you can use any folder and the cli will consider it a route. Check CLI Commands before to achieve this. +- CLI flag for custom port added to avoid using the general environment variable + +### Performace + +Screenshot of `autocannon` to benchmark `/api` from the examples folder + +![GitHub Logo](/docs/perf.png) ### Warning @@ -24,20 +28,32 @@ This library is still in active development and is bound to have bugs , kindly m - A very limited cli, no hot reload, no file watcher, it literally just runs a simple processor for reading the file system as of now. -- Since the lib uses the native node HTTP right now, you are limited to it's request and response functions. - -### Usage +### Installation -Any file inside the folder `api` is mapped to `/api/*` and will be treated as an API endpoint and all HTTP requests will be passed to this file. GET, POST, PUT, DELETE +#### Stable Cli ```sh # for global install to avoid installing the devDependencies npm i -g barelyhuman/routex --only=prod # for local install to avoid installing the devDependencies npm i barelyhuman/routex --only=prod + +``` + +#### Canary Cli + +```sh +# for global install to avoid installing the devDependencies +npm i -g barelyhuman/routex#canary --only=prod +# for local install to avoid installing the devDependencies +npm i barelyhuman/routex#canary --only=prod ``` -Then go ahead and create directories and files under the `api` folder as mentioned or check the `examples` folder for reference. +### Usage + +Any folder that routex is run in will be considered the API root and will look for an `api` folder in the run location. + +Then go ahead and create directories and files under any folder as mentioned or check the `examples` folder for reference. Example file tree: @@ -78,7 +94,7 @@ module.exports = (req, res) => { ``` -Then run routex on the root folder of the project, this folder should contain the `api` folder +Then run routex on the root folder of the project, this folder should contain the `api` folder or specify a directory using the `-d` or `--dir` command. ```sh # If installed globally @@ -88,8 +104,14 @@ npx routex ``` -### Rules +### CLI Commands -- No copying of code from Next.js -- Don't use micro, setup and parse node http from scratch -- Try to keep it 0 Deps. +- `-d | --dir` to specify the directory to be used for routes, defaults to `api` +- `-p | --port` to specify the port to start the http server on , defaults to `3000` + +Example, the following would use the `example` folder as the base path for the routes and start the server on port `3001` + +```sh + routex -d ./example -p 3001 + +``` diff --git a/app.js b/app.js index 2dea75b..a2d19ed 100644 --- a/app.js +++ b/app.js @@ -1,14 +1,21 @@ #!/usr/bin/env node -const microServer = require('./lib/micro-server'); -const setupRoutes = require('./lib/setup-routes'); -const http = require('http'); -const PORT = process.env.PORT || 3000; +const microServer = require('./lib/micro-server') +const setupRoutes = require('./lib/setup-routes') +const http = require('http') -setupRoutes(); +const argv = require('minimist')(process.argv.slice(2)) +const port = argv.p || argv.port || 3000 -http.createServer((req, res) => { - microServer(req, res); -}).listen(PORT, () => { - console.log('> Listening on ' + PORT); -}); +setupRoutes() + .then((availableRoutes) => { + http.createServer((req, res) => { + microServer(req, res, availableRoutes) + }).listen(port, () => { + console.log('> Listening on ' + port) + }) + }) + .catch((err) => { + console.log(err) + throw err + }) diff --git a/create-docs.js b/create-docs.js index 8a6053f..882c73e 100644 --- a/create-docs.js +++ b/create-docs.js @@ -1,10 +1,10 @@ -const fs = require('fs').promises; -const marked = require('marked'); +const fs = require('fs').promises +const marked = require('marked') async function main() { try { - const fileMarkdownString = await fs.readFile('README.md'); - const htmlString = marked(fileMarkdownString.toString()); + const fileMarkdownString = await fs.readFile('README.md') + const htmlString = marked(fileMarkdownString.toString()) const template = ` @@ -23,13 +23,13 @@ async function main() { ${htmlString} - `; + ` - await fs.writeFile('docs/index.html', template); + await fs.writeFile('docs/index.html', template) } catch (err) { - console.error(err); - throw err; + console.error(err) + throw err } } -main(); +main() diff --git a/dist/index.js b/dist/index.js index 712a79e..f78de21 100755 --- a/dist/index.js +++ b/dist/index.js @@ -55,89 +55,87 @@ module.exports = /***/ 22: /***/ (function(module, __unusedexports, __webpack_require__) { -const basePath = __webpack_require__(973); -const path = __webpack_require__(622); -const parseUrl = __webpack_require__(304); -const { send, status } = __webpack_require__(876); +const basePath = __webpack_require__(973) +const path = __webpack_require__(622) +const parseUrl = __webpack_require__(304) +const { send, status } = __webpack_require__(876) module.exports = async (availableRoutes, req, res) => { try { - const parsedRouteUrl = parseUrl(req.url); - let handlerPath = ''; - let currentPointer = availableRoutes; + const parsedRouteUrl = parseUrl(req.url) - // Attach Helpers - res.send = send(res); - res.status = status(res); - // + let handlerPath = '' + let currentPointer = availableRoutes['.'] - parsedRouteUrl.paths.forEach((item) => { - let matchingKey; + for (let i = 0; i < parsedRouteUrl.paths.length; i += 1) { + const item = parsedRouteUrl.paths[i] + let matchingKey if (!currentPointer[item]) { matchingKey = Object.keys(currentPointer).find( (key) => currentPointer[key].params && currentPointer[key].params.length > 0 - ); + ) if (matchingKey) { - currentPointer = currentPointer[matchingKey]; - const key = matchingKey.replace(/[\[\]]/g, ''); + currentPointer = currentPointer[matchingKey] + const key = matchingKey.replace(/[\[\]]/g, '') req.params = { ...req.params, [key]: item, - }; + } } else { - currentPointer = null; - return; + currentPointer = null + break } } else { - currentPointer = currentPointer[item]; + currentPointer = currentPointer[item] } if (currentPointer) { if (currentPointer.type === 'file') { - handlerPath += currentPointer.index; + handlerPath += currentPointer.index } else { if (matchingKey) { - handlerPath += matchingKey + '/'; + handlerPath += matchingKey + '/' } else { - handlerPath += item + '/'; + handlerPath += item + '/' } } } - }); + } if (!currentPointer || !currentPointer.type) { - res.statusCode = 404; - res.end(); - return; + res.statusCode = 404 + res.end() + return } if (currentPointer.type === 'dir') { if (currentPointer.index) { - handlerPath += currentPointer.index; + handlerPath += currentPointer.index } else { - res.statusCode = 404; - res.end(); - return; + res.statusCode = 404 + res.end() + return } } - let _handlerPath = path.join(basePath(), handlerPath); + let _handlerPath = path.join(basePath(), handlerPath) - req.query = parsedRouteUrl.query; + // Attach helpers and parsed query data + res.send = send(res) + res.status = status(res) + req.query = parsedRouteUrl.query - const handler = require(_handlerPath); - - return handler(req, res); + return require(_handlerPath)(req, res) } catch (err) { - console.error(err); - res.statusCode(500); - res.end(); - throw err; + console.error(err) + res.status(500) + res.end() + throw err } -}; +} /***/ }), @@ -147,18 +145,6 @@ module.exports = async (availableRoutes, req, res) => { module.exports = require("readline"); -/***/ }), - -/***/ 66: -/***/ (function(module) { - -module.exports = (dirs) => { - const exists = dirs.find((item) => item === 'api'); - const valid = exists ? true : false; - return { valid, path: exists }; -}; - - /***/ }), /***/ 87: @@ -353,69 +339,269 @@ if ( true && module.exports) { /***/ }), -/***/ 104: -/***/ (function(module, __unusedexports, __webpack_require__) { +/***/ 109: +/***/ (function(module) { -const basePath = __webpack_require__(973); -const fs = __webpack_require__(747); -const path = __webpack_require__(622); +module.exports = function (args, opts) { + if (!opts) opts = {}; + + var flags = { bools : {}, strings : {}, unknownFn: null }; -module.exports = async () => { - try { - const creationPath = path.join(basePath(), '.route'); - const exists = await new Promise((resolve, reject) => { - fs.stat(creationPath, (err, stat) => { - if ( - (err && err.code === 'ENOENT') || - (err && err.code === 'ENOTDIR') - ) { - resolve(false); - } - return resolve(true); - }); + if (typeof opts['unknown'] === 'function') { + flags.unknownFn = opts['unknown']; + } + + if (typeof opts['boolean'] === 'boolean' && opts['boolean']) { + flags.allBools = true; + } else { + [].concat(opts['boolean']).filter(Boolean).forEach(function (key) { + flags.bools[key] = true; + }); + } + + var aliases = {}; + Object.keys(opts.alias || {}).forEach(function (key) { + aliases[key] = [].concat(opts.alias[key]); + aliases[key].forEach(function (x) { + aliases[x] = [key].concat(aliases[key].filter(function (y) { + return x !== y; + })); }); + }); - if (exists) { - return creationPath; - } else { - await new Promise((resolve, reject) => { - fs.mkdir(creationPath, (err, done) => { - if (err) reject(err); - resolve(done); - }); - }); + [].concat(opts.string).filter(Boolean).forEach(function (key) { + flags.strings[key] = true; + if (aliases[key]) { + flags.strings[aliases[key]] = true; } + }); - return creationPath; - } catch (err) { - console.error(err); - throw err; + var defaults = opts['default'] || {}; + + var argv = { _ : [] }; + Object.keys(flags.bools).forEach(function (key) { + setArg(key, defaults[key] === undefined ? false : defaults[key]); + }); + + var notFlags = []; + + if (args.indexOf('--') !== -1) { + notFlags = args.slice(args.indexOf('--')+1); + args = args.slice(0, args.indexOf('--')); + } + + function argDefined(key, arg) { + return (flags.allBools && /^--[^=]+$/.test(arg)) || + flags.strings[key] || flags.bools[key] || aliases[key]; + } + + function setArg (key, val, arg) { + if (arg && flags.unknownFn && !argDefined(key, arg)) { + if (flags.unknownFn(arg) === false) return; + } + + var value = !flags.strings[key] && isNumber(val) + ? Number(val) : val + ; + setKey(argv, key.split('.'), value); + + (aliases[key] || []).forEach(function (x) { + setKey(argv, x.split('.'), value); + }); + } + + function setKey (obj, keys, value) { + var o = obj; + for (var i = 0; i < keys.length-1; i++) { + var key = keys[i]; + if (key === '__proto__') return; + if (o[key] === undefined) o[key] = {}; + if (o[key] === Object.prototype || o[key] === Number.prototype + || o[key] === String.prototype) o[key] = {}; + if (o[key] === Array.prototype) o[key] = []; + o = o[key]; + } + + var key = keys[keys.length - 1]; + if (key === '__proto__') return; + if (o === Object.prototype || o === Number.prototype + || o === String.prototype) o = {}; + if (o === Array.prototype) o = []; + if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') { + o[key] = value; + } + else if (Array.isArray(o[key])) { + o[key].push(value); + } + else { + o[key] = [ o[key], value ]; + } + } + + function aliasIsBoolean(key) { + return aliases[key].some(function (x) { + return flags.bools[x]; + }); + } + + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + + if (/^--.+=/.test(arg)) { + // Using [\s\S] instead of . because js doesn't support the + // 'dotall' regex modifier. See: + // http://stackoverflow.com/a/1068308/13216 + var m = arg.match(/^--([^=]+)=([\s\S]*)$/); + var key = m[1]; + var value = m[2]; + if (flags.bools[key]) { + value = value !== 'false'; + } + setArg(key, value, arg); + } + else if (/^--no-.+/.test(arg)) { + var key = arg.match(/^--no-(.+)/)[1]; + setArg(key, false, arg); + } + else if (/^--.+/.test(arg)) { + var key = arg.match(/^--(.+)/)[1]; + var next = args[i + 1]; + if (next !== undefined && !/^-/.test(next) + && !flags.bools[key] + && !flags.allBools + && (aliases[key] ? !aliasIsBoolean(key) : true)) { + setArg(key, next, arg); + i++; + } + else if (/^(true|false)$/.test(next)) { + setArg(key, next === 'true', arg); + i++; + } + else { + setArg(key, flags.strings[key] ? '' : true, arg); + } + } + else if (/^-[^-]+/.test(arg)) { + var letters = arg.slice(1,-1).split(''); + + var broken = false; + for (var j = 0; j < letters.length; j++) { + var next = arg.slice(j+2); + + if (next === '-') { + setArg(letters[j], next, arg) + continue; + } + + if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) { + setArg(letters[j], next.split('=')[1], arg); + broken = true; + break; + } + + if (/[A-Za-z]/.test(letters[j]) + && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { + setArg(letters[j], next, arg); + broken = true; + break; + } + + if (letters[j+1] && letters[j+1].match(/\W/)) { + setArg(letters[j], arg.slice(j+2), arg); + broken = true; + break; + } + else { + setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg); + } + } + + var key = arg.slice(-1)[0]; + if (!broken && key !== '-') { + if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1]) + && !flags.bools[key] + && (aliases[key] ? !aliasIsBoolean(key) : true)) { + setArg(key, args[i+1], arg); + i++; + } + else if (args[i+1] && /^(true|false)$/.test(args[i+1])) { + setArg(key, args[i+1] === 'true', arg); + i++; + } + else { + setArg(key, flags.strings[key] ? '' : true, arg); + } + } + } + else { + if (!flags.unknownFn || flags.unknownFn(arg) !== false) { + argv._.push( + flags.strings['_'] || !isNumber(arg) ? arg : Number(arg) + ); + } + if (opts.stopEarly) { + argv._.push.apply(argv._, args.slice(i + 1)); + break; + } + } + } + + Object.keys(defaults).forEach(function (key) { + if (!hasKey(argv, key.split('.'))) { + setKey(argv, key.split('.'), defaults[key]); + + (aliases[key] || []).forEach(function (x) { + setKey(argv, x.split('.'), defaults[key]); + }); + } + }); + + if (opts['--']) { + argv['--'] = new Array(); + notFlags.forEach(function(key) { + argv['--'].push(key); + }); } + else { + notFlags.forEach(function(key) { + argv._.push(key); + }); + } + + return argv; }; +function hasKey (obj, keys) { + var o = obj; + keys.slice(0,-1).forEach(function (key) { + o = (o[key] || {}); + }); + + var key = keys[keys.length - 1]; + return key in o; +} + +function isNumber (x) { + if (typeof x === 'number') return true; + if (/^0x[0-9a-f]+$/i.test(x)) return true; + return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); +} + + /***/ }), /***/ 116: /***/ (function(module, __unusedexports, __webpack_require__) { -const basePath = __webpack_require__(973); -const fs = __webpack_require__(747); -const path = __webpack_require__(622); -const checkApiDir = __webpack_require__(66); -const processDirectories = __webpack_require__(239); +const basePath = __webpack_require__(973) +const path = __webpack_require__(622) +const processDirectories = __webpack_require__(239) module.exports = () => { - fs.readdir(basePath(), function (err, dirs) { - if (err) throw err; - const apiDirExists = checkApiDir(dirs); - if (!apiDirExists.valid) { - throw new Error('cannot find an `api` directory'); - } - const processingPath = path.join(basePath()); - return processDirectories(processingPath); - }); -}; + const processingPath = path.join(basePath()) + return processDirectories(processingPath) +} /***/ }), @@ -594,91 +780,82 @@ module.exports = function (str) { /***/ 168: /***/ (function(module, __unusedexports, __webpack_require__) { -const fs = __webpack_require__(747).promises; -const path = __webpack_require__(622); +const fs = __webpack_require__(747).promises +const path = __webpack_require__(622) module.exports = async (directory) => { try { - const routeTree = {}; - - let currentPointer = routeTree; - - await processDirectory(directory, 'api', currentPointer); - - return routeTree; + const routeTree = {} + let currentPointer = routeTree + await processDirectory(directory, '.', currentPointer) + return routeTree } catch (err) { - console.error(err); - throw err; + console.error(err) + throw err } -}; +} async function processDirectory(currPath, dir, pointer) { try { - const pathToCheck = path.join(currPath, dir); - const pathStat = await fs.stat(pathToCheck); + const pathToCheck = path.join(currPath, dir) + const pathStat = await fs.stat(pathToCheck) if (pathStat.isDirectory()) { - const dirContent = await fs.readdir(pathToCheck); + const dirContent = await fs.readdir(pathToCheck) const treeMods = dirContent.map(async (fileRecord) => { - const nextPathToCheck = path.join(pathToCheck, fileRecord); - const nextFile = await fs.stat(nextPathToCheck); + const nextPathToCheck = path.join(pathToCheck, fileRecord) + const nextFile = await fs.stat(nextPathToCheck) const nextPointer = pointer[dir] || (pointer[dir] = { type: 'dir', - }); - const paramRegex = /^\[(\w+)\]$/; + }) + const paramRegex = /^\[(\w+)\]$/ if (paramRegex.test(dir)) { - debugger; - const matchingParams = dir.match(paramRegex); - const param = matchingParams[1]; - pointer[dir].params = [param]; - debugger; + const matchingParams = dir.match(paramRegex) + const param = matchingParams[1] + pointer[dir].params = [param] } if (nextFile.isDirectory()) { - await processDirectory( - pathToCheck, - fileRecord, - nextPointer - ); + await processDirectory(pathToCheck, fileRecord, nextPointer) } else if (nextFile.isFile()) { - processFile(fileRecord, nextPointer); + processFile(fileRecord, nextPointer) } - return Promise.resolve(); - }); + return Promise.resolve() + }) - await Promise.all(treeMods); + await Promise.all(treeMods) } else if (pathStat.isFile()) { - processFile(dir, pointer); + processFile(dir, pointer) } } catch (err) { - console.error(err); - throw err; + console.error(err) + throw err } } function processFile(file, pointer) { - const paramRegex = /^\[(\w+)\].js$/; + const paramRegex = /^\[(\w+)\].js$/ if (paramRegex.test(file)) { - const matchingParams = file.match(paramRegex); - const param = matchingParams[1]; - const noExt = file.replace('.js', ''); + const matchingParams = file.match(paramRegex) + const param = matchingParams[1] + const noExt = file.replace('.js', '') const valuesInsertion = { type: 'file', params: [param], index: file, - }; - pointer[noExt] = valuesInsertion; + } + pointer[noExt] = valuesInsertion } else if (file === 'index.js') { - pointer.type = 'dir'; - pointer.index = 'index.js'; + pointer.type = 'dir' + pointer.index = 'index.js' } else { - const noExt = file.replace('.js', ''); + const noExt = file.replace('.js', '') const valuesInsertion = { type: 'file', index: file, - }; - pointer[noExt] = valuesInsertion; + } + pointer[noExt] = valuesInsertion } } @@ -712,41 +889,23 @@ module.exports = require("querystring"); /***/ 239: /***/ (function(module, __unusedexports, __webpack_require__) { -const fs = __webpack_require__(747); -const path = __webpack_require__(622); -const createRouteDir = __webpack_require__(104); -const createAvailableRoutes = __webpack_require__(168); -const ora = __webpack_require__(937); +const createAvailableRoutes = __webpack_require__(168) +const ora = __webpack_require__(937) module.exports = async (directory) => { - const spinner = ora('Compiling...').start(); try { - const availableRoutesTree = await createAvailableRoutes(directory); - - const routePath = await createRouteDir(); - - await new Promise((resolve, reject) => { - fs.writeFile( - path.join(routePath, 'routes.json'), - JSON.stringify(availableRoutesTree), - (err, done) => { - if (err) reject(err); - resolve(done); - } - ); - }); - - setTimeout(() => { - spinner.succeed('Compiled'); - }, 1000); + const spinner = ora('Compiling...').start() + const availableRoutesTree = await createAvailableRoutes(directory) + spinner.succeed('Compiled') + return availableRoutesTree } catch (err) { - spinner.color = 'red'; - spinner.text = 'Failed'; - spinner.fail(); - console.error(err); - throw err; + spinner.color = 'red' + spinner.text = 'Failed' + spinner.fail() + console.error(err) + throw err } -}; +} /***/ }), @@ -1208,21 +1367,21 @@ exports.toggle = (force, writableStream) => { /***/ 304: /***/ (function(module, __unusedexports, __webpack_require__) { -const url = __webpack_require__(835); -const querystring = __webpack_require__(191); +const url = __webpack_require__(835) +const querystring = __webpack_require__(191) module.exports = (urlstring) => { - const _url = url.parse(urlstring); - const paths = _url.pathname.split('/').filter((item) => item); - let queryParams = {}; + const _url = url.parse(urlstring) + const paths = _url.pathname.split('/').filter((item) => item) + let queryParams = {} if (_url.search && _url.search.length > 0) { - queryParams = querystring.parse(_url.search.replace('?', '')); + queryParams = querystring.parse(_url.search.replace('?', '')) } return { paths, query: queryParams, - }; -}; + } +} /***/ }), @@ -2387,21 +2546,21 @@ module.exports = require("stream"); /***/ (function(module) { module.exports = (res, type) => { - let _type = type; + let _type = type const cases = { json: 'application/json', buffer: 'application/octet-stream', text: 'text/html', - }; + } if (!cases[type]) { - _type = cases.text; + _type = cases.text } - res.setHeader('Content-Type', _type); - return; -}; + res.setHeader('Content-Type', _type) + return +} /***/ }), @@ -2422,53 +2581,6 @@ module.exports = ({onlyFirst = false} = {}) => { }; -/***/ }), - -/***/ 493: -/***/ (function(module) { - -"use strict"; - - -const stringReplaceAll = (string, substring, replacer) => { - let index = string.indexOf(substring); - if (index === -1) { - return string; - } - - const substringLength = substring.length; - let endIndex = 0; - let returnValue = ''; - do { - returnValue += string.substr(endIndex, index - endIndex) + substring + replacer; - endIndex = index + substringLength; - index = string.indexOf(substring, endIndex); - } while (index !== -1); - - returnValue += string.substr(endIndex); - return returnValue; -}; - -const stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => { - let endIndex = 0; - let returnValue = ''; - do { - const gotCR = string[index - 1] === '\r'; - returnValue += string.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? '\r\n' : '\n') + postfix; - endIndex = index + 1; - index = string.indexOf('\n', endIndex); - } while (index !== -1); - - returnValue += string.substr(endIndex); - return returnValue; -}; - -module.exports = { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex -}; - - /***/ }), /***/ 497: @@ -2644,19 +2756,16 @@ function processEmit (ev, arg) { /***/ 544: /***/ (function(module, __unusedexports, __webpack_require__) { -const router = __webpack_require__(22); -const getAvailableRoutes = __webpack_require__(917); +const router = __webpack_require__(22) -module.exports = async (req, res) => { +module.exports = async (req, res, availableRoutes) => { try { - const availableRoutes = await getAvailableRoutes(); - - return router(availableRoutes, req, res); + return router(availableRoutes, req, res) } catch (err) { - console.error(err); - throw err; + console.error(err) + throw err } -}; +} /***/ }), @@ -3868,83 +3977,225 @@ module.exports = require("http"); /***/ }), -/***/ 614: +/***/ 606: /***/ (function(module) { -module.exports = require("events"); - -/***/ }), - -/***/ 622: -/***/ (function(module) { +"use strict"; -module.exports = require("path"); +const TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; +const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; +const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; +const ESCAPE_REGEX = /\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.)|([^\\])/gi; -/***/ }), +const ESCAPES = new Map([ + ['n', '\n'], + ['r', '\r'], + ['t', '\t'], + ['b', '\b'], + ['f', '\f'], + ['v', '\v'], + ['0', '\0'], + ['\\', '\\'], + ['e', '\u001B'], + ['a', '\u0007'] +]); -/***/ 634: -/***/ (function(module) { +function unescape(c) { + const u = c[0] === 'u'; + const bracket = c[1] === '{'; -module.exports = [ - [ 0x0300, 0x036F ], [ 0x0483, 0x0486 ], [ 0x0488, 0x0489 ], - [ 0x0591, 0x05BD ], [ 0x05BF, 0x05BF ], [ 0x05C1, 0x05C2 ], - [ 0x05C4, 0x05C5 ], [ 0x05C7, 0x05C7 ], [ 0x0600, 0x0603 ], - [ 0x0610, 0x0615 ], [ 0x064B, 0x065E ], [ 0x0670, 0x0670 ], - [ 0x06D6, 0x06E4 ], [ 0x06E7, 0x06E8 ], [ 0x06EA, 0x06ED ], - [ 0x070F, 0x070F ], [ 0x0711, 0x0711 ], [ 0x0730, 0x074A ], - [ 0x07A6, 0x07B0 ], [ 0x07EB, 0x07F3 ], [ 0x0901, 0x0902 ], - [ 0x093C, 0x093C ], [ 0x0941, 0x0948 ], [ 0x094D, 0x094D ], - [ 0x0951, 0x0954 ], [ 0x0962, 0x0963 ], [ 0x0981, 0x0981 ], - [ 0x09BC, 0x09BC ], [ 0x09C1, 0x09C4 ], [ 0x09CD, 0x09CD ], - [ 0x09E2, 0x09E3 ], [ 0x0A01, 0x0A02 ], [ 0x0A3C, 0x0A3C ], - [ 0x0A41, 0x0A42 ], [ 0x0A47, 0x0A48 ], [ 0x0A4B, 0x0A4D ], - [ 0x0A70, 0x0A71 ], [ 0x0A81, 0x0A82 ], [ 0x0ABC, 0x0ABC ], - [ 0x0AC1, 0x0AC5 ], [ 0x0AC7, 0x0AC8 ], [ 0x0ACD, 0x0ACD ], - [ 0x0AE2, 0x0AE3 ], [ 0x0B01, 0x0B01 ], [ 0x0B3C, 0x0B3C ], - [ 0x0B3F, 0x0B3F ], [ 0x0B41, 0x0B43 ], [ 0x0B4D, 0x0B4D ], - [ 0x0B56, 0x0B56 ], [ 0x0B82, 0x0B82 ], [ 0x0BC0, 0x0BC0 ], - [ 0x0BCD, 0x0BCD ], [ 0x0C3E, 0x0C40 ], [ 0x0C46, 0x0C48 ], - [ 0x0C4A, 0x0C4D ], [ 0x0C55, 0x0C56 ], [ 0x0CBC, 0x0CBC ], - [ 0x0CBF, 0x0CBF ], [ 0x0CC6, 0x0CC6 ], [ 0x0CCC, 0x0CCD ], - [ 0x0CE2, 0x0CE3 ], [ 0x0D41, 0x0D43 ], [ 0x0D4D, 0x0D4D ], - [ 0x0DCA, 0x0DCA ], [ 0x0DD2, 0x0DD4 ], [ 0x0DD6, 0x0DD6 ], - [ 0x0E31, 0x0E31 ], [ 0x0E34, 0x0E3A ], [ 0x0E47, 0x0E4E ], - [ 0x0EB1, 0x0EB1 ], [ 0x0EB4, 0x0EB9 ], [ 0x0EBB, 0x0EBC ], - [ 0x0EC8, 0x0ECD ], [ 0x0F18, 0x0F19 ], [ 0x0F35, 0x0F35 ], - [ 0x0F37, 0x0F37 ], [ 0x0F39, 0x0F39 ], [ 0x0F71, 0x0F7E ], - [ 0x0F80, 0x0F84 ], [ 0x0F86, 0x0F87 ], [ 0x0F90, 0x0F97 ], - [ 0x0F99, 0x0FBC ], [ 0x0FC6, 0x0FC6 ], [ 0x102D, 0x1030 ], - [ 0x1032, 0x1032 ], [ 0x1036, 0x1037 ], [ 0x1039, 0x1039 ], - [ 0x1058, 0x1059 ], [ 0x1160, 0x11FF ], [ 0x135F, 0x135F ], - [ 0x1712, 0x1714 ], [ 0x1732, 0x1734 ], [ 0x1752, 0x1753 ], - [ 0x1772, 0x1773 ], [ 0x17B4, 0x17B5 ], [ 0x17B7, 0x17BD ], - [ 0x17C6, 0x17C6 ], [ 0x17C9, 0x17D3 ], [ 0x17DD, 0x17DD ], - [ 0x180B, 0x180D ], [ 0x18A9, 0x18A9 ], [ 0x1920, 0x1922 ], - [ 0x1927, 0x1928 ], [ 0x1932, 0x1932 ], [ 0x1939, 0x193B ], - [ 0x1A17, 0x1A18 ], [ 0x1B00, 0x1B03 ], [ 0x1B34, 0x1B34 ], - [ 0x1B36, 0x1B3A ], [ 0x1B3C, 0x1B3C ], [ 0x1B42, 0x1B42 ], - [ 0x1B6B, 0x1B73 ], [ 0x1DC0, 0x1DCA ], [ 0x1DFE, 0x1DFF ], - [ 0x200B, 0x200F ], [ 0x202A, 0x202E ], [ 0x2060, 0x2063 ], - [ 0x206A, 0x206F ], [ 0x20D0, 0x20EF ], [ 0x302A, 0x302F ], - [ 0x3099, 0x309A ], [ 0xA806, 0xA806 ], [ 0xA80B, 0xA80B ], - [ 0xA825, 0xA826 ], [ 0xFB1E, 0xFB1E ], [ 0xFE00, 0xFE0F ], - [ 0xFE20, 0xFE23 ], [ 0xFEFF, 0xFEFF ], [ 0xFFF9, 0xFFFB ], - [ 0x10A01, 0x10A03 ], [ 0x10A05, 0x10A06 ], [ 0x10A0C, 0x10A0F ], - [ 0x10A38, 0x10A3A ], [ 0x10A3F, 0x10A3F ], [ 0x1D167, 0x1D169 ], - [ 0x1D173, 0x1D182 ], [ 0x1D185, 0x1D18B ], [ 0x1D1AA, 0x1D1AD ], - [ 0x1D242, 0x1D244 ], [ 0xE0001, 0xE0001 ], [ 0xE0020, 0xE007F ], - [ 0xE0100, 0xE01EF ] -] + if ((u && !bracket && c.length === 5) || (c[0] === 'x' && c.length === 3)) { + return String.fromCharCode(parseInt(c.slice(1), 16)); + } + if (u && bracket) { + return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); + } -/***/ }), + return ESCAPES.get(c) || c; +} -/***/ 654: -/***/ (function(module) { +function parseArguments(name, arguments_) { + const results = []; + const chunks = arguments_.trim().split(/\s*,\s*/g); + let matches; -// This is not the set of all possible signals. -// -// It IS, however, the set of all signals that trigger + for (const chunk of chunks) { + const number = Number(chunk); + if (!Number.isNaN(number)) { + results.push(number); + } else if ((matches = chunk.match(STRING_REGEX))) { + results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, character) => escape ? unescape(escape) : character)); + } else { + throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); + } + } + + return results; +} + +function parseStyle(style) { + STYLE_REGEX.lastIndex = 0; + + const results = []; + let matches; + + while ((matches = STYLE_REGEX.exec(style)) !== null) { + const name = matches[1]; + + if (matches[2]) { + const args = parseArguments(name, matches[2]); + results.push([name].concat(args)); + } else { + results.push([name]); + } + } + + return results; +} + +function buildStyle(chalk, styles) { + const enabled = {}; + + for (const layer of styles) { + for (const style of layer.styles) { + enabled[style[0]] = layer.inverse ? null : style.slice(1); + } + } + + let current = chalk; + for (const [styleName, styles] of Object.entries(enabled)) { + if (!Array.isArray(styles)) { + continue; + } + + if (!(styleName in current)) { + throw new Error(`Unknown Chalk style: ${styleName}`); + } + + current = styles.length > 0 ? current[styleName](...styles) : current[styleName]; + } + + return current; +} + +module.exports = (chalk, temporary) => { + const styles = []; + const chunks = []; + let chunk = []; + + // eslint-disable-next-line max-params + temporary.replace(TEMPLATE_REGEX, (m, escapeCharacter, inverse, style, close, character) => { + if (escapeCharacter) { + chunk.push(unescape(escapeCharacter)); + } else if (style) { + const string = chunk.join(''); + chunk = []; + chunks.push(styles.length === 0 ? string : buildStyle(chalk, styles)(string)); + styles.push({inverse, styles: parseStyle(style)}); + } else if (close) { + if (styles.length === 0) { + throw new Error('Found extraneous } in Chalk template literal'); + } + + chunks.push(buildStyle(chalk, styles)(chunk.join(''))); + chunk = []; + styles.pop(); + } else { + chunk.push(character); + } + }); + + chunks.push(chunk.join('')); + + if (styles.length > 0) { + const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; + throw new Error(errMsg); + } + + return chunks.join(''); +}; + + +/***/ }), + +/***/ 614: +/***/ (function(module) { + +module.exports = require("events"); + +/***/ }), + +/***/ 622: +/***/ (function(module) { + +module.exports = require("path"); + +/***/ }), + +/***/ 634: +/***/ (function(module) { + +module.exports = [ + [ 0x0300, 0x036F ], [ 0x0483, 0x0486 ], [ 0x0488, 0x0489 ], + [ 0x0591, 0x05BD ], [ 0x05BF, 0x05BF ], [ 0x05C1, 0x05C2 ], + [ 0x05C4, 0x05C5 ], [ 0x05C7, 0x05C7 ], [ 0x0600, 0x0603 ], + [ 0x0610, 0x0615 ], [ 0x064B, 0x065E ], [ 0x0670, 0x0670 ], + [ 0x06D6, 0x06E4 ], [ 0x06E7, 0x06E8 ], [ 0x06EA, 0x06ED ], + [ 0x070F, 0x070F ], [ 0x0711, 0x0711 ], [ 0x0730, 0x074A ], + [ 0x07A6, 0x07B0 ], [ 0x07EB, 0x07F3 ], [ 0x0901, 0x0902 ], + [ 0x093C, 0x093C ], [ 0x0941, 0x0948 ], [ 0x094D, 0x094D ], + [ 0x0951, 0x0954 ], [ 0x0962, 0x0963 ], [ 0x0981, 0x0981 ], + [ 0x09BC, 0x09BC ], [ 0x09C1, 0x09C4 ], [ 0x09CD, 0x09CD ], + [ 0x09E2, 0x09E3 ], [ 0x0A01, 0x0A02 ], [ 0x0A3C, 0x0A3C ], + [ 0x0A41, 0x0A42 ], [ 0x0A47, 0x0A48 ], [ 0x0A4B, 0x0A4D ], + [ 0x0A70, 0x0A71 ], [ 0x0A81, 0x0A82 ], [ 0x0ABC, 0x0ABC ], + [ 0x0AC1, 0x0AC5 ], [ 0x0AC7, 0x0AC8 ], [ 0x0ACD, 0x0ACD ], + [ 0x0AE2, 0x0AE3 ], [ 0x0B01, 0x0B01 ], [ 0x0B3C, 0x0B3C ], + [ 0x0B3F, 0x0B3F ], [ 0x0B41, 0x0B43 ], [ 0x0B4D, 0x0B4D ], + [ 0x0B56, 0x0B56 ], [ 0x0B82, 0x0B82 ], [ 0x0BC0, 0x0BC0 ], + [ 0x0BCD, 0x0BCD ], [ 0x0C3E, 0x0C40 ], [ 0x0C46, 0x0C48 ], + [ 0x0C4A, 0x0C4D ], [ 0x0C55, 0x0C56 ], [ 0x0CBC, 0x0CBC ], + [ 0x0CBF, 0x0CBF ], [ 0x0CC6, 0x0CC6 ], [ 0x0CCC, 0x0CCD ], + [ 0x0CE2, 0x0CE3 ], [ 0x0D41, 0x0D43 ], [ 0x0D4D, 0x0D4D ], + [ 0x0DCA, 0x0DCA ], [ 0x0DD2, 0x0DD4 ], [ 0x0DD6, 0x0DD6 ], + [ 0x0E31, 0x0E31 ], [ 0x0E34, 0x0E3A ], [ 0x0E47, 0x0E4E ], + [ 0x0EB1, 0x0EB1 ], [ 0x0EB4, 0x0EB9 ], [ 0x0EBB, 0x0EBC ], + [ 0x0EC8, 0x0ECD ], [ 0x0F18, 0x0F19 ], [ 0x0F35, 0x0F35 ], + [ 0x0F37, 0x0F37 ], [ 0x0F39, 0x0F39 ], [ 0x0F71, 0x0F7E ], + [ 0x0F80, 0x0F84 ], [ 0x0F86, 0x0F87 ], [ 0x0F90, 0x0F97 ], + [ 0x0F99, 0x0FBC ], [ 0x0FC6, 0x0FC6 ], [ 0x102D, 0x1030 ], + [ 0x1032, 0x1032 ], [ 0x1036, 0x1037 ], [ 0x1039, 0x1039 ], + [ 0x1058, 0x1059 ], [ 0x1160, 0x11FF ], [ 0x135F, 0x135F ], + [ 0x1712, 0x1714 ], [ 0x1732, 0x1734 ], [ 0x1752, 0x1753 ], + [ 0x1772, 0x1773 ], [ 0x17B4, 0x17B5 ], [ 0x17B7, 0x17BD ], + [ 0x17C6, 0x17C6 ], [ 0x17C9, 0x17D3 ], [ 0x17DD, 0x17DD ], + [ 0x180B, 0x180D ], [ 0x18A9, 0x18A9 ], [ 0x1920, 0x1922 ], + [ 0x1927, 0x1928 ], [ 0x1932, 0x1932 ], [ 0x1939, 0x193B ], + [ 0x1A17, 0x1A18 ], [ 0x1B00, 0x1B03 ], [ 0x1B34, 0x1B34 ], + [ 0x1B36, 0x1B3A ], [ 0x1B3C, 0x1B3C ], [ 0x1B42, 0x1B42 ], + [ 0x1B6B, 0x1B73 ], [ 0x1DC0, 0x1DCA ], [ 0x1DFE, 0x1DFF ], + [ 0x200B, 0x200F ], [ 0x202A, 0x202E ], [ 0x2060, 0x2063 ], + [ 0x206A, 0x206F ], [ 0x20D0, 0x20EF ], [ 0x302A, 0x302F ], + [ 0x3099, 0x309A ], [ 0xA806, 0xA806 ], [ 0xA80B, 0xA80B ], + [ 0xA825, 0xA826 ], [ 0xFB1E, 0xFB1E ], [ 0xFE00, 0xFE0F ], + [ 0xFE20, 0xFE23 ], [ 0xFEFF, 0xFEFF ], [ 0xFFF9, 0xFFFB ], + [ 0x10A01, 0x10A03 ], [ 0x10A05, 0x10A06 ], [ 0x10A0C, 0x10A0F ], + [ 0x10A38, 0x10A3A ], [ 0x10A3F, 0x10A3F ], [ 0x1D167, 0x1D169 ], + [ 0x1D173, 0x1D182 ], [ 0x1D185, 0x1D18B ], [ 0x1D1AA, 0x1D1AD ], + [ 0x1D242, 0x1D244 ], [ 0xE0001, 0xE0001 ], [ 0xE0020, 0xE007F ], + [ 0xE0100, 0xE01EF ] +] + + +/***/ }), + +/***/ 654: +/***/ (function(module) { + +// This is not the set of all possible signals. +// +// It IS, however, the set of all signals that trigger // an exit on either Linux or BSD systems. Linux is a // superset of the signal names supported on BSD, and // the unknown signals just fail to register, so we can @@ -4178,380 +4429,526 @@ module.exports = {"dots":{"interval":80,"frames":["⠋","⠙","⠹","⠸","⠼", /***/ }), -/***/ 706: -/***/ (function(module) { +/***/ 723: +/***/ (function(module, __unusedexports, __webpack_require__) { "use strict"; -const TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; -const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; -const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; -const ESCAPE_REGEX = /\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.)|([^\\])/gi; - -const ESCAPES = new Map([ - ['n', '\n'], - ['r', '\r'], - ['t', '\t'], - ['b', '\b'], - ['f', '\f'], - ['v', '\v'], - ['0', '\0'], - ['\\', '\\'], - ['e', '\u001B'], - ['a', '\u0007'] -]); +const mimicFn = __webpack_require__(750); -function unescape(c) { - const u = c[0] === 'u'; - const bracket = c[1] === '{'; +const calledFunctions = new WeakMap(); - if ((u && !bracket && c.length === 5) || (c[0] === 'x' && c.length === 3)) { - return String.fromCharCode(parseInt(c.slice(1), 16)); +const oneTime = (fn, options = {}) => { + if (typeof fn !== 'function') { + throw new TypeError('Expected a function'); } - if (u && bracket) { - return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); - } + let ret; + let isCalled = false; + let callCount = 0; + const functionName = fn.displayName || fn.name || ''; - return ESCAPES.get(c) || c; -} + const onetime = function (...args) { + calledFunctions.set(onetime, ++callCount); -function parseArguments(name, arguments_) { - const results = []; - const chunks = arguments_.trim().split(/\s*,\s*/g); - let matches; + if (isCalled) { + if (options.throw === true) { + throw new Error(`Function \`${functionName}\` can only be called once`); + } - for (const chunk of chunks) { - const number = Number(chunk); - if (!Number.isNaN(number)) { - results.push(number); - } else if ((matches = chunk.match(STRING_REGEX))) { - results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, character) => escape ? unescape(escape) : character)); - } else { - throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); + return ret; } - } - return results; -} + isCalled = true; + ret = fn.apply(this, args); + fn = null; -function parseStyle(style) { - STYLE_REGEX.lastIndex = 0; + return ret; + }; - const results = []; - let matches; + mimicFn(onetime, fn); + calledFunctions.set(onetime, callCount); - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; + return onetime; +}; - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); - } +module.exports = oneTime; +// TODO: Remove this for the next major release +module.exports.default = oneTime; + +module.exports.callCount = fn => { + if (!calledFunctions.has(fn)) { + throw new Error(`The given function \`${fn.name}\` is not wrapped by the \`onetime\` package`); } - return results; -} + return calledFunctions.get(fn); +}; -function buildStyle(chalk, styles) { - const enabled = {}; - for (const layer of styles) { - for (const style of layer.styles) { - enabled[style[0]] = layer.inverse ? null : style.slice(1); - } - } +/***/ }), - let current = chalk; - for (const [styleName, styles] of Object.entries(enabled)) { - if (!Array.isArray(styles)) { - continue; - } +/***/ 727: +/***/ (function(module, __unusedexports, __webpack_require__) { - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); - } +var clone = __webpack_require__(97); - current = styles.length > 0 ? current[styleName](...styles) : current[styleName]; - } +module.exports = function(options, defaults) { + options = options || {}; - return current; -} + Object.keys(defaults).forEach(function(key) { + if (typeof options[key] === 'undefined') { + options[key] = clone(defaults[key]); + } + }); -module.exports = (chalk, temporary) => { - const styles = []; - const chunks = []; - let chunk = []; + return options; +}; - // eslint-disable-next-line max-params - temporary.replace(TEMPLATE_REGEX, (m, escapeCharacter, inverse, style, close, character) => { - if (escapeCharacter) { - chunk.push(unescape(escapeCharacter)); - } else if (style) { - const string = chunk.join(''); - chunk = []; - chunks.push(styles.length === 0 ? string : buildStyle(chalk, styles)(string)); - styles.push({inverse, styles: parseStyle(style)}); - } else if (close) { - if (styles.length === 0) { - throw new Error('Found extraneous } in Chalk template literal'); - } +/***/ }), - chunks.push(buildStyle(chalk, styles)(chunk.join(''))); - chunk = []; - styles.pop(); - } else { - chunk.push(character); - } - }); +/***/ 747: +/***/ (function(module) { - chunks.push(chunk.join('')); +module.exports = require("fs"); - if (styles.length > 0) { - const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; - throw new Error(errMsg); +/***/ }), + +/***/ 750: +/***/ (function(module) { + +"use strict"; + + +const mimicFn = (to, from) => { + for (const prop of Reflect.ownKeys(from)) { + Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop)); } - return chunks.join(''); + return to; }; +module.exports = mimicFn; +// TODO: Remove this for the next major release +module.exports.default = mimicFn; + /***/ }), -/***/ 723: -/***/ (function(module, __unusedexports, __webpack_require__) { +/***/ 754: +/***/ (function(module) { "use strict"; -const mimicFn = __webpack_require__(750); - -const calledFunctions = new WeakMap(); -const oneTime = (fn, options = {}) => { - if (typeof fn !== 'function') { - throw new TypeError('Expected a function'); +const stringReplaceAll = (string, substring, replacer) => { + let index = string.indexOf(substring); + if (index === -1) { + return string; } - let ret; - let isCalled = false; - let callCount = 0; - const functionName = fn.displayName || fn.name || ''; - - const onetime = function (...args) { - calledFunctions.set(onetime, ++callCount); + const substringLength = substring.length; + let endIndex = 0; + let returnValue = ''; + do { + returnValue += string.substr(endIndex, index - endIndex) + substring + replacer; + endIndex = index + substringLength; + index = string.indexOf(substring, endIndex); + } while (index !== -1); - if (isCalled) { - if (options.throw === true) { - throw new Error(`Function \`${functionName}\` can only be called once`); - } + returnValue += string.substr(endIndex); + return returnValue; +}; - return ret; - } +const stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => { + let endIndex = 0; + let returnValue = ''; + do { + const gotCR = string[index - 1] === '\r'; + returnValue += string.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? '\r\n' : '\n') + postfix; + endIndex = index + 1; + index = string.indexOf('\n', endIndex); + } while (index !== -1); - isCalled = true; - ret = fn.apply(this, args); - fn = null; + returnValue += string.substr(endIndex); + return returnValue; +}; - return ret; - }; +module.exports = { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex +}; - mimicFn(onetime, fn); - calledFunctions.set(onetime, callCount); - return onetime; -}; +/***/ }), -module.exports = oneTime; -// TODO: Remove this for the next major release -module.exports.default = oneTime; +/***/ 772: +/***/ (function(module) { -module.exports.callCount = fn => { - if (!calledFunctions.has(fn)) { - throw new Error(`The given function \`${fn.name}\` is not wrapped by the \`onetime\` package`); - } +"use strict"; - return calledFunctions.get(fn); +module.exports = (flag, argv) => { + argv = argv || process.argv; + const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); + const pos = argv.indexOf(prefix + flag); + const terminatorPos = argv.indexOf('--'); + return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos); }; /***/ }), -/***/ 727: +/***/ 833: /***/ (function(module, __unusedexports, __webpack_require__) { -var clone = __webpack_require__(97); +"use strict"; -module.exports = function(options, defaults) { - options = options || {}; - Object.keys(defaults).forEach(function(key) { - if (typeof options[key] === 'undefined') { - options[key] = clone(defaults[key]); - } - }); +var defaults = __webpack_require__(727) +var combining = __webpack_require__(634) + +var DEFAULTS = { + nul: 0, + control: 0 +} + +module.exports = function wcwidth(str) { + return wcswidth(str, DEFAULTS) +} + +module.exports.config = function(opts) { + opts = defaults(opts || {}, DEFAULTS) + return function wcwidth(str) { + return wcswidth(str, opts) + } +} + +/* + * The following functions define the column width of an ISO 10646 + * character as follows: + * - The null character (U+0000) has a column width of 0. + * - Other C0/C1 control characters and DEL will lead to a return value + * of -1. + * - Non-spacing and enclosing combining characters (general category + * code Mn or Me in the + * Unicode database) have a column width of 0. + * - SOFT HYPHEN (U+00AD) has a column width of 1. + * - Other format characters (general category code Cf in the Unicode + * database) and ZERO WIDTH + * SPACE (U+200B) have a column width of 0. + * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) + * have a column width of 0. + * - Spacing characters in the East Asian Wide (W) or East Asian + * Full-width (F) category as + * defined in Unicode Technical Report #11 have a column width of 2. + * - All remaining characters (including all printable ISO 8859-1 and + * WGL4 characters, Unicode control characters, etc.) have a column + * width of 1. + * This implementation assumes that characters are encoded in ISO 10646. +*/ + +function wcswidth(str, opts) { + if (typeof str !== 'string') return wcwidth(str, opts) + + var s = 0 + for (var i = 0; i < str.length; i++) { + var n = wcwidth(str.charCodeAt(i), opts) + if (n < 0) return -1 + s += n + } + + return s +} + +function wcwidth(ucs, opts) { + // test for 8-bit control characters + if (ucs === 0) return opts.nul + if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) return opts.control + + // binary search in table of non-spacing characters + if (bisearch(ucs)) return 0 + + // if we arrive here, ucs is not a combining or C0/C1 control character + return 1 + + (ucs >= 0x1100 && + (ucs <= 0x115f || // Hangul Jamo init. consonants + ucs == 0x2329 || ucs == 0x232a || + (ucs >= 0x2e80 && ucs <= 0xa4cf && + ucs != 0x303f) || // CJK ... Yi + (ucs >= 0xac00 && ucs <= 0xd7a3) || // Hangul Syllables + (ucs >= 0xf900 && ucs <= 0xfaff) || // CJK Compatibility Ideographs + (ucs >= 0xfe10 && ucs <= 0xfe19) || // Vertical forms + (ucs >= 0xfe30 && ucs <= 0xfe6f) || // CJK Compatibility Forms + (ucs >= 0xff00 && ucs <= 0xff60) || // Fullwidth Forms + (ucs >= 0xffe0 && ucs <= 0xffe6) || + (ucs >= 0x20000 && ucs <= 0x2fffd) || + (ucs >= 0x30000 && ucs <= 0x3fffd))); +} + +function bisearch(ucs) { + var min = 0 + var max = combining.length - 1 + var mid + + if (ucs < combining[0][0] || ucs > combining[max][1]) return false + + while (max >= min) { + mid = Math.floor((min + max) / 2) + if (ucs > combining[mid][1]) min = mid + 1 + else if (ucs < combining[mid][0]) max = mid - 1 + else return true + } + + return false +} - return options; -}; /***/ }), -/***/ 747: +/***/ 835: /***/ (function(module) { -module.exports = require("fs"); +module.exports = require("url"); /***/ }), -/***/ 750: -/***/ (function(module) { +/***/ 843: +/***/ (function(module, __unusedexports, __webpack_require__) { + +"use strict"; + +const ansiStyles = __webpack_require__(663); +const {stdout: stdoutColor, stderr: stderrColor} = __webpack_require__(247); +const { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex +} = __webpack_require__(754); + +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = [ + 'ansi', + 'ansi', + 'ansi256', + 'ansi16m' +]; + +const styles = Object.create(null); + +const applyOptions = (object, options = {}) => { + if (options.level > 3 || options.level < 0) { + throw new Error('The `level` option should be an integer from 0 to 3'); + } + + // Detect level if not set manually + const colorLevel = stdoutColor ? stdoutColor.level : 0; + object.level = options.level === undefined ? colorLevel : options.level; +}; + +class ChalkClass { + constructor(options) { + return chalkFactory(options); + } +} + +const chalkFactory = options => { + const chalk = {}; + applyOptions(chalk, options); + + chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_); + + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); + + chalk.template.constructor = () => { + throw new Error('`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.'); + }; + + chalk.template.Instance = ChalkClass; + + return chalk.template; +}; + +function Chalk(options) { + return chalkFactory(options); +} + +for (const [styleName, style] of Object.entries(ansiStyles)) { + styles[styleName] = { + get() { + const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); + Object.defineProperty(this, styleName, {value: builder}); + return builder; + } + }; +} + +styles.visible = { + get() { + const builder = createBuilder(this, this._styler, true); + Object.defineProperty(this, 'visible', {value: builder}); + return builder; + } +}; + +const usedModels = ['rgb', 'hex', 'keyword', 'hsl', 'hsv', 'hwb', 'ansi', 'ansi256']; + +for (const model of usedModels) { + styles[model] = { + get() { + const {level} = this; + return function (...arguments_) { + const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); + return createBuilder(this, styler, this._isEmpty); + }; + } + }; +} -"use strict"; +for (const model of usedModels) { + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const {level} = this; + return function (...arguments_) { + const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); + return createBuilder(this, styler, this._isEmpty); + }; + } + }; +} +const proto = Object.defineProperties(() => {}, { + ...styles, + level: { + enumerable: true, + get() { + return this._generator.level; + }, + set(level) { + this._generator.level = level; + } + } +}); -const mimicFn = (to, from) => { - for (const prop of Reflect.ownKeys(from)) { - Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop)); +const createStyler = (open, close, parent) => { + let openAll; + let closeAll; + if (parent === undefined) { + openAll = open; + closeAll = close; + } else { + openAll = parent.openAll + open; + closeAll = close + parent.closeAll; } - return to; + return { + open, + close, + openAll, + closeAll, + parent + }; }; -module.exports = mimicFn; -// TODO: Remove this for the next major release -module.exports.default = mimicFn; - - -/***/ }), +const createBuilder = (self, _styler, _isEmpty) => { + const builder = (...arguments_) => { + // Single argument is hot path, implicit coercion is faster than anything + // eslint-disable-next-line no-implicit-coercion + return applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' ')); + }; -/***/ 772: -/***/ (function(module) { + // `__proto__` is used because we must return a function, but there is + // no way to create a function with a different prototype + builder.__proto__ = proto; // eslint-disable-line no-proto -"use strict"; + builder._generator = self; + builder._styler = _styler; + builder._isEmpty = _isEmpty; -module.exports = (flag, argv) => { - argv = argv || process.argv; - const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); - const pos = argv.indexOf(prefix + flag); - const terminatorPos = argv.indexOf('--'); - return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos); + return builder; }; +const applyStyle = (self, string) => { + if (self.level <= 0 || !string) { + return self._isEmpty ? '' : string; + } -/***/ }), - -/***/ 833: -/***/ (function(module, __unusedexports, __webpack_require__) { - -"use strict"; - - -var defaults = __webpack_require__(727) -var combining = __webpack_require__(634) - -var DEFAULTS = { - nul: 0, - control: 0 -} - -module.exports = function wcwidth(str) { - return wcswidth(str, DEFAULTS) -} + let styler = self._styler; -module.exports.config = function(opts) { - opts = defaults(opts || {}, DEFAULTS) - return function wcwidth(str) { - return wcswidth(str, opts) - } -} + if (styler === undefined) { + return string; + } -/* - * The following functions define the column width of an ISO 10646 - * character as follows: - * - The null character (U+0000) has a column width of 0. - * - Other C0/C1 control characters and DEL will lead to a return value - * of -1. - * - Non-spacing and enclosing combining characters (general category - * code Mn or Me in the - * Unicode database) have a column width of 0. - * - SOFT HYPHEN (U+00AD) has a column width of 1. - * - Other format characters (general category code Cf in the Unicode - * database) and ZERO WIDTH - * SPACE (U+200B) have a column width of 0. - * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) - * have a column width of 0. - * - Spacing characters in the East Asian Wide (W) or East Asian - * Full-width (F) category as - * defined in Unicode Technical Report #11 have a column width of 2. - * - All remaining characters (including all printable ISO 8859-1 and - * WGL4 characters, Unicode control characters, etc.) have a column - * width of 1. - * This implementation assumes that characters are encoded in ISO 10646. -*/ + const {openAll, closeAll} = styler; + if (string.indexOf('\u001B') !== -1) { + while (styler !== undefined) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + string = stringReplaceAll(string, styler.close, styler.open); -function wcswidth(str, opts) { - if (typeof str !== 'string') return wcwidth(str, opts) + styler = styler.parent; + } + } - var s = 0 - for (var i = 0; i < str.length; i++) { - var n = wcwidth(str.charCodeAt(i), opts) - if (n < 0) return -1 - s += n - } + // We can move both next actions out of loop, because remaining actions in loop won't have + // any/visible effect on parts we add here. Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92 + const lfIndex = string.indexOf('\n'); + if (lfIndex !== -1) { + string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); + } - return s -} + return openAll + string + closeAll; +}; -function wcwidth(ucs, opts) { - // test for 8-bit control characters - if (ucs === 0) return opts.nul - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) return opts.control +let template; +const chalkTag = (chalk, ...strings) => { + const [firstString] = strings; - // binary search in table of non-spacing characters - if (bisearch(ucs)) return 0 + if (!Array.isArray(firstString)) { + // If chalk() was called by itself or with a string, + // return the string itself as a string. + return strings.join(' '); + } - // if we arrive here, ucs is not a combining or C0/C1 control character - return 1 + - (ucs >= 0x1100 && - (ucs <= 0x115f || // Hangul Jamo init. consonants - ucs == 0x2329 || ucs == 0x232a || - (ucs >= 0x2e80 && ucs <= 0xa4cf && - ucs != 0x303f) || // CJK ... Yi - (ucs >= 0xac00 && ucs <= 0xd7a3) || // Hangul Syllables - (ucs >= 0xf900 && ucs <= 0xfaff) || // CJK Compatibility Ideographs - (ucs >= 0xfe10 && ucs <= 0xfe19) || // Vertical forms - (ucs >= 0xfe30 && ucs <= 0xfe6f) || // CJK Compatibility Forms - (ucs >= 0xff00 && ucs <= 0xff60) || // Fullwidth Forms - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2fffd) || - (ucs >= 0x30000 && ucs <= 0x3fffd))); -} + const arguments_ = strings.slice(1); + const parts = [firstString.raw[0]]; -function bisearch(ucs) { - var min = 0 - var max = combining.length - 1 - var mid + for (let i = 1; i < firstString.length; i++) { + parts.push( + String(arguments_[i - 1]).replace(/[{}\\]/g, '\\$&'), + String(firstString.raw[i]) + ); + } - if (ucs < combining[0][0] || ucs > combining[max][1]) return false + if (template === undefined) { + template = __webpack_require__(606); + } - while (max >= min) { - mid = Math.floor((min + max) / 2) - if (ucs > combining[mid][1]) min = mid + 1 - else if (ucs < combining[mid][0]) max = mid - 1 - else return true - } + return template(chalk, parts.join('')); +}; - return false -} +Object.defineProperties(Chalk.prototype, styles); +const chalk = Chalk(); // eslint-disable-line new-cap +chalk.supportsColor = stdoutColor; +chalk.stderr = Chalk({level: stderrColor ? stderrColor.level : 0}); // eslint-disable-line new-cap +chalk.stderr.supportsColor = stderrColor; -/***/ }), +// For TypeScript +chalk.Level = { + None: 0, + Basic: 1, + Ansi256: 2, + TrueColor: 3, + 0: 'None', + 1: 'Basic', + 2: 'Ansi256', + 3: 'TrueColor' +}; -/***/ 835: -/***/ (function(module) { +module.exports = chalk; -module.exports = require("url"); /***/ }), @@ -4565,41 +4962,41 @@ module.exports = require("tty"); /***/ 876: /***/ (function(__unusedmodule, exports, __webpack_require__) { -const setContentType = __webpack_require__(427); +const setContentType = __webpack_require__(427) exports.status = (res) => { return (code) => { if (typeof code !== 'number') { - throw new Error('Status Code should be a number'); + throw new Error('Status Code should be a number') } - return (res.statusCode = code); - }; -}; + return (res.statusCode = code) + } +} exports.send = (res) => { return (body) => { - let _body = body; + let _body = body if (Buffer.isBuffer(body)) { - setContentType(res, 'buffer'); + setContentType(res, 'buffer') } else if (typeof body === 'string') { - setContentType(res, 'text'); + setContentType(res, 'text') } else if ( typeof body === 'object' || typeof body === 'boolean' || typeof body === 'number' ) { if (_body === null) { - _body = ''; + _body = '' } - _body = JSON.stringify(_body); - setContentType(res, 'json'); + _body = JSON.stringify(_body) + setContentType(res, 'json') } - res.write(_body); - res.end(); - return; - }; -}; + res.write(_body) + res.end() + return + } +} /***/ }), @@ -5033,37 +5430,11 @@ function assembleStyles() { return styles; } -// Make the export immutable -Object.defineProperty(module, 'exports', { - enumerable: true, - get: assembleStyles -}); - - -/***/ }), - -/***/ 917: -/***/ (function(module, __unusedexports, __webpack_require__) { - -const fs = __webpack_require__(747); -const createRouteDir = __webpack_require__(104); -const path = __webpack_require__(622); - -module.exports = async () => { - try { - const routeDir = await createRouteDir(); - - return new Promise((resolve, reject) => { - fs.readFile(path.join(routeDir, 'routes.json'), (err, data) => { - if (err) reject(err); - resolve(JSON.parse(Buffer.from(data).toString())); - }); - }); - } catch (err) { - console.error(err); - throw err; - } -}; +// Make the export immutable +Object.defineProperty(module, 'exports', { + enumerable: true, + get: assembleStyles +}); /***/ }), @@ -5205,247 +5576,6 @@ module.exports = { }; -/***/ }), - -/***/ 931: -/***/ (function(module, __unusedexports, __webpack_require__) { - -"use strict"; - -const ansiStyles = __webpack_require__(663); -const {stdout: stdoutColor, stderr: stderrColor} = __webpack_require__(247); -const { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex -} = __webpack_require__(493); - -// `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = [ - 'ansi', - 'ansi', - 'ansi256', - 'ansi16m' -]; - -const styles = Object.create(null); - -const applyOptions = (object, options = {}) => { - if (options.level > 3 || options.level < 0) { - throw new Error('The `level` option should be an integer from 0 to 3'); - } - - // Detect level if not set manually - const colorLevel = stdoutColor ? stdoutColor.level : 0; - object.level = options.level === undefined ? colorLevel : options.level; -}; - -class ChalkClass { - constructor(options) { - return chalkFactory(options); - } -} - -const chalkFactory = options => { - const chalk = {}; - applyOptions(chalk, options); - - chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_); - - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); - - chalk.template.constructor = () => { - throw new Error('`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.'); - }; - - chalk.template.Instance = ChalkClass; - - return chalk.template; -}; - -function Chalk(options) { - return chalkFactory(options); -} - -for (const [styleName, style] of Object.entries(ansiStyles)) { - styles[styleName] = { - get() { - const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); - Object.defineProperty(this, styleName, {value: builder}); - return builder; - } - }; -} - -styles.visible = { - get() { - const builder = createBuilder(this, this._styler, true); - Object.defineProperty(this, 'visible', {value: builder}); - return builder; - } -}; - -const usedModels = ['rgb', 'hex', 'keyword', 'hsl', 'hsv', 'hwb', 'ansi', 'ansi256']; - -for (const model of usedModels) { - styles[model] = { - get() { - const {level} = this; - return function (...arguments_) { - const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); - return createBuilder(this, styler, this._isEmpty); - }; - } - }; -} - -for (const model of usedModels) { - const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); - styles[bgModel] = { - get() { - const {level} = this; - return function (...arguments_) { - const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); - return createBuilder(this, styler, this._isEmpty); - }; - } - }; -} - -const proto = Object.defineProperties(() => {}, { - ...styles, - level: { - enumerable: true, - get() { - return this._generator.level; - }, - set(level) { - this._generator.level = level; - } - } -}); - -const createStyler = (open, close, parent) => { - let openAll; - let closeAll; - if (parent === undefined) { - openAll = open; - closeAll = close; - } else { - openAll = parent.openAll + open; - closeAll = close + parent.closeAll; - } - - return { - open, - close, - openAll, - closeAll, - parent - }; -}; - -const createBuilder = (self, _styler, _isEmpty) => { - const builder = (...arguments_) => { - // Single argument is hot path, implicit coercion is faster than anything - // eslint-disable-next-line no-implicit-coercion - return applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' ')); - }; - - // `__proto__` is used because we must return a function, but there is - // no way to create a function with a different prototype - builder.__proto__ = proto; // eslint-disable-line no-proto - - builder._generator = self; - builder._styler = _styler; - builder._isEmpty = _isEmpty; - - return builder; -}; - -const applyStyle = (self, string) => { - if (self.level <= 0 || !string) { - return self._isEmpty ? '' : string; - } - - let styler = self._styler; - - if (styler === undefined) { - return string; - } - - const {openAll, closeAll} = styler; - if (string.indexOf('\u001B') !== -1) { - while (styler !== undefined) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - string = stringReplaceAll(string, styler.close, styler.open); - - styler = styler.parent; - } - } - - // We can move both next actions out of loop, because remaining actions in loop won't have - // any/visible effect on parts we add here. Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92 - const lfIndex = string.indexOf('\n'); - if (lfIndex !== -1) { - string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); - } - - return openAll + string + closeAll; -}; - -let template; -const chalkTag = (chalk, ...strings) => { - const [firstString] = strings; - - if (!Array.isArray(firstString)) { - // If chalk() was called by itself or with a string, - // return the string itself as a string. - return strings.join(' '); - } - - const arguments_ = strings.slice(1); - const parts = [firstString.raw[0]]; - - for (let i = 1; i < firstString.length; i++) { - parts.push( - String(arguments_[i - 1]).replace(/[{}\\]/g, '\\$&'), - String(firstString.raw[i]) - ); - } - - if (template === undefined) { - template = __webpack_require__(706); - } - - return template(chalk, parts.join('')); -}; - -Object.defineProperties(Chalk.prototype, styles); - -const chalk = Chalk(); // eslint-disable-line new-cap -chalk.supportsColor = stdoutColor; -chalk.stderr = Chalk({level: stderrColor ? stderrColor.level : 0}); // eslint-disable-line new-cap -chalk.stderr.supportsColor = stderrColor; - -// For TypeScript -chalk.Level = { - None: 0, - Basic: 1, - Ansi256: 2, - TrueColor: 3, - 0: 'None', - 1: 'Basic', - 2: 'Ansi256', - 3: 'TrueColor' -}; - -module.exports = chalk; - - /***/ }), /***/ 937: @@ -5454,7 +5584,7 @@ module.exports = chalk; "use strict"; const readline = __webpack_require__(58); -const chalk = __webpack_require__(931); +const chalk = __webpack_require__(843); const cliCursor = __webpack_require__(275); const cliSpinners = __webpack_require__(403); const logSymbols = __webpack_require__(598); @@ -5815,29 +5945,44 @@ module.exports.promise = (action, options) => { /***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { -const microServer = __webpack_require__(544); -const setupRoutes = __webpack_require__(116); -const http = __webpack_require__(605); -const PORT = process.env.PORT || 3000; +const microServer = __webpack_require__(544) +const setupRoutes = __webpack_require__(116) +const http = __webpack_require__(605) -setupRoutes(); +const argv = __webpack_require__(109)(process.argv.slice(2)) +const port = argv.p || argv.port || 3000 -http.createServer((req, res) => { - microServer(req, res); -}).listen(PORT, () => { - console.log('> Listening on ' + PORT); -}); +setupRoutes() + .then((availableRoutes) => { + http.createServer((req, res) => { + microServer(req, res, availableRoutes) + }).listen(port, () => { + console.log('> Listening on ' + port) + }) + }) + .catch((err) => { + console.log(err) + throw err + }) /***/ }), /***/ 973: -/***/ (function(module) { +/***/ (function(module, __unusedexports, __webpack_require__) { + +const path = __webpack_require__(622) +const argv = __webpack_require__(109)(process.argv.slice(2)) + +let _basePath module.exports = () => { - const currPath = `${process.cwd()}`; - return currPath; -}; + if (!_basePath) { + const dir = argv.d || argv.dir || 'api' + _basePath = path.join(process.cwd(), dir) + } + return _basePath +} /***/ }) diff --git a/docs/index.html b/docs/index.html index 98d80ee..22bed47 100644 --- a/docs/index.html +++ b/docs/index.html @@ -17,40 +17,43 @@

Routex

A minimal file tree based api router for building rest api's with node.

-

Motivation

+

About

- I'm one of the many people who use - Next.js(Vercel) and - while the whole framework is great, I'm a huge fan of the API - routes mechanism and thought I'd implement my own version of it - so I can continue having seperate backend and frontend code while - having the ease of writing api routes also, wanted to learn how this - stuff works. (I'm curious like that). + RouteX started as a clone of the Next.js' Api Routes + implmentation and is now on it's path to compete with other + frameworks as the simplest way to setup API routes. There's been + numerous posts on why using the folder tree makes it atomic and + easier to handle the separation between logic. While you cannot + bundle code with routex since each file is independent of the other + and doesn't need the others for its execution.

-

Roadmap (as of now)

+

+ The Idea and Inspiration for the creation remains to be Vercel's + Next.js +

+

Changes (6/Jul/2020)

-

That's all I want the routex to do for now.

+

Performace

+

+ Screenshot of autocannon to benchmark + /api from the examples folder +

+

GitHub Logo

Warning

This library is still in active development and is bound to have @@ -60,33 +63,31 @@

Warning

Current Limitations

-

Usage

-

- Any file inside the folder api is mapped to - /api/* and will be treated as an API endpoint and all - HTTP requests will be passed to this file. GET, POST, PUT, DELETE -

+

Installation

+

Stable Cli

# for global install to avoid installing the devDependencies
 npm i -g barelyhuman/routex --only=prod
 # for local install to avoid installing the devDependencies
-npm i barelyhuman/routex --only=prod
+npm i barelyhuman/routex --only=prod + +

Canary Cli

+
# for global install to avoid installing the devDependencies
+npm i -g barelyhuman/routex#canary --only=prod
+# for local install to avoid installing the devDependencies
+npm i barelyhuman/routex#canary --only=prod
+

Usage

- Then go ahead and create directories and files under the - api folder as mentioned or check the - examples folder for reference. + Any folder that routex is run in will be considered the API root and + will look for an api folder in the run location. +

+

+ Then go ahead and create directories and files under any folder as + mentioned or check the examples folder for reference.

Example file tree:

- api
@@ -119,18 +120,31 @@ 

Usage

Then run routex on the root folder of the project, this folder - should contain the api folder + should contain the api folder or specify a directory + using the -d or --dir command.

# If installed globally
 routex
 # If installed locally
 npx routex
 
-

Rules

+

CLI Commands

+

+ Example, the following would use the example folder as + the base path for the routes and start the server on port + 3001 +

+
  routex -d ./example -p 3001
+
diff --git a/docs/perf.png b/docs/perf.png new file mode 100644 index 0000000..f903a67 Binary files /dev/null and b/docs/perf.png differ diff --git a/example/api/[id]/[userId]/index.js b/example/api/[id]/[userId]/index.js index 015bd38..9b6124f 100644 --- a/example/api/[id]/[userId]/index.js +++ b/example/api/[id]/[userId]/index.js @@ -1,5 +1,5 @@ module.exports = (req, res) => { - res.write('From /api/:id/:userId'); - res.write(`\n${JSON.stringify(req.params)}`); - res.end(); -}; + res.write('From /api/:id/:userId') + res.write(`\n${JSON.stringify(req.params)}`) + res.end() +} diff --git a/example/api/[id]/index.js b/example/api/[id]/index.js index e664ce3..3134d2c 100644 --- a/example/api/[id]/index.js +++ b/example/api/[id]/index.js @@ -1,10 +1,7 @@ module.exports = (req, res) => { if (req.method === 'GET') { - res.write('Dynamic folder route'); - res.end(); - return; + return res.send('Dynamic folder route') } - res.statusCode = 404; - res.end(); - return; -}; + res.status(404) + return res.end() +} diff --git a/example/api/hello/index.js b/example/api/hello/index.js index 60884dd..52caa0f 100644 --- a/example/api/hello/index.js +++ b/example/api/hello/index.js @@ -1,3 +1,3 @@ module.exports = (req, res) => { - return res.end('hello'); -}; + return res.end('hello') +} diff --git a/example/api/hello/user.js b/example/api/hello/user.js index b49952f..161ca42 100644 --- a/example/api/hello/user.js +++ b/example/api/hello/user.js @@ -1,3 +1,3 @@ module.exports = (req, res) => { - return res.end('user'); -}; + return res.end('user') +} diff --git a/example/api/index.js b/example/api/index.js index 0855163..fe6c6d6 100644 --- a/example/api/index.js +++ b/example/api/index.js @@ -1,8 +1,7 @@ module.exports = (req, res) => { if (req.method === 'GET') { - res.status(200); - return res.send({ status: 'up' }); + return res.send({ status: 'up' }) } - res.status(400); - res.send('

Error

'); -}; + res.status(400) + res.send('

Error

') +} diff --git a/example/api/me.js b/example/api/me.js index 8d2d5d8..3086e8e 100644 --- a/example/api/me.js +++ b/example/api/me.js @@ -1,6 +1,6 @@ module.exports = (req, res) => { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write(JSON.stringify(req.query)); - res.write('Hello World!'); - res.end(); -}; + return res.send({ + query: JSON.stringify(req.query), + message: 'Hello', + }) +} diff --git a/example/api/profile/[profileId].js b/example/api/profile/[profileId].js index 9735294..daabadb 100644 --- a/example/api/profile/[profileId].js +++ b/example/api/profile/[profileId].js @@ -1,4 +1,4 @@ module.exports = (req, res) => { - res.write(JSON.stringify(req.params)); - res.end(); -}; + res.write(JSON.stringify(req.params)) + res.end() +} diff --git a/example/api/user/[id].js b/example/api/user/[id].js index d037655..8b6d8c5 100644 --- a/example/api/user/[id].js +++ b/example/api/user/[id].js @@ -1,5 +1,5 @@ module.exports = (req, res) => { - res.write('from dynamic route'); - res.write('\npath param ' + JSON.stringify(req.params)); - res.end(); -}; + res.write('from dynamic route') + res.write('\npath param ' + JSON.stringify(req.params)) + res.end() +} diff --git a/example/api/user/delete/[id].js b/example/api/user/delete/[id].js index f177380..50885a0 100644 --- a/example/api/user/delete/[id].js +++ b/example/api/user/delete/[id].js @@ -1,4 +1,4 @@ module.exports = (req, res) => { - res.write('Deleting,' + JSON.stringify(req.params)); - res.end(); -}; + res.write('Deleting,' + JSON.stringify(req.params)) + res.end() +} diff --git a/example/index.js b/example/index.js new file mode 100644 index 0000000..e21c1ca --- /dev/null +++ b/example/index.js @@ -0,0 +1,3 @@ +module.exports = (req, res) => { + return res.send({ index: 'up' }) +} diff --git a/example/outer-route.js b/example/outer-route.js new file mode 100644 index 0000000..e6a2de1 --- /dev/null +++ b/example/outer-route.js @@ -0,0 +1,3 @@ +module.exports = (req, res) => { + return res.send({ outer: 'up' }) +} diff --git a/lib/base-path.js b/lib/base-path.js index 83b1fd8..bdd0dd8 100644 --- a/lib/base-path.js +++ b/lib/base-path.js @@ -1,4 +1,12 @@ +const path = require('path') +const argv = require('minimist')(process.argv.slice(2)) + +let _basePath + module.exports = () => { - const currPath = `${process.cwd()}`; - return currPath; -}; + if (!_basePath) { + const dir = argv.d || argv.dir || 'api' + _basePath = path.join(process.cwd(), dir) + } + return _basePath +} diff --git a/lib/check-api-dir.js b/lib/check-api-dir.js index 9fb030e..46c0d61 100644 --- a/lib/check-api-dir.js +++ b/lib/check-api-dir.js @@ -1,5 +1,5 @@ module.exports = (dirs) => { - const exists = dirs.find((item) => item === 'api'); - const valid = exists ? true : false; - return { valid, path: exists }; -}; + const exists = dirs.find((item) => item === 'api') + const valid = exists ? true : false + return { valid, path: exists } +} diff --git a/lib/create-available-routes.js b/lib/create-available-routes.js index c5e2f23..caa894f 100644 --- a/lib/create-available-routes.js +++ b/lib/create-available-routes.js @@ -1,87 +1,78 @@ -const fs = require('fs').promises; -const path = require('path'); +const fs = require('fs').promises +const path = require('path') module.exports = async (directory) => { try { - const routeTree = {}; - - let currentPointer = routeTree; - - await processDirectory(directory, 'api', currentPointer); - - return routeTree; + const routeTree = {} + let currentPointer = routeTree + await processDirectory(directory, '.', currentPointer) + return routeTree } catch (err) { - console.error(err); - throw err; + console.error(err) + throw err } -}; +} async function processDirectory(currPath, dir, pointer) { try { - const pathToCheck = path.join(currPath, dir); - const pathStat = await fs.stat(pathToCheck); + const pathToCheck = path.join(currPath, dir) + const pathStat = await fs.stat(pathToCheck) if (pathStat.isDirectory()) { - const dirContent = await fs.readdir(pathToCheck); + const dirContent = await fs.readdir(pathToCheck) const treeMods = dirContent.map(async (fileRecord) => { - const nextPathToCheck = path.join(pathToCheck, fileRecord); - const nextFile = await fs.stat(nextPathToCheck); + const nextPathToCheck = path.join(pathToCheck, fileRecord) + const nextFile = await fs.stat(nextPathToCheck) const nextPointer = pointer[dir] || (pointer[dir] = { type: 'dir', - }); - const paramRegex = /^\[(\w+)\]$/; + }) + const paramRegex = /^\[(\w+)\]$/ if (paramRegex.test(dir)) { - debugger; - const matchingParams = dir.match(paramRegex); - const param = matchingParams[1]; - pointer[dir].params = [param]; - debugger; + const matchingParams = dir.match(paramRegex) + const param = matchingParams[1] + pointer[dir].params = [param] } if (nextFile.isDirectory()) { - await processDirectory( - pathToCheck, - fileRecord, - nextPointer - ); + await processDirectory(pathToCheck, fileRecord, nextPointer) } else if (nextFile.isFile()) { - processFile(fileRecord, nextPointer); + processFile(fileRecord, nextPointer) } - return Promise.resolve(); - }); + return Promise.resolve() + }) - await Promise.all(treeMods); + await Promise.all(treeMods) } else if (pathStat.isFile()) { - processFile(dir, pointer); + processFile(dir, pointer) } } catch (err) { - console.error(err); - throw err; + console.error(err) + throw err } } function processFile(file, pointer) { - const paramRegex = /^\[(\w+)\].js$/; + const paramRegex = /^\[(\w+)\].js$/ if (paramRegex.test(file)) { - const matchingParams = file.match(paramRegex); - const param = matchingParams[1]; - const noExt = file.replace('.js', ''); + const matchingParams = file.match(paramRegex) + const param = matchingParams[1] + const noExt = file.replace('.js', '') const valuesInsertion = { type: 'file', params: [param], index: file, - }; - pointer[noExt] = valuesInsertion; + } + pointer[noExt] = valuesInsertion } else if (file === 'index.js') { - pointer.type = 'dir'; - pointer.index = 'index.js'; + pointer.type = 'dir' + pointer.index = 'index.js' } else { - const noExt = file.replace('.js', ''); + const noExt = file.replace('.js', '') const valuesInsertion = { type: 'file', index: file, - }; - pointer[noExt] = valuesInsertion; + } + pointer[noExt] = valuesInsertion } } diff --git a/lib/create-route-dir.js b/lib/create-route-dir.js index 255dea2..1570c57 100644 --- a/lib/create-route-dir.js +++ b/lib/create-route-dir.js @@ -1,36 +1,36 @@ -const basePath = require('./base-path'); -const fs = require('fs'); -const path = require('path'); +const basePath = require('./base-path') +const fs = require('fs') +const path = require('path') module.exports = async () => { try { - const creationPath = path.join(basePath(), '.route'); + const creationPath = path.join(basePath(), '.route') const exists = await new Promise((resolve, reject) => { fs.stat(creationPath, (err, stat) => { if ( (err && err.code === 'ENOENT') || (err && err.code === 'ENOTDIR') ) { - resolve(false); + resolve(false) } - return resolve(true); - }); - }); + return resolve(true) + }) + }) if (exists) { - return creationPath; + return creationPath } else { await new Promise((resolve, reject) => { fs.mkdir(creationPath, (err, done) => { - if (err) reject(err); - resolve(done); - }); - }); + if (err) reject(err) + resolve(done) + }) + }) } - return creationPath; + return creationPath } catch (err) { - console.error(err); - throw err; + console.error(err) + throw err } -}; +} diff --git a/lib/get-available-routes.js b/lib/get-available-routes.js index d898586..b641424 100644 --- a/lib/get-available-routes.js +++ b/lib/get-available-routes.js @@ -1,19 +1,19 @@ -const fs = require('fs'); -const createRouteDir = require('./create-route-dir'); -const path = require('path'); +const fs = require('fs') +const createRouteDir = require('./create-route-dir') +const path = require('path') module.exports = async () => { try { - const routeDir = await createRouteDir(); + const routeDir = await createRouteDir() return new Promise((resolve, reject) => { fs.readFile(path.join(routeDir, 'routes.json'), (err, data) => { - if (err) reject(err); - resolve(JSON.parse(Buffer.from(data).toString())); - }); - }); + if (err) reject(err) + resolve(JSON.parse(Buffer.from(data).toString())) + }) + }) } catch (err) { - console.error(err); - throw err; + console.error(err) + throw err } -}; +} diff --git a/lib/is-dynamic-param.js b/lib/is-dynamic-param.js index 13119c6..acba610 100644 --- a/lib/is-dynamic-param.js +++ b/lib/is-dynamic-param.js @@ -1,17 +1,17 @@ -const paramRegexExt = /^\[(\w+)\].js$/; -const paramRegex = /^\[(\w+)\]$/; +const paramRegexExt = /^\[(\w+)\].js$/ +const paramRegex = /^\[(\w+)\]$/ module.exports = (pathParam) => { if (paramRegex.test(pathParam)) { return { valid: true, regex: paramRegex, - }; + } } if (paramRegexExt.test(pathParam)) { - return { valid: true, regex: paramRegexExt }; + return { valid: true, regex: paramRegexExt } } - return { valid: false }; -}; + return { valid: false } +} diff --git a/lib/micro-server.js b/lib/micro-server.js index d653951..d5f5e51 100644 --- a/lib/micro-server.js +++ b/lib/micro-server.js @@ -1,13 +1,10 @@ -const router = require('./router'); -const getAvailableRoutes = require('./get-available-routes'); +const router = require('./router') -module.exports = async (req, res) => { +module.exports = async (req, res, availableRoutes) => { try { - const availableRoutes = await getAvailableRoutes(); - - return router(availableRoutes, req, res); + return router(availableRoutes, req, res) } catch (err) { - console.error(err); - throw err; + console.error(err) + throw err } -}; +} diff --git a/lib/parse-url.js b/lib/parse-url.js index fdf93c8..c05b5de 100644 --- a/lib/parse-url.js +++ b/lib/parse-url.js @@ -1,15 +1,15 @@ -const url = require('url'); -const querystring = require('querystring'); +const url = require('url') +const querystring = require('querystring') module.exports = (urlstring) => { - const _url = url.parse(urlstring); - const paths = _url.pathname.split('/').filter((item) => item); - let queryParams = {}; + const _url = url.parse(urlstring) + const paths = _url.pathname.split('/').filter((item) => item) + let queryParams = {} if (_url.search && _url.search.length > 0) { - queryParams = querystring.parse(_url.search.replace('?', '')); + queryParams = querystring.parse(_url.search.replace('?', '')) } return { paths, query: queryParams, - }; -}; + } +} diff --git a/lib/process-dirs.js b/lib/process-dirs.js index 10e4f2c..3751aa8 100644 --- a/lib/process-dirs.js +++ b/lib/process-dirs.js @@ -1,35 +1,17 @@ -const fs = require('fs'); -const path = require('path'); -const createRouteDir = require('./create-route-dir'); -const createAvailableRoutes = require('./create-available-routes'); -const ora = require('ora'); +const createAvailableRoutes = require('./create-available-routes') +const ora = require('ora') module.exports = async (directory) => { - const spinner = ora('Compiling...').start(); try { - const availableRoutesTree = await createAvailableRoutes(directory); - - const routePath = await createRouteDir(); - - await new Promise((resolve, reject) => { - fs.writeFile( - path.join(routePath, 'routes.json'), - JSON.stringify(availableRoutesTree), - (err, done) => { - if (err) reject(err); - resolve(done); - } - ); - }); - - setTimeout(() => { - spinner.succeed('Compiled'); - }, 1000); + const spinner = ora('Compiling...').start() + const availableRoutesTree = await createAvailableRoutes(directory) + spinner.succeed('Compiled') + return availableRoutesTree } catch (err) { - spinner.color = 'red'; - spinner.text = 'Failed'; - spinner.fail(); - console.error(err); - throw err; + spinner.color = 'red' + spinner.text = 'Failed' + spinner.fail() + console.error(err) + throw err } -}; +} diff --git a/lib/request-helpers.js b/lib/request-helpers.js index 2dab8d2..867e846 100644 --- a/lib/request-helpers.js +++ b/lib/request-helpers.js @@ -1,35 +1,35 @@ -const setContentType = require('./set-content-type'); +const setContentType = require('./set-content-type') exports.status = (res) => { return (code) => { if (typeof code !== 'number') { - throw new Error('Status Code should be a number'); + throw new Error('Status Code should be a number') } - return (res.statusCode = code); - }; -}; + return (res.statusCode = code) + } +} exports.send = (res) => { return (body) => { - let _body = body; + let _body = body if (Buffer.isBuffer(body)) { - setContentType(res, 'buffer'); + setContentType(res, 'buffer') } else if (typeof body === 'string') { - setContentType(res, 'text'); + setContentType(res, 'text') } else if ( typeof body === 'object' || typeof body === 'boolean' || typeof body === 'number' ) { if (_body === null) { - _body = ''; + _body = '' } - _body = JSON.stringify(_body); - setContentType(res, 'json'); + _body = JSON.stringify(_body) + setContentType(res, 'json') } - res.write(_body); - res.end(); - return; - }; -}; + res.write(_body) + res.end() + return + } +} diff --git a/lib/router.js b/lib/router.js index 56caf5a..5a44d89 100644 --- a/lib/router.js +++ b/lib/router.js @@ -1,83 +1,81 @@ -const basePath = require('./base-path'); -const path = require('path'); -const parseUrl = require('./parse-url'); -const { send, status } = require('./request-helpers'); +const basePath = require('./base-path') +const path = require('path') +const parseUrl = require('./parse-url') +const { send, status } = require('./request-helpers') module.exports = async (availableRoutes, req, res) => { try { - const parsedRouteUrl = parseUrl(req.url); - let handlerPath = ''; - let currentPointer = availableRoutes; + const parsedRouteUrl = parseUrl(req.url) - // Attach Helpers - res.send = send(res); - res.status = status(res); - // + let handlerPath = '' + let currentPointer = availableRoutes['.'] - parsedRouteUrl.paths.forEach((item) => { - let matchingKey; + for (let i = 0; i < parsedRouteUrl.paths.length; i += 1) { + const item = parsedRouteUrl.paths[i] + let matchingKey if (!currentPointer[item]) { matchingKey = Object.keys(currentPointer).find( (key) => currentPointer[key].params && currentPointer[key].params.length > 0 - ); + ) if (matchingKey) { - currentPointer = currentPointer[matchingKey]; - const key = matchingKey.replace(/[\[\]]/g, ''); + currentPointer = currentPointer[matchingKey] + const key = matchingKey.replace(/[\[\]]/g, '') req.params = { ...req.params, [key]: item, - }; + } } else { - currentPointer = null; - return; + currentPointer = null + break } } else { - currentPointer = currentPointer[item]; + currentPointer = currentPointer[item] } if (currentPointer) { if (currentPointer.type === 'file') { - handlerPath += currentPointer.index; + handlerPath += currentPointer.index } else { if (matchingKey) { - handlerPath += matchingKey + '/'; + handlerPath += matchingKey + '/' } else { - handlerPath += item + '/'; + handlerPath += item + '/' } } } - }); + } if (!currentPointer || !currentPointer.type) { - res.statusCode = 404; - res.end(); - return; + res.statusCode = 404 + res.end() + return } if (currentPointer.type === 'dir') { if (currentPointer.index) { - handlerPath += currentPointer.index; + handlerPath += currentPointer.index } else { - res.statusCode = 404; - res.end(); - return; + res.statusCode = 404 + res.end() + return } } - let _handlerPath = path.join(basePath(), handlerPath); - - req.query = parsedRouteUrl.query; + let _handlerPath = path.join(basePath(), handlerPath) - const handler = require(_handlerPath); + // Attach helpers and parsed query data + res.send = send(res) + res.status = status(res) + req.query = parsedRouteUrl.query - return handler(req, res); + return require(_handlerPath)(req, res) } catch (err) { - console.error(err); - res.statusCode(500); - res.end(); - throw err; + console.error(err) + res.status(500) + res.end() + throw err } -}; +} diff --git a/lib/set-content-type.js b/lib/set-content-type.js index 441d479..94a9bdf 100644 --- a/lib/set-content-type.js +++ b/lib/set-content-type.js @@ -1,16 +1,16 @@ module.exports = (res, type) => { - let _type = type; + let _type = type const cases = { json: 'application/json', buffer: 'application/octet-stream', text: 'text/html', - }; + } if (!cases[type]) { - _type = cases.text; + _type = cases.text } - res.setHeader('Content-Type', _type); - return; -}; + res.setHeader('Content-Type', _type) + return +} diff --git a/lib/setup-routes.js b/lib/setup-routes.js index 3adc663..c2e3000 100644 --- a/lib/setup-routes.js +++ b/lib/setup-routes.js @@ -1,17 +1,8 @@ -const basePath = require('./base-path'); -const fs = require('fs'); -const path = require('path'); -const checkApiDir = require('./check-api-dir'); -const processDirectories = require('./process-dirs'); +const basePath = require('./base-path') +const path = require('path') +const processDirectories = require('./process-dirs') module.exports = () => { - fs.readdir(basePath(), function (err, dirs) { - if (err) throw err; - const apiDirExists = checkApiDir(dirs); - if (!apiDirExists.valid) { - throw new Error('cannot find an `api` directory'); - } - const processingPath = path.join(basePath()); - return processDirectories(processingPath); - }); -}; + const processingPath = path.join(basePath()) + return processDirectories(processingPath) +} diff --git a/package-lock.json b/package-lock.json index ea5a0fb..35d65d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -85,7 +85,8 @@ "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true }, "@types/parse-json": { "version": "4.0.0", @@ -127,12 +128,14 @@ "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, "requires": { "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" @@ -144,6 +147,31 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "dev": true, + "requires": { + "follow-redirects": "1.5.10" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -163,6 +191,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -184,6 +213,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, "requires": { "restore-cursor": "^3.1.0" } @@ -191,7 +221,8 @@ "cli-spinners": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz", - "integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==" + "integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==", + "dev": true }, "cli-truncate": { "version": "2.1.0", @@ -206,12 +237,14 @@ "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { "color-name": "~1.1.4" } @@ -219,7 +252,8 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "commander": { "version": "5.1.0", @@ -233,6 +267,12 @@ "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", "dev": true }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, "cosmiconfig": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", @@ -276,10 +316,20 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, "requires": { "clone": "^1.0.2" } }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -313,10 +363,41 @@ "is-arrayish": "^0.2.1" } }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "execa": { "version": "4.0.2", @@ -372,6 +453,38 @@ "semver-regex": "^2.0.0" } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dev": true, + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "get-own-enumerable-property-symbols": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", @@ -387,10 +500,38 @@ "pump": "^3.0.0" } }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true }, "human-signals": { "version": "1.1.1", @@ -450,6 +591,18 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -459,7 +612,8 @@ "is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true }, "is-number": { "version": "7.0.0", @@ -473,6 +627,15 @@ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, "is-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", @@ -485,6 +648,15 @@ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -581,6 +753,30 @@ } } }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + } + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -594,6 +790,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, "requires": { "chalk": "^2.4.2" }, @@ -602,6 +799,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -610,6 +808,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -620,6 +819,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -627,17 +827,20 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -675,6 +878,12 @@ "integrity": "sha512-EkE7RW6KcXfMHy2PA7Jg0YJE1l8UPEZE8k45tylzmZM30/r1M1MUXWQfJlrSbsTeh7m/XTwHbWUENvAJZpp1YA==", "dev": true }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -694,7 +903,23 @@ "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true }, "ms": { "version": "2.1.2", @@ -705,7 +930,26 @@ "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } }, "normalize-path": { "version": "3.0.0", @@ -713,6 +957,118 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -722,6 +1078,30 @@ "path-key": "^3.0.0" } }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -735,6 +1115,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, "requires": { "mimic-fn": "^2.1.0" } @@ -749,6 +1130,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/ora/-/ora-4.0.4.tgz", "integrity": "sha512-77iGeVU1cIdRhgFzCK8aw1fbtT1B/iZAvWjS+l/o1x0RShMgxHUZaD2yDpWsNCPwXg9z1ZA78Kbdvr8kBmG/Ww==", + "dev": true, "requires": { "chalk": "^3.0.0", "cli-cursor": "^3.1.0", @@ -826,6 +1208,12 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -838,6 +1226,18 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, + "pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, "pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -872,6 +1272,37 @@ "once": "^1.3.1" } }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + } + } + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -882,6 +1313,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, "requires": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -896,6 +1328,12 @@ "tslib": "^1.9.0" } }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, "semver-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", @@ -923,10 +1361,17 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true }, "slash": { "version": "3.0.0", @@ -945,6 +1390,38 @@ "is-fullwidth-code-point": "^3.0.0" } }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, "string-argv": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", @@ -962,6 +1439,36 @@ "strip-ansi": "^6.0.0" } }, + "string.prototype.padend": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz", + "integrity": "sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "stringify-object": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", @@ -977,10 +1484,17 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, "requires": { "ansi-regex": "^5.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -991,6 +1505,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -1022,10 +1537,21 @@ "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", "dev": true }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, "requires": { "defaults": "^1.0.3" } diff --git a/package.json b/package.json index cab5494..804af9c 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "routex": "dist/index.js" }, "scripts": { - "dev": "cd example && nodemon ../app.js", - "dev:inspect": "cd example && nodemon --inspect-brk ../app.js", - "start": "cd example && node ../app.js", + "dev": "nodemon --inspect ./app.js -p 3000 --dir ./example", + "dev:inspect": "nodemon --inspect-brk ./app.js -p 3000 --dir ./example", + "start": "node ./app.js -d ./example", "format": "prettier --write .", "create:doc": "node create-docs.js && git add docs/index.html", "build": "ncc build app.js -o dist && git add .", @@ -26,17 +26,17 @@ "url": "https://github.com/barelyhuman/routex/issues" }, "homepage": "https://github.com/barelyhuman/routex#readme", - "dependencies": { - "ora": "^4.0.4" - }, + "dependencies": {}, "devDependencies": { "@zeit/ncc": "^0.22.3", - "npm-run-all": "^4.1.5", "axios": "^0.19.2", "husky": ">=4", "lint-staged": ">=10", "marked": "^1.1.0", - "prettier": "^2.0.5" + "npm-run-all": "^4.1.5", + "prettier": "^2.0.5", + "minimist": "^1.2.5", + "ora": "^4.0.4" }, "husky": { "hooks": { diff --git a/tests/endpoints.js b/tests/endpoints.js index 138788d..fa66940 100644 --- a/tests/endpoints.js +++ b/tests/endpoints.js @@ -1,6 +1,6 @@ -const axios = require('axios'); +const axios = require('axios') -const baseURL = 'http://localhost:3000'; +const baseURL = 'http://localhost:3000' const passingCases = [ { @@ -39,7 +39,15 @@ const passingCases = [ path: 'api/me?query=somequerystring', method: 'get', }, -]; + { + path: '/', + method: 'get', + }, + { + path: '/outer-route', + method: 'get', + }, +] const failingCases = [ { @@ -54,49 +62,49 @@ const failingCases = [ path: 'api/hello/idexist', method: 'post', }, -]; +] const instance = axios.create({ baseURL, -}); +}) function runCases(cases, shouldFail) { - let successful = []; - let failed = []; + let successful = [] + let failed = [] const promises = cases.map((item) => { return instance[item.method](item.path) .then(() => { if (shouldFail) { - failed.push(item); + failed.push(item) } else { - successful.push(item); + successful.push(item) } }) .catch((err) => { if (shouldFail) { - successful.push(item); + successful.push(item) } else { - failed.push(item); + failed.push(item) } - }); - }); + }) + }) return Promise.all(promises).then(() => { - console.log('================================================='); - console.log('Successful' + JSON.stringify(successful, null, 2)); - console.log('================================================='); - console.log('Failed' + JSON.stringify(failed, null, 2)); - console.log('================================================='); - }); + console.log('=================================================') + console.log('Successful' + JSON.stringify(successful, null, 2)) + console.log('=================================================') + console.log('Failed' + JSON.stringify(failed, null, 2)) + console.log('=================================================') + }) } -console.log('================================================='); -console.log('Running Passing Cases'); +console.log('=================================================') +console.log('Running Passing Cases') runCases(passingCases, false).then(() => { - console.log('================================================='); - console.log('Running Failing Cases'); + console.log('=================================================') + console.log('Running Failing Cases') runCases(failingCases, true).then(() => { - process.exit(0); - }); -}); + process.exit(0) + }) +})