Skip to content

Commit

Permalink
fix: fenced code doesn't need a trailing newline (#2756)
Browse files Browse the repository at this point in the history
* fix: fenced code doesn't need a trailing newline

* build marked for demo

* clean up
  • Loading branch information
UziTech committed Mar 22, 2023
1 parent d1f1319 commit 3acbb7f
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 31 deletions.
30 changes: 22 additions & 8 deletions lib/marked.cjs
Expand Up @@ -28,6 +28,20 @@ function _createClass(Constructor, protoProps, staticProps) {
});
return Constructor;
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
Expand Down Expand Up @@ -1101,7 +1115,7 @@ var Tokenizer = /*#__PURE__*/function () {
var block = {
newline: /^(?: *(?:\n|$))+/,
code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
Expand Down Expand Up @@ -1143,13 +1157,13 @@ block.blockquote = edit(block.blockquote).replace('paragraph', block.paragraph).
* Normal Block Grammar
*/

block.normal = merge({}, block);
block.normal = _extends({}, block);

/**
* GFM Block Grammar
*/

block.gfm = merge({}, block.normal, {
block.gfm = _extends({}, block.normal, {
table: '^ *([^\\n ].*\\|.*)\\n' // Header
+ ' {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?' // Align
+ '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
Expand All @@ -1167,7 +1181,7 @@ block.gfm.paragraph = edit(block._paragraph).replace('hr', block.hr).replace('he
* Pedantic grammar (original John Gruber's loose markdown specification)
*/

block.pedantic = merge({}, block.normal, {
block.pedantic = _extends({}, block.normal, {
html: edit('^ *(?: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+|$)/,
Expand Down Expand Up @@ -1242,13 +1256,13 @@ inline.reflinkSearch = edit(inline.reflinkSearch, 'g').replace('reflink', inline
* Normal Inline Grammar
*/

inline.normal = merge({}, inline);
inline.normal = _extends({}, inline);

/**
* Pedantic Inline Grammar
*/

inline.pedantic = merge({}, inline.normal, {
inline.pedantic = _extends({}, inline.normal, {
strong: {
start: /^__|\*\*/,
middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
Expand All @@ -1269,7 +1283,7 @@ inline.pedantic = merge({}, inline.normal, {
* GFM Inline Grammar
*/

inline.gfm = merge({}, inline.normal, {
inline.gfm = _extends({}, inline.normal, {
escape: edit(inline.escape).replace('])', '~|])').getRegex(),
_extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
Expand All @@ -1282,7 +1296,7 @@ inline.gfm.url = edit(inline.gfm.url, 'i').replace('email', inline.gfm._extended
* GFM + Line Breaks Inline Grammar
*/

inline.breaks = merge({}, inline.gfm, {
inline.breaks = _extends({}, inline.gfm, {
br: edit(inline.br).replace('{2,}', '*').getRegex(),
text: edit(inline.gfm.text).replace('\\b_', '\\b_| {2,}\\n').replace(/\{2,\}/g, '*').getRegex()
});
Expand Down
31 changes: 18 additions & 13 deletions lib/marked.esm.js
Expand Up @@ -1109,7 +1109,7 @@ class Tokenizer {
const block = {
newline: /^(?: *(?:\n|$))+/,
code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
Expand Down Expand Up @@ -1184,17 +1184,18 @@ block.blockquote = edit(block.blockquote)
* Normal Block Grammar
*/

block.normal = merge({}, block);
block.normal = { ...block };

/**
* GFM Block Grammar
*/

block.gfm = merge({}, block.normal, {
block.gfm = {
...block.normal,
table: '^ *([^\\n ].*\\|.*)\\n' // Header
+ ' {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?' // Align
+ '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
});
};

block.gfm.table = edit(block.gfm.table)
.replace('hr', block.hr)
Expand Down Expand Up @@ -1222,7 +1223,8 @@ block.gfm.paragraph = edit(block._paragraph)
* Pedantic grammar (original John Gruber's loose markdown specification)
*/

block.pedantic = merge({}, block.normal, {
block.pedantic = {
...block.normal,
html: edit(
'^ *(?:comment *(?:\\n|\\s*$)'
+ '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
Expand All @@ -1246,7 +1248,7 @@ block.pedantic = merge({}, block.normal, {
.replace('|list', '')
.replace('|html', '')
.getRegex()
});
};

/**
* Inline-Level Grammar
Expand Down Expand Up @@ -1348,13 +1350,14 @@ inline.reflinkSearch = edit(inline.reflinkSearch, 'g')
* Normal Inline Grammar
*/

inline.normal = merge({}, inline);
inline.normal = { ...inline };

/**
* Pedantic Inline Grammar
*/

inline.pedantic = merge({}, inline.normal, {
inline.pedantic = {
...inline.normal,
strong: {
start: /^__|\*\*/,
middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
Expand All @@ -1373,20 +1376,21 @@ inline.pedantic = merge({}, inline.normal, {
reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
.replace('label', inline._label)
.getRegex()
});
};

/**
* GFM Inline Grammar
*/

inline.gfm = merge({}, inline.normal, {
inline.gfm = {
...inline.normal,
escape: edit(inline.escape).replace('])', '~|])').getRegex(),
_extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
_backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
});
};

inline.gfm.url = edit(inline.gfm.url, 'i')
.replace('email', inline.gfm._extended_email)
Expand All @@ -1395,13 +1399,14 @@ inline.gfm.url = edit(inline.gfm.url, 'i')
* GFM + Line Breaks Inline Grammar
*/

inline.breaks = merge({}, inline.gfm, {
inline.breaks = {
...inline.gfm,
br: edit(inline.br).replace('{2,}', '*').getRegex(),
text: edit(inline.gfm.text)
.replace('\\b_', '\\b_| {2,}\\n')
.replace(/\{2,\}/g, '*')
.getRegex()
});
};

/**
* smartypants text replacement
Expand Down
30 changes: 22 additions & 8 deletions lib/marked.umd.js
Expand Up @@ -32,6 +32,20 @@
});
return Constructor;
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
Expand Down Expand Up @@ -1105,7 +1119,7 @@
var block = {
newline: /^(?: *(?:\n|$))+/,
code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
Expand Down Expand Up @@ -1147,13 +1161,13 @@
* Normal Block Grammar
*/

block.normal = merge({}, block);
block.normal = _extends({}, block);

/**
* GFM Block Grammar
*/

block.gfm = merge({}, block.normal, {
block.gfm = _extends({}, block.normal, {
table: '^ *([^\\n ].*\\|.*)\\n' // Header
+ ' {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?' // Align
+ '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
Expand All @@ -1171,7 +1185,7 @@
* Pedantic grammar (original John Gruber's loose markdown specification)
*/

block.pedantic = merge({}, block.normal, {
block.pedantic = _extends({}, block.normal, {
html: edit('^ *(?: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+|$)/,
Expand Down Expand Up @@ -1246,13 +1260,13 @@
* Normal Inline Grammar
*/

inline.normal = merge({}, inline);
inline.normal = _extends({}, inline);

/**
* Pedantic Inline Grammar
*/

inline.pedantic = merge({}, inline.normal, {
inline.pedantic = _extends({}, inline.normal, {
strong: {
start: /^__|\*\*/,
middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
Expand All @@ -1273,7 +1287,7 @@
* GFM Inline Grammar
*/

inline.gfm = merge({}, inline.normal, {
inline.gfm = _extends({}, inline.normal, {
escape: edit(inline.escape).replace('])', '~|])').getRegex(),
_extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
Expand All @@ -1286,7 +1300,7 @@
* GFM + Line Breaks Inline Grammar
*/

inline.breaks = merge({}, inline.gfm, {
inline.breaks = _extends({}, inline.gfm, {
br: edit(inline.br).replace('{2,}', '*').getRegex(),
text: edit(inline.gfm.text).replace('\\b_', '\\b_| {2,}\\n').replace(/\{2,\}/g, '*').getRegex()
});
Expand Down
2 changes: 1 addition & 1 deletion marked.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/rules.js
Expand Up @@ -10,7 +10,7 @@ import {
export const block = {
newline: /^(?: *(?:\n|$))+/,
code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
fences: /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
Expand Down
5 changes: 5 additions & 0 deletions test/specs/new/code_block_no_ending_newline.html
@@ -0,0 +1,5 @@
<pre>
<code>
no newline at end of file
</code>
</pre>
2 changes: 2 additions & 0 deletions test/specs/new/code_block_no_ending_newline.md
@@ -0,0 +1,2 @@
```
no newline at end of file

1 comment on commit 3acbb7f

@vercel
Copy link

@vercel vercel bot commented on 3acbb7f Mar 22, 2023

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.