Fork me on GitHub Dox

Dox

JavaScript documentation parser for node. Check out the Github Repo for the source and installation guide.

index

lib/dox/index.js

Module dependencies.

require.paths.unshift(__dirname + '/koala/lib');
var sys = require('sys'),
    fs = require('fs'),
    path = require('path'),
    koala = require('koala'),
    utils = require('./utils'),
    markdown = require('./markdown/lib/markdown');

Library version.

var version = '0.0.3';

Style name.

  • type: String

var style = 'default';

Project title.

  • type: String

var title = 'Dont forget to use --title to specify me!';

Parse JSDoc.

  • type: Boolean

var jsdoc = true;

Project description.

  • type: String

var desc = '';

Show private code.

  • type: Boolean

var showPrivate = false;

Github url for the ribbon.

  • type: String

var ribbon = '';

Usage documentation.

var usage = ''
    + 'Usage: dox [options] <file ...>\n'
    + '\n'
    + 'Options:\n'
    + '  -t, --title STR   Project title\n'
    + '  -d, --desc STR    Project description (markdown)\n'
    + '  -r, --ribbon URL  Github ribbon url\n'
    + '  -s, --style NAME  Document style, available: ["default"]\n'
    + '  -J, --no-jsdoc    Disable jsdoc parsing (coverts to markdown)\n'
    + '  -p, --private     Output private code in documentation\n'
    + '  -v, --version     Output dox library version\n'
    + '  -h, --help        Display help information'
    + '\n';

Parse the given arguments.

  • param: Array args

  • api: public

exports.parse = function(args){
    var files = [];
    
    // Require an argument
    function requireArg(){
        if (args.length) {
            return args.shift();
        } else {
            throw new Error(arg + ' requires an argument.');
        }
    }

    // Parse arguments
    while (args.length) {
        var arg = args.shift();
        switch (arg) {
            case '-h':
            case '--help':
                sys.puts(usage);
                process.exit(1);
                break;
            case '-v':
            case '--version':
                sys.puts(version);
                process.exit(1);
                break;
            case '-t':
            case '--title':
                title = requireArg();
                break;
            case '-d':
            case '--desc':
                desc = requireArg();
                break;
            case '-s':
            case '--style':
                style = requireArg();
                break;
            case '-J':
            case '--no-jsdoc':
                jsdoc = false;
                break;
            case '-p':
            case '--private':
                showPrivate = true;
                break;
            case '-r':
            case '--ribbon':
                ribbon = requireArg();
                break;
            default:
                files.push(arg);
        }
    }
    
    if (files.length) {
        log('parsing ' + files.length + ' file(s)');
        var pending = files.length;
        
        // Style
        log('loading ' + style + ' style');
        var head = fs.readFileSync(__dirname + '/styles/' + style + '/head.html', 'utf8');
        var foot = fs.readFileSync(__dirname + '/styles/' + style + '/foot.html', 'utf8');
        var css = fs.readFileSync(__dirname + '/styles/' + style + '/style.css', 'utf8');
    
        // Substitutions
        head = head.replace(/\{\{title\}\}/g, title).replace(/\{\{style\}\}/, css);
        
        // Ribbon
        if (ribbon) {
            log('generating ribbon');
            sys.print('<a href="' + ribbon + '">'
                  + '<img alt="Fork me on GitHub" id="ribbon"'
                  + ' src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png">'
                  + '</a>');
        }
        
        sys.print(head);
        sys.print('<table id="source"><tbody>');
        
        // Render files
        var first = true;
        files.forEach(function(file){
            log('parsing ' + file);
            fs.readFile(file, 'utf8', function(err, str){
                if (err) throw err;
                if (first) {
                    if (desc) desc = markdown.toHTML(desc);
                    sys.print('<tr><td><h1>' + title + '</h1>' + desc + '</td><td></td></tr>');
                    first = false;
                }
                sys.print('<tr class="filename"><td><h2 id="' + file + '"><a href="#">' 
                    + path.basename(file, '.js') + '</a></h2></td><td>' 
                    + file + '</td></tr>');
                sys.print(render(str, file));
                --pending || sys.print(foot, '</tbody></table>');
            });
        });
        
    } else {
        throw new Error('files required.');
    }
};

Generate html for the given string of code.

  • foo
    • bar
  • baz

  • param: String str

  • param: String file

  • return: String

  • api: public

var render = exports.render = function(str, file){
    var parts = str.split(/\s*\/\*([^]+?)\*\/\s*/g),
        blocks = [];

    // Populate blocks
    for (var i = 0, len = parts.length; i &lt; len; ++i) {
        var part = parts[i],
            next = parts[i + 1] || '';
        // Empty
        if (/^\s*$/.test(part)) {
            continue;
        // Ignored comment
        } else if (/^!\s*\*/.test(part)) {
            continue;
        } else {
            ++i;
            
            // Support @ignore and --private
            if (utils.ignore(part) || (utils.isPrivate(part) &amp;&amp; !showPrivate)) continue;
            var part = part.replace(/^ *\* ?/gm, '');
            blocks.push({
               comment: markdown.toHTML(utils.toMarkdown(part)),
               code: koala.render(&quot;.js&quot;, utils.escape(next)) 
            });
        }
    }

    // Generate html
    var html = [];
    for (var i = 0, len = blocks.length; i &lt; len; ++i) {
        var block = blocks[i];
        html.push('<tr class="code">');
        html.push('<td class="docs">', block.comment || '', '</td>');
        html.push('<td class="code">', block.code
            ? '<pre><code>' + block.code + '</code></pre>'
            : '', '</td>');
        html.push('</tr>');
    }

    return html.join('\n');
};

utils

lib/dox/utils.js

Check if the given string of docs appears to be private.

  • param: String str

  • return: Boolean

  • api: public

exports.isPrivate = function(str) {
    return str.indexOf('@private') &gt;= 0
        || str.indexOf('@api private') &gt;= 0;
}

Convert the given string of jsdoc to markdown.

  • param: String str

  • return: String

  • api: public

exports.toMarkdown = function(str) {
    var first = true;
    return str
        .replace(/^((?:[A-Z]\w* ?)+):/gm, '## $1')
        .replace(/^ *@(\w+) *\{([^}]+)\}( *[^\n]+)?/gm, function(_, key, type, desc){
            var prefix = '';
            if (first) {
                first = false;
                prefix = '## \n';
            }
            return prefix + '\n - **' + key + '**: _' + type.split(/ *[|\/] */).join(' | ') + '_ ' + (desc || '') + '\n';
        })
        .replace(/^ *@(\w+) *(\w+)/gm, ' - **$1**: _$2_\n');
}

Escape the given string of html.

Examples

escape('<foo>');
// => "&lt;foo&gt;"

  • param: String html

  • return: String

  • api: public

exports.escape = function(html){
    return String(html)
        .replace(/&(?!\w+;)/g, '&')
        .replace(/</g, '<')
        .replace(/>/g, '>')
        .replace(/"/g, '"');
}