/*! * Connect - compiler * Copyright(c) 2010 Sencha Inc. * Copyright(c) 2011 TJ Holowaychuk * MIT Licensed */ /** * Module dependencies. */ var fs = require('fs') , path = require('path') , parse = require('url').parse; /** * Require cache. */ var cache = {}; /** * Setup compiler. * * Options: * * - `src` Source directory, defaults to **CWD**. * - `dest` Destination directory, defaults `src`. * - `enable` Array of enabled compilers. * * Compilers: * * - `sass` Compiles sass to css * - `less` Compiles less to css * - `coffeescript` Compiles coffee to js * * @param {Object} options * @api public */ exports = module.exports = function compiler(options){ options = options || {}; var srcDir = options.src || process.cwd() , destDir = options.dest || srcDir , enable = options.enable; if (!enable || enable.length === 0) { throw new Error('compiler\'s "enable" option is not set, nothing will be compiled.'); } return function compiler(req, res, next){ if ('GET' != req.method) return next(); var pathname = parse(req.url).pathname; for (var i = 0, len = enable.length; i < len; ++i) { var name = enable[i] , compiler = compilers[name]; if (compiler.match.test(pathname)) { var src = (srcDir + pathname).replace(compiler.match, compiler.ext) , dest = destDir + pathname; // Compare mtimes fs.stat(src, function(err, srcStats){ if (err) { if ('ENOENT' == err.code) { next(); } else { next(err); } } else { fs.stat(dest, function(err, destStats){ if (err) { // Oh snap! it does not exist, compile it if ('ENOENT' == err.code) { compile(); } else { next(err); } } else { // Source has changed, compile it if (srcStats.mtime > destStats.mtime) { compile(); } else { // Defer file serving next(); } } }); } }); // Compile to the destination function compile() { fs.readFile(src, 'utf8', function(err, str){ if (err) { next(err); } else { compiler.compile(str, function(err, str){ if (err) { next(err); } else { fs.writeFile(dest, str, 'utf8', function(err){ next(err); }); } }); } }); } return; } } next(); }; }; /** * Bundled compilers: * * - [sass](http://github.com/visionmedia/sass.js) to _css_ * - [less](http://github.com/cloudhead/less.js) to _css_ * - [coffee](http://github.com/jashkenas/coffee-script) to _js_ */ var compilers = exports.compilers = { sass: { match: /\.css$/, ext: '.sass', compile: function(str, fn){ var sass = cache.sass || (cache.sass = require('sass')); try { fn(null, sass.render(str)); } catch (err) { fn(err); } } }, less: { match: /\.css$/, ext: '.less', compile: function(str, fn){ var less = cache.less || (cache.less = require('less')); try { less.render(str, fn); } catch (err) { fn(err); } } }, coffeescript: { match: /\.js$/, ext: '.coffee', compile: function(str, fn){ var coffee = cache.coffee || (cache.coffee = require('coffee-script')); try { fn(null, coffee.compile(str)); } catch (err) { fn(err); } } } };