pour-engine 1.31.3 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/config/project.config.js
CHANGED
|
@@ -11,12 +11,28 @@ export default {
|
|
|
11
11
|
selector: 'dl:not([role])', // a role attribute replaces the dl semantics
|
|
12
12
|
evaluate(element) {
|
|
13
13
|
const invalid = [...element.children].filter((child) => !ALLOWED.has(child.tagName));
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
if (invalid.length) {
|
|
15
|
+
const tags = [...new Set(invalid.map((child) => `<${child.tagName.toLowerCase()}>`))].join(', ');
|
|
16
|
+
return {
|
|
17
|
+
status: 'fail',
|
|
18
|
+
message: `This <dl> contains ${tags} directly — only <dt>, <dd> (optionally grouped in <div>) are allowed, otherwise the term/description pairing breaks.`,
|
|
19
|
+
fix: 'Restructure the list into <dt>/<dd> pairs, or use a different element.',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// A <div> child is only a valid wrapper when it holds the dt/dd group
|
|
23
|
+
// ITSELF (HTML: each div contains one or more dt followed by one or
|
|
24
|
+
// more dd). Pairs buried another level down (dl > div > div > dt) fall
|
|
25
|
+
// out of the dl's content model, so the term/description association is
|
|
26
|
+
// no longer guaranteed to assistive technology.
|
|
27
|
+
const emptyWrappers = [...element.children].filter((child) =>
|
|
28
|
+
child.tagName === 'DIV' && ![...child.children].some((inner) => inner.tagName === 'DT' || inner.tagName === 'DD'));
|
|
29
|
+
if (emptyWrappers.length) {
|
|
30
|
+
return {
|
|
31
|
+
status: 'fail',
|
|
32
|
+
message: `${emptyWrappers.length} <div> wrapper(s) in this <dl> hold no <dt>/<dd> directly — the term/description pairing breaks when the pairs sit deeper than the wrapper.`,
|
|
33
|
+
fix: 'Make each <div> child of the <dl> contain its <dt>/<dd> pair directly, or flatten the pairs into the <dl> itself.',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return { status: 'pass' };
|
|
21
37
|
},
|
|
22
38
|
};
|
|
@@ -26,11 +26,13 @@ export default {
|
|
|
26
26
|
if (!isGrid || textCells < 4) return { status: 'pass' }; // likely layout or trivial
|
|
27
27
|
// Nested tables are the signature of legacy LAYOUT markup, not data —
|
|
28
28
|
// asserting "missing headers" there flags email-style scaffolding. A
|
|
29
|
-
// human can tell in a glance; the machine can't.
|
|
30
|
-
|
|
29
|
+
// human can tell in a glance; the machine can't. The signature reads in
|
|
30
|
+
// both directions: a table INSIDE another table (Hacker News's story
|
|
31
|
+
// list inside its page-scaffold table) is the same legacy layout.
|
|
32
|
+
if (!element.querySelector('th') && (element.querySelector('table') || element.parentElement?.closest('table'))) {
|
|
31
33
|
return {
|
|
32
34
|
status: 'incomplete',
|
|
33
|
-
message: 'This table has no header cells
|
|
35
|
+
message: 'This table has no header cells and is part of a nested-table structure — a layout-table signature. If it really presents data, mark its header cells with <th>; if it is layout scaffolding, add role="presentation".',
|
|
34
36
|
};
|
|
35
37
|
}
|
|
36
38
|
|
package/package.json
CHANGED