diff --git a/lib/jsdoc/util/markdown.js b/lib/jsdoc/util/markdown.js index 766bffdd..3f1389b3 100644 --- a/lib/jsdoc/util/markdown.js +++ b/lib/jsdoc/util/markdown.js @@ -9,6 +9,7 @@ var logger = require('jsdoc/util/logger'); var MarkdownIt = require('markdown-it'); var marked = require('marked'); var mdnh = require('markdown-it-named-headers'); +var path = require('jsdoc/path'); var util = require('util'); /** @@ -137,6 +138,51 @@ function unencodeQuotes(source) { }); } +/** + * Get the appropriate function for applying syntax highlighting to text, based on the user's + * Markdown configuration settings. + * + * @param {Object} conf - The user's Markdown configuration settings. + * @return {function} The highlighter function. + */ +function getHighlighter(conf) { + var highlighter; + var highlighterPath; + + switch (typeof conf.highlight) { + case 'string': + highlighterPath = path.getResourcePath(conf.highlight); + + if (highlighterPath) { + highlighter = require(highlighterPath).highlight; + + if (typeof highlighter !== 'function') { + logger.error('The syntax highlighting module "%s" does not assign a method ' + + 'to exports.highlight. Using the default syntax highlighter.', + conf.highlight); + highlighter = highlight; + } + } + else { + logger.error('Unable to find the syntax highlighting module "%s". Using the ' + + 'default syntax highlighter.', conf.highlight); + highlighter = highlight; + } + + break; + + case 'function': + highlighter = conf.highlight; + + break; + + default: + highlighter = highlight; + } + + return highlighter; +} + /** * Retrieve a function that accepts a single parameter containing Markdown source. The function uses * the specified parser to transform the Markdown source to HTML, then returns the HTML as a string. @@ -148,10 +194,12 @@ function unencodeQuotes(source) { * returns the resulting HTML. */ function getParseFunction(parserName, conf) { + var highlighter; var parserFunction; var renderer; conf = conf || {}; + highlighter = getHighlighter(conf); switch (parserName) { case parserNames.marked: @@ -168,7 +216,7 @@ function getParseFunction(parserName, conf) { }; } - renderer.code = highlight; + renderer.code = highlighter; parserFunction = function(source) { var result; @@ -192,7 +240,7 @@ function getParseFunction(parserName, conf) { case parserNames.markdownit: renderer = new MarkdownIt({ breaks: Boolean(conf.hardwrap), - highlight: highlight, + highlight: highlighter, html: true }); diff --git a/test/fixtures/markdown/badhighlighter.js b/test/fixtures/markdown/badhighlighter.js new file mode 100644 index 00000000..d734b9b2 --- /dev/null +++ b/test/fixtures/markdown/badhighlighter.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.highlight = 'Not a real highlighter'; diff --git a/test/fixtures/markdown/highlighter.js b/test/fixtures/markdown/highlighter.js new file mode 100644 index 00000000..637361c5 --- /dev/null +++ b/test/fixtures/markdown/highlighter.js @@ -0,0 +1,5 @@ +'use strict'; + +exports.highlight = function(code, language) { + return '
' + code + ' in this language: ' + language + '';
+};
diff --git a/test/specs/jsdoc/util/markdown.js b/test/specs/jsdoc/util/markdown.js
index 9ee116de..a3739dc7 100644
--- a/test/specs/jsdoc/util/markdown.js
+++ b/test/specs/jsdoc/util/markdown.js
@@ -2,6 +2,7 @@
describe('jsdoc/util/markdown', function() {
var env = require('jsdoc/env');
+ var logger = require('jsdoc/util/logger');
var markdown = require('jsdoc/util/markdown');
it('should exist', function() {
@@ -66,11 +67,10 @@ describe('jsdoc/util/markdown', function() {
});
it('should log an error if an unrecognized Markdown parser is requested', function() {
- var logger = require('jsdoc/util/logger');
-
setMarkdownConf({parser: 'not-a-real-markdown-parser'});
spyOn(logger, 'error');
markdown.getParser();
+
expect(logger.error).toHaveBeenCalled();
});
@@ -131,5 +131,53 @@ describe('jsdoc/util/markdown', function() {
expect(parser(markdownText)).toBe(convertedText);
});
+
+ describe('syntax highlighter', function() {
+ it('should support a `highlight` function defined in the config file', function() {
+ var parser;
+
+ setMarkdownConf({
+ highlight: function(code, language) {
+ return '' + code + ' highlighted as ' + language +
+ '';
+ }
+ });
+ parser = markdown.getParser();
+
+ expect(parser('```js\nhello\n```')).toBe(
+ 'hello\n highlighted as js'
+ );
+ });
+
+ it('should support `highlight` as the path to a highlighter module', function() {
+ var parser;
+
+ setMarkdownConf({ highlight: 'test/fixtures/markdown/highlighter' });
+ parser = markdown.getParser();
+
+ expect(parser('```js\nhello\n```')).toBe(
+ 'hello\n in this language: js'
+ );
+ });
+
+ it('should log an error if the `highlight` module cannot be found', function() {
+ spyOn(logger, 'error');
+
+ setMarkdownConf({ highlight: 'foo/bar/baz' });
+ markdown.getParser();
+
+ expect(logger.error).toHaveBeenCalled();
+ });
+
+ it('should log an error if the `highlight` module does not assign a method to ' +
+ '`exports.highlight`', function() {
+ spyOn(logger, 'error');
+
+ setMarkdownConf({ highlight: 'test/fixtures/markdown/badhighlighter' });
+ markdown.getParser();
+
+ expect(logger.error).toHaveBeenCalled();
+ });
+ });
});
});