185 lines
5.0 KiB
JavaScript
185 lines
5.0 KiB
JavaScript
|
/*
|
||
|
* grunt-contrib-sass
|
||
|
* http://gruntjs.com/
|
||
|
*
|
||
|
* Copyright (c) 2013 Sindre Sorhus, contributors
|
||
|
* Licensed under the MIT license.
|
||
|
*/
|
||
|
'use strict';
|
||
|
var path = require('path');
|
||
|
var dargs = require('dargs');
|
||
|
var numCPUs = require('os').cpus().length || 1;
|
||
|
var async = require('async');
|
||
|
var chalk = require('chalk');
|
||
|
var spawn = require('win-spawn');
|
||
|
var which = require('which');
|
||
|
|
||
|
module.exports = function (grunt) {
|
||
|
var bannerCallback = function (filename, banner) {
|
||
|
grunt.verbose.writeln('Writing CSS banner for ' + filename);
|
||
|
grunt.file.write(filename, banner + grunt.util.linefeed + grunt.file.read(filename));
|
||
|
};
|
||
|
|
||
|
var checkBinary = function (cmd, errMess) {
|
||
|
try {
|
||
|
which.sync(cmd);
|
||
|
} catch (err) {
|
||
|
return grunt.warn(
|
||
|
'\n' + errMess + '\n' +
|
||
|
'More info: https://github.com/gruntjs/grunt-contrib-sass\n'
|
||
|
);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var checkFiles = function (files, options, cb) {
|
||
|
var failCount = 0;
|
||
|
var filesToCheck = files.filter(function (src) {
|
||
|
return path.basename(src)[0] !== '_' && grunt.file.exists(src);
|
||
|
});
|
||
|
|
||
|
async.eachLimit(filesToCheck, numCPUs, function (src, next) {
|
||
|
var bin;
|
||
|
var args;
|
||
|
|
||
|
if (options.bundleExec) {
|
||
|
bin = 'bundle';
|
||
|
args = ['exec', 'sass', '--check', src];
|
||
|
} else {
|
||
|
bin = 'sass';
|
||
|
args = ['--check', src];
|
||
|
}
|
||
|
|
||
|
grunt.verbose.writeln('Command: ' + bin + ' ' + args.join(' '));
|
||
|
|
||
|
grunt.verbose.writeln('Checking file ' + chalk.cyan(src) + ' syntax.');
|
||
|
spawn(bin, args, { stdio: 'inherit' })
|
||
|
.on('error', grunt.warn)
|
||
|
.on('close', function (code) {
|
||
|
if (code > 0) {
|
||
|
failCount++;
|
||
|
grunt.log.error('Checking file ' + chalk.cyan(src) + ' - ' + chalk.red('failed') + '.');
|
||
|
} else {
|
||
|
grunt.verbose.ok('Checking file ' + chalk.cyan(src) + ' - ' + chalk.green('passed') + '.');
|
||
|
}
|
||
|
|
||
|
next();
|
||
|
});
|
||
|
}, function () {
|
||
|
if (failCount > 0) {
|
||
|
grunt.warn('Sass check failed for ' + failCount + ' files.');
|
||
|
} else {
|
||
|
grunt.log.ok('All ' + chalk.cyan(filesToCheck.length) + ' files passed.');
|
||
|
}
|
||
|
|
||
|
cb();
|
||
|
});
|
||
|
};
|
||
|
|
||
|
grunt.registerMultiTask('sass', 'Compile Sass to CSS', function () {
|
||
|
var cb = this.async();
|
||
|
var options = this.options();
|
||
|
var bundleExec = options.bundleExec;
|
||
|
var banner;
|
||
|
var passedArgs;
|
||
|
|
||
|
if (bundleExec) {
|
||
|
checkBinary('bundle',
|
||
|
'bundleExec options set but no Bundler executable found in your PATH.'
|
||
|
);
|
||
|
} else {
|
||
|
checkBinary('sass',
|
||
|
'You need to have Ruby and Sass installed and in your PATH for this task to work.'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (options.check) {
|
||
|
checkFiles(this.filesSrc, options, cb);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Unset banner option if set
|
||
|
if (options.banner) {
|
||
|
banner = options.banner;
|
||
|
delete options.banner;
|
||
|
}
|
||
|
|
||
|
passedArgs = dargs(options, ['bundleExec']);
|
||
|
|
||
|
async.eachLimit(this.files, numCPUs, function (file, next) {
|
||
|
var src = file.src[0];
|
||
|
|
||
|
if (typeof src !== 'string') {
|
||
|
src = file.orig.src[0];
|
||
|
}
|
||
|
|
||
|
if (!grunt.file.exists(src)) {
|
||
|
grunt.log.warn('Source file "' + src + '" not found.');
|
||
|
return next();
|
||
|
}
|
||
|
|
||
|
if (path.basename(src)[0] === '_') {
|
||
|
return next();
|
||
|
}
|
||
|
|
||
|
var args = [
|
||
|
src,
|
||
|
file.dest
|
||
|
].concat(passedArgs);
|
||
|
|
||
|
if (options.update) {
|
||
|
// When the source file hasn't yet been compiled SASS will write an empty file.
|
||
|
// If this is the first time the file has been written we treat it as a if update was not passed
|
||
|
if (!grunt.file.exists(file.dest)) {
|
||
|
// Find where the --update flag is and remove it.
|
||
|
var index = args.indexOf('--update');
|
||
|
args.splice(index, 1);
|
||
|
} else {
|
||
|
// The first two elements in args is our source and destination files,
|
||
|
// we use those values to build a path that SASS recognizes namely: source:destination
|
||
|
var sassPath = args.shift() + ':' + args.shift();
|
||
|
args.push(sassPath);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var bin = 'sass';
|
||
|
|
||
|
if (bundleExec) {
|
||
|
bin = 'bundle';
|
||
|
args.unshift('exec', 'sass');
|
||
|
}
|
||
|
|
||
|
// If we're compiling scss or css files
|
||
|
if (path.extname(src) === '.css') {
|
||
|
args.push('--scss');
|
||
|
}
|
||
|
|
||
|
// Make sure grunt creates the destination folders if they don't exist
|
||
|
if (!grunt.file.exists(file.dest)) {
|
||
|
grunt.file.write(file.dest, '');
|
||
|
}
|
||
|
|
||
|
grunt.verbose.writeln('Command: ' + bin + ' ' + args.join(' '));
|
||
|
|
||
|
var cp = spawn(bin, args, {stdio: 'inherit'});
|
||
|
|
||
|
cp.on('error', function (err) {
|
||
|
grunt.warn(err);
|
||
|
});
|
||
|
|
||
|
cp.on('close', function (code) {
|
||
|
if (code > 0) {
|
||
|
return grunt.warn('Exited with error code ' + code);
|
||
|
}
|
||
|
|
||
|
// Callback to insert banner
|
||
|
if (banner) {
|
||
|
bannerCallback(file.dest, banner);
|
||
|
}
|
||
|
|
||
|
grunt.verbose.writeln('File ' + chalk.cyan(file.dest) + ' created.');
|
||
|
next();
|
||
|
});
|
||
|
}, cb);
|
||
|
});
|
||
|
};
|