diff --git a/src/nodes/html.ts b/src/nodes/html.ts
index f6f4ea7..05b99ea 100644
--- a/src/nodes/html.ts
+++ b/src/nodes/html.ts
@@ -1011,6 +1011,10 @@ const kElementsClosedByOpening = {
H5: { h5: true, H5: true },
h6: { h6: true, H6: true },
H6: { h6: true, H6: true },
+ dt: { dt: true, dd: true, DT: true, DD: true },
+ DT: { dt: true, dd: true, DT: true, DD: true },
+ dd: { dt: true, dd: true, DT: true, DD: true },
+ DD: { dt: true, dd: true, DT: true, DD: true },
} as Record>;
const kElementsClosedByClosing = {
li: { ul: true, ol: true, UL: true, OL: true },
@@ -1027,6 +1031,10 @@ const kElementsClosedByClosing = {
TD: { tr: true, table: true, TR: true, TABLE: true },
th: { tr: true, table: true, TR: true, TABLE: true },
TH: { tr: true, table: true, TR: true, TABLE: true },
+ dt: { dl: true, body: true, html: true, DL: true, BODY: true, HTML: true },
+ DT: { dl: true, body: true, html: true, DL: true, BODY: true, HTML: true },
+ dd: { dl: true, body: true, html: true, DL: true, BODY: true, HTML: true },
+ DD: { dl: true, body: true, html: true, DL: true, BODY: true, HTML: true },
} as Record>;
const kElementsClosedByClosingExcept = {
p: { a: true, audio: true, del: true, ins: true, map: true, noscript: true, video: true },
diff --git a/test/tests/issues/315.js b/test/tests/issues/315.js
new file mode 100644
index 0000000..fff113d
--- /dev/null
+++ b/test/tests/issues/315.js
@@ -0,0 +1,37 @@
+const { parse } = require('@test/test-target');
+
+describe('issue 315 unclosed dt/dd tags', function () {
+ it('keeps the document tree when dt and dd omit their end tags', function () {
+ const html = `
+
+
+
+-
+
-
+
+
+
+`;
+ const root = parse(html);
+ root.querySelector('body').should.be.ok();
+ root.querySelector('dl').should.be.ok();
+ root.querySelectorAll('dt').length.should.eql(1);
+ root.querySelectorAll('dd').length.should.eql(1);
+ root.toString().should.containEql('');
+ root.toString().should.containEql('');
+ });
+
+ it('does not drop body when a lone dt is unclosed', function () {
+ const root = parse('- ');
+ root.querySelector('body').should.be.ok();
+ root.querySelectorAll('dt').length.should.eql(1);
+ root.toString().should.containEql('');
+ });
+
+ it('closes an open dt when a dd starts', function () {
+ const root = parse('
- term
- def
');
+ root.querySelector('dt').text.should.eql('term');
+ root.querySelector('dd').text.should.eql('def');
+ root.querySelector('dl').childNodes.filter((n) => n.tagName).map((n) => n.tagName).should.eql(['DT', 'DD']);
+ });
+});