description and source-codenode-sass-middleware = function (options) {
options = options || {};
// Accept single src/dest dir
if (typeof options == 'string') {
options = { src: options };
}
// Source directory (required)
var src = options.src || function() {
throw new Error('sass.middleware() requires "src" directory.');
}();
// Destination directory (source by default)
var dest = options.dest || src;
// Optional base path for src and dest
var root = options.root || null;
// Force compilation everytime
var force = options.force || options.response;
// Enable debug output
var debug = options.debug;
var sassExtension = (options.indentedSyntax === true) ? '.sass' : '.scss';
var sourceMap = options.sourceMap || null;
var maxAge = options.maxAge || 0;
//Allow custom log function or default one
var log = options.log || function(severity, key, val, text) {
if (!debug && severity === 'debug') { // skip debug when debug is off
return;
}
text = text || '';
if (typeof (console[severity]) === 'function') {
console[severity]('[sass] \x1B[90m%s:\x1B[0m \x1B[36m%s %s\x1B[0m', key, val, text);
} else {
console.error('[sass] \x1B[90m%s:\x1B[0m \x1B[36m%s %s\x1B[0m', key, val, text);
}
};
// Default compile callback
options.compile = options.compile || function() {
return sass;
};
// Middleware
return function sass(req, res, next) {
var sassMiddlewareError = null;
// This function will be called if something goes wrong
var error = function(err, errorMessage) {
log('error', 'error', errorMessage || err);
if (options.error) {
options.error(err);
}
sassMiddlewareError = err;
};
if (req.method != 'GET' && req.method != 'HEAD') {
return next();
}
var path = url.parse(req.url).pathname;
if (!/\.css$/.test(path)) {
log('debug', 'skip', path, 'nothing to do');
return next();
}
if (options.prefix) {
if (0 === path.indexOf(options.prefix)) {
path = path.substring(options.prefix.length);
} else {
log('debug', 'skip', path, 'prefix mismatch');
return next();
}
}
var cssPath = join(dest, path),
sassPath = join(src, path.replace(/\.css$/, sassExtension)),
sassDir = dirname(sassPath);
if (root) {
cssPath = join(root, dest, path.replace(new RegExp('^' + dest), ''));
sassPath = join(root, src, path
.replace(new RegExp('^' + dest), '')
.replace(/\.css$/, sassExtension));
sassDir = dirname(sassPath);
}
log('debug', 'source', sassPath);
log('debug', 'dest', options.response ? '<response>' : cssPath);
// When render is done, respond to the request accordingly
var done = function(err, result) {
if (err) {
var file = sassPath;
if (err.file && err.file != 'stdin') {
file = err.file;
}
var fileLineColumn = file + ':' + err.line + ':' + err.column;
var errorMessage = '\x07\x1B[31m' + err.message.replace(/^ +/, '') + '\n\nin ' + fileLineColumn + '\x1B[91m';
error(err, errorMessage);
return next(err);
}
var data = result.css;
log('debug', 'render', options.response ? '<response>' : sassPath);
if (sourceMap) {
log('debug', 'render', this.options.sourceMap);
}
imports[sassPath] = result.stats.includedFiles;
var cssDone = true;
var sourceMapDone = true;
function doneWriting() {
if (!cssDone || !sourceMapDone) {
return;
}
if (options.response === false) {
return next(sassMiddlewareError);
}
res.writeHead(200, {
'Content-Type': 'text/css',
'Cache-Control': 'max-age=' + maxAge
});
res.end(data);
}
// If response is true, do not write to file
if (options.response) {
return doneWriting();
}
cssDone = false;
sourceMapDone = !sourceMap;
mkdirp(dirname(cssPath), '0700', function(err) {
if ( ...