Refactor CLI and add tests

This commit is contained in:
Typicode
2015-07-15 18:44:33 +02:00
parent e3a7db949b
commit ccf67724e3
22 changed files with 368 additions and 172 deletions

48
src/cli/index.js Normal file
View File

@ -0,0 +1,48 @@
var updateNotifier = require('update-notifier')
var yargs = require('yargs')
var run = require('./run')
var pkg = require('../../package.json')
module.exports = function () {
updateNotifier({ pkg: pkg }).notify()
var argv = yargs
.usage('$0 [options] <source>')
.options({
port: {
alias: 'p',
description: 'Set port',
default: 3000
},
host: {
alias: 'H',
description: 'Set host',
default: '0.0.0.0'
},
watch: {
alias: 'w',
description: 'Watch file(s)'
},
routes: {
alias: 'r',
description: 'Load routes file'
},
id: {
description: 'Set database id property (e.g. _id)',
default: 'id'
}
})
.boolean('watch')
.help('help').alias('help', 'h')
.version(pkg.version).alias('version', 'v')
.example('$0 db.json', '')
.example('$0 file.js', '')
.example('$0 http://example.com/db.json', '')
.epilog('https://github.com/typicode/json-server')
.require(1, 'Missing <source> argument')
.argv
run(argv)
}

102
src/cli/run.js Normal file
View File

@ -0,0 +1,102 @@
var fs = require('fs')
var chalk = require('chalk')
var is = require('./utils/is')
var load = require('./utils/load')
var watch = require('./watch')
var jsonServer = require('../server')
function prettyPrint (argv, object, rules) {
var host = argv.host === '0.0.0.0' ? 'localhost' : argv.host
var port = argv.port
var root = 'http://' + host + ':' + port
console.log()
console.log(chalk.bold(' Resources'))
for (var prop in object) {
console.log(' ' + root + '/' + prop)
}
if (rules) {
console.log()
console.log(chalk.bold(' Other routes'))
for (var rule in rules) {
console.log(' ' + rule + ' -> ' + rules[rule])
}
}
console.log()
console.log(chalk.bold(' Home'))
console.log(' ' + root)
console.log()
}
function createServer (source, object, routes) {
var server = jsonServer.create()
var router = jsonServer.router(
is.JSON(source) ?
source :
object
)
server.use(jsonServer.defaults)
if (routes) {
var rewriter = jsonServer.rewriter(routes)
server.use(rewriter)
}
server.use(router)
return server
}
module.exports = function (argv) {
var source = argv._[0]
var server
console.log()
console.log(chalk.cyan(' \\{^_^}/ hi!'))
function start () {
console.log()
console.log(chalk.gray(' Loading', source))
// Load JSON, JS or HTTP database
load(source, function (err, data) {
if (err) throw err
// Load additional routes
if (argv.routes) {
console.log(chalk.gray(' Loading', argv.routes))
var routes = JSON.parse(fs.readFileSync(argv.routes))
}
console.log(chalk.gray(' Done'))
// Create server and listen
server = createServer(source, data, routes).listen(argv.port, argv.host)
// Display server informations
prettyPrint(argv, data, routes)
})
}
// Start server
start()
// Watch files
if (argv.watch) {
console.log(chalk.gray(' Watching...'))
console.log()
watch(argv, function (file) {
console.log(chalk.gray(' ' + file + ' has changed, reloading...'))
// Restart server
server && server.close()
start()
})
}
}

17
src/cli/utils/is.js Normal file
View File

@ -0,0 +1,17 @@
module.exports = {
JSON: isJSON,
JS: isJS,
URL: isURL
}
function isJSON (s) {
return /\.json$/.test(s)
}
function isJS (s) {
return /\.js$/.test(s)
}
function isURL (s) {
return /^(http|https):/.test(s)
}

18
src/cli/utils/load.js Normal file
View File

@ -0,0 +1,18 @@
var path = require('path')
var got = require('got')
var is = require('./is')
module.exports = function (source, cb) {
if (is.URL(source)) {
// Load URL
got(source, { json: true }, function (err, data) {
cb(err, data)
})
} else {
// Load JS or JSON
var filename = path.resolve(source)
delete require.cache[filename]
var data = is.JSON(source) ? require(filename) : require(filename)()
cb(null, data)
}
}

44
src/cli/watch.js Normal file
View File

@ -0,0 +1,44 @@
var fs = require('fs')
var path = require('path')
var is = require('./utils/is')
module.exports = watch
// Because JSON file can be modified by the server, we need to be able to
// distinguish between user modification vs server modification.
// When the server modifies the JSON file, it generates a rename event.
// When the user modifies the JSON file, it generate a change event.
function watchDB (file, cb) {
var watchedDir = path.dirname(file)
var watchedFile = path.basename(file)
fs.watch(watchedDir, function (event, changedFile) {
if (event === 'change' && changedFile === watchedFile) cb()
})
}
function watchJS (file, cb) {
fs.watchFile(file, cb)
}
function watchSource (source, cb) {
if (is.JSON(source)) {
return watchDB(source, cb)
}
if (is.JS(source)) return watchJS(source, cb)
if (is.URL(source)) throw new Error('Can\'t watch URL')
}
function watch (argv, cb) {
var source = argv._[0]
watchSource(source, function () {
cb(source)
})
if (argv.routes) {
fs.watchFile(argv.routes, function () {
cb(argv.routes)
})
}
}