Source: apc-static/task/worker/concat_and_compile_coffee_script_files.js

/**
 * Concat and compile coffee files.
 * @function task.concatAndCompileCoffeeScriptFiles
 * @param {object} config - Work configuration.
 * @param {string} config.src - Source file names. Glob.
 * @param {string} [config.ignore] - Ignore  file name pattern. Glob.
 * @param {string} config.dest - Destination file name.
 * @param {string} [config.tmpl] - Template file name.
 * @param {function} callback - Callback when done.
 * @author Taka Okunishi
 *
 */
var path = require('path'),
    fs = require('fs'),
    lib = require('../../lib'),
    debug = require('./_debug'),
    file = lib.file,
    compile = lib.compile,
    object = lib.object,
    deepCopy = object.deepCopy,
    writeReadonlyFile = file.writeReadonlyFile,
    compileCoffeeScriptString = compile.compileCoffeeScriptString,
    mkdirP = file.mkdirP,
    loadHbsTmpl = file.loadHbsTmpl,
    _beautifyJavascriptString = require('./_beautify_javascript_string'),
    _expandGlobUnlessIgnored = require('./_expand_glob_unless_ignored');

exports = module.exports = function (config, callback) {
    var src = [].concat(config.src).map(function (src) {
            return path.resolve(src)
        }),
        ignore = [].concat(config.ignore || []).map(function (ignore) {
            return path.resolve(ignore);
        }),
        dest = path.resolve(config.dest),
        tmpl = config.tmpl && path.resolve(config.tmpl);
    _expandGlobUnlessIgnored(src, ignore, function (err, filenames) {
        if (err) {
            callback(err);
            return;
        }
        require('async').map(filenames.sort(), exports._readAndCompile, function (err, contents) {
            if (err) {
                callback(err);
                return;
            }

            exports._concatContents(contents, tmpl, function (err, content) {
                if (err) {
                    callback(err);
                    return;
                }
                var beautified = _beautifyJavascriptString(content);
                writeReadonlyFile(dest, beautified, function (err) {
                    if (!err) {
                        debug.didCreateFile(dest);
                    }
                    callback(err);
                });
            });
        });
    });
};


/**
 * Concat contents.
 * @param {string[]} contents
 * @param {string} tmpl
 * @param {function} callback - Callback when done.
 * @private
 */
exports._concatContents = function (contents, tmpl, callback) {
    var joined = contents.length && contents.reduce(function (a, b) {
        return [a.toString(), b.toString()].join('\n');
    }) || '';
    if (tmpl) {
        loadHbsTmpl(tmpl, function (err, tmpl) {
            if (err) {
                callback(err);
                return;
            }

            var renderData = deepCopy(global.apemandata, {
                contents: joined
            });
            callback(null, tmpl(renderData));
        })
    } else {
        callback(null, joined);

    }
};

/**
 * Read file and compile it.
 * @param {string} filename - Filename to compile.
 * @param {function} callback - Callback when done.
 * @protected
 * @ignore
 */
exports._readAndCompile = function (filename, callback) {
    fs.readFile(filename, function (err, content) {
        if (err) {
            callback(err);
            return;
        }
        compileCoffeeScriptString(content.toString(), function (err, compiled) {
            callback(err, compiled);
        });
    });
};