Comparing version 0.4.6 to 0.5.0
@@ -45,3 +45,3 @@ | ||
function headings(str) { | ||
return str.match(/^#+ *([^\n]+)/gm).map(function(str){ | ||
return (str.match(/^#+ *([^\n]+)/gm) || []).map(function(str){ | ||
str = str.replace(/^(#+) */, ''); | ||
@@ -58,7 +58,16 @@ return { | ||
var tags = comment.tags; | ||
var alias = tags.map(function(tag) { | ||
return tag.type === 'alias' && tag.string | ||
}).filter(Boolean); | ||
switch (ctx.type) { | ||
case 'function': | ||
var name = alias.pop() || ctx.name; | ||
return name + '(' + params(tags) + ')' | ||
case 'method': | ||
return (ctx.cons || ctx.receiver) + '.' + ctx.name + '(' + params(tags) + ')'; | ||
var name = alias.pop() || (ctx.cons || ctx.receiver) + '.' + ctx.name; | ||
return name + '(' + params(tags) + ')'; | ||
default: | ||
return ctx.string; | ||
return alias.pop() || ctx.string; | ||
} | ||
@@ -73,2 +82,2 @@ } | ||
}).join(', '); | ||
} | ||
} |
162
lib/dox.js
@@ -22,3 +22,3 @@ /*! | ||
markdown.setOptions({ | ||
var markedOptions = { | ||
renderer: renderer | ||
@@ -32,4 +32,6 @@ , gfm: true | ||
, smartypants: false | ||
}); | ||
}; | ||
markdown.setOptions(markedOptions); | ||
/** | ||
@@ -62,3 +64,8 @@ * Expose api. | ||
, withinSingle = false | ||
, code; | ||
, code | ||
, linterPrefixes = options.skipPrefixes || ['jslint', 'jshint', 'eshint'] | ||
, skipPattern = new RegExp('^<p>('+ linterPrefixes.join('|') + ')') | ||
, lineNum = 1 | ||
, lineNumStarting = 1 | ||
, parentContext; | ||
@@ -68,2 +75,3 @@ for (var i = 0, len = js.length; i < len; ++i) { | ||
if (!withinMultiline && !withinSingle && '/' == js[i] && '*' == js[i+1]) { | ||
lineNumStarting = lineNum; | ||
// code following previous comment | ||
@@ -73,4 +81,16 @@ if (buf.trim().length) { | ||
if(comment) { | ||
comment.code = code = buf.trim(); | ||
comment.ctx = exports.parseCodeContext(code); | ||
// Adjust codeStart for any vertical space between comment and code | ||
comment.codeStart += buf.match(/^(\s*)/)[0].split('\n').length - 1; | ||
comment.code = code = exports.trimIndentation(buf).trim(); | ||
comment.ctx = exports.parseCodeContext(code, parentContext); | ||
// starting a new namespace | ||
if (comment.ctx && comment.ctx.type === 'prototype'){ | ||
parentContext = comment.ctx; | ||
} | ||
// reasons to clear the namespace | ||
// new property/method in a different constructor | ||
else if (!parentContext || !comment.ctx || !comment.ctx.constructor || !parentContext.constructor || parentContext.constructor !== comment.ctx.constructor){ | ||
parentContext = null; | ||
} | ||
} | ||
@@ -82,2 +102,7 @@ buf = ''; | ||
ignore = '!' == js[i]; | ||
// if the current character isn't whitespace and isn't an ignored comment, | ||
// back up one character so we don't clip the contents | ||
if (' ' !== js[i] && '\n' !== js[i] && '\t' !== js[i] && '!' !== js[i]) i--; | ||
// end comment | ||
@@ -87,5 +112,9 @@ } else if (withinMultiline && !withinSingle && '*' == js[i] && '/' == js[i+1]) { | ||
buf = buf.replace(/^[ \t]*\* ?/gm, ''); | ||
var comment = exports.parseComment(buf, options); | ||
comment = exports.parseComment(buf, options); | ||
comment.ignore = ignore; | ||
comments.push(comment); | ||
comment.line = lineNumStarting; | ||
comment.codeStart = lineNum + 1; | ||
if (!comment.description.full.match(skipPattern)) { | ||
comments.push(comment); | ||
} | ||
withinMultiline = ignore = false; | ||
@@ -103,2 +132,11 @@ buf = ''; | ||
} | ||
if (comment && comment.isConstructor && comment.ctx){ | ||
comment.ctx.type = "constructor"; | ||
} | ||
if('\n' == js[i]) { | ||
lineNum++; | ||
} | ||
} | ||
@@ -110,3 +148,5 @@ | ||
description: {full: '', summary: '', body: ''}, | ||
isPrivate: false | ||
isPrivate: false, | ||
isConstructor: false, | ||
line: lineNumStarting | ||
}); | ||
@@ -118,5 +158,7 @@ } | ||
comment = comments[comments.length - 1]; | ||
code = buf.trim(); | ||
// Adjust codeStart for any vertical space between comment and code | ||
comment.codeStart += buf.match(/^(\s*)/)[0].split('\n').length - 1; | ||
code = exports.trimIndentation(buf).trim(); | ||
comment.code = code; | ||
comment.ctx = exports.parseCodeContext(code); | ||
comment.ctx = exports.parseCodeContext(code, parentContext); | ||
} | ||
@@ -128,2 +170,20 @@ | ||
/** | ||
* Removes excess indentation from string of code. | ||
* | ||
* @param {String} str | ||
* @return {String} | ||
* @api public | ||
*/ | ||
exports.trimIndentation = function (str) { | ||
// Find indentation from first line of code. | ||
var indent = str.match(/(?:^|\n)([ \t]*)[^\s]/); | ||
if (indent) { | ||
// Replace indentation on all lines. | ||
str = str.replace(new RegExp('(^|\n)' + indent[1], 'g'), '$1'); | ||
} | ||
return str; | ||
}; | ||
/** | ||
* Parse the given comment `str`. | ||
@@ -155,2 +215,7 @@ * | ||
// A comment has no description | ||
if (tags[0].charAt(0) === '@') { | ||
tags.unshift(''); | ||
} | ||
// parse comment body | ||
@@ -168,2 +233,5 @@ description.full = tags[0]; | ||
}); | ||
comment.isConstructor = comment.tags.some(function(tag){ | ||
return 'constructor' == tag.type || 'augments' == tag.type; | ||
}) | ||
} | ||
@@ -206,5 +274,7 @@ | ||
tag.description = parts.join(' '); | ||
tag.optional = exports.parseParamOptional(tag); | ||
break; | ||
case 'define': | ||
case 'return': | ||
case 'returns': | ||
tag.types = exports.parseTagTypes(parts.shift()); | ||
@@ -276,2 +346,20 @@ tag.description = parts.join(' '); | ||
/** | ||
* Determine if a parameter is optional. | ||
* | ||
* Examples: | ||
* JSDoc: {Type} [name] | ||
* Google: {Type=} name | ||
* TypeScript: {Type?} name | ||
* | ||
* @param {Object} tag | ||
* @return {Boolean} | ||
* @api public | ||
*/ | ||
exports.parseParamOptional = function(tag) { | ||
var lastTypeChar = tag.types.slice(-1)[0].slice(-1); | ||
return tag.name.slice(0,1) === '[' || lastTypeChar === '=' || lastTypeChar === '?'; | ||
}; | ||
/** | ||
* Parse the context from the given `str` of js. | ||
@@ -292,2 +380,3 @@ * | ||
* @param {String} str | ||
* @param {Object=} parentContext An indication if we are already in something. Like a namespace or an inline declaration. | ||
* @return {Object} | ||
@@ -297,4 +386,5 @@ * @api public | ||
exports.parseCodeContext = function(str){ | ||
exports.parseCodeContext = function(str, parentContext) { | ||
var str = str.split('\n')[0]; | ||
parentContext = parentContext || {}; | ||
@@ -334,2 +424,48 @@ // function statement | ||
}; | ||
// prototype property without assignment | ||
} else if (/^([\w$]+)\.prototype\.([\w$]+);/.exec(str)) { | ||
return { | ||
type: 'property' | ||
, constructor: RegExp.$1 | ||
, cons: RegExp.$1 | ||
, name: RegExp.$2 | ||
, string: RegExp.$1 + '.prototype.' + RegExp.$2 | ||
}; | ||
// inline prototype | ||
} else if (/^([\w$.]+)\.prototype[ \t]*=[ \t]*{/.exec(str)) { | ||
return { | ||
type: 'prototype' | ||
, constructor: RegExp.$1 | ||
, cons: RegExp.$1 | ||
, name: RegExp.$1 | ||
, string: RegExp.$1 + '.prototype' | ||
}; | ||
// inline method | ||
} else if (/^[ \t]*([\w$.]+)[ \t]*:[ \t]*function/.exec(str)) { | ||
return { | ||
type: 'method' | ||
, constructor: parentContext.name | ||
, cons: parentContext.name | ||
, name: RegExp.$1 | ||
, string: (parentContext && parentContext.name && parentContext.name + '.prototype.' || '') + RegExp.$1 + '()' | ||
}; | ||
// inline property | ||
} else if (/^[ \t]*([\w$.]+)[ \t]*:[ \t]*([^\n;]+)/.exec(str)) { | ||
return { | ||
type: 'property' | ||
, constructor: parentContext.name | ||
, cons: parentContext.name | ||
, name: RegExp.$1 | ||
, value: RegExp.$2 | ||
, string: (parentContext && parentContext.name && parentContext.name + '.' || '') + RegExp.$1 | ||
}; | ||
// inline getter/setter | ||
} else if (/^[ \t]*(get|set)[ \t]*([\w$.]+)[ \t]*\(/.exec(str)) { | ||
return { | ||
type: 'property' | ||
, constructor: parentContext.name | ||
, cons: parentContext.name | ||
, name: RegExp.$2 | ||
, string: (parentContext && parentContext.name && parentContext.name + '.prototype.' || '') + RegExp.$2 | ||
}; | ||
// method | ||
@@ -362,1 +498,5 @@ } else if (/^([\w$.]+)\.([\w$]+)[ \t]*=[ \t]*function/.exec(str)) { | ||
}; | ||
exports.setMarkedOptions = function(opts) { | ||
markdown.setOptions(opts); | ||
}; |
@@ -1,19 +0,39 @@ | ||
{ "name": "dox" | ||
, "description": "Markdown / JSdoc documentation generator" | ||
, "version": "0.4.6" | ||
, "author": "TJ Holowaychuk <tj@vision-media.ca>" | ||
, "repository": { "type": "git", "url": "git://github.com/visionmedia/dox.git" } | ||
, "keywords": ["documentation", "docs", "markdown", "jsdoc"] | ||
, "bin": { "dox": "./bin/dox" } | ||
, "dependencies": { | ||
"marked": ">=0.3.1" | ||
, "commander": "0.6.1" | ||
} | ||
, "devDependencies": { | ||
"mocha": "^1.20.1" | ||
, "should": "^4.0.4" | ||
} | ||
, "scripts": { | ||
{ | ||
"name": "dox", | ||
"description": "Markdown / JSdoc documentation generator", | ||
"version": "0.5.0", | ||
"author": "TJ Holowaychuk <tj@vision-media.ca>", | ||
"contributors": [ | ||
"Arseny Zarechnev <me@evindor.com>", | ||
"Thomas Parisot <hi@oncletom.io>", | ||
"Jarvis Badgley <chiper@chipersoft.com>", | ||
"Stephen Mathieson <me@stephenmathieson.com>", | ||
"Vladimir Tsvang <vtsvang@gmail.com>", | ||
"Nathan Rajlich <nathan@tootallnate.net>", | ||
"ForbesLindesay" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/visionmedia/dox.git" | ||
}, | ||
"keywords": [ | ||
"documentation", | ||
"docs", | ||
"markdown", | ||
"jsdoc" | ||
], | ||
"bin": { | ||
"dox": "./bin/dox" | ||
}, | ||
"dependencies": { | ||
"marked": ">=0.3.1", | ||
"commander": "0.6.1" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^1.20.1", | ||
"should": "^4.0.4" | ||
}, | ||
"scripts": { | ||
"test": "make test" | ||
} | ||
} |
# Dox | ||
[![build status](https://secure.travis-ci.org/visionmedia/dox.png)](http://travis-ci.org/visionmedia/dox) | ||
[![Build Status](https://travis-ci.org/visionmedia/dox.svg?branch=master)](https://travis-ci.org/visionmedia/dox) | ||
@@ -118,2 +118,15 @@ Dox is a JavaScript documentation generator written with [node](http://nodejs.org). Dox no longer generates an opinionated structure or style for your docs, it simply gives you a JSON representation, allowing you to use _markdown_ and _JSDoc_-style tags. | ||
### Programmatic Usage | ||
``` javascript | ||
var dox = require('dox'), | ||
code = "..."; | ||
var obj = dox.parseComments(code); | ||
// [{ tags:[ ... ], description, ... }, { ... }, ...] | ||
``` | ||
## Properties | ||
@@ -120,0 +133,0 @@ |
Sorry, the diff of this file is not supported yet
28351
517
350