Skip to content

Commit

Permalink
Process descriptions for @link tags.
Browse files Browse the repository at this point in the history
Symbols within the same AST are linked via generated hash targets.  Absolute
URLs starting with `http://` and `https://` are linked normally.  Any other
values are not linked and output as text.

Note: Cross-AST (aka multi-file) symbol linking could be achieved in the future
by creating a global symbol map before generating the output.
  • Loading branch information
nicksay committed Dec 24, 2014
1 parent 92e9508 commit 9a85fd3
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 29 deletions.
8 changes: 4 additions & 4 deletions fixtures/test6.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
@overview This sample handles namespaces and interfaces.
@overview This sample handles namespaces, interfaces, and links.
@license MIT
*/

Expand All @@ -24,7 +24,7 @@ main.dispose = function() {};


/**
* Definition for a Thing object.
* Definition for a Thing object used by a Worker. See {@link main.Worker}.
* @interface
*/
main.Thing;
Expand Down Expand Up @@ -52,9 +52,9 @@ main.Worker;


/**
* Have a Worker do some Thing.
* Have a Worker do some Thing. See {@link main.Thing}.
*
* @param {main.Thing} thing The Thing to do.
* @param {main.Thing} thing The Thing to do. See {@link main.Thing}.
*/
main.Worker.prototype.do = function(thing) {};

Expand Down
63 changes: 63 additions & 0 deletions lib/generateMD.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,55 @@
var Mustache = require('mustache');
var fs = require('fs');
var path = require('path');
var util = require('util');


/**
* Replaces {@link ...} with `[...](...)`.
* @param {string} str - string to process
* @param {Object} targets - map of targets to use for links (optional)
* @return {string}
*/
function replaceLink(str, targets) {
return str.replace(/\{@link\s+([^}]+)\}/g, function(full, link) {
if (link in targets) {
return util.format('[%s](%s)', link, targets[link]);
} else if (link.match(/^(https?:)?\/\//)) {
return util.format('[%s](%s)', link, link);
}
return link;
});
}


/**
* Processes a tag for Markdown replacements.
* @param {Object} tag - tag to process
* @param {Object} targets - map of targets to use for links (optional)
*/
function processTag(tag, targets) {
if (tag.description) {
tag.description = replaceLink(tag.description, targets);
}
if (tag.params) {
tag.params.forEach(function (param) {
if (param.description) {
param.description = replaceLink(param.description, targets);
}
});
}
if (tag.members) {
tag.members.forEach(function (member) {
processTag(member, targets);
});
}
if (tag.methods) {
tag.methods.forEach(function (method) {
processTag(method, targets);
});
}
}


