Coddoc

Description

coddoc is a jsdoc parsing library. Coddoc is different in that it is easily extensible by allowing users to add tag and code parsers through the use of coddoc.addTagHandler and coddoc.addCodeHandler. coddoc also parses source code to be used in APIs.

Coddoc also supports the generation of markdown and html through the use of different templates. Currently the templates use Handlebars but you may use any templating engine you wish

JSDOC Tags

JSDoc tags currently supported are:

Coddoc Tags

Coddoc also has a few additional tags.

Installation

Locally
 npm install coddoc
Globally
 npm install -g coddoc

Usage

Down doc does not currently create multi file docs instead will output to a single file. You may however implement your own formatter to create multiple files. Command line options Examples JSON output
 coddoc -d ./lib > symbols.json
To use the markdown formatter
 coddoc -d ./lib -f markdown > README.md
To use the HTML formatter
 coddoc -d ./lib -f html > index.html
To use pragmatically

var coddoc = require("coddoc");
var tree = coddoc.parse({directory : __dirname + "/lib"});
var classes = tree.classes, namespaces = tree.namespaces;
//do something

API

Defined index.js

Entry point for parsing code.

Example
var tree = coddoc({directory : path.resolve(__dirname + "lib")});

//To use markdown formatter
var doc = coddoc({directory : path.resolve(__dirname + "lib"), formatter : coddoc.formatters.markdown});

//To use html formatter
var doc = coddoc({directory : path.resolve(__dirname + "lib"), formatter : coddoc.formatters.html});

//To use custom file pattern
var doc = coddoc({directory : path.resolve(__dirname + "lib"), patter : /.+\.test\.js$/i, formatter : coddoc.html});
        
Arguments Source
function (options){
   options = options || {};
   var baseDir = options.dir, filePattern = options.pattern || FILE_PATTERN;
   if (!baseDir) {
       console.log("directory required");
   }
   var fileMap = {};
   (function findFiles(dir) {
       var files = fs.readdirSync(dir);
       files.forEach(function (file) {
           var filePath = path.resolve(dir, file);
           var stat = fs.statSync(filePath);
           if (stat.isDirectory()) {
               findFiles(filePath);
           } else if (stat.isFile() && filePattern.test(file)) {
               fileMap[filePath] = fs.readFileSync(filePath, "utf8");
           }
       });
   }(baseDir));
   var context = new Context(), tree = new Tree();
   Object.keys(fileMap).forEach(function (i, j) {
       emitter.emit("file", i);
       context.activateScope("global");
       parser.parse(fileMap[i], path.relative(baseDir, i), tree, context, emitter);
   });
   return tree;
       
}
    

addCodeHandler Static Function Public


Defined parser/code.js

Adds a handler for a particular code regular expression. Useful if you want to match a specific type of code not handled by default. When inside of of the parse function you can use the RegExp.$ properties to access match sub expressions. By Default code blocks of the following form are parsed.

// /^function (\w+) *\{/
function(){}

// /^var *(\w+) *= *function/
var x = function(){};

// /^(\w+(?:\.\w+)*)\.prototype\.(\w+(?:\.\w+)?) *= *function/
MyObject.prototype.testFunction = function(){};

// /^(\w+(?:\.\w+)*)\.prototype\.(\w+(?:\.\w+)?) *= *([^\n;]+)/
MyObject.prototype.testProperty = "property";

// /^(\w+(?:\.\w+)+) *= *function/
some.object.testFunction = function(){}

// /^(\w+(?:\.\w+)+) *= *([^\n;]+)/
some.object.testFunction = ["some", "property"];

// /^var +(\w+) *= *([^\n;]+)/
var testProperty = {my : "property"};

var myObject = {
   // /^\"?(\w+)\"? *\: *function/
   testFunction : function(){},

   // /^\"?(\w+)\"? *\: *([^,\n]+)/
   testProperty : "some property"
}

Example
var util = require("coddoc").util;
//parse code in the format of var myLocal = name.space.myFunction = function(){};
//give it a high priority to allow it to override current handlers.
addHandler(/^var *\w+ *= * (\w+(?:\.\w+)*) = *function/, 20, function (str, symbol, context) {
     var splitName = util.splitName(RegExp.$1), name = splitName.name, activeScope = splitName.memberof, params = util.getParamList(str);
     return {
         type:'function',
         isFunction:true,
         memberof:activeScope,
         isStatic:activeScope ? !activeScope.match(".prototype") : false,
         isPrivate:name.match(/^_/) != null,
         name:name,
         params:params,
         code:['function (', params.map(
             function (n) {
                 return n.name.name;
             }).join(","), '){\n   ', util.getCode(str, "{").split("\n").join("\n   "), "\n}"].join("")
    };
});
        
