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 currently supported are:
@includeDoc [Title Of Doc] ../location/of_doc.md
example
tag
Example {@code var test = "test"; }
npm install coddocGlobally
npm install -g coddoc
coddoc -d ./lib > symbols.jsonTo use the markdown formatter
coddoc -d ./lib -f markdown > README.mdTo use the HTML formatter
coddoc -d ./lib -f html > index.htmlTo use pragmatically
var coddoc = require("coddoc"); var tree = coddoc.parse({directory : __dirname + "/lib"}); var classes = tree.classes, namespaces = tree.namespaces; //do something
Entry point for parsing code.
Examplevar 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
String
: the directory of code to parse./.+\.js$/i
] RegExp
: a regular expression to test files againsObject
: And optional formatter to format the tree. The object must contain
a generate
method. See coddoc.formatters.htmlfunction (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; }
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
0
] : the priority to give this code handler if not provided
it is defaulted to 0.codeObject
on the coddoc.Symbol. The properties of the object will be added to the coddoc.Symbol for processing later.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); }
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
function (tag,parse){ tag.split("|").forEach(function (tag) { tags[tag] = { parse:parse || function () { return {tag:tag, props:{}}; }}; }); }
Returns a regular expression that can be used to parse tags
ReturnsRegExp
a regular expression to parse valid tags.function (){ return new RegExp("@(" + Object.keys(tags).join("|") + ")"); }
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.
ArgumentsObject
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}; }
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.
Argumentsfunction (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]; }); } }
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.
Examplecoddoc.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
String
: the tag name being parsed from the commentfunction (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.
function (){ this.scopes = {}; this.nameSpaces = {global:[]}; this.aliases = {}; this.activateScope("global"); }
Activates a scope for.
ArgumentsObject
the activated scope object.function (name){ this.activeScope = name; return this.addScope(name); }
Adds a namespace the the context object.
ArgumentsObject
the object for the namespace.function (name){ if ("undefined" === typeof this.nameSpaces[name]) { this.nameSpaces[name] = {}; } return this.nameSpaces[name]; }
Adds a scope to the context
ArgumentsObject
the object for the namespace.function (name){ if ("undefined" === typeof this.scopes[name]) { this.scopes[name] = {}; } return this.scopes[name]; }
Returns the active scope.
ReturnsObject
the scope objectfunction (){ return this.getScope(this.activeScope); }
Returns the name of the active scope.
ReturnsString
the active scope name.function (){ return this.activeScope; }
Gets a namespace, creating it if it does not exist.
ArgumentsObject
the object for the namespace.function (name){ return this.addNamespace(name); }
Gets a scope creating it if it does not exist.
ArgumentsObject
the object for the namespace.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 PropertiesProperty | Type | Default Value | Description |
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. |
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.
function (){ this.symbols = {global:[]}; }
Adds a symbol to this tree.
ArgumentsArray
function (name){ var ret = this.symbols[name]; if (!ret) { ret = this.symbols[name] = []; } return ret; }
Entry point to add the symbol
ArgumentsString
: the path of the symbol. i.e the memberof property of a symbolfunction (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); }
Returns all classes in the tree. The following properties are added to each class symbol.
Array
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; }); }
Gets all members( coddoc.Symbol) for a particular path.
ArgumentsArray
and array of symbols.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; }
Returns all namespaces in this tree. This method also adds the following values to the namespace.
Array
array of namespacesfunction (){ 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); }
Returns a symbol from this tree. The Tree will create the symbol if it does not exist.
ArgumentsArray
the array for the symbol.function (name){ return this._addSymbol(name); }
Returns true if this tree contains a symbol.
ArgumentsBoolean
true if the tree contains the symbol.function (name){ var parts = name.split("."); return !!this.symbols[name]; }
MIT LICENSE
Code: git clone git://github.com/pollenware/coddoc.git