Source: apc-abstract/task/worker/generate_apiguide.js

/**
 * Generate api guide document. Using jsdoc.
 * @function task.worker.generateStyleguide
 * @see {@link http://usejsdoc.org/ | jsdoc}
 * @see {@link http://github.com/terryweiss/docstrap | docstrap}
 * @param {object} config - Work configuration.
 * @param {string} config.src - Source files to generate jsdoc. Could be a glob pattern.
 * @param {string} config.destDir - Directory to generate documents.
 * @param {string} config.theme - Theme name. Valid options are
 *  "amelia","cerulean","cosmo","cyborg","flatly","journal","readable",
 *  "simplex","slate","spacelab","spruce","superhero","united"
 * @param {function} callback - Callback when done.
 * @author Taka Okunishi
 *
 */
var path = require('path'),
    fs = require('fs'),
    debug = require('./_debug'),
    file = require('../../lib/file'),
    expandGlob = file.expandGlob,
    copyDir = file.copyDir,
    prepareCleanDir = file.prepareCleanDir,
    fork = require('child_process').fork;

exports = module.exports = function (config, callback) {
    var src = [].concat(config.src || './*').map(function (filename) {
            return path.resolve(filename);
        }),
        destDir = path.resolve(config.destDir);
    expandGlob(src, function (err, src) {
        if (err) {
            callback(err);
            return;
        }
        exports._prepareAPIGuideWorkDir(function (err, workDir) {
            if (err) {
                callback(err);
                return;
            }
            var confFilename = path.resolve(workDir, 'jsdoc.conf.json'),
                confFileData = exports._confFileData(config.theme);
            exports._writeJSONFile(confFilename, confFileData, function (err) {
                if (err) {
                    callback(err);
                    return;
                }
                file.mkdirP(destDir, function (err) {
                    if (err) {
                        callback(err);
                        return;
                    }
                    exports._prepareAPIGuideTmpl({}, function (err, tmplDir) {
                        exports._lookUpJsdocBin('.', function (err, bin) {
                            if (err) {
                                callback(err);
                                return;
                            }
                            var args = [
                            ]
                                .concat(src)
                                .concat([
                                    '--verbose',
                                    '--template', tmplDir + '/template',
                                    '--configure', confFilename,
                                    '--destination', destDir
                                ]);
                            var jsdoc = fork(bin, args);
                            jsdoc.on('exit', function () {
                                callback(null);
                            });
                        });
                    });
                });
            });
        });
    });
};

exports._writeJSONFile = function (filename, data, callback) {
    fs.writeFile(filename, JSON.stringify(data, null, 4), callback);
};

exports._lookUpJsdocBin = function (dirname, callback) {
    dirname = path.resolve(dirname);
    var filename = path.resolve(dirname, 'node_modules/jsdoc/jsdoc.js');
    fs.exists(filename, function (exists) {
        if (exists) {
            callback(null, filename);
        } else {
            var parentDir = path.dirname(dirname);
            var notFound = dirname == parentDir;
            if (notFound) {
                callback(new Error('Jsdoc bin not found'));
            } else {
                exports._lookUpJsdocBin(parentDir, callback);
            }
        }
    });
};

/**
 * Conf json file data.
 * @param {string} theme - Document theme.
 * @returns {object}
 * @protected
 * @ignore
 */
exports._confFileData = function (theme) {
    require('apeman').load('.');
    var apemandata = global.apemandata || {},
        metaData = apemandata.meta || {};
    return {
        "tags": {
            "allowUnknownTags": true
        },
        "plugins": ["plugins/markdown"],
        "templates": {
            "cleverLinks": false,
            "monospaceLinks": false,
            "default": {
                "outputSourceFiles": true
            },
            "systemName": metaData.name,
            "footer": "",
            "copyright": metaData.copyright || "DocStrap Copyright © 2012-2013 The contributors to the JSDoc3 and DocStrap projects.",
            "navType": "vertical",
            "theme": (theme || "spacelab").toLowerCase(),
            "linenums": true,
            "collapseSymbols": false,
            "inverseNav": false
        },
        "markdown": {
            "parser": "gfm",
            "hardwrap": true
        }
    }
};

exports._prepareAPIGuideWorkDir = function (callback) {
    var workDir = path.resolve(__dirname, '../../work/generate_apiguide_work');
    prepareCleanDir(workDir, function (err) {
        callback(err, workDir);
    });
};
/**
 * Prepare API guide document template.
 * @param {object} data
 * @param {function} callback
 * @protected
 * @ignore
 */
exports._prepareAPIGuideTmpl = function (data, callback) {
    var src = exports._apiguideTmplFile(),
        dest = path.resolve(__dirname, '../../work/apiguide_tmpl');
    copyDir(src, dest, function (err) {
        if (err) {
            callback(err);
            return;
        }
        callback(null, dest)
    });
};

exports._apiguideTmplFile = function () {
    return path.resolve(__dirname, '../../tmpl/_doc/apiguide');
};