diff --git a/examples/strong-docs/lib/annotation.js b/examples/strong-docs/lib/annotation.js index c2bd6fc60305..b75c7cef7a20 100644 --- a/examples/strong-docs/lib/annotation.js +++ b/examples/strong-docs/lib/annotation.js @@ -66,8 +66,20 @@ function Annotation(comment, doc) { var name = ctx && ctx.string; var functionName = attrs.method; var header; + var anchorId; var memberOf = attrs.memberof; + if (args) { + args.forEach(function(arg) { + if (!arg.types) return; + // workaround for dox splitting function types on comma + // E.g. @param {function(Error=,Object=)} + if (/^[fF]unction\([^\)]+$/.test(arg.types[0])) { + arg.types = [arg.types.join(', ')]; + } + }); + } + // @static / @instance + @memberof if(!name) { switch(type) { @@ -95,13 +107,15 @@ function Annotation(comment, doc) { // build header if (typeof attrs.class === 'string') { - header = attrs.class; + anchorId = header = attrs.class; } else if(type === 'overview') { header = doc.filename; + anchorId = 'file-' + header; if(!desc) { desc = attrs.overview || attrs.file; } } else if(type === 'module') { + anchorId = 'module-' + attrs.module; header = 'Module: ' + attrs.module; this.moduleExample = (this.isConstructor ? pascal : camel)(attrs.module) + " = require('" + attrs.module + "')"; } else if(Array.isArray(args) && args.length && name) { @@ -117,9 +131,11 @@ function Annotation(comment, doc) { }) .join(', '); - header = name.replace(/\(\)\s*$/, '') + '('+ argNames +')'; + name = name.replace(/\(\)\s*$/, ''); + header = name + '('+ argNames +')'; + anchorId = name; } else if(name) { - header = name; + anchorId = header = name; } // header modifiers/override @@ -137,6 +153,8 @@ function Annotation(comment, doc) { if(typeof attrs.header === 'string') { header = attrs.header; + // Remove function arg signature from the anchor + anchorId = header.replace(/\(.*$/, ''); } // could not parse annotation @@ -147,12 +165,12 @@ function Annotation(comment, doc) { } if(desc) { - this.html = marked(desc, doc.markedOptions); + this.html = this._renderDescriptionHtml(desc); } this.header = header; this.sectionTitle = stringToSectionTitle(this.sectionTitle || header); - this.anchor = docs.getUniqueAnchor(header); + this.anchor = docs.getUniqueAnchor(anchorId); this.section = this.buildSection(); } @@ -260,6 +278,26 @@ Annotation.prototype.render = function () { }); } +Annotation.prototype._renderDescriptionHtml = function(desc) { + var self = this; + // handle @link annotations - see http://usejsdoc.org/tags-link.html + desc = desc + // {@link http://some.url.com} + .replace(/{@link (http[^ }]+)}/g, '[$1]($1)') + // {@link http://some.url.com Caption Here (after the first space)} + .replace(/{@link (http[^ }]+) ([^}]+)}/g, '[$2]($1)') + // {@link someSymbol} + .replace(/{@link ([^ }]+)}/g, function(match, symbol) { + return '[' + symbol + '](#' + self.docs.getUrlSafeAnchor(symbol) + ')'; + }) + // {@link someSymbol Caption Here (after the first space)} + .replace(/{@link ([^ }]+) ([^}]+)}/g, function(match, symbol, caption) { + return '[' + caption + '](#' + self.docs.getUrlSafeAnchor(symbol) + ')'; + }); + + return marked(desc, self.doc.markedOptions); +}; + var aliases = { function: 'method', file: 'overview', diff --git a/examples/strong-docs/lib/docs.js b/examples/strong-docs/lib/docs.js index 46a5771d48de..cdf1642fb536 100644 --- a/examples/strong-docs/lib/docs.js +++ b/examples/strong-docs/lib/docs.js @@ -268,10 +268,14 @@ Docs.prototype.buildSections = function () { } } +Docs.prototype.getUrlSafeAnchor = function(title) { + return string.slugify(title.toLowerCase().replace(/\./g, '-')); +}; + Docs.prototype.getUniqueAnchor = function (title) { var anchors = this.anchors = this.anchors || {}; var anchor; - var urlSafe = string.slugify(title.toLowerCase()); + var urlSafe = this.getUrlSafeAnchor(title); var isUsed = anchors[urlSafe]; if(!urlSafe) { diff --git a/examples/strong-docs/package.json b/examples/strong-docs/package.json index f5dfd4149019..083e388972d3 100644 --- a/examples/strong-docs/package.json +++ b/examples/strong-docs/package.json @@ -26,6 +26,7 @@ "underscore.string": "~2.3.3" }, "devDependencies": { + "chai": "^1.9.2", "mocha": "~1.13.0" }, "bin": { diff --git a/examples/strong-docs/test/docs.test.js b/examples/strong-docs/test/docs.test.js index 6bf26c501549..7ba3ce470c0e 100644 --- a/examples/strong-docs/test/docs.test.js +++ b/examples/strong-docs/test/docs.test.js @@ -1,6 +1,8 @@ var fs = require('fs'); var path = require('path'); var assert = require('assert'); +var expect = require('chai').expect; + var SAMPLE = [ 'fixtures/a.md', 'fixtures/b/b.md', @@ -65,8 +67,8 @@ describe('Docs', function() { it('should have unique anchors', function () { var docs = new Docs(); var samples = [ - 'Model.validatesNumericalityOf(property, options)', - 'Model.validatesNumericalityOf(property, options)', + 'Model.validatesNumericalityOf', + 'Model.validatesNumericalityOf', 'foo', 'foo', 'foo', @@ -75,8 +77,8 @@ describe('Docs', function() { ]; var expected = [ - 'modelvalidatesnumericalityofproperty-options', - 'modelvalidatesnumericalityofproperty-options-1', + 'model-validatesnumericalityof', + 'model-validatesnumericalityof-1', 'foo', 'foo-1', 'foo-2', @@ -158,4 +160,32 @@ describe('Docs', function() { }); }); }); + + describe('ngdoc flavour', function() { + var annotation; + + beforeEach(function parseNgDocSourceFile(done) { + Docs.parse( + { + content: ['fixtures/ngdoc.js'], + root: __dirname + }, + function(err, docs) { + if (err) return done(err); + annotation = docs.content[0].sections[0].annotation; + done(); + }); + }); + + it('should include @description', function() { + expect(annotation.html).to.contain('Some description'); + }); + + it('should handle multi-param function type', function() { + // @param {String|Number} + expect(annotation.args[0].types).to.eql(['String', 'Number']); + // @param {function(Error=,Object=)} + expect(annotation.args[1].types).to.eql(['function(Error=, Object=)']); + }); + }); }); diff --git a/examples/strong-docs/test/fixtures/ngdoc.js b/examples/strong-docs/test/fixtures/ngdoc.js new file mode 100644 index 000000000000..1e01e70d58b4 --- /dev/null +++ b/examples/strong-docs/test/fixtures/ngdoc.js @@ -0,0 +1,12 @@ +/** + * + * @ngdoc method + * @param {String|Number} arg + * @param {function(Error=,Object=)} callback + * @description + * + * Some description. + */ +function async(arg, callback) { + callback(); +}