diff --git a/package.json b/package.json index abec865..f30e0f2 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "extend": "^2.0.0", "handlebars": "^3.0.0", "module-deps": "^3.7.3", + "remarkable": "^1.6.0", "through": "^2.3.6", "traverse": "^0.6.6", "yargs": "^3.5.4" diff --git a/streams/html.js b/streams/html.js new file mode 100644 index 0000000..b5e83b6 --- /dev/null +++ b/streams/html.js @@ -0,0 +1,41 @@ +'use strict'; + +var through = require('through'), + Remarkable = require('remarkable'), + extend = require('extend'); + +var defaultTags = ['author', 'classdesc', 'description', + 'param', 'property', 'returns', 'see', 'throws']; + +/** + * Create a transform stream that parses Markdown in the 'description' + * tag and formats it as HTML. + * + * @param {Object} markdownOptions Options given to the Remarkable Markdown parser. + * @param {Array} [overrideTags=author,classdesc,description,param,property,returns,see,throws] + * Tags which will be parsed and translated. + * @name markdown + * @return {stream.Transform} + */ +module.exports = function (opts, overrideTags) { + var tagsToParse = overrideTags || defaultTags; + var md = new Remarkable(opts); + return through(function (comment) { + + var description = (tagsToParse.indexOf('description') !== -1 && + comment.description) ? { + description: md.render(comment.description) + } : {}; + + var parsedTags = comment.tags ? { + tags: comment.tags.map(function (tag) { + return tagsToParse.indexOf(tag.title) !== -1 ? + extend({}, tag, { + description: md.render(tag.description) + }) : tag; + }) + } : {}; + + this.push(extend({}, comment, parsedTags, description)); + }); +}; diff --git a/test/streams/html.js b/test/streams/html.js new file mode 100644 index 0000000..5fc35ad --- /dev/null +++ b/test/streams/html.js @@ -0,0 +1,89 @@ +'use strict'; + +var test = require('prova'), + html = require('../../streams/html'), + concat = require('concat-stream'); + +test('normalizes tags', function (t) { + var stream = html(); + + stream.pipe(concat(function (data) { + t.deepEqual(data, [{ + 'description': '

this is markdown

\n', + 'tags': [{ + 'title': 'returns', + 'description': '

numberone or google

\n', + 'type': { + 'type': 'NameExpression', + 'name': 'Number' + } + }] + }]); + t.end(); + })); + + stream.end({ + description: '**this is markdown**', + tags: [ + { + 'title': 'returns', + 'description': 'numberone or [google](http://google.com)', + 'type': { + 'type': 'NameExpression', + 'name': 'Number' + } + } + ] + }); +}); + +test('opt-out of param parsing', function (t) { + var stream = html({}, ['description']); + + stream.pipe(concat(function (data) { + t.deepEqual(data, [{ + 'description': '

this is markdown

\n', + 'tags': [{ + 'title': 'returns', + 'description': 'numberone or [google](http://google.com)', + 'type': { + 'type': 'NameExpression', + 'name': 'Number' + } + }] + }]); + t.end(); + })); + + stream.end({ + description: '**this is markdown**', + tags: [ + { + 'title': 'returns', + 'description': 'numberone or [google](http://google.com)', + 'type': { + 'type': 'NameExpression', + 'name': 'Number' + } + } + ] + }); +}); + +test('passing options to remarkable', function (t) { + var stream = html({ + linkify: true + }); + + stream.pipe(concat(function (data) { + t.deepEqual(data, [{ + 'description': '\n' + }]); + t.end(); + })); + + stream.end({ + description: '+ http://foo.com/' + }); +}); +