Skip to content

Commit

Permalink
fix: fix atx heading and make regex safe (#1853)
Browse files Browse the repository at this point in the history
  • Loading branch information
UziTech committed Dec 10, 2020
1 parent 656c3e4 commit 70ee29c
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 13 deletions.
19 changes: 16 additions & 3 deletions lib/marked.esm.js
Expand Up @@ -435,11 +435,24 @@ var Tokenizer_1 = class Tokenizer {
heading(src) {
const cap = this.rules.block.heading.exec(src);
if (cap) {
let text = cap[2].trim();

// remove trailing #s
if (text.endsWith('#')) {
const trimmed = rtrim$1(text, '#');
if (this.options.pedantic) {
text = trimmed.trim();
} else if (!trimmed || trimmed.endsWith(' ')) {
// CommonMark requires space before trailing #s
text = trimmed.trim();
}
}

return {
type: 'heading',
raw: cap[0],
depth: cap[1].length,
text: cap[2]
text: text
};
}
}
Expand Down Expand Up @@ -1003,7 +1016,7 @@ const block = {
code: /^( {4}[^\n]+\n*)+/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,
heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,
html: '^ {0,3}(?:' // optional indentation
Expand Down Expand Up @@ -1134,7 +1147,7 @@ block.pedantic = merge$1({}, block.normal, {
+ '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
.getRegex(),
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
heading: /^(#{1,6})(.*)(?:\n+|$)/,
fences: noopTest$1, // fences not supported
paragraph: edit$1(block.normal._paragraph)
.replace('hr', block.hr)
Expand Down
19 changes: 16 additions & 3 deletions lib/marked.js
Expand Up @@ -532,11 +532,24 @@
var cap = this.rules.block.heading.exec(src);

if (cap) {
var text = cap[2].trim(); // remove trailing #s

if (text.endsWith('#')) {
var trimmed = rtrim$1(text, '#');

if (this.options.pedantic) {
text = trimmed.trim();
} else if (!trimmed || trimmed.endsWith(' ')) {
// CommonMark requires space before trailing #s
text = trimmed.trim();
}
}

return {
type: 'heading',
raw: cap[0],
depth: cap[1].length,
text: cap[2]
text: text
};
}
};
Expand Down Expand Up @@ -1122,7 +1135,7 @@
code: /^( {4}[^\n]+\n*)+/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,
heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,
html: '^ {0,3}(?:' // optional indentation
Expand Down Expand Up @@ -1193,7 +1206,7 @@
html: edit$1('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
+ '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))').replace('comment', block._comment).replace(/tag/g, '(?!(?:' + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b').getRegex(),
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
heading: /^(#{1,6})(.*)(?:\n+|$)/,
fences: noopTest$1,
// fences not supported
paragraph: edit$1(block.normal._paragraph).replace('hr', block.hr).replace('heading', ' *#{1,6} *[^\n]').replace('lheading', block.lheading).replace('blockquote', ' {0,3}>').replace('|fences', '').replace('|list', '').replace('|html', '').getRegex()
Expand Down
15 changes: 14 additions & 1 deletion src/Tokenizer.js
Expand Up @@ -121,11 +121,24 @@ module.exports = class Tokenizer {
heading(src) {
const cap = this.rules.block.heading.exec(src);
if (cap) {
let text = cap[2].trim();

// remove trailing #s
if (text.endsWith('#')) {
const trimmed = rtrim(text, '#');
if (this.options.pedantic) {
text = trimmed.trim();
} else if (!trimmed || trimmed.endsWith(' ')) {
// CommonMark requires space before trailing #s
text = trimmed.trim();
}
}

return {
type: 'heading',
raw: cap[0],
depth: cap[1].length,
text: cap[2]
text: text
};
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/rules.js
Expand Up @@ -12,7 +12,7 @@ const block = {
code: /^( {4}[^\n]+\n*)+/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,
heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,
html: '^ {0,3}(?:' // optional indentation
Expand Down Expand Up @@ -143,7 +143,7 @@ block.pedantic = merge({}, block.normal, {
+ '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
.getRegex(),
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
heading: /^(#{1,6})(.*)(?:\n+|$)/,
fences: noopTest, // fences not supported
paragraph: edit(block.normal._paragraph)
.replace('hr', block.hr)
Expand Down
3 changes: 1 addition & 2 deletions test/specs/commonmark/commonmark.0.29.json
Expand Up @@ -389,8 +389,7 @@
"example": 49,
"start_line": 963,
"end_line": 971,
"section": "ATX headings",
"shouldFail": true
"section": "ATX headings"
},
{
"markdown": "Foo *bar*\n=========\n\nFoo *bar*\n---------\n",
Expand Down
3 changes: 1 addition & 2 deletions test/specs/gfm/commonmark.0.29.json
Expand Up @@ -389,8 +389,7 @@
"example": 49,
"start_line": 963,
"end_line": 971,
"section": "ATX headings",
"shouldFail": true
"section": "ATX headings"
},
{
"markdown": "Foo *bar*\n=========\n\nFoo *bar*\n---------\n",
Expand Down
9 changes: 9 additions & 0 deletions test/specs/new/pedantic_heading.html
@@ -0,0 +1,9 @@
<h1 id="h1">h1</h1>

<h1 id="h1-1">h1</h1>

<h1 id="h1-">h1 #</h1>

<h1 id="h1-2">h1</h1>

<p># h1</p>
12 changes: 12 additions & 0 deletions test/specs/new/pedantic_heading.md
@@ -0,0 +1,12 @@
---
pedantic: true
---
#h1

#h1#

#h1 # #

#h1####

# h1
7 changes: 7 additions & 0 deletions test/specs/redos/quadratic_heading.js
@@ -0,0 +1,7 @@
module.exports = {
markdown: `# #${' '.repeat(50000)}a`,
html: '<h1># a</h1>',
options: {
headerIds: false
}
};

1 comment on commit 70ee29c

@vercel
Copy link

@vercel vercel bot commented on 70ee29c Dec 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.