Commit 4ad2e739 by Andrew Nesbitt

Merge pull request #147 from arian/improve-cli

Improve cli, merging node-sass-cli, which includes --watch
parents 65ee8fdd 2aa6ca57
#!/usr/bin/env node
var path = require('path'),
fs = require('fs'),
colors = require('colors'),
sass = require(path.join(__dirname, '..', 'sass')),
cwd = process.cwd(),
var cli = require('../lib/cli')(process.argv.slice(2));
optimist = require('optimist')
.usage('Compile .scss files with node-sass\nUsage: node-sass [options] <input.scss> [<output.css>]')
.describe('output-style', 'CSS output style (nested|expanded|compact|compressed)')
.default('output-style', 'nested')
.describe('source-comments', 'Include debug info in output (none|normal|map)')
.default('source-comments', 'none')
.describe('include-path', 'Path to look for @import-ed files')
.default('include-path', cwd)
.string('h').alias('h', 'help')
.describe('help', 'Print usage info'),
argv = optimist.argv,
inFile = argv._[0],
outFile = argv._[1];
if(argv.help || !inFile) return optimist.showHelp();
console.log('Starting Render Process...'.green);
sass.render({
file: inFile,
includePaths: [argv['include-path']],
outputStyle: argv['output-style'],
sourceComments: argv['source-comments'],
success: function(css) {
console.log('Rendering Complete, saving .css file...'.green);
if(!outFile) outFile = path.join(cwd, path.basename(inFile, '.scss') + '.css');
cli.on('log', function(msg){
console.log(msg);
});
fs.writeFile(outFile, css, function(err) {
if(err) return console.log(('Error: ' + err).red);
console.log(('Wrote CSS to ' + outFile).green);
});
},
cli.on('error', function(msg){
console.error(msg);
});
error: function(err) {
console.log('** Error Rendering SASS **'.red);
console.log(err.yellow);
}
cli.on('warn', function(msg){
console.warn(msg);
});
var watch = require('node-watch'),
render = require('./render'),
path = require('path'),
Emitter = require('events').EventEmitter,
cwd = process.cwd();
var optimist = require('optimist')
.usage('Compile .scss files with node-sass.\nUsage: $0 [options] <input.scss> [<output.css>]')
.options('output-style', {
describe: 'CSS output style (nested|expanded|compact|compressed)',
'default': 'nested'
})
.options('source-comments', {
describe: 'Include debug info in output (none|normal|map)',
'default': 'none'
})
.options('include-path', {
describe: 'Path to look for @import-ed files',
'default': cwd
})
.options('watch', {
describe: 'Watch a directory or file',
alias: 'w'
})
.options('output', {
describe: 'Output css file',
alias: 'o'
})
.options('stdout', {
describe: 'Print the resulting CSS to stdout'
})
.options('help', {
describe: 'Print usage info',
type: 'string',
alias: 'help'
})
.check(function(argv){
if (argv.help) return true;
if (argv._.length < 1) return false;
});
// throttle function, used so when multiple files change at the same time
// (e.g. git pull) the files are only compiled once.
function throttle(fn) {
var timer;
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var self = this;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(self, args);
}, 20);
};
}
function isSassFile(file) {
return file.match(/\.(sass|scss)/);
}
exports = module.exports = function(args) {
var argv = optimist.parse(args);
if (argv.help) {
optimist.showHelp();
process.exit(0);
return;
}
var emitter = new Emitter();
emitter.on('error', function(){});
var options = {
stdout: argv.stdout
};
var inFile = options.inFile = argv._[0];
var outFile = options.outFile = argv.o || argv._[1];
if (!outFile) {
outFile = options.outFile = path.join(cwd, path.basename(inFile, '.scss') + '.css');
}
// make sure it's an array
options.includePaths = argv['include-paths'];
if (!Array.isArray(options.includePaths)) {
options.includePaths = [options.includePaths];
}
// if it's an array, make it a string
options.outputStyle = argv['output-style'];
if (Array.isArray(options.outputStyle)) {
options.outputStyle = options.outputStyle[0];
}
// if it's an array, make it a string
options.sourceComments = argv['source-comments'];
if (Array.isArray(options.sourceComments)) {
options.sourceComments = options.sourceComments[0];
}
if (argv.w) {
var watchDir = argv.w;
if (watchDir === true) {
watchDir = []
} else if (!Array.isArray(watchDir)) {
watchDir = [watchDir];
}
watchDir.push(inFile)
var throttledRender = throttle(render, options, emitter);
watch(watchDir, function(file){
emitter.emit('warn', '=> changed: '.grey + file.blue);
if (isSassFile(file)) {
throttledRender();
}
});
throttledRender();
} else {
render(options, emitter);
}
return emitter;
};
exports.optimist = optimist;
var sass = require('../sass'),
colors = require('colors'),
fs = require('fs');
var cwd = process.cwd();
function render(options, emitter) {
sass.render({
file: options.inFile,
includePaths: options.includePaths,
outputStyle: options.outputStyle,
sourceComments: options.sourceComments,
success: function(css) {
emitter.emit('warn', 'Rendering Complete, saving .css file...'.green);
fs.writeFile(options.outFile, css, function(err) {
if (err) return emitter.emit('error', ('Error: ' + err).red);
emitter.emit('warn', ('Wrote CSS to ' + options.outFile).green);
});
if (options.stdout) {
emitter.emit('log', css);
}
emitter.emit('render', css);
},
error: function(error) {
emitter.emit('error', error);
}
});
}
module.exports = render;
......@@ -37,7 +37,8 @@
"dependencies": {
"mkdirp": "0.3.x",
"colors": "0.6.0-1",
"optimist": "0.4.x"
"optimist": "0.6.x",
"node-watch": "0.3.x"
},
"devDependencies": {
"mocha": "1.7.x"
......
......@@ -88,3 +88,4 @@ exports.renderSync = function(options) {
};
exports.middleware = require('./lib/middleware');
exports.cli = require('./lib/cli');
......@@ -3,10 +3,27 @@ var path = require('path'),
fs = require('fs'),
exec = require('child_process').exec,
sass = require(path.join(__dirname, '..', 'sass')),
cli = require(path.join(__dirname, '..', 'lib', 'cli')),
cliPath = path.resolve(__dirname, '..', 'bin', 'node-sass'),
sampleFilename = path.resolve(__dirname, 'sample.scss');
var expectedSampleCompressed = '#navbar {width:80%;height:23px;}\
#navbar ul {list-style-type:none;}\
#navbar li {float:left;}\
#navbar li a {font-weight:bold;}';
var expectedSampleNoComments = '#navbar {\n\
width: 80%;\n\
height: 23px; }\n\
\n\
#navbar ul {\n\
list-style-type: none; }\n\
\n\
#navbar li {\n\
float: left; }\n\
#navbar li a {\n\
font-weight: bold; }\n';
describe('cli', function() {
it('should print help when run with no arguments', function(done) {
......@@ -44,4 +61,52 @@ describe('cli', function() {
});
});
});
it('should compile with --include-paths option', function(done){
var emitter = cli(['--include-paths', __dirname + '/lib', __dirname + '/include_path.scss']);
emitter.on('error', function(err){
done(err);
});
emitter.on('render', function(css){
assert.equal(css.trim(), 'body {\n background: red; }');
done();
});
});
it('should compile with the --output style', function(done){
var emitter = cli(['--output-style', 'compressed', __dirname + '/sample.scss']);
emitter.on('error', function(err){
done(err);
});
emitter.on('render', function(css){
assert.equal(css, expectedSampleCompressed);
done();
});
});
it('should compile with the --source-comments option', function(done){
var emitter = cli(['--source-comments', 'none', __dirname + '/sample.scss']);
emitter.on('error', function(err){
done(err);
});
emitter.on('render', function(css){
assert.equal(css, expectedSampleNoComments);
done();
});
});
it('should write the output to the file specified with the --output option', function(done){
var resultPath = path.resolve(__dirname, '..', 'output.css');
var emitter = cli(['--output', resultPath, __dirname + '/sample.scss']);
emitter.on('error', function(err){
done(err);
});
emitter.on('render', function(css){
fs.exists(resultPath, function(exists) {
assert(exists);
fs.unlink(resultPath, done);
});
});
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment