diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..777998e --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,39 @@ +{ + "root": true, + "rules": { + "indent": [ 2, "tab", { "SwitchCase": 1 } ], + "semi": [ 2, "always" ], + "space-before-blocks": [ 2, "always" ], + "no-mixed-spaces-and-tabs": [ 2, "smart-tabs" ], + "no-cond-assign": 0, + "no-unused-vars": 2, + "object-shorthand": [ 2, "always" ], + "no-const-assign": 2, + "no-class-assign": 2, + "no-this-before-super": 2, + "no-var": 2, + "no-unreachable": 2, + "valid-typeof": 2, + "quote-props": [ 2, "as-needed" ], + "one-var": [ 2, "never" ], + "prefer-arrow-callback": 2, + "prefer-const": [ 2, { "destructuring": "all" } ], + "arrow-spacing": 2, + "no-inner-declarations": 0 + }, + "env": { + "es6": true, + "browser": true, + "node": true, + "mocha": true + }, + "extends": [ + "eslint:recommended", + "plugin:import/errors", + "plugin:import/warnings" + ], + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + } +} diff --git a/cli/index.js b/cli/index.js new file mode 100755 index 0000000..4c50494 --- /dev/null +++ b/cli/index.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +const cmd = process.argv[2]; + +if (cmd === 'build') { + process.env.NODE_ENV = 'production'; + require('../lib/build.js')(); +} \ No newline at end of file diff --git a/lib/build.js b/lib/build.js new file mode 100644 index 0000000..22e6e38 --- /dev/null +++ b/lib/build.js @@ -0,0 +1,38 @@ +const fs = require('fs'); +const path = require('path'); +const glob = require('glob'); +const { client, server } = require('./utils/compilers.js'); +const create_app = require('./utils/create_app.js'); +const generate_asset_cache = require('./utils/generate_asset_cache.js'); +const { dest } = require('./config.js'); + +module.exports = () => { + // create main.js and server-routes.js + create_app(); + + function handleErrors(err, stats) { + if (err) { + console.error(err ? err.details || err.stack || err.message || err : 'Unknown error'); + process.exit(1); + } + + if (stats.hasErrors()) { + console.log(stats.toString({ colors: true })); + process.exit(1); + } + } + + client.run((err, clientStats) => { + handleErrors(err, clientStats); + const clientInfo = clientStats.toJson(); + fs.writeFileSync(path.join(dest, 'stats.client.json'), JSON.stringify(clientInfo, null, ' ')); + + server.run((err, serverStats) => { + handleErrors(err, serverStats); + const serverInfo = serverStats.toJson(); + fs.writeFileSync(path.join(dest, 'stats.server.json'), JSON.stringify(serverInfo, null, ' ')); + + generate_asset_cache(clientInfo, serverInfo); + }); + }); +}; \ No newline at end of file diff --git a/lib/config.js b/lib/config.js index 18e3732..0c77c59 100644 --- a/lib/config.js +++ b/lib/config.js @@ -13,7 +13,9 @@ exports.dest = path.resolve( process.env.SAPPER_DEST || '.sapper' ); -mkdirp(exports.dest); -rimraf.sync(path.join(exports.dest, '**/*')); +if (exports.dev) { + mkdirp(exports.dest); + rimraf.sync(path.join(exports.dest, '**/*')); +} exports.server_routes = path.resolve(exports.dest, 'server-routes.js'); \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 536ea0b..5d5a7bb 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,91 +4,137 @@ const glob = require('glob'); const rimraf = require('rimraf'); const mkdirp = require('mkdirp'); const webpack = require('webpack'); -const create_routes = require('./utils/create_routes.js'); +const route_manager = require('./route_manager.js'); const templates = require('./templates.js'); const create_app = require('./utils/create_app.js'); -const create_compiler = require('./utils/create_compiler.js'); +const create_watcher = require('./utils/create_watcher.js'); +const compilers = require('./utils/compilers.js'); +const generate_asset_cache = require('./utils/generate_asset_cache.js'); const escape_html = require('escape-html'); const { src, dest, dev } = require('./config.js'); -module.exports = function connect(opts) { - let routes = create_routes( - glob.sync('**/*.+(html|js|mjs)', { cwd: src }) - ); +function connect_dev() { + // create main.js and server-routes.js + // TODO update on changes + create_app(); - create_app(src, dest, routes, opts); + const watcher = create_watcher(); - const client = webpack( - require(path.resolve('webpack.client.config.js')) - ); + let asset_cache; - const server = webpack( - require(path.resolve('webpack.server.config.js')) - ); + return compose_handlers([ + require('webpack-hot-middleware')(compilers.client, { + reload: true, + path: '/__webpack_hmr', + heartbeat: 10 * 1000 + }), - const compiler = create_compiler( - client, - server, - dest, - routes, - dev - ); - - async function handle_webpack_generated_files(req, res, next) { - if (req.pathname.startsWith('/client/')) { - await compiler.ready; - res.set({ - 'Content-Type': 'application/javascript', - 'Cache-Control': 'max-age=31536000' - }); - res.end(compiler.asset_cache[req.pathname]); - } else { + async (req, res, next) => { + asset_cache = await watcher.ready; next(); - } - } + }, - async function handle_index(req, res, next) { - if (req.pathname === '/index.html') { - await compiler.ready; - res.set({ - 'Content-Type': 'text/html', - 'Cache-Control': dev ? 'no-cache' : 'max-age=600' - }); - res.end(compiler.shell); - } else { - next(); - } - } + set_req_pathname, - async function handle_service_worker(req, res, next) { - if (req.pathname === '/service-worker.js') { - await compiler.ready; - res.set({ - 'Content-Type': 'application/javascript', - 'Cache-Control': dev ? 'no-cache' : 'max-age=600' - }); - res.end(compiler.service_worker); - } else { - next(); - } - } + get_asset_handler({ + filter: pathname => pathname === '/index.html', + type: 'text/html', + cache: 'max-age=600', + fn: () => asset_cache.client.index + }), - async function handle_route(req, res, next) { + get_asset_handler({ + filter: pathname => pathname === '/service-worker.js', + type: 'application/javascript', + cache: 'max-age=600', + fn: () => asset_cache.client.service_worker + }), + + get_asset_handler({ + filter: pathname => pathname.startsWith('/client/'), + type: 'application/javascript', + cache: 'max-age=31536000', + fn: pathname => asset_cache.client.chunks[pathname] + }), + + get_route_handler(() => asset_cache), + + not_found + ]); +} + +function connect_prod() { + const asset_cache = generate_asset_cache( + read_json(path.join(dest, 'stats.client.json')), + read_json(path.join(dest, 'stats.server.json')) + ); + + return compose_handlers([ + set_req_pathname, + + get_asset_handler({ + filter: pathname => pathname === '/index.html', + type: 'text/html', + cache: 'max-age=600', + fn: () => asset_cache.client.index + }), + + get_asset_handler({ + filter: pathname => pathname === '/service-worker.js', + type: 'application/javascript', + cache: 'max-age=600', + fn: () => asset_cache.client.service_worker + }), + + get_asset_handler({ + filter: pathname => pathname.startsWith('/client/'), + type: 'application/javascript', + cache: 'max-age=31536000', + fn: pathname => asset_cache.client.chunks[pathname] + }), + + get_route_handler(() => asset_cache), + + not_found + ]); +} + +module.exports = dev ? connect_dev : connect_prod; + +function set_req_pathname(req, res, next) { + req.pathname = req.url.replace(/\?.+/, ''); + next(); +} + +function get_asset_handler(opts) { + return (req, res, next) => { + if (!opts.filter(req.pathname)) return next(); + + res.set({ + 'Content-Type': opts.type, + 'Cache-Control': opts.cache + }); + res.end(opts.fn(req.pathname)); + }; +} + +function get_route_handler(fn) { + return async function handle_route(req, res, next) { const url = req.pathname; + const { client, server } = fn(); + // whatever happens, we're going to serve some HTML res.set({ 'Content-Type': 'text/html' }); try { - for (const route of routes) { + for (const route of route_manager.routes) { if (route.test(url)) { - await compiler.ready; - req.params = route.exec(url); - const mod = require(compiler.server_routes)[route.id]; + const mod = require(server.entry)[route.id]; if (route.type === 'page') { let data = { params: req.params, query: req.query }; @@ -97,7 +143,7 @@ module.exports = function connect(opts) { const { html, head, css } = mod.render(data); const page = templates.render(200, { - main: compiler.client_main, + main: client.main_file, html, head: `${head}`, styles: (css && css.code ? `` : '') @@ -116,12 +162,7 @@ module.exports = function connect(opts) { } } - res.status(404).end(templates.render(404, { - title: 'Not found', - status: 404, - method: req.method, - url - })); + next(); } catch(err) { res.status(500).end(templates.render(500, { title: (err && err.name) || 'Internal server error', @@ -131,25 +172,16 @@ module.exports = function connect(opts) { })); } } +} - const handler = compose_handlers([ - dev && require('webpack-hot-middleware')(client, { - reload: true, - path: '/__webpack_hmr', - heartbeat: 10 * 1000 - }), - - handle_index, - handle_service_worker, - handle_webpack_generated_files, - handle_route - ].filter(Boolean)); - - return function(req, res, next) { - req.pathname = req.url.replace(/\?.+/, ''); - handler(req, res, next); - }; -}; +function not_found(req, res) { + res.status(404).end(templates.render(404, { + title: 'Not found', + status: 404, + method: req.method, + url + })); +} function compose_handlers(handlers) { return (req, res, next) => { @@ -169,4 +201,8 @@ function compose_handlers(handlers) { go(); } +} + +function read_json(file) { + return JSON.parse(fs.readFileSync(file, 'utf-8')); } \ No newline at end of file diff --git a/lib/utils/compilers.js b/lib/utils/compilers.js new file mode 100644 index 0000000..58bf7d2 --- /dev/null +++ b/lib/utils/compilers.js @@ -0,0 +1,11 @@ +const path = require('path'); +const relative = require('require-relative'); +const webpack = relative('webpack', process.cwd()); + +exports.client = webpack( + require(path.resolve('webpack.client.config.js')) +); + +exports.server = webpack( + require(path.resolve('webpack.server.config.js')) +); \ No newline at end of file diff --git a/lib/utils/create_app.js b/lib/utils/create_app.js index 1cc5375..46f9aeb 100644 --- a/lib/utils/create_app.js +++ b/lib/utils/create_app.js @@ -1,8 +1,11 @@ const fs = require('fs'); const path = require('path'); -const { dest, server_routes, dev } = require('../config.js'); +const route_manager = require('../route_manager.js'); +const { src, dest, server_routes, dev } = require('../config.js'); + +module.exports = function create_app() { + const { routes } = route_manager; -module.exports = function create_app(src, dest, routes, options) { function create_client_main() { const template = fs.readFileSync('templates/main.js', 'utf-8'); diff --git a/lib/utils/create_compiler.js b/lib/utils/create_compiler.js deleted file mode 100644 index d05745f..0000000 --- a/lib/utils/create_compiler.js +++ /dev/null @@ -1,160 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const glob = require('glob'); -const chalk = require('chalk'); -const { dev } = require('../config.js'); -const templates = require('../templates.js'); - -module.exports = function create_compiler(client, server, dest, routes, dev) { - const compiler = {}; - - function client_updated(stats) { - console.log(stats.toString({ colors: true })); - - const info = stats.toJson(); - - compiler.client_main = `/client/${info.assetsByChunkName.main}`; - compiler.assets = info.assets.map(asset => `/client/${asset.name}`); - - const _fs = client.outputFileSystem && client.outputFileSystem.readFileSync ? client.outputFileSystem : fs; - compiler.asset_cache = {}; - compiler.assets.forEach(file => { - compiler.asset_cache[file] = _fs.readFileSync(path.join(dest, file), 'utf-8'); - }); - } - - function server_updated(stats) { - console.log(stats.toString({ colors: true })); - - const info = stats.toJson(); - compiler.server_routes = path.resolve(dest, 'server', info.assetsByChunkName.server_routes); - compiler.chunks = info.assetsByChunkName; - } - - function both_updated() { - const assets = glob.sync('**', { cwd: 'assets', nodir: true }); - - const route_code = `[${ - routes - .filter(route => route.type === 'page') - .map(route => `{ pattern: ${route.pattern} }`) - .join(', ') - }]`; - - compiler.service_worker = fs.readFileSync('templates/service-worker.js', 'utf-8') - .replace('__timestamp__', Date.now()) - .replace('__assets__', JSON.stringify(assets)) - .replace('__shell__', JSON.stringify(compiler.assets.concat('/index.html'))) - .replace('__routes__', route_code); - - compiler.shell = templates.render(200, { - styles: '', - head: '', - html: '', - main: compiler.client_main - }); - - // useful for debugging, but the files are served from memory - fs.writeFileSync(path.resolve(dest, 'service-worker.js'), compiler.service_worker); - fs.writeFileSync(path.resolve(dest, 'index.html'), compiler.shell); - } - - if (dev) { - let client_is_ready = false; - let server_is_ready = false; - - let fulfil; - let reject; - - const invalidate = () => new Promise((f, r) => { - fulfil = f; - reject = r; - }); - - compiler.ready = invalidate(); - - client.plugin('invalid', filename => { - console.log(chalk.red(`client bundle invalidated, file changed: ${chalk.bold(filename)}`)); - client_is_ready = false; - compiler.ready = invalidate(); - }); - - client.plugin('done', stats => { - if (stats.hasErrors()) { - reject(stats.toJson().errors[0]); - } else { - client_updated(stats); - } - - client_is_ready = true; - if (server_is_ready) fulfil(); - }); - - client.plugin('failed', reject); - - server.plugin('invalid', filename => { - console.log(chalk.red(`server bundle invalidated, file changed: ${chalk.bold(filename)}`)); - server_is_ready = false; - compiler.ready = invalidate(); - }); - - server.plugin('done', stats => { - if (stats.hasErrors()) { - reject(stats.toJson().errors[0]); - } else { - server_updated(stats); - } - - server_is_ready = true; - if (client_is_ready) fulfil(); - }); - - server.plugin('failed', reject); - - client.watch({}, (err, stats) => { - if (stats.hasErrors()) { - reject(stats.toJson().errors[0]); - } else { - client_updated(stats); - client_is_ready = true; - if (server_is_ready) fulfil(); - } - }); - - server.watch({}, (err, stats) => { - if (stats.hasErrors()) { - reject(stats.toJson().errors[0]); - } else { - server_updated(stats); - server_is_ready = true; - if (client_is_ready) fulfil(); - } - }); - } else { - compiler.ready = Promise.all([ - new Promise((fulfil, reject) => { - client.run((err, stats) => { - if (stats.hasErrors()) { - reject(stats.toJson().errors[0]); - } else { - client_updated(stats); - } - fulfil(); - }); - }), - - new Promise((fulfil, reject) => { - server.run((err, stats) => { - if (stats.hasErrors()) { - reject(stats.toJson().errors[0]); - } else { - server_updated(stats); - } - fulfil(); - }); - }) - ]).then(both_updated); - } - - return compiler; -}; \ No newline at end of file diff --git a/lib/utils/create_watcher.js b/lib/utils/create_watcher.js new file mode 100644 index 0000000..c8ed310 --- /dev/null +++ b/lib/utils/create_watcher.js @@ -0,0 +1,63 @@ +const path = require('path'); +const chalk = require('chalk'); +const compilers = require('./compilers.js'); +const generate_asset_cache = require('./generate_asset_cache.js'); + +function deferred() { + const d = {}; + + d.promise = new Promise((fulfil, reject) => { + d.fulfil = fulfil; + d.reject = reject; + }); + + return d; +} + +module.exports = function create_watcher() { + const deferreds = { + client: deferred(), + server: deferred() + }; + + const invalidate = () => Promise.all([ + deferreds.client.promise, + deferreds.server.promise + ]).then(([client_stats, server_stats]) => { + return generate_asset_cache( + client_stats.toJson(), + server_stats.toJson() + ); + }); + + watcher = { + ready: invalidate() + }; + + function watch_compiler(type) { + const compiler = compilers[type]; + + compiler.plugin('invalid', filename => { + console.log(chalk.red(`${type} bundle invalidated, file changed: ${chalk.bold(filename)}`)); + deferreds[type] = deferred(); + watcher.ready = invalidate(); + }); + + compiler.plugin('failed', err => { + deferreds[type].reject(err); + }); + + compiler.watch({}, (err, stats) => { + if (stats.hasErrors()) { + deferreds[type].reject(stats.toJson().errors[0]); + } else { + deferreds[type].fulfil(stats); + } + }); + } + + watch_compiler('client'); + watch_compiler('server'); + + return watcher; +}; \ No newline at end of file diff --git a/lib/utils/generate_asset_cache.js b/lib/utils/generate_asset_cache.js new file mode 100644 index 0000000..20db8b5 --- /dev/null +++ b/lib/utils/generate_asset_cache.js @@ -0,0 +1,67 @@ +const fs = require('fs'); +const path = require('path'); +const glob = require('glob'); +const templates = require('../templates.js'); +const route_manager = require('../route_manager.js'); +const { dest } = require('../config.js'); + +module.exports = function generate_asset_cache(clientInfo, serverInfo) { + const main_file = `/client/${clientInfo.assetsByChunkName.main}`; + const chunk_files = clientInfo.assets.map(chunk => `/client/${chunk.name}`); + + const service_worker = generate_service_worker(chunk_files); + const index = generate_index(main_file); + + fs.writeFileSync(path.join(dest, 'service-worker.js'), service_worker); + fs.writeFileSync(path.join(dest, 'index.html'), index); + + return { + client: { + main_file, + chunk_files, + + main: read(`${dest}${main_file}`), + chunks: chunk_files.reduce((lookup, file) => { + lookup[file] = read(`${dest}${file}`); + return lookup; + }, {}), + + index, + service_worker + }, + + server: { + entry: path.resolve(dest, 'server', serverInfo.assetsByChunkName.server_routes) + } + }; +}; + +function generate_service_worker(chunk_files) { + const assets = glob.sync('**', { cwd: 'assets', nodir: true }); + + const route_code = `[${ + route_manager.routes + .filter(route => route.type === 'page') + .map(route => `{ pattern: ${route.pattern} }`) + .join(', ') + }]`; + + return read('templates/service-worker.js') + .replace('__timestamp__', Date.now()) + .replace('__assets__', JSON.stringify(assets)) + .replace('__shell__', JSON.stringify(chunk_files.concat('/index.html'))) + .replace('__routes__', route_code); +} + +function generate_index(main_file) { + return templates.render(200, { + styles: '', + head: '', + html: '', + main: main_file + }); +} + +function read(file) { + return fs.readFileSync(file, 'utf-8'); +} diff --git a/package-lock.json b/package-lock.json index c69e140..a4c6a87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,23 @@ } } }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, "ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", @@ -50,6 +67,12 @@ "repeat-string": "1.6.1" } }, + "ansi-escapes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", + "dev": true + }, "ansi-html": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", @@ -77,6 +100,15 @@ "normalize-path": "2.1.1" } }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", @@ -90,11 +122,32 @@ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, "array-unique": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, "asn1.js": { "version": "4.9.2", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.2.tgz", @@ -126,6 +179,44 @@ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -270,6 +361,21 @@ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, "camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", @@ -294,6 +400,12 @@ "supports-color": "4.5.0" } }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -319,6 +431,27 @@ "safe-buffer": "5.1.1" } }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", @@ -363,6 +496,17 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", @@ -469,6 +613,27 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, "des.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", @@ -494,6 +659,15 @@ "randombytes": "2.0.5" } }, + "doctrine": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.2.tgz", + "integrity": "sha512-y0tm5Pq6ywp3qSTZ1vPgVdAnbDEoeoc5wlOHXoY1c4Wug/a7JvqHIl7BTvwodaHmejWkK/9dSb3sCYfyo/om8A==", + "dev": true, + "requires": { + "esutils": "2.0.2" + } + }, "domain-browser": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", @@ -630,6 +804,103 @@ "estraverse": "4.2.0" } }, + "eslint": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.13.1.tgz", + "integrity": "sha512-UCJVV50RtLHYzBp1DZ8CMPtRSg4iVZvjgO9IJHIKyWU/AnJVjtdRikoUPLB29n5pzMB7TnsLQWf0V6VUJfoPfw==", + "dev": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.3.0", + "concat-stream": "1.6.0", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.0.2", + "eslint-scope": "3.7.1", + "espree": "3.5.2", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.1.0", + "ignore": "3.3.7", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.0.1", + "js-yaml": "3.10.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "require-uncached": "1.0.3", + "semver": "5.4.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, + "requires": { + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } + }, + "espree": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz", + "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==", + "dev": true, + "requires": { + "acorn": "5.2.1", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, "esrecurse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", @@ -644,6 +915,12 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", @@ -697,6 +974,17 @@ "fill-range": "2.2.3" } }, + "external-editor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", + "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", + "dev": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.19", + "tmp": "0.0.33" + } + }, "extglob": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", @@ -715,6 +1003,31 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", @@ -740,6 +1053,18 @@ "locate-path": "2.0.0" } }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "dev": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -1547,6 +1872,12 @@ } } }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "get-caller-file": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", @@ -1587,6 +1918,26 @@ "is-glob": "2.0.1" } }, + "globals": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.1.0.tgz", + "integrity": "sha512-uEuWt9mqTlPDwSqi+sHjD4nWU/1N+q0fiWI9T1mZpD2UENqX20CFD5T/ziLZvztPaBKl7ZylUi1q6Qfm7E2CiQ==", + "dev": true + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -1598,6 +1949,15 @@ "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", "dev": true }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, "has-flag": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", @@ -1651,11 +2011,29 @@ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, "ieee754": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" }, + "ignore": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", + "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", @@ -1675,6 +2053,45 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.3.0", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.1.0", + "figures": "2.0.0", + "lodash": "4.17.4", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, "interpret": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", @@ -1758,6 +2175,30 @@ "kind-of": "3.2.2" } }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, "is-posix-bracket": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", @@ -1768,6 +2209,18 @@ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-resolvable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz", + "integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==", + "dev": true + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -1791,6 +2244,22 @@ "isarray": "1.0.0" } }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + }, "json-loader": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", @@ -1801,6 +2270,12 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", @@ -1827,6 +2302,16 @@ "invert-kv": "1.0.0" } }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -2018,12 +2503,24 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "nan": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", "optional": true }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "node-libs-browser": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", @@ -2108,6 +2605,37 @@ "wrappy": "1.0.2" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", @@ -2123,6 +2651,12 @@ "mem": "1.1.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -2192,6 +2726,12 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -2222,6 +2762,33 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", @@ -2237,6 +2804,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -2380,6 +2953,14 @@ "is-equal-shallow": "0.1.3" } }, + "relative": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/relative/-/relative-3.0.2.tgz", + "integrity": "sha1-Dc2OxUpdNaPBXhBFA9ZTdbWlNn8=", + "requires": { + "isobject": "2.1.0" + } + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -2405,6 +2986,37 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -2430,6 +3042,30 @@ "inherits": "2.0.3" } }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "4.0.8" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -2482,6 +3118,23 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, "source-list-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", @@ -2510,6 +3163,12 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "stream-browserify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", @@ -2586,6 +3245,12 @@ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, "supports-color": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", @@ -2594,11 +3259,37 @@ "has-flag": "2.0.0" } }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.3.0", + "lodash": "4.17.4", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, "tapable": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=" }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, "timers-browserify": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.4.tgz", @@ -2607,6 +3298,15 @@ "setimmediate": "1.0.5" } }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", @@ -2617,6 +3317,21 @@ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", @@ -2824,6 +3539,15 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/package.json b/package.json index c294bb3..4632d88 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,9 @@ "version": "0.1.5", "description": "Military-grade apps, engineered by Svelte", "main": "lib/index.js", + "bin": { + "sapper": "cli/index.js" + }, "directories": { "test": "test" }, @@ -10,11 +13,14 @@ "chalk": "^2.3.0", "escape-html": "^1.0.3", "mkdirp": "^0.5.1", + "relative": "^3.0.2", + "require-relative": "^0.8.7", "rimraf": "^2.6.2", "webpack": "^3.10.0", "webpack-hot-middleware": "^2.21.0" }, "devDependencies": { + "eslint": "^4.13.1", "mocha": "^4.0.1" }, "scripts": { diff --git a/lib/utils/create_routes.test.js b/test/unit/create_routes.test.js similarity index 94% rename from lib/utils/create_routes.test.js rename to test/unit/create_routes.test.js index e998923..3a91e77 100644 --- a/lib/utils/create_routes.test.js +++ b/test/unit/create_routes.test.js @@ -1,7 +1,7 @@ const path = require('path'); const assert = require('assert'); -const create_matchers = require('./create_matchers.js'); +const create_matchers = require('../../lib/utils/create_routes.js'); describe('create_matchers', () => { it('sorts routes correctly', () => {