Skip to content

Commit 619abb5

Browse files
authored
Make table diff ignore newlines (#46)
If a table is provided in multiple lines in the HTML, that shouldn't mark the whole table as invalid. So before we compare the elements of a table we should first trim any #text nodes, and ignore them if they're empty
1 parent 67224d0 commit 619abb5

File tree

2 files changed

+39
-16
lines changed

2 files changed

+39
-16
lines changed

src/diff.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,17 @@ test.each<[string, Node, Node, string, Options | undefined]>([
510510
'<p>123</p><p class="vdd-removed">456</p><p>789</p>',
511511
undefined,
512512
],
513+
[
514+
'table - identical (but with newline breaks)',
515+
htmlToFragment(
516+
'<table>\n<thead>\n<tr><th>Environment variable</th>\n<th>Zope option</th>\n<th>Default value</th>\n</tr>\n</thead>\n<tbody>\n<tr><td>DEBUG_MODE</td>\n<td>debug-mode</td>\n<td>off</td>\n</tr>\n</tbody>\n</table>',
517+
),
518+
htmlToFragment(
519+
'<table>\n<thead>\n<tr><th>Environment variable</th>\n<th>Zope option</th>\n<th>Default value</th>\n</tr>\n</thead>\n<tbody>\n<tr><td>DEBUG_MODE</td>\n<td>debug-mode</td>\n<td>off</td>\n</tr>\n</tbody>\n</table>',
520+
),
521+
'<table>\n<thead>\n<tr><th>Environment variable</th>\n<th>Zope option</th>\n<th>Default value</th>\n</tr>\n</thead>\n<tbody>\n<tr><td>DEBUG_MODE</td>\n<td>debug-mode</td>\n<td>off</td>\n</tr>\n</tbody>\n</table>',
522+
undefined,
523+
],
513524
[
514525
'table - added',
515526
htmlToFragment('<table><tbody><tr><td>one</td></tr></tbody></table>'),

src/util.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ function getAttributeNames(element: Element): string[] {
6464
}
6565
}
6666

67+
function stripNewlines(nodes: NodeList): Node[] {
68+
return Array.from(nodes).filter((node: Node) => {
69+
return (
70+
node.nodeName !== '#text' ||
71+
(node.textContent && node.textContent.trim() !== '')
72+
)
73+
})
74+
}
75+
6776
/**
6877
* Compares DOM nodes for equality.
6978
* @param node1 The first node to compare.
@@ -322,31 +331,32 @@ export function isTableValid(table: Node, verifyColumns: boolean): boolean {
322331
return validateTable(table)
323332

324333
function validateTable({ childNodes }: Node): boolean {
325-
const l = childNodes.length
334+
const filteredChildNodes = stripNewlines(childNodes)
335+
const l = filteredChildNodes.length
326336
let i = 0
327337

328-
if (i < l && childNodes[i].nodeName === 'CAPTION') {
338+
if (i < l && filteredChildNodes[i].nodeName === 'CAPTION') {
329339
i++
330340
}
331341

332-
if (i < l && childNodes[i].nodeName === 'THEAD') {
333-
if (!validateRowGroup(childNodes[i])) {
342+
if (i < l && filteredChildNodes[i].nodeName === 'THEAD') {
343+
if (!validateRowGroup(filteredChildNodes[i])) {
334344
return false
335345
}
336346
i++
337347
}
338348

339-
if (i < l && childNodes[i].nodeName === 'TBODY') {
340-
if (!validateRowGroup(childNodes[i])) {
349+
if (i < l && filteredChildNodes[i].nodeName === 'TBODY') {
350+
if (!validateRowGroup(filteredChildNodes[i])) {
341351
return false
342352
}
343353
i++
344354
} else {
345355
return false
346356
}
347357

348-
if (i < l && childNodes[i].nodeName === 'TFOOT') {
349-
if (!validateRowGroup(childNodes[i])) {
358+
if (i < l && filteredChildNodes[i].nodeName === 'TFOOT') {
359+
if (!validateRowGroup(filteredChildNodes[i])) {
350360
return false
351361
}
352362
i++
@@ -356,30 +366,32 @@ export function isTableValid(table: Node, verifyColumns: boolean): boolean {
356366
}
357367

358368
function validateRowGroup({ childNodes, nodeName }: Node): boolean {
359-
if (nodeName === 'TBODY' && childNodes.length === 0) {
369+
const filteredChildNodes = stripNewlines(childNodes)
370+
if (nodeName === 'TBODY' && filteredChildNodes.length === 0) {
360371
return false
361372
}
362-
for (let i = 0, l = childNodes.length; i < l; ++i) {
363-
if (!validateRow(childNodes[i])) {
373+
for (let i = 0, l = filteredChildNodes.length; i < l; ++i) {
374+
if (!validateRow(filteredChildNodes[i])) {
364375
return false
365376
}
366377
}
367378
return true
368379
}
369380

370381
function validateRow({ childNodes, nodeName }: Node): boolean {
371-
if (nodeName !== 'TR' || childNodes.length === 0) {
382+
const filteredChildNodes = stripNewlines(childNodes)
383+
if (nodeName !== 'TR' || filteredChildNodes.length === 0) {
372384
return false
373385
}
374386
if (verifyColumns) {
375387
if (columnCount === undefined) {
376-
columnCount = childNodes.length
377-
} else if (columnCount !== childNodes.length) {
388+
columnCount = filteredChildNodes.length
389+
} else if (columnCount !== filteredChildNodes.length) {
378390
return false
379391
}
380392
}
381-
for (let i = 0, l = childNodes.length; i < l; ++i) {
382-
if (!validateCell(childNodes[i])) {
393+
for (let i = 0, l = filteredChildNodes.length; i < l; ++i) {
394+
if (!validateCell(filteredChildNodes[i])) {
383395
return false
384396
}
385397
}

0 commit comments

Comments
 (0)