Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions src/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,88 @@ describe("Parser", () => {
);
});

it("uses tight source position ends for lazy-closing block quotes", () => {
const ast = parse("> q\n\nAfter.\n", {sourcePositions: true}) as any;
const blockQuote = ast.children[0];
const para = ast.children[1];
expect(blockQuote.pos).toEqual({
"start": { "line": 1, "col": 1, "offset": 0 },
"end": { "line": 2, "col": 0, "offset": 3 }
});
expect(para.pos).toEqual({
"start": { "line": 3, "col": 1, "offset": 5 },
"end": { "line": 4, "col": 0, "offset": 11 }
});
expect(blockQuote.pos.end.offset).toBeLessThan(para.pos.start.offset);
});

it("uses tight source position ends for lazy-closing tables", () => {
const ast = parse("| a |\n| --- |\n| 1 |\n\nAfter.\n",
{sourcePositions: true}) as any;
const table = ast.children[0];
const para = ast.children[1];
expect(table.pos).toEqual({
"start": { "line": 1, "col": 1, "offset": 0 },
"end": { "line": 4, "col": 0, "offset": 19 }
});
expect(para.pos).toEqual({
"start": { "line": 5, "col": 1, "offset": 21 },
"end": { "line": 6, "col": 0, "offset": 27 }
});
expect(table.pos.end.offset).toBeLessThan(para.pos.start.offset);
});

it("uses tight source position ends for lazy-closing lists", () => {
const ast = parse("- a\n- b\n\nAfter.\n",
{sourcePositions: true}) as any;
const list = ast.children[0];
const para = ast.children[1];
expect(list.pos).toEqual({
"start": { "line": 1, "col": 1, "offset": 0 },
"end": { "line": 3, "col": 0, "offset": 7 }
});
expect(para.pos).toEqual({
"start": { "line": 4, "col": 1, "offset": 9 },
"end": { "line": 5, "col": 0, "offset": 15 }
});
expect(list.pos.end.offset).toBeLessThan(para.pos.start.offset);
// The lazily closed last item must stay contained in the list's range.
const lastItem = list.children[list.children.length - 1];
expect(lastItem.pos.end.offset).toBeLessThanOrEqual(list.pos.end.offset);
});

it("uses tight source position ends for lazy-closing definition lists", () => {
const ast = parse(": term\n def\n\nAfter.\n",
{sourcePositions: true}) as any;
const list = ast.children[0];
const para = ast.children[1];
expect(list.pos).toEqual({
"start": { "line": 1, "col": 1, "offset": 0 },
"end": { "line": 3, "col": 0, "offset": 12 }
});
expect(para.pos).toEqual({
"start": { "line": 4, "col": 1, "offset": 14 },
"end": { "line": 5, "col": 0, "offset": 20 }
});
expect(list.pos.end.offset).toBeLessThan(para.pos.start.offset);
});

it("uses tight source position ends for lazy-closing footnotes", () => {
const ast = parse("[^a]: note\n\nAfter.\n",
{sourcePositions: true}) as any;
const footnote = ast.footnotes.a;
const para = ast.children[0];
expect(footnote.pos).toEqual({
"start": { "line": 1, "col": 1, "offset": 0 },
"end": { "line": 2, "col": 0, "offset": 10 }
});
expect(para.pos).toEqual({
"start": { "line": 3, "col": 1, "offset": 12 },
"end": { "line": 4, "col": 0, "offset": 18 }
});
expect(footnote.pos.end.offset).toBeLessThan(para.pos.start.offset);
});

it("renders pretty", () => {
const ast = parse("hi there\nfriend\n\nnew para\n", {sourcePositions: true});
expect(renderAST(ast)).toEqual(
Expand Down
15 changes: 15 additions & 0 deletions src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,13 @@ const parseFromEvents = function(events: Event[],
}
}

const tightenContainerEnd = function(node: Container): void {
const lastChild = node.children[node.children.length - 1];
if (node.pos && lastChild && lastChild.pos) {
node.pos.end = lastChild.pos.end;
}
}


const handlers : Record<string, (suffixes : string[],
startpos : number,
Expand Down Expand Up @@ -812,6 +819,7 @@ const parseFromEvents = function(events: Event[],
if (!listStyle) {
throw (new Error("No style defined for list"));
}
tightenContainerEnd(node);
const listStart = getListStart(node.data.firstMarker, listStyle);
if (listStyle === ":") {
addChildToTip({
Expand Down Expand Up @@ -869,6 +877,10 @@ const parseFromEvents = function(events: Event[],

["-list_item"]: (suffixes, startpos, endpos, pos) => {
const node = popContainer(pos);
// A lazily closed item (e.g. before a blank line that ends the list)
// must not extend past its own content, so the parent list's
// tightened range still contains it.
tightenContainerEnd(node);
if (node.data.definitionList) {
if (node.children[0] && node.children[0].tag === "para") {
const term: Term =
Expand Down Expand Up @@ -934,6 +946,7 @@ const parseFromEvents = function(events: Event[],

["-block_quote"]: (suffixes, startpos, endpos, pos) => {
const node = popContainer(pos);
tightenContainerEnd(node);
addChildToTip({
tag: "block_quote",
children: node.children,
Expand All @@ -949,6 +962,7 @@ const parseFromEvents = function(events: Event[],

["-table"]: (suffixes, startpos, endpos, pos) => {
const node = popContainer(pos);
tightenContainerEnd(node);
const rows = node.children;
let caption: Caption = {
tag: "caption",
Expand Down Expand Up @@ -1059,6 +1073,7 @@ const parseFromEvents = function(events: Event[],

["-footnote"]: (suffixes, startpos, endpos, pos) => {
const node = popContainer(pos);
tightenContainerEnd(node);
if (node.data.label) {
const lab = normalizeLabel(node.data.label);
footnotes[lab] =
Expand Down
2 changes: 1 addition & 1 deletion test/sourcepos.test
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
.
doc
bullet_list (1:2:1-3:0:9) tight=true style="-"
list_item (1:2:1-2:1:5)
list_item (1:2:1-2:0:4)
para (1:4:3-2:0:4)
str (1:4:3-1:4:3) text="a"
list_item (2:2:6-3:0:9)
Expand Down
Loading