corrected a parsing edge cases for bbcode blocks

This commit is contained in:
Sam 2017-06-27 10:06:55 -04:00
parent 38950cdc10
commit 0e0092d738
2 changed files with 66 additions and 16 deletions

View File

@ -1,6 +1,19 @@
let isWhiteSpace;
function trailingSpaceOnly(src, start, max) {
let i;
for(i=start;i<max;i++) {
let code = src.charCodeAt(i);
if (code === 0x0A) { return true; }
if (!isWhiteSpace(code)) { return false; }
}
return true;
}
// parse a tag [test a=1 b=2] to a data structure // parse a tag [test a=1 b=2] to a data structure
// {tag: "test", attrs={a: "1", b: "2"} // {tag: "test", attrs={a: "1", b: "2"}
export function parseBBCodeTag(src, start, max) { export function parseBBCodeTag(src, start, max, multiline) {
let i; let i;
let tag; let tag;
@ -31,6 +44,11 @@ export function parseBBCodeTag(src, start, max) {
if (closingTag) { if (closingTag) {
if (src[i] === ']') { if (src[i] === ']') {
if (multiline && !trailingSpaceOnly(src, i+1, max)) {
return;
}
return {tag, length: tag.length+3, closing: true}; return {tag, length: tag.length+3, closing: true};
} }
return; return;
@ -81,6 +99,10 @@ export function parseBBCodeTag(src, start, max) {
} }
} }
if (multiline && !trailingSpaceOnly(src, start+length, max)) {
return;
}
tag = tag.toLowerCase(); tag = tag.toLowerCase();
return {tag, attrs, length}; return {tag, attrs, length};
@ -89,9 +111,8 @@ export function parseBBCodeTag(src, start, max) {
function applyBBCode(state, startLine, endLine, silent, md) { function applyBBCode(state, startLine, endLine, silent, md) {
var i, pos, nextLine, var i, nextLine,
old_parent, old_line_max, rule, old_parent, old_line_max, rule,
auto_closed = false,
start = state.bMarks[startLine] + state.tShift[startLine], start = state.bMarks[startLine] + state.tShift[startLine],
initial = start, initial = start,
max = state.eMarks[startLine]; max = state.eMarks[startLine];
@ -99,9 +120,9 @@ function applyBBCode(state, startLine, endLine, silent, md) {
// [ === 91 // [ === 91
if (91 !== state.src.charCodeAt(start)) { return false; } if (91 !== state.src.charCodeAt(start)) { return false; }
let info = parseBBCodeTag(state.src, start, max); let info = parseBBCodeTag(state.src, start, max, true);
if (!info) { if (!info || info.closing) {
return false; return false;
} }
@ -124,6 +145,9 @@ function applyBBCode(state, startLine, endLine, silent, md) {
// Search for the end of the block // Search for the end of the block
nextLine = startLine; nextLine = startLine;
let closeTag;
let nesting = 0;
for (;;) { for (;;) {
nextLine++; nextLine++;
if (nextLine >= endLine) { if (nextLine >= endLine) {
@ -150,15 +174,25 @@ function applyBBCode(state, startLine, endLine, silent, md) {
continue; continue;
} }
closeTag = parseBBCodeTag(state.src, start, max, true);
if (state.src.slice(start+2, max-1) !== rule.tag) { continue; } if (closeTag && closeTag.closing && closeTag.tag === info.tag) {
if (nesting === 0) {
if (pos < max) { continue; }
// found!
auto_closed = true;
break; break;
} }
nesting--;
}
if (closeTag && !closeTag.closing && closeTag.tag === info.tag) {
nesting++;
}
closeTag = null;
}
if (!closeTag) {
return false;
}
old_parent = state.parentType; old_parent = state.parentType;
old_line_max = state.lineMax; old_line_max = state.lineMax;
@ -199,9 +233,8 @@ function applyBBCode(state, startLine, endLine, silent, md) {
lastToken = state.tokens[state.tokens.length-1]; lastToken = state.tokens[state.tokens.length-1];
state.parentType = old_parent; state.parentType = old_parent;
state.lineMax = old_line_max; state.lineMax = old_line_max;
state.line = nextLine + (auto_closed ? 1 : 0); state.line = nextLine+1;
return true; return true;
} }
@ -210,8 +243,9 @@ export function setup(helper) {
if (!helper.markdownIt) { return; } if (!helper.markdownIt) { return; }
helper.registerPlugin(md => { helper.registerPlugin(md => {
isWhiteSpace = md.utils.isWhiteSpace;
md.block.ruler.after('fence', 'bbcode', (state, startLine, endLine, silent)=> { md.block.ruler.after('fence', 'bbcode', (state, startLine, endLine, silent)=> {
return applyBBCode(state, startLine, endLine, silent, md); return applyBBCode(state, startLine, endLine, silent, md);
}); }, { alt: ['paragraph', 'reference', 'blockquote', 'list'] });
}); });
} }

View File

@ -637,9 +637,25 @@ HTML
end end
it "can handle quote edge cases" do it "can handle quote edge cases" do
# expect(cook("a\n[quote]\ntest\n[quote]")).to include('aside') expect(PrettyText.cook("a\n[quote]\ntest\n[/quote]\n\n\na")).to include('aside')
expect(cook("[quote]\ntest")).not_to include('aside') expect(PrettyText.cook("- a\n[quote]\ntest\n[/quote]\n\n\na")).to include('aside')
# expect(cook("[quote]abc\ntest\n[quote]")).not_to include('aside') expect(PrettyText.cook("[quote]\ntest")).not_to include('aside')
expect(PrettyText.cook("[quote]abc\ntest\n[/quote]")).not_to include('aside')
expect(PrettyText.cook("[quote]\ntest\n[/quote]z")).not_to include('aside')
nested = <<~QUOTE
[quote]
a
[quote]
b
[/quote]
c
[/quote]
QUOTE
cooked = PrettyText.cook(nested)
expect(cooked.scan('aside').length).to eq(4)
expect(cooked.scan('quote]').length).to eq(0)
end end
it "do off topic quoting with emoji unescape" do it "do off topic quoting with emoji unescape" do