Skip to content

Commit 667ccf6

Browse files
Try and record previous indicies and rewrite if needed
1 parent 4f00e5c commit 667ccf6

File tree

3 files changed

+70
-7
lines changed

3 files changed

+70
-7
lines changed

src/index.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,16 @@ export const parser = (html: string, options: Options = {}): Node[] => {
4444
const locationTracker = new LocationTracker(html);
4545
const bufArray: Node[] = [];
4646
const results: Node[] = [];
47+
let lastIndices: [number, number];
4748

48-
function bufferArrayLast(): Node {
49+
function bufferArrayLast(): Node | undefined {
4950
return bufArray[bufArray.length - 1];
5051
}
5152

53+
function resultsLast(): Node | undefined {
54+
return results[results.length - 1];
55+
}
56+
5257
function isDirective(directive: Directive, tag: string): boolean {
5358
if (directive.name instanceof RegExp) {
5459
const regex = new RegExp(directive.name.source, 'i');
@@ -122,10 +127,20 @@ export const parser = (html: string, options: Options = {}): Node[] => {
122127
}
123128

124129
function onopentag(tag: string, attrs: Attributes) {
125-
const start = locationTracker.getPosition(parser.startIndex);
126130
const buf: NodeTag = { tag };
127131

128132
if (options.sourceLocations) {
133+
if (lastIndices?.[0] === parser.startIndex && lastIndices?.[1] === parser.endIndex) {
134+
// The last closing tag was inferred, so we need to update its end location
135+
const last = bufferArrayLast() || resultsLast();
136+
137+
if (typeof last === 'object' && Array.isArray(last.content) && last.location) {
138+
last.location.end = locationTracker.getPosition(parser.startIndex - 1)
139+
}
140+
}
141+
142+
const start = locationTracker.getPosition(parser.startIndex);
143+
129144
buf.location = {
130145
start,
131146
end: start
@@ -142,8 +157,9 @@ export const parser = (html: string, options: Options = {}): Node[] => {
142157
function onclosetag() {
143158
const buf: Node | undefined = bufArray.pop();
144159

145-
if (buf && typeof buf === 'object' && buf.location && parser.endIndex !== null) {
146-
buf.location.end = locationTracker.getPosition((!parser.tagname || parser.tagname === buf.tag) ? parser.endIndex : parser.startIndex - 1);
160+
if (buf && typeof buf === 'object' && buf.location && buf.location.end === buf.location.start && parser.endIndex !== null) {
161+
lastIndices = [parser.startIndex, parser.endIndex];
162+
buf.location.end = locationTracker.getPosition(parser.endIndex);
147163
}
148164

149165
if (buf) {
@@ -167,7 +183,7 @@ export const parser = (html: string, options: Options = {}): Node[] => {
167183
}
168184

169185
function ontext(text: string) {
170-
const last: Node = bufferArrayLast();
186+
const last = bufferArrayLast();
171187

172188
if (last === undefined) {
173189
results.push(text);

src/location-tracker.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ export class LocationTracker {
2525

2626
getPosition(index: number): Position {
2727
if (index < this.lastIndex) {
28-
throw new Error('Source indices must be monotonic');
28+
this.lastPosition = {
29+
line: 1,
30+
column: 1
31+
};
32+
33+
this.lastIndex = 0;
2934
}
3035

3136
while (this.lastIndex < index) {

test/test-core.spec.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ test('should be not converting html entity name', t => {
243243
});
244244

245245
test('should parse with source locations', t => {
246-
const html = '<h1>Test</h1>\n<p><b>Foo</b><hr>';
246+
const html = '<h1>Test</h1>\n<p><b>Foo</b><hr></p><p>Bar\n<hr>';
247247
const tree = parser(html, { sourceLocations: true });
248248
const expected = [
249249
{
@@ -303,6 +303,48 @@ test('should parse with source locations', t => {
303303
}
304304
}
305305
},
306+
{
307+
tag: 'p',
308+
location: {
309+
start: {
310+
line: 2,
311+
column: 18,
312+
},
313+
end: {
314+
line: 2,
315+
column: 21,
316+
},
317+
},
318+
},
319+
{
320+
tag: 'p',
321+
content: [
322+
'Bar\n',
323+
],
324+
location: {
325+
start: {
326+
line: 2,
327+
column: 22
328+
},
329+
end: {
330+
line: 2,
331+
column: 28
332+
}
333+
}
334+
},
335+
{
336+
tag: 'hr',
337+
location: {
338+
start: {
339+
line: 3,
340+
column: 1
341+
},
342+
end: {
343+
line: 3,
344+
column: 4
345+
}
346+
}
347+
},
306348
];
307349
t.deepEqual(tree, expected);
308350
});

0 commit comments

Comments
 (0)