Arguments Source
function (regexp,priority,parse){
   if (util.isFunction(priority)) {
       parse = priority;
       priority = 0;
   }
   handlers.push({
       priority:priority,
       match:function (str) {
           return regexp.exec(str);
       },
       parse:parse
   });
   handlers.sort(sortHandlers);
       
}
    

addTagHandler Static Function Public


Defined parser/tags.js

Adds a new tag to be parsed. You can use this to add custom tags. coddoc will not do anything with the new tag by default, however you can add functionality to handle the new tag in the template.

Example
//if a tag is contains a '|' character then each variation will resolve the the same parser function.
coddoc.addTagHandler("void|VOID|Void", function(comment, symbol, context){
   //do something with the tag or add properties to the symbol.
   symbol.isVoid = true;
   symbol.tags.push({tag : "void", props : {}});
});
//in the template you can add functionality to handle the new tag. For example:
//in the html symbol.tmpl you could add a new label to the name header
<h3>
{{name}}
{{#if isStatic}}
<span class="label label-info">Static</span>
{{/if}}
{{#if isFunction}}
<span class="label label-label">Function</span>
{{/if}}
{{#if isPrivate}}
<span class="label label-important">Private</span>
{{else}}
     {{#if isProtected}}
<span class="label label-warning">Protected</span>
     {{else}}
<span class="label label-success">Public</span>
     {{/if}}
{{/if}}
{{#if isVoid}}
<span class="label label-label">Void</span>
{{/if}}
</h3>
        
Arguments Source
function (tag,parse){
   tag.split("|").forEach(function (tag) {
       tags[tag] = {
           parse:parse || function () {
               return {tag:tag, props:{}};
           }};
   });
       
}
    

getTagRegexp Static Function Protected


Defined parser/tags.js

Returns a regular expression that can be used to parse tags

Returns Source
function (){
   return new RegExp("@(" + Object.keys(tags).join("|") + ")");
       
}
    

parse Static Function Protected


Defined parser/index.js

Parses a string of code into coddoc.Symbols. All processed symbols are added to the coddoc.Tree. This method is not intended to be used directly by user code.

Arguments Returns Source
function (str,filepath,tree,context,emitter){
   var l = str.length;
   var symbols = [];
   for (var i = 0; i < l; i++) {
       var tags = [];
       var comment = "", c = str[i], startIndex = i, endIndex, ret = [];
       var startCIndex = str.indexOf("/**", i);
       if (startCIndex !== -1) {
           i = startCIndex + 2;
           var endCIndex = str.indexOf("*/", i);
           if (endCIndex !== -1) {
               comment = str.substr(startCIndex + 2, endCIndex - (startCIndex + 2)).split("\n").map(joinAndReplace).join("\n");
               emitter.emit("comment", comment);
               i = endCIndex + 1;
               //console.log(str.substr(startCIndex, endCIndex - startCIndex));
               //console.log(comment);
               var res = parseTags({comment:comment, start:startCIndex, end:endCIndex + 2}, str, filepath, context),
                   sym = res.symbol;
               symbols.push(sym);
               emitter.emit("symbol", sym);
               var memberof = sym.memberof;
               if (!sym.ignore && !sym.lends) {
                   tree.addSymbol(sym);
               }
           }
       } else {
           i++;
       }
   }
   return {symbols:symbols, code:str};
       
}
    

parseCode Static Function Protected


Defined parser/code.js

Uses Registered handlers to parse the next block of code from a code fragment. This function is used by coddoc.parse to parse code for comments.

Arguments Source
function (str,symbol,context){
   var l = handlers.length, ret = {};
   for (var i = 0; i < l; i++) {
       var h = handlers[i];
       if (h.match(str)) {
           ret = h.parse(str, symbol, context);
           break;
       }
   }
   if (ret) {
       symbol.codeObject = ret;
       Object.keys(ret).forEach(function (i) {
           symbol[i] = ret[i];
       });
   }
       
}
    

parseTag Static Function Protected


Defined parser/tags.js

Parses a tag and the coresponding comment using a matching tag handler. Each parsed tag could add a new property to the coddoc.Symbol. The parsed tag will be added the the coddoc.Symbol#tags array.

Example
coddoc.parseTag("someTag", "@someTag props...", sym, src, index, context);
//would add a new tag to the symbols property
{
     tag : "tagname",
     props : {...}
}

//the props value would also be added to the symbols params array.
        
Arguments Source
function (comment,sym,context){
   var tag = comment.match(TAG_REGEXP), ret = {};
   if (tag && tag.length === 2) {
       var t = tags[tag[1]];
       if (t) {
           t.parse(comment, sym, context);
       } else {
           throw new Error("Invalid tag " + tag);
       }
   }
       
}
    

A Context object used to keep state when parsing symbols. The context should not be used directly by user code.

Constructor

Defined context.js Source
function (){
   this.scopes = {};
   this.nameSpaces = {global:[]};
   this.aliases = {};
   this.activateScope("global");
       
}
            

activateScope Function Public


Defined context.js

Activates a scope for.

Arguments Returns Source
function (name){
   this.activeScope = name;
   return this.addScope(name);
       
}
    

addNamespace Function Public


Defined context.js

Adds a namespace the the context object.

Arguments Returns Source
function (name){
   if ("undefined" === typeof this.nameSpaces[name]) {
       this.nameSpaces[name] = {};
   }
   return this.nameSpaces[name];
       
}
    

addScope Function Public


Defined context.js

Adds a scope to the context

Arguments Returns Source
function (name){
   if ("undefined" === typeof this.scopes[name]) {
       this.scopes[name] = {};
   }
   return this.scopes[name];
       
}
    

getActiveScope Function Public


Defined context.js

Returns the active scope.

Returns Source
function (){
   return this.getScope(this.activeScope);
       
}
    

getActiveScopeName Function Public


Defined context.js

Returns the name of the active scope.

Returns Source
function (){
   return this.activeScope;
       
}
    

getNamespace Function Public


Defined context.js

Gets a namespace, creating it if it does not exist.

Arguments Returns Source
function (name){
   return this.addNamespace(name);
       
}
    

getScope Function Public


Defined context.js

Gets a scope creating it if it does not exist.

Arguments Returns Source
function (name){
   return this.addScope(name);
       
}
    

A Symbol represents a comment and code pair. Each code handler added through coddoc.addCodeHandler and tag handler added through coddoc.addTagHandler adds/removes properties from a the symbol. Each symbol is added to the coddoc.Tree which is either returned from coddoc or passed into a template handler. NOTE: This object should not be instantiated by user code

Instance Properties
PropertyTypeDefault ValueDescription
augments{Array} [] Any symbols this symbol augments
borrows{Array} [] Any properties this symbol borrows
codeObject{Object}null The codeObject of this symbol
description{String}"" The description of this symbol.
examples{Array} [] The examples for this symbol
file{String}"" The file where the symbol was found.
fullname{String}"" The fullname i.e ({memberof}.{name})
ignore{Boolean}false Set to true if the symbol should be ignored and not put into coddoc.Tree
ignoreCode{Boolean}false Set to true if the code object from this symbol should be ignored.
isConstant{Boolean}false Set to true if this symbol is a constant.
isConstructor{Boolean}false Set to true is this symbol is a constructor
isFunction{Boolean}false Set to true if this symbol is a function.
isPrivate{Boolean}false Set to true if this symbol is private.
isProtected{Boolean}false Set to true if this symbol is protected.
isStatic{Boolean}false Set to true if this symbol is static
memberof{String}"" Who this symbol belongs to.
name{String}"" The name of this symbol
params{Array} [] The associated params for this symbol if it is a funciton.
properties{Array} [] The associated properties for this symbol
returns{Array} [] Array of return types for this symbol
see{Array} [] Any link for this symbol
tags{Array} [] The associated tags for this symbol
throws{Array} [] Exceptions thrown by this symbol
type{*}null The type that is symbol represents.

Constructor

Defined symbol.js Arguments Source
function (options){
   this.tags = [];
   this.params = [];
   this.properties = [];
   this.examples = [];
   this.borrows = [];
   this.augments = [];
   this.includedDocs = [];
   this.see = [];
   this.throws = [];
   this.returns = [];
   options = options || {};
   for (var i in options) {
       if (i in this) {
           this[i] = options[i];
       }
   }
       
}
            

A Tree object which contains symbols.

Constructor

Defined tree.js Source
function (){
   this.symbols = {global:[]};
       
}
            

_addSymbol Function Private


Defined tree.js

Adds a symbol to this tree.

Arguments Returns Source
function (name){
   var ret = this.symbols[name];
   if (!ret) {
       ret = this.symbols[name] = [];
   }
   return ret;
       
}
    

addSymbol Function Public


Defined tree.js

Entry point to add the symbol

Arguments Source
function (symbol){
   var nameParts = utils.splitName(symbol.fullName);
   var path = nameParts.memberof, name = nameParts.name;
   if (path === "global") {
       path = name;
   }
   var sym = this.getSymbol(path);
   sym.push(symbol);
       
}
    

getClasses Function Public


Defined tree.js

Returns all classes in the tree. The following properties are added to each class symbol.

Returns Source
function (){
   var symbols = this.symbols,
       objects = [],
       keys = Object.keys(this.symbols);
   keys.forEach(function (k) {
       objects = objects.concat(symbols[k].filter(function (s) {
           return s.isConstructor;
       }));
   });
   return objects.map(function (s) {
       var name = s.fullName;
       var statics = symbols[name] || [];
       var instance = symbols[name + ".prototype"] || [];
       var borrowedMethods = [], borrowedProperties = [], staticBorrowedMethods = [], staticBorrowedProperties = [];
       s.borrows.map(function (b) {
           var borrows = b.borrows;
           var symbol = symbols[borrows.memberof || "global"].filter(function (s) {
               return s.name === borrows.name;
           });
           if (symbol.length) {
               symbol = symbol[0];
               var memberof = b.isStatic ? name : name + ".prototype";
               var newSymb = new Symbol(utils.merge({}, symbol, {name:b.as, isStatic:b.isStatic, fullName:memberof + "." + b.as, memberof:memberof}));
               if (b.isStatic) {
                   if (s.isFunction) {
                       staticBorrowedMethods.push(newSymb);
                   } else {
                       staticBorrowedProperties.push(newSymb);
                   }
               } else {
                   if (s.isFunction) {
                       borrowedMethods.push(newSymb);
                   } else {
                       borrowedProperties.push(newSymb);
                   }
               }
           }
       });
       s.name = name;
       s.staticMethods = statics.filter(
           function (s) {
               return s.isFunction && !s.isConstructor;
           }).concat(staticBorrowedMethods);
       s.staticProperties = statics.filter(
           function (s) {
               return !s.isFunction && !s.isNamespace;
           }).concat(staticBorrowedProperties);
       s.instanceMethods = instance.filter(
           function (s) {
               return s.isFunction && !s.isConstructor;
           }).concat(borrowedMethods);
       s.instanceProperties = instance.filter(
           function (s) {
               return !s.isFunction && !s.isNamespace;
           }).concat(s.properties || []).concat(borrowedProperties);
       return s;
   });
       
}
    

getMembers Function Public


Defined tree.js

Gets all members( coddoc.Symbol) for a particular path.

Arguments Returns Source
function (path){
   var symbols = this.symbols,
       namespaces = [],
       keys = Object.keys(this.symbols);
   keys.forEach(function (k) {
       namespaces = namespaces.concat(symbols[k].filter(function (s) {
           return !s.isNamespace && !s.isConstructor && s.memberof === path;
       }));
   });
   return namespaces;
       
}
    

getNamespaces Function Public


Defined tree.js

Returns all namespaces in this tree. This method also adds the following values to the namespace.

Returns Source
function (){
   var symbols = this.symbols,
       namespaces = [],
       keys = Object.keys(this.symbols);
   keys.forEach(function (k) {
       namespaces = namespaces.concat(symbols[k].filter(function (s) {
           return s.isNamespace;
       }));
   });
   return namespaces.map(function (s) {
       var realName = s.memberof && s.memberof !== "global" ? [s.memberof, s.name].join(".") : s.name;
       var members = this.getMembers(realName);
       s.name = realName;
       s.properties = s.properties.concat(members.filter(function (m) {
           return !m.isFunction;
       }));
       s.methods = members.filter(function (m) {
           return m.isFunction;
       });
       return s;
   }, this);
       
}
    

getSymbol Function Public


Defined tree.js

Returns a symbol from this tree. The Tree will create the symbol if it does not exist.

Arguments Returns Source
function (name){
   return this._addSymbol(name);
       
}
    

hasSymbol Function Public


Defined tree.js

Returns true if this tree contains a symbol.

Arguments Returns Source
function (name){
   var parts = name.split(".");
   return !!this.symbols[name];
       
}
    

License

MIT LICENSE

Meta


Code: git clone git://github.com/pollenware/coddoc.git