Marked: Support image size instructions

Created on 28 May 2018  路  8Comments  路  Source: markedjs/marked

IMPORTANT: Unfortunately this was working in version 0.3.19 and is "broken" in 0.4.0 (I think from your perspective this is "by design" to comply with the standards...?).

Describe the feature
I'd like marked to detect

![the name](files/foo.jpg =20%x)

as an image link so that this piece of code would execute

renderer.image = function (href, title, text) {
    links.push(href);
    return marked.Renderer.prototype.image.apply(this, arguments);
};

https://github.com/tcort/markdown-link-extractor/blob/master/index.js

Is this feasible regarding the "standards move" you're going through atm?
I don't think I have to write too much about this feature, it is simply WIDTHxHEIGHT.

Why is this feature necessary?
https://github.com/tcort/markdown-link-check or to be more precise https://github.com/tcort/markdown-link-extractor is using marked to detect links in Markdown and this is currently not working with the case mentioned above.

Describe alternatives you've considered
I already tried to modify https://github.com/markedjs/marked/blob/1548175640db4f458e4d4cd0d7b6a4f4de72f735/lib/marked.js#L519

to understand the image size instructions and this worked for my special case but broke several tests.
I also know this wouldn't suffice the need of marked because this token needs to be transformed as well.

![the name](files/foo.jpg =20%x)

->

<p>
  <img src="files/foo.jpg" alt="the name" width="20%">
</p>

=150x     width="150"
=x100                  height="100"
=150x100  width="150"  height="100"
=20%x     width="20%"
=x10%                  height="10%"
=20%x10%  width="20%"  height="10%"
=150x10%  width="150"  height="10%"
=20%x100  width="20%"  height="100"

If the implementation does not match with your goals/roadmap can you guide me to what the easiest way would be to recognize these patterns as an image (renderer.image() is called)?

This is the regex I was using/adding: https://regex101.com/r/YF3Z3b/3/tests
Applied to the link pattern:

link: /^!?\[(label)\]\(href(?: =\d*%?x\d*)(?:\s+(title))?\s*\)/,

Most helpful comment

  1. "I came up with" just means I think it should work based on the way the code is written. Why? because I wanted to see what it would be like to change the lexer from a wrapper. (Conclusion: we should make it easier.)

  2. The regexes in marked are constructed using an edit function.

    The actual regex construction is:

    ...
       link: /^!?\[(label)\]\(href(?:\s+(title))?\s*\)/
    ...
    
    inline._label = /(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/;
    inline._href = /\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?)/;
    inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
    
    inline.link = edit(inline.link)
     .replace('label', inline._label)
     .replace('href', inline._href)
     .replace('title', inline._title)
     .getRegex();
    

    Which results in the regex:

    inline.link = /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?)\]\(\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?)(?:\s+("(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)))?\s*\)/
    

    I just added (?:\s+=(?:[\w%]+)?x(?:[\w%]+)?)? at the end of inline._href and used the href from the lexer inside the renderer to get ahold of the image size

We are currently trying to resurrect marked and make sure it is secure and spec compliant for the >3000 dependents of marked.

Hopefully in the future we will be able to make marked easier to extend.

All 8 comments

Hi @timmkrause thanks for reporting an issue!

It seems like if this was working before, it was undocumented and likely broke in the standards move (as you mentioned).

Is this "image size instruction" part of CommonMark, GFM, or other Standard?

@styfle I double checked this and did not find something in any of the standards you're currently focusing on. On the other hand this is a pretty wide spread feature.

Can you or someone guide me to what I need to do to get a correct call to renderer.image() with a working href?

pretty wide spread feature.

I've never heard of this feature. What other markdown libraries support this?

I don't have experience with other Markdown libraries. I can only mention some editors/platforms that do support it, just to mention a few: Mou, Marked 2, Visual Studio Code, VSTS Wiki...

I am not asking you to push this through or move away from your GFM/CommonMark goals.

I'd just like to know what the best approach would be to extend/adjust this to my needs as marked is also built for extensibility, right?

You can check out the documentation to changing the parser and renderer

It seems that syntax is very limited and the work around is to use html
https://stackoverflow.com/a/14747656/806777

<img src="files/foo.jpg" alt="the name" style="width: 20%;"/>

Duplicate of #339

Here is a little script I came up with to create a wrapper around marked that does this:

// marked-with-image-size module
var marked = require("marked")

var imageSizeLink = /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?)\]\(\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?(?:\s+=(?:[\w%]+)?x(?:[\w%]+)?)?)(?:\s+("(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)))?\s*\)/;

marked.InlineLexer.rules.normal.link = imageSizeLink;
marked.InlineLexer.rules.gfm.link = imageSizeLink;
marked.InlineLexer.rules.breaks.link = imageSizeLink;

var renderer = new marked.Renderer();
renderer.image = function(href, title, text) {
  if (this.options.baseUrl && !originIndependentUrl.test(href)) {
    href = resolveUrl(this.options.baseUrl, href);
  }
  var size = href.match(/\s+=([\w%]+)?x([\w%]+)?$/);
  if (size) {
    href = href.substring(0, href.length - size[0].length);
  }
  var out = '<img src="' + href + '" alt="' + text + '"';
  if (title) {
    out += ' title="' + title + '"';
  }
  if (size) {
    out += ' style="width:' + size[1] + '; height:' + size[2] + ';"';
  }
  out += this.options.xhtml ? '/>' : '>';
  return out;
};

marked.setOptions({renderer: renderer});

module.exports = marked;

Then to use the wrapper module:

var marked = require('marked-with-image-size');

marked('![alt](src.png =20%x20% "hi")');
// outputs: <p><img src="src.png" alt="alt" title="hi" style="width:20%; height:20%;"></p>

__馃毃 NOT PRODUCTION CODE 馃毃__

To use this in production you will need to do more error checks and make sure there are no ReDoS vectors in the new regex (Which I'm pretty sure there are).

But this should give you an idea of how to update Lexer.

Hopefully we can make it easier in the future.

@UziTech I really appreciate your code! Thank you so much, this will really help in markdown-link-check.

Two questions left and then I will leave this topic alone... ;-)

  1. You wrote "I came up with" - In which context did you came up with it and why?
  2. In case something breaks someday: How have you build this crazy regex? Currently it is

    link: /^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,
    

Is there some pattern to achieve the one you mentioned above?

  1. "I came up with" just means I think it should work based on the way the code is written. Why? because I wanted to see what it would be like to change the lexer from a wrapper. (Conclusion: we should make it easier.)

  2. The regexes in marked are constructed using an edit function.

    The actual regex construction is:

    ...
       link: /^!?\[(label)\]\(href(?:\s+(title))?\s*\)/
    ...
    
    inline._label = /(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/;
    inline._href = /\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?)/;
    inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
    
    inline.link = edit(inline.link)
     .replace('label', inline._label)
     .replace('href', inline._href)
     .replace('title', inline._title)
     .getRegex();
    

    Which results in the regex:

    inline.link = /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?)\]\(\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?)(?:\s+("(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)))?\s*\)/
    

    I just added (?:\s+=(?:[\w%]+)?x(?:[\w%]+)?)? at the end of inline._href and used the href from the lexer inside the renderer to get ahold of the image size

We are currently trying to resurrect marked and make sure it is secure and spec compliant for the >3000 dependents of marked.

Hopefully in the future we will be able to make marked easier to extend.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

raguay picture raguay  路  4Comments

pigtooter picture pigtooter  路  4Comments

chunhei2008 picture chunhei2008  路  3Comments

eGavr picture eGavr  路  4Comments

toc
zoe-cjf picture zoe-cjf  路  3Comments