Code coverage report for master/lib/jsdoc/util/markdown.js

Statements: 100% (42 / 42)      Branches: 100% (12 / 12)      Functions: 100% (10 / 10)      Lines: 100% (42 / 42)      Ignored: none     

All files » master/lib/jsdoc/util/ » markdown.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160                1 1           1                                                   1 17 4                   1 17                 1 17                 1 2                             1 14 14   14 14   14   14 13 1       13   13 2       13 2   2       13 17   17 17   17     17   17   13 13     1                           1 14 14 8       6      
/**
 * Provides access to Markdown-related functions.
 * @module jsdoc/util/markdown
 * @author Michael Mathews <micmath@gmail.com>
 * @author Ben Blank <ben.blank@gmail.com>
 */
'use strict';
 
var env = require('jsdoc/env');
var util = require('util');
 
/**
 * Enumeration of Markdown parsers that are available.
 * @enum {String}
 */
var parserNames = {
    /**
     * The "[markdown-js](https://github.com/evilstreak/markdown-js)" (aka "evilstreak") parser.
     *
     * @deprecated Replaced by "marked," as markdown-js does not support inline HTML.
     */
    evilstreak: 'marked',
    /**
     * The "GitHub-flavored Markdown" parser.
     * @deprecated Replaced by "marked."
     */
    gfm: 'marked',
    /**
     * The "[Marked](https://github.com/chjj/marked)" parser.
     */
    marked: 'marked'
};
 
/**
 * 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\\_');
    });
}
 
/**
 * Escape HTTP/HTTPS URLs so that they are not automatically converted to HTML links.
 *
 * @param {string} source - The source text to escape.
 * @return {string} The source text with escape characters added to HTTP/HTTPS URLs.
 */
function escapeUrls(source) {
    return source.replace(/(https?)\:\/\//g, '$1:\\/\\/');
}
 
/**
 * Unescape HTTP/HTTPS URLs after Markdown parsing is complete.
 *
 * @param {string} source - The source text to unescape.
 * @return {string} The source text with escape characters removed from HTTP/HTTPS URLs.
 */
function unescapeUrls(source) {
    return source.replace(/(https?)\:\\\/\\\//g, '$1://');
}
 
/**
 * Escape characters in text within a code block.
 *
 * @param {string} source - The source text to escape.
 * @return {string} The escaped source text.
 */
function escapeCode(source) {
    return source.replace(/</g, '&lt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
}
 
/**
 * 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.
 *
 * @private
 * @param {String} parserName The name of the selected parser.
 * @param {Object} [conf] Configuration for the selected parser, if any.
 * @returns {Function} A function that accepts Markdown source, feeds it to the selected parser, and
 * returns the resulting HTML.
 */
function getParseFunction(parserName, conf) {
    var logger = require('jsdoc/util/logger');
    var marked = require('marked');
 
    var markedRenderer;
    var parserFunction;
 
    conf = conf || {};
 
    if (parserName === parserNames.marked) {
        if (conf.hardwrap) {
            marked.setOptions({breaks: true});
        }
 
        // Marked generates an "id" attribute for headers; this custom renderer suppresses it
        markedRenderer = new marked.Renderer();
 
        markedRenderer.heading = function(text, level) {
            return util.format('<h%s>%s</h%s>', level, text, level);
        };
 
        // Allow prettyprint to work on inline code samples
        markedRenderer.code = function(code, language) {
            var langClass = language ? ' lang-' + language : '';
 
            return util.format( '<pre class="prettyprint source%s"><code>%s</code></pre>',
                langClass, escapeCode(code) );
        };
 
        parserFunction = function(source) {
            var result;
 
            source = escapeUnderscores(source);
            source = escapeUrls(source);
 
            result = marked(source, { renderer: markedRenderer })
                .replace(/\s+$/, '')
                .replace(/&#39;/g, "'");
            result = unescapeUrls(result);
 
            return result;
        };
        parserFunction._parser = parserNames.marked;
        return parserFunction;
    }
    else {
        logger.error('Unrecognized Markdown parser "%s". Markdown support is disabled.',
            parserName);
    }
}
 
/**
 * Retrieve a Markdown parsing function based on the value of the `conf.json` file's
 * `env.conf.markdown` property. The parsing function accepts a single parameter containing Markdown
 * source. The function uses the parser specified in `conf.json` to transform the Markdown source to
 * HTML, then returns the HTML as a string.
 *
 * @returns {function} A function that accepts Markdown source, feeds it to the selected parser, and
 * returns the resulting HTML.
 */
exports.getParser = function() {
    var conf = env.conf.markdown;
    if (conf && conf.parser) {
        return getParseFunction(parserNames[conf.parser], conf);
    }
    else {
        // marked is the default parser
        return getParseFunction(parserNames.marked, conf);
    }
};