Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to write custom InlineLexer rule for marked.js?

With Marked I can easily override/add/change lexer rules during implementation, and its great! For example I can force to use space between hash sign an text to make a header like this:

var lexer = new marked.Lexer(options);
console.log(lexer);
lexer.rules.heading = /^\s*(#{1,6})\s+([^\n]+?) *#* *(?:\n+|$)/

console.log(marked.parser(lexer.lex('#hashtag?'), options));
//<p>#hashtag?</p>
console.log(marked.parser(lexer.lex('# heading?'), options));
//<h1 id="undefinedheading-">heading?</h1>

Cool!

But is there a way, to easily do same for inlineLexer? Like i need to make people be able to add an images with next sequence: %[My Image](http://example.com/img.jpg)? So i modified:

var inlineLexer = marked.InlineLexer;
inlineLexer.rules.link = /^[!%]{0,1}?\[((?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*)\]\(\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*\)/;
...

What should I do next? How to bind a custom inlineLexer to a marked instance? Please show me an example of how to do this! How can I modify/add custom inline lexer rules?

like image 460
Alexander Arutinyants Avatar asked Oct 22 '14 12:10

Alexander Arutinyants


1 Answers

I've looked at the source code for marked.js to find a way of overriding parts of it in order to allow some customization of the inline lexer, without changing the library source or affecting the global marked instance or prototypes.

var renderer = new marked.Renderer();
var lexer = new marked.Lexer();
var parser = new marked.Parser();

var options = {
    renderer: renderer,
    gfm: true,
    tables: false,
    breaks: true,
    pedantic: false,
    sanitize: true,
    smartLists: true,
    smartypants: false
}

parser.inline = new marked.InlineLexer([], options);
parser.inline.rules = angular.copy(parser.inline.rules); // deep copy, otherwise global marked will be affected

parser.inline.rules.link = /^[!%]{0,1}?\[((?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*)\]\(\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*\)/;
renderer.link =  function(href, title, text) {
    // this is the standard link renderer that can be altered if desired ...
    if (this.options.sanitize) {
        try {
            var prot = decodeURIComponent(unescape(href))
                .replace(/[^\w:]/g, '')
                .toLowerCase();
        } catch (e) {
            return '';
        }
        if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
            return '';
        }
    }
    var out = '<a href="' + href + '"';
    if (title) {
        out += ' title="' + title + '"';
    }
    out += '>' + text + '</a>';
    return out;
}

function parse(src) {
    parser.inline.links = src.links;
    parser.tokens = src.reverse();
    var out = '';
    while (parser.next()) {
        out += parser.tok();
    }
    return out;
};

function parseText(text) {
    var lex = lexer.lex(text);
    var r = parse(lex);
    return r;
}
like image 131
barry_j_northern Avatar answered Nov 11 '22 10:11

barry_j_northern