diff --git a/rhino_modules/jsdoc/util/markdown.js b/rhino_modules/jsdoc/util/markdown.js index 08671712..0711d4d9 100644 --- a/rhino_modules/jsdoc/util/markdown.js +++ b/rhino_modules/jsdoc/util/markdown.js @@ -7,8 +7,6 @@ * @author Ben Blank */ -var conf = env.conf.markdown; - /** * Enumeration of Markdown parsers that are available. * @enum {String} @@ -23,6 +21,20 @@ var parsers = { gfm: "github-flavored-markdown" }; +/** + * Escape underscores that occur within {@ ... } in order to protect them + * from the markdown parser(s). + * @param {String} source the source text to sanitize. + * @returns {String} `source` where underscores within {@ ... } have been + * protected with a preceding backslash (i.e. \_) -- the markdown parsers + * will strip the backslash and protect the underscore. + */ +function escapeUnderscores(source) { + return source.replace(/\{@[^}\r\n]+\}/g, function (wholeMatch) { + return wholeMatch.replace(/(^|[^\\])_/g, '$1\\_'); + }); +} + /** * 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. @@ -50,12 +62,14 @@ function getParseFunction(parser, conf) { parser.hardwrap = !!conf.hardwrap; return function(source) { + source = escapeUnderscores(source); return parser.parse(source, githubConf); }; } else if (parser === parsers.evilstreak) { parser = require(parser).markdown; return function(source) { + source = escapeUnderscores(source); // evilstreak parser expects line endings to be \n source = source.replace(/\r\n|\r/g, '\n'); return parser.toHTML(source, conf.dialect); @@ -75,6 +89,7 @@ function getParseFunction(parser, conf) { * @throws {Error} If the value of `env.conf.markdown.parser` does not correspond to a known parser. */ exports.getParser = function() { + var conf = env.conf.markdown; if (conf && conf.parser) { return getParseFunction(parsers[conf.parser], conf); } else if (conf && conf.githubRepoOwner && conf.githubRepoName) { diff --git a/test/specs/jsdoc/util/markdown.js b/test/specs/jsdoc/util/markdown.js index 8a56b992..f6ae402a 100644 --- a/test/specs/jsdoc/util/markdown.js +++ b/test/specs/jsdoc/util/markdown.js @@ -30,11 +30,39 @@ describe('jsdoc/util/markdown', function() { }); it('should not apply formatting to inline tags when the evilstreak parser is enabled', function() { - // TODO + // store the old configuration + var old = (env.conf.markdown ? env.conf.markdown.parser : undefined); + env.conf.markdown = {parser: 'evilstreak'}; + + // get the evilstreak parser and do the test + var parser = markdown.getParser(); + expect(parser('{@link MyClass#_x} and {@link MyClass#_y}')).toEqual( + '

{@link MyClass#_x} and {@link MyClass#_y}

'); + + // restore the old value + if (old === undefined) { + env.conf.markdown.parser = old; + } else { + delete env.conf.markdown; + } }); it('should not apply formatting to inline tags when the GFM parser is enabled', function() { - // TODO + // store the old configuration + var old = (env.conf.markdown ? env.conf.markdown.parser : undefined); + env.conf.markdown = {parser: 'gfm'}; + + // get the gfm parser and do the test + var parser = markdown.getParser(); + expect(parser('{@link MyClass#_x} and {@link MyClass#_y}')).toEqual( + '

{@link MyClass#_x} and {@link MyClass#_y}

'); + + // restore the old value + if (old === undefined) { + env.conf.markdown.parser = old; + } else { + delete env.conf.markdown; + } }); }); -}); \ No newline at end of file +});