| |
| /*! |
| * 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); |
| } |
| } |
| } |
| }; |