/**
* Renders markdown from the given analyzed AST
Expand All @@ -24,6 +73,16 @@ module.exports = function(ast, templateDir, isIndex, sort) {
templateDir = templateDir.replace(/\\/g, '/');
}

var tags = (ast.modules || [])
.concat(ast.classes || [])
.concat(ast.functions || []);
var targets = {};
tags.forEach(function (tag) {
if (tag.longname) {
tag.target = targets[tag.longname] = '#' + tag.longname.toLowerCase();
}
});

//if ast is an index file, we need to sort the contents and to use the right templates;
if (isIndex) {
console.log('Now generating index');
Expand Down Expand Up @@ -60,6 +119,10 @@ module.exports = function(ast, templateDir, isIndex, sort) {
return Mustache.render(templates.index, ast, templates);
}

tags.forEach(function (tag) {
processTag(tag, targets);
});

templates = {
file: fs.readFileSync(templateDir + '/file.mustache', 'utf8'),
class: fs.readFileSync(templateDir + '/class.mustache', 'utf8'),
Expand Down
8 changes: 4 additions & 4 deletions sample_output/test6.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Disposes everything.


## Class: Thing
Definition for a Thing object.
Definition for a Thing object used by a Worker. See [main.Worker](#main.worker).

**name**: `string` , Every Thing has a name.
**data**: `* | undefined` , Every Thing might have some data.
Expand All @@ -29,11 +29,11 @@ Definition for a Worker.

### main.Worker.do(thing)

Have a Worker do some Thing.
Have a Worker do some Thing. See [main.Thing](#main.thing).

**Parameters**

**thing**: `main.Thing`, The Thing to do.
**thing**: `main.Thing`, The Thing to do. See [main.Thing](#main.thing).



Expand Down Expand Up @@ -67,6 +67,6 @@ Run the Bar utility.

**License:** MIT

**Overview:** This sample handles namespaces and interfaces.
**Overview:** This sample handles namespaces, interfaces, and links.


42 changes: 21 additions & 21 deletions test/lib/generateMD.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ describe('generateMD', function() {
generateMD(analyzed, null, true, 'standard');

expect(analyzed.functions).to.eql([
{name: 'four', longname: 'foo.four' },
{name: 'one', longname: 'foo.one' },
{name: 'three', longname: 'bar.three' },
{name: 'two', longname: 'bar.two' },
{name: 'zero', longname: 'zero' }
{name: 'four', longname: 'foo.four', target: '#foo.four' },
{name: 'one', longname: 'foo.one', target: '#foo.one' },
{name: 'three', longname: 'bar.three', target: '#bar.three' },
{name: 'two', longname: 'bar.two', target: '#bar.two' },
{name: 'zero', longname: 'zero', target: '#zero' }
]);
expect(analyzed.classes).to.eql([
{name: 'Five', longname: 'Five' },
{name: 'Six', longname: 'bar.Six' }
{name: 'Five', longname: 'Five', target: '#five' },
{name: 'Six', longname: 'bar.Six', target: '#bar.six' }
]);
});

Expand All @@ -112,15 +112,15 @@ describe('generateMD', function() {
generateMD(analyzed, null, true, 'namespace');

expect(analyzed.functions).to.eql([
{name: 'zero', longname: 'zero' },
{name: 'three', longname: 'bar.three' },
{name: 'two', longname: 'bar.two' },
{name: 'four', longname: 'foo.four' },
{name: 'one', longname: 'foo.one' }
{name: 'zero', longname: 'zero', target: '#zero' },
{name: 'three', longname: 'bar.three', target: '#bar.three' },
{name: 'two', longname: 'bar.two', target: '#bar.two' },
{name: 'four', longname: 'foo.four', target: '#foo.four' },
{name: 'one', longname: 'foo.one', target: '#foo.one' }
]);
expect(analyzed.classes).to.eql([
{name: 'Five', longname: 'Five' },
{name: 'Six', longname: 'bar.Six' }
{name: 'Five', longname: 'Five', target: '#five' },
{name: 'Six', longname: 'bar.Six', target: '#bar.six' }
]);
});

Expand All @@ -142,15 +142,15 @@ describe('generateMD', function() {
generateMD(analyzed, null, true, 'none');

expect(analyzed.functions).to.eql([
{name: 'zero', longname: 'zero' },
{name: 'one', longname: 'foo.one' },
{name: 'two', longname: 'bar.two' },
{name: 'three', longname: 'bar.three' },
{name: 'four', longname: 'foo.four' }
{name: 'zero', longname: 'zero', target: '#zero' },
{name: 'one', longname: 'foo.one', target: '#foo.one' },
{name: 'two', longname: 'bar.two', target: '#bar.two' },
{name: 'three', longname: 'bar.three', target: '#bar.three' },
{name: 'four', longname: 'foo.four', target: '#foo.four' }
]);
expect(analyzed.classes).to.eql([
{name: 'Five', longname: 'Five' },
{name: 'Six', longname: 'bar.Six' }
{name: 'Five', longname: 'Five', target: '#five' },
{name: 'Six', longname: 'bar.Six', target: '#bar.six' }
]);
});
});

0 comments on commit 9a85fd3

Please sign in to comment.