diff --git a/bin/styleguide b/bin/styleguide index f34b3127..944d99d3 100755 --- a/bin/styleguide +++ b/bin/styleguide @@ -1,3 +1,8 @@ #!/usr/bin/env node -require('../lib/cli').main(); +var path = require('path'), + cli = require(path.resolve(__dirname, '../lib/modules/cli')), + yargs = require('yargs'), + args = cli.argv(yargs).argv; + +cli.styleguide(args); diff --git a/lib/cli.js b/lib/cli.js deleted file mode 100755 index 648fd5f6..00000000 --- a/lib/cli.js +++ /dev/null @@ -1,66 +0,0 @@ -exports.main = function() { - - var path = require('path'), - styleguide = require(path.resolve(__dirname, '../lib/styleguide.js')), - gulp = require('gulp'), - runSequence = require('run-sequence'), - chalk = require('chalk'), - yargs = require('yargs'), - argv; - - argv = yargs - .usage('Generate sc5-styleguide') - .example('$0 --kssSource --styleSource --output ', 'Generate a styleguide') - .demand('kssSource', chalk.red('Please provide sources of KSS files')) - .demand('styleSource', chalk.red('Please provide sources of preprocessed files')) - .demand('output', chalk.red('Please provide output path')) - .describe('kssSource', 'KSS source file(s)') - .describe('styleSource', 'Preprocessed styles') - .describe('title', 'This string is used as a page title and in the page header') - .describe('extraHead', 'These HTML elements are injected inside the style guide head-tag') - .describe('commonClass', 'The provided classes are added to all preview blocks in the generated style guide') - .describe('appRoot', 'Define the appRoot parameter if you are hosting the style guide from a directory other than the root directory of the HTTP server') - .describe('styleVariables', 'By default variable definitions are searched from every file passed in gulp.src. styleVariables parameter could be used to filter from which files variables are loaded') - .describe('server', 'Enable built-in web-server. To enable Desiger tool the style guide must be served with the built-in web server') - .describe('port', 'Port of the server. Default is 3000') - .describe('watch', 'Automatically generate styleguide on file change') - .argv; - - gulp.task('styleguide:generate', function() { - return gulp.src(argv.kssSource) - .pipe(styleguide.generate({ - title: argv.title, - rootPath: argv.output, - extraHead: argv.extraHead, - commonClass: argv.commonClass, - appRoot: argv.appRoot, - styleVariables: argv.styleVariables, - server: argv.server, - port: argv.port - })) - .pipe(gulp.dest(argv.output)); - }); - - gulp.task('styleguide:applystyles', function() { - return gulp.src(argv.styleSource) - .pipe(styleguide.applyStyles()) - .pipe(gulp.dest(argv.output)); - }); - - gulp.task('watch:kss', function() { - return gulp.watch(argv.kssSource, ['styleguide:generate']); - }); - - gulp.task('watch:styles', function() { - return gulp.watch(argv.styleSource, ['styleguide:applystyles']); - }); - - var tasks = ['styleguide:generate', 'styleguide:applystyles']; - if (argv.watch) { - tasks.push('watch:styles'); - tasks.push('watch:kss'); - } - - runSequence.apply(this, tasks); - -}; diff --git a/lib/modules/cli/argv.js b/lib/modules/cli/argv.js new file mode 100644 index 00000000..0a4ea03e --- /dev/null +++ b/lib/modules/cli/argv.js @@ -0,0 +1,21 @@ +var chalk = require('chalk'); + +module.exports = function(argLib) { + return argLib + .usage('Generate sc5-styleguide') + .example('$0 --kssSource --styleSource --output ', 'Generate a styleguide') + .demand('kssSource', chalk.red('Please provide sources of KSS files')) + .demand('styleSource', chalk.red('Please provide sources of preprocessed files')) + .demand('output', chalk.red('Please provide output path')) + .describe('kssSource', 'KSS source file(s)') + .describe('styleSource', 'Preprocessed styles') + .describe('output', 'Output directory') + .describe('title', 'This string is used as a page title and in the page header') + .describe('extraHead', 'These HTML elements are injected inside the style guide head-tag') + .describe('commonClass', 'The provided classes are added to all preview blocks in the generated style guide') + .describe('appRoot', 'Define the appRoot parameter if you are hosting the style guide from a directory other than the root directory of the HTTP server') + .describe('styleVariables', 'Specify the files to parse variable definitions from (defaults to all files/glob pattern passed to kssSource') + .describe('server', 'Enable built-in web-server. To enable Desiger tool the style guide must be served with the built-in web server') + .describe('port', 'Port of the server. Default is 3000') + .describe('watch', 'Automatically generate styleguide on file change'); +}; diff --git a/lib/modules/cli/index.js b/lib/modules/cli/index.js new file mode 100644 index 00000000..e526289a --- /dev/null +++ b/lib/modules/cli/index.js @@ -0,0 +1,4 @@ +module.exports = { + argv: require('./argv'), + styleguide: require('./styleguide-cli') +}; diff --git a/lib/modules/cli/styleguide-cli.js b/lib/modules/cli/styleguide-cli.js new file mode 100755 index 00000000..9c975a85 --- /dev/null +++ b/lib/modules/cli/styleguide-cli.js @@ -0,0 +1,46 @@ +var path = require('path'), + gulp = require('gulp'), + runSequence = require('run-sequence'); + +module.exports = function(argv) { + + var styleguide = require(path.resolve(__dirname, '../../styleguide')); + + gulp.task('styleguide:generate', function() { + return gulp.src(argv.kssSource) + .pipe(styleguide.generate({ + title: argv.title, + rootPath: argv.output, + extraHead: argv.extraHead, + commonClass: argv.commonClass, + appRoot: argv.appRoot, + styleVariables: argv.styleVariables, + server: argv.server, + port: argv.port + })) + .pipe(gulp.dest(argv.output)); + }); + + gulp.task('styleguide:applystyles', function() { + return gulp.src(argv.styleSource) + .pipe(styleguide.applyStyles()) + .pipe(gulp.dest(argv.output)); + }); + + gulp.task('watch:kss', function() { + return gulp.watch(argv.kssSource, ['styleguide:generate']); + }); + + gulp.task('watch:styles', function() { + return gulp.watch(argv.styleSource, ['styleguide:applystyles']); + }); + + var tasks = ['styleguide:generate', 'styleguide:applystyles']; + if (argv.watch) { + tasks.push('watch:styles'); + tasks.push('watch:kss'); + } + + runSequence.apply(this, tasks); + +}; diff --git a/test/unit/modules/cli/argv.test.js b/test/unit/modules/cli/argv.test.js new file mode 100644 index 00000000..9a45c0b8 --- /dev/null +++ b/test/unit/modules/cli/argv.test.js @@ -0,0 +1,80 @@ +'use strict'; + +var path = require('path'), + chai = require('chai'), + expect = chai.expect, + sinon = require('sinon'), + argv = require(path.resolve(__dirname, '../../../../lib/modules/cli/argv')), + mockApi = ['usage', 'example', 'demand', 'describe'], + required = ['kssSource', 'styleSource', 'output'], + optional = ['title', 'extraHead', 'commonClass', 'appRoot', 'styleVariables', 'server', 'port', 'watch']; + +chai.use(require('sinon-chai')); + +/** + * override .calledWith default failure message (prints the whole object) with something more readable + */ +chai.Assertion.addMethod('calledWith', function(arg) { + var obj = this._obj; + this.assert( + obj.calledWith(arg) === true, + 'expected function to have been called with #{exp}', + 'expected function not to have been called with #{exp}', + arg, + '' + ); +}); + +describe('cli arguments', function() { + + var spy, args; + + beforeEach(function() { + spy = mock(mockApi); + args = argv(spy); + }); + + it('returns the passed arg itself', function() { + expect(args).to.deep.eql(spy); + }); + + it('registers usage', function() { + expect(spy.usage).to.have.been.calledWith(sinon.match.string); + }); + + it('has an example', function() { + expect(spy.example).to.have.been.calledWith(sinon.match.string); + }); + + describe('requires argument', function() { + required.forEach(function(arg) { + it(arg, function() { + expect(spy.demand, 'demand').to.have.been.calledWith(arg); + }); + }); + }); + + describe('allows optional argument', function() { + optional.forEach(function(arg) { + it(arg, function() { + expect(spy.demand, 'demand').not.to.have.been.calledWith(arg); + }); + }); + }); + + describe('describes argument', function() { + required.concat(optional).forEach(function(arg) { + it(arg, function() { + expect(spy.describe, 'describe').to.have.been.calledWith(arg); + }); + }); + }); + +}); + +function mock(api) { + return api.reduce(function(spy, func) { + spy[func] = sinon.stub().returns(spy); + return spy; + }, {}); +}