commonmark
Advanced tools
Comparing version 0.25.1 to 0.26.0
@@ -0,1 +1,32 @@ | ||
[0.26.0] | ||
* Implemented spec changes to lists: | ||
- Don't allow ordered lists to interrupt a paragraph unless | ||
they start with 1. | ||
- Remove two-blanks-break-out-of-lists feature. | ||
- Blank list item can't interrupt paragraph. | ||
* Fixed minor regex bug with raw HTML blocks (#98). | ||
This would affect things like: | ||
<a>[SPACE][SPACE] | ||
x | ||
which, with the change, gets parsed as a raw HTML block, instead of a | ||
single paragraph with inline HTML, a line break, and 'x'. The new | ||
behavior conforms to the spec. See #7 in 4.6. Added regression. | ||
* Remove unnecessary check (Nik Ryby). It looks like `columns` is always | ||
true in this block, so there's no need to check it during the assignment | ||
to `count`. | ||
* Simplify and optimize brackets processing (links/images) (Robin Stocker). | ||
Together, these changes make the "nested brackets 10000 deep" | ||
pathological case go from 400 ms to 20 ms. | ||
* Changes in emph/strong emph parsing to match changes in spec. | ||
This implements the rule that we can't have emphasis matches | ||
when (a) one of the delimiters can open AND can close, and (b) | ||
the sum of the lengths of the delimiter runs containing open | ||
and close delimiters is a multiple of 3. | ||
* Fix not existing property usage (Maksim Dzikun). | ||
* Fixed tabs in ATX headers and thematic breaks. | ||
* Remove unused write-only variable (Maksim Dzikun). | ||
[0.25.1] | ||
@@ -2,0 +33,0 @@ |
@@ -27,3 +27,3 @@ "use strict"; | ||
/^<[/]?(?:address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h1|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|title|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)(?:\s|[/]?[>]|$)/i, | ||
new RegExp('^(?:' + OPENTAG + '|' + CLOSETAG + ')\s*$', 'i') | ||
new RegExp('^(?:' + OPENTAG + '|' + CLOSETAG + ')\\s*$', 'i') | ||
]; | ||
@@ -40,3 +40,3 @@ | ||
var reThematicBreak = /^(?:(?:\* *){3,}|(?:_ *){3,}|(?:- *){3,}) *$/; | ||
var reThematicBreak = /^(?:(?:\*[ \t]*){3,}|(?:_[ \t]*){3,}|(?:-[ \t]*){3,})[ \t]*$/; | ||
@@ -51,3 +51,3 @@ var reMaybeSpecial = /^[#`~*+_=<>0-9-]/; | ||
var reATXHeadingMarker = /^#{1,6}(?: +|$)/; | ||
var reATXHeadingMarker = /^#{1,6}(?:[ \t]+|$)/; | ||
@@ -100,26 +100,2 @@ var reCodeFence = /^`{3,}(?!.*`)|^~{3,}(?!.*~)/; | ||
// Break out of all containing lists, resetting the tip of the | ||
// document to the parent of the highest list, and finalizing | ||
// all the lists. (This is used to implement the "two blank lines | ||
// break out of all lists" feature.) | ||
var breakOutOfLists = function(block) { | ||
var b = block; | ||
var last_list = null; | ||
do { | ||
if (b.type === 'list') { | ||
last_list = b; | ||
} | ||
b = b._parent; | ||
} while (b); | ||
if (last_list) { | ||
while (block !== last_list) { | ||
this.finalize(block, this.lineNumber); | ||
block = block._parent; | ||
} | ||
this.finalize(last_list, this.lineNumber); | ||
this.tip = last_list._parent; | ||
} | ||
}; | ||
// Add a line to the block at the tip. We assume the tip | ||
@@ -155,3 +131,3 @@ // can accept lines -- that check should be done before calling this. | ||
// start, delimiter, bullet character, padding) or null. | ||
var parseListMarker = function(parser) { | ||
var parseListMarker = function(parser, container) { | ||
var rest = parser.currentLine.slice(parser.nextNonspace); | ||
@@ -173,3 +149,5 @@ var match; | ||
} else if ((match = rest.match(reOrderedListMarker))) { | ||
} else if ((match = rest.match(reOrderedListMarker)) && | ||
(container.type !== 'paragraph' || | ||
match[1] === '1')) { | ||
data.type = 'ordered'; | ||
@@ -187,2 +165,7 @@ data.start = parseInt(match[1]); | ||
// if it interrupts paragraph, make sure first line isn't blank | ||
if (container.type === 'paragraph' && !parser.currentLine.slice(parser.nextNonspace + match[0].length).match(reNonSpace)) { | ||
return null; | ||
} | ||
// we've got a match! advance offset and calculate padding | ||
@@ -549,3 +532,3 @@ parser.advanceNextNonspace(); // to start of marker | ||
if ((!parser.indented || container.type === 'list') | ||
&& (data = parseListMarker(parser))) { | ||
&& (data = parseListMarker(parser, container))) { | ||
parser.closeUnmatchedBlocks(); | ||
@@ -587,3 +570,2 @@ | ||
var advanceOffset = function(count, columns) { | ||
var cols = 0; | ||
var currentLine = this.currentLine; | ||
@@ -600,3 +582,3 @@ var charsToTab, charsToAdvance; | ||
this.offset += this.partiallyConsumedTab ? 0 : 1; | ||
count -= (columns ? charsToAdvance : 1); | ||
count -= charsToAdvance; | ||
} else { | ||
@@ -606,7 +588,6 @@ this.partiallyConsumedTab = false; | ||
this.offset += 1; | ||
this.count -= 1; | ||
count -= 1; | ||
} | ||
} else { | ||
this.partiallyConsumedTab = false; | ||
cols += 1; | ||
this.offset += 1; | ||
@@ -701,8 +682,2 @@ this.column += 1; // assume ascii; block starts are ascii | ||
// Check to see if we've hit 2nd blank line; if so break out of list: | ||
if (this.blank && container._lastLineBlank) { | ||
this.breakOutOfLists(container); | ||
container = this.tip; | ||
} | ||
var matchedLeaf = container.type !== 'paragraph' && | ||
@@ -899,3 +874,2 @@ blocks[container.type].acceptsLines; | ||
advanceNextNonspace: advanceNextNonspace, | ||
breakOutOfLists: breakOutOfLists, | ||
addLine: addLine, | ||
@@ -902,0 +876,0 @@ addChild: addChild, |
@@ -14,3 +14,3 @@ "use strict"; | ||
module.exports.version = '0.25.1'; | ||
module.exports.version = '0.26.0'; | ||
module.exports.Node = require('./node'); | ||
@@ -17,0 +17,0 @@ module.exports.Parser = require('./blocks'); |
@@ -309,4 +309,3 @@ "use strict"; | ||
can_open: res.can_open, | ||
can_close: res.can_close, | ||
active: true }; | ||
can_close: res.can_close }; | ||
if (this.delimiters.previous !== null) { | ||
@@ -347,2 +346,3 @@ this.delimiters.previous.next = this.delimiters; | ||
var openers_bottom = []; | ||
var odd_match = false; | ||
@@ -362,6 +362,3 @@ openers_bottom[C_UNDERSCORE] = stack_bottom; | ||
var closercc = closer.cc; | ||
if (!(closer.can_close && (closercc === C_UNDERSCORE || | ||
closercc === C_ASTERISK || | ||
closercc === C_SINGLEQUOTE || | ||
closercc === C_DOUBLEQUOTE))) { | ||
if (!closer.can_close) { | ||
closer = closer.next; | ||
@@ -374,3 +371,5 @@ } else { | ||
opener !== openers_bottom[closercc]) { | ||
if (opener.cc === closer.cc && opener.can_open) { | ||
odd_match = (closer.can_open || opener.can_close) && | ||
(opener.numdelims + closer.numdelims) % 3 === 0; | ||
if (opener.cc === closer.cc && opener.can_open && !odd_match) { | ||
opener_found = true; | ||
@@ -454,4 +453,8 @@ break; | ||
} | ||
if (!opener_found) { | ||
if (!opener_found && !odd_match) { | ||
// Set lower bound for future searches for openers: | ||
// We don't do this with odd_match because a ** | ||
// that doesn't match an earlier * might turn into | ||
// an opener, and the * might be matched by something | ||
// else. | ||
openers_bottom[closercc] = old_closer.previous; | ||
@@ -521,17 +524,4 @@ if (!old_closer.can_open) { | ||
// Add entry to stack for this opener | ||
this.delimiters = { cc: C_OPEN_BRACKET, | ||
numdelims: 1, | ||
node: node, | ||
previous: this.delimiters, | ||
next: null, | ||
can_open: true, | ||
can_close: false, | ||
index: startpos, | ||
active: true }; | ||
if (this.delimiters.previous !== null) { | ||
this.delimiters.previous.next = this.delimiters; | ||
} | ||
this.addBracket(node, startpos, false); | ||
return true; | ||
}; | ||
@@ -551,14 +541,3 @@ | ||
// Add entry to stack for this opener | ||
this.delimiters = { cc: C_BANG, | ||
numdelims: 1, | ||
node: node, | ||
previous: this.delimiters, | ||
next: null, | ||
can_open: true, | ||
can_close: false, | ||
index: startpos + 1, | ||
active: true }; | ||
if (this.delimiters.previous !== null) { | ||
this.delimiters.previous.next = this.delimiters; | ||
} | ||
this.addBracket(node, startpos + 1, true); | ||
} else { | ||
@@ -586,12 +565,5 @@ block.appendChild(text('!')); | ||
// look through stack of delimiters for a [ or ![ | ||
opener = this.delimiters; | ||
// get last [ or ![ | ||
opener = this.brackets; | ||
while (opener !== null) { | ||
if (opener.cc === C_OPEN_BRACKET || opener.cc === C_BANG) { | ||
break; | ||
} | ||
opener = opener.previous; | ||
} | ||
if (opener === null) { | ||
@@ -606,4 +578,4 @@ // no matched opener, just return a literal | ||
block.appendChild(text(']')); | ||
// take opener off emphasis stack | ||
this.removeDelimiter(opener); | ||
// take opener off brackets stack | ||
this.removeBracket(); | ||
return true; | ||
@@ -613,3 +585,3 @@ } | ||
// If we got here, open is a potential opener | ||
is_image = opener.cc === C_BANG; | ||
is_image = opener.image; | ||
@@ -638,7 +610,8 @@ // Check to see if we have a link/image | ||
var n = this.parseLinkLabel(); | ||
if (n === 0 || n === 2) { | ||
// empty or missing second label | ||
if (n > 2) { | ||
reflabel = this.subject.slice(beforelabel, beforelabel + n); | ||
} else if (!opener.bracketAfter) { | ||
// Empty or missing second label means to use the first label as the reference. | ||
// The reference must not contain a bracket. If we know there's a bracket, we don't even bother checking it. | ||
reflabel = this.subject.slice(opener.index, startpos); | ||
} else { | ||
reflabel = this.subject.slice(beforelabel, beforelabel + n); | ||
} | ||
@@ -650,8 +623,10 @@ if (n === 0) { | ||
// lookup rawlabel in refmap | ||
var link = this.refmap[normalizeReference(reflabel)]; | ||
if (link) { | ||
dest = link.destination; | ||
title = link.title; | ||
matched = true; | ||
if (reflabel) { | ||
// lookup rawlabel in refmap | ||
var link = this.refmap[normalizeReference(reflabel)]; | ||
if (link) { | ||
dest = link.destination; | ||
title = link.title; | ||
matched = true; | ||
} | ||
} | ||
@@ -674,13 +649,13 @@ } | ||
block.appendChild(node); | ||
this.processEmphasis(opener.previous); | ||
this.processEmphasis(opener.previousDelimiter); | ||
this.removeBracket(); | ||
opener.node.unlink(); | ||
// processEmphasis will remove this and later delimiters. | ||
// We remove this bracket and processEmphasis will remove later delimiters. | ||
// Now, for a link, we also deactivate earlier link openers. | ||
// (no links in links) | ||
if (!is_image) { | ||
opener = this.delimiters; | ||
opener = this.brackets; | ||
while (opener !== null) { | ||
if (opener.cc === C_OPEN_BRACKET) { | ||
if (!opener.image) { | ||
opener.active = false; // deactivate this opener | ||
@@ -696,3 +671,3 @@ } | ||
this.removeDelimiter(opener); // remove this opener from stack | ||
this.removeBracket(); // remove this opener from stack | ||
this.pos = startpos; | ||
@@ -705,2 +680,18 @@ block.appendChild(text(']')); | ||
var addBracket = function(node, index, image) { | ||
if (this.brackets !== null) { | ||
this.brackets.bracketAfter = true; | ||
} | ||
this.brackets = { node: node, | ||
previous: this.brackets, | ||
previousDelimiter: this.delimiters, | ||
index: index, | ||
image: image, | ||
active: true }; | ||
}; | ||
var removeBracket = function() { | ||
this.brackets = this.brackets.previous; | ||
}; | ||
// Attempt to parse an entity. | ||
@@ -906,2 +897,3 @@ var parseEntity = function(block) { | ||
this.delimiters = null; | ||
this.brackets = null; | ||
while (this.parseInline(block)) { | ||
@@ -918,2 +910,3 @@ } | ||
delimiters: null, // used by handleDelim method | ||
brackets: null, | ||
pos: 0, | ||
@@ -934,4 +927,6 @@ refmap: {}, | ||
parseOpenBracket: parseOpenBracket, | ||
parseBang: parseBang, | ||
parseCloseBracket: parseCloseBracket, | ||
parseBang: parseBang, | ||
addBracket: addBracket, | ||
removeBracket: removeBracket, | ||
parseEntity: parseEntity, | ||
@@ -938,0 +933,0 @@ parseString: parseString, |
@@ -7,3 +7,2 @@ "use strict"; | ||
var reHtmlTag = /\<[^>]*\>/; | ||
var reUnsafeProtocol = /^javascript:|vbscript:|file:|data:/i; | ||
@@ -10,0 +9,0 @@ var reSafeDataProtocol = /^data:image\/(?:png|gif|jpeg|webp)/i; |
{ "name": "commonmark", | ||
"description": "a strongly specified, highly compatible variant of Markdown", | ||
"version": "0.25.1", | ||
"version": "0.26.0", | ||
"homepage": "http://commonmark.org", | ||
@@ -5,0 +5,0 @@ "keywords": |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
429640
6382