Skip to content

Commit 405ccb2

Browse files
authored
Merge pull request #299 from ig3/close-tags
Feat: add option closeAllByClosing
2 parents d604652 + c4cc706 commit 405ccb2

3 files changed

Lines changed: 35 additions & 1 deletion

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ Parse the data provided, wrap the result in a new node, and return the root of t
9696
noscript: true, // keep text content when parsing
9797
style: true, // keep text content when parsing
9898
pre: true // keep text content when parsing
99-
}
99+
},
100+
closeAllOnClosing: false // Close all non-closed tags when containing element closes
100101
}
101102
```
102103

src/nodes/html.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,7 @@ export interface Options {
10461046
*/
10471047
closingSlash?: boolean;
10481048
};
1049+
closeAllByClosing?: boolean;
10491050
}
10501051

10511052
const frameflag = 'documentfragmentcontainer';
@@ -1231,6 +1232,22 @@ export function base_parse(data: string, options = {} as Partial<Options>) {
12311232
}
12321233
}
12331234
}
1235+
if (options.closeAllByClosing === true) {
1236+
// If tag was opened, close all nested tags
1237+
let i;
1238+
for (i = stack.length - 2; i >= 0; i--) {
1239+
if (stack[i].rawTagName === tagName) break;
1240+
}
1241+
if (i >= 0) {
1242+
while (stack.length > i) {
1243+
// Update range end for closed tag
1244+
(<[number, number]>currentParent.range)[1] = createRange(-1, Math.max(lastTextPos, tagEndPos))[1];
1245+
stack.pop();
1246+
currentParent = arr_back(stack);
1247+
}
1248+
continue;
1249+
}
1250+
}
12341251
// Use aggressive strategy to handle unmatching markups.
12351252
break;
12361253
}

test/tests/unclosedtags.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const { parse, valid } = require('@test/test-target');
2+
3+
describe('Unclosed tags', function () {
4+
it('Unclosed tags should be closed at end of parent element', function () {
5+
const html = '<p>not bold<b>bold</p><p>more</p>';
6+
valid(html, { closeAllByClosing: true }).should.be.true();
7+
const root = parse(html, { closeAllByClosing: true });
8+
root.outerHTML.should.equal('<p>not bold<b>bold</b></p><p>more</p>');
9+
});
10+
it('Nested unclosed tags should be closed at end of parent element', function () {
11+
const html = '<p>not bold<b>bold<i>bold italic</p><p>more</p>';
12+
valid(html, { closeAllByClosing: true }).should.be.true();
13+
const root = parse(html, { closeAllByClosing: true });
14+
root.outerHTML.should.equal('<p>not bold<b>bold<i>bold italic</i></b></p><p>more</p>');
15+
});
16+
});

0 commit comments

Comments
 (0)