diff --git a/lib/index.js b/lib/index.js index ac42009..5c50fba 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,9 +5,8 @@ const EventEmitter = require('events').EventEmitter const ArgumentParser = require('argparse').ArgumentParser const reduce = require('lodash.reduce') -// TODO: this should reflect spike version, or cli should always mirror const pkg = require('../package.json') -let Spike = require('spike-core') +let Spike = require('spike-core') // this is a let because of test mocking /** * @class CLI @@ -30,6 +29,7 @@ module.exports = class CLI extends EventEmitter { this.addWatch() this.addClean() this.addNew() + this.addTemplate() } /** @@ -52,12 +52,15 @@ module.exports = class CLI extends EventEmitter { // they should also wait to execute anything until nextTick const emitter = fn(Spike, args) + // standard events emitter.on('error', this.emit.bind(this, 'error')) emitter.on('warning', this.emit.bind(this, 'warning')) + emitter.on('success', this.emit.bind(this, 'success')) + emitter.on('info', this.emit.bind(this, 'info')) + + // instance-method-specific emitter.on('compile', this.emit.bind(this, 'compile')) emitter.on('remove', this.emit.bind(this, 'success')) - emitter.on('create', this.emit.bind(this, 'success')) - emitter.on('info', this.emit.bind(this, 'info')) return this } @@ -137,6 +140,72 @@ module.exports = class CLI extends EventEmitter { s.setDefaults({ fn: 'new' }) } + + addTemplate () { + const main = this.sub.addParser('template', { + aliases: ['tpl'], + help: 'Manage spike project templates' + }) + const sub = main.addSubparsers() + let s + + // add + + s = sub.addParser('add', { + aliases: ['install'], + help: 'Add a project template' + }) + + s.addArgument(['name'], { + help: 'Name of the template' + }) + + s.addArgument(['src'], { + help: 'Url that can be git-clone\'d to download the template' + }) + + s.setDefaults({ fn: 'template/add' }) + + // remove + + s = sub.addParser(['remove'], { + help: 'Remove an existing template' + }) + + s.addArgument(['name'], { + help: "Name of the template you'd like to remove" + }) + + s.setDefaults({ fn: 'template/remove' }) + + // list + + s = sub.addParser(['list'], { + help: 'List all of the templates you have installed' + }) + + s.setDefaults({ fn: 'template/list' }) + + // default + + s = sub.addParser(['default'], { + help: 'Make a certain template your default' + }) + + s.addArgument(['name'], { + help: "Name of the template you'd like to make the default" + }) + + s.setDefaults({ fn: 'template/default' }) + + // reset + + s = sub.addParser(['reset'], { + help: 'Reset all existing information about templates' + }) + + s.setDefaults({ fn: 'template/reset' }) + } } /** diff --git a/lib/new.js b/lib/new.js index 5766b3d..d9bbd60 100644 --- a/lib/new.js +++ b/lib/new.js @@ -6,13 +6,14 @@ module.exports = function (Spike, args) { const emitter = new EventEmitter() emitter.on('done', (project) => { - emitter.emit('create', `project created at ${path.resolve(project.config.context)}`) + emitter.emit('success', `project created at ${path.resolve(project.config.context)}`) }) process.nextTick(() => Spike.new({ root: args.path, emitter: emitter, locals: args.overrides, + template: args.template, inquirer: inquirer.prompt.bind(inquirer) })) diff --git a/lib/template/add.js b/lib/template/add.js new file mode 100644 index 0000000..30eb7f8 --- /dev/null +++ b/lib/template/add.js @@ -0,0 +1,9 @@ +const EventEmitter = require('events') + +module.exports = function (Spike, args) { + const emitter = new EventEmitter() + process.nextTick(() => { + Spike.template.add(Object.assign(args, { emitter: emitter })) + }) + return emitter +} diff --git a/lib/template/default.js b/lib/template/default.js new file mode 100644 index 0000000..5bc5137 --- /dev/null +++ b/lib/template/default.js @@ -0,0 +1,9 @@ +const EventEmitter = require('events') + +module.exports = function (Spike, args) { + const emitter = new EventEmitter() + process.nextTick(() => { + Spike.template.default(Object.assign(args, { emitter: emitter })) + }) + return emitter +} diff --git a/lib/template/list.js b/lib/template/list.js new file mode 100644 index 0000000..3a7415f --- /dev/null +++ b/lib/template/list.js @@ -0,0 +1,9 @@ +const EventEmitter = require('events') + +module.exports = function (Spike, args) { + const emitter = new EventEmitter() + process.nextTick(() => { + Spike.template.list(Object.assign(args, { emitter: emitter })) + }) + return emitter +} diff --git a/lib/template/remove.js b/lib/template/remove.js new file mode 100644 index 0000000..4941e34 --- /dev/null +++ b/lib/template/remove.js @@ -0,0 +1,9 @@ +const EventEmitter = require('events') + +module.exports = function (Spike, args) { + const emitter = new EventEmitter() + process.nextTick(() => { + Spike.template.remove(Object.assign(args, { emitter: emitter })) + }) + return emitter +} diff --git a/lib/template/reset.js b/lib/template/reset.js new file mode 100644 index 0000000..7a1ba7e --- /dev/null +++ b/lib/template/reset.js @@ -0,0 +1,10 @@ +const EventEmitter = require('events') + +module.exports = function (Spike, args) { + const emitter = new EventEmitter() + process.nextTick(() => { + Spike.template.reset() + emitter.emit('success', 'settings and templates reset') + }) + return emitter +} diff --git a/package.json b/package.json index c2f4fd9..9d28e30 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "chalk": "^1.1.3", "inquirer": "^1.0.2", "lodash.reduce": "^4.4.0", - "spike-core": "^0.4.0" + "spike-core": "^0.6.0" }, "devDependencies": { "ava": "^0.15.0", diff --git a/test/index.js b/test/index.js index b0c7062..2d86ffa 100644 --- a/test/index.js +++ b/test/index.js @@ -30,6 +30,24 @@ class SpikeMock extends EventEmitter { } } +SpikeMock.template = { + add: (opts) => { + opts.emitter.emit('success', opts) + }, + remove: (opts) => { + opts.emitter.emit('success', opts) + }, + default: (opts) => { + opts.emitter.emit('success', opts) + }, + list: (opts) => { + opts.emitter.emit('success', opts) + }, + reset: () => { + return true + } +} + test.beforeEach((t) => { CLI.__set__('Spike', SpikeMock) cli = new CLI() @@ -60,7 +78,7 @@ test.cb('compile with env option', (t) => { }) test.cb('new', (t) => { - t.plan(4) + t.plan(5) cli.on('error', t.end) cli.on('warning', t.end) @@ -68,6 +86,7 @@ test.cb('new', (t) => { t.truthy(opts.root) t.truthy(opts.emitter) t.truthy(opts.locals) + t.falsy(opts.template) }) cli.on('success', (res) => { t.truthy(res.match(/project created at.*test/)) @@ -77,6 +96,22 @@ test.cb('new', (t) => { cli.run('new test -o foo:bar') }) +test.cb('new with template option', (t) => { + t.plan(2) + + cli.on('error', t.end) + cli.on('warning', t.end) + cli.on('info', (opts) => { + t.truthy(opts.template) + }) + cli.on('success', (res) => { + t.truthy(res.match(/project created at.*test/)) + t.end() + }) + + cli.run('new test -t foo') +}) + test.cb('watch', (t) => { cli.on('error', t.end) cli.on('warning', t.end) @@ -98,3 +133,62 @@ test.cb('watch with env option', (t) => { cli.run('watch -e production') }) + +test.cb('add', (t) => { + cli.on('error', t.end) + cli.on('warning', t.end) + cli.on('success', (res) => { + t.truthy(res.name === 'foo') + t.truthy(res.src === 'http://github.com/foo/foo') + t.truthy(res.emitter) + t.end() + }) + + cli.run('tpl add foo http://github.com/foo/foo') +}) + +test.cb('remove', (t) => { + cli.on('error', t.end) + cli.on('warning', t.end) + cli.on('success', (res) => { + t.truthy(res.name === 'foo') + t.truthy(res.emitter) + t.end() + }) + + cli.run('tpl remove foo') +}) + +test.cb('default', (t) => { + cli.on('error', t.end) + cli.on('warning', t.end) + cli.on('success', (res) => { + t.truthy(res.name === 'foo') + t.truthy(res.emitter) + t.end() + }) + + cli.run('tpl default foo') +}) + +test.cb('list', (t) => { + cli.on('error', t.end) + cli.on('warning', t.end) + cli.on('success', (res) => { + t.truthy(res.emitter) + t.end() + }) + + cli.run('tpl list') +}) + +test.cb('reset', (t) => { + cli.on('error', t.end) + cli.on('warning', t.end) + cli.on('success', (res) => { + t.truthy(res === 'settings and templates reset') + t.end() + }) + + cli.run('tpl reset') +})