html-validate 10.9.0 → 10.11.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/dist/cjs/cli.js +10 -10
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/core-browser.js +1 -1
- package/dist/cjs/core-browser.js.map +1 -1
- package/dist/cjs/core-nodejs.js +1 -1
- package/dist/cjs/core-nodejs.js.map +1 -1
- package/dist/cjs/core.js +286 -189
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/elements.js +24 -16
- package/dist/cjs/elements.js.map +1 -1
- package/dist/cjs/html-validate.js +23 -15
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/matchers-jestonly.js +2 -2
- package/dist/cjs/matchers-jestonly.js.map +1 -1
- package/dist/cjs/tsdoc-metadata.json +1 -1
- package/dist/cjs/utils/natural-join.js +1 -1
- package/dist/cjs/utils/natural-join.js.map +1 -1
- package/dist/esm/cli.js +10 -10
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/core-browser.js +1 -1
- package/dist/esm/core-browser.js.map +1 -1
- package/dist/esm/core-nodejs.js +1 -1
- package/dist/esm/core-nodejs.js.map +1 -1
- package/dist/esm/core.js +286 -189
- package/dist/esm/core.js.map +1 -1
- package/dist/esm/elements.js +24 -16
- package/dist/esm/elements.js.map +1 -1
- package/dist/esm/html-validate.js +24 -16
- package/dist/esm/html-validate.js.map +1 -1
- package/dist/esm/matchers-jestonly.js +2 -2
- package/dist/esm/matchers-jestonly.js.map +1 -1
- package/dist/esm/utils/natural-join.js +1 -1
- package/dist/esm/utils/natural-join.js.map +1 -1
- package/dist/schema/elements.json +6 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types/browser.d.ts +24 -9
- package/dist/types/index.d.ts +24 -9
- package/package.json +3 -3
package/dist/esm/core.js
CHANGED
|
@@ -395,6 +395,7 @@ function stringify(value) {
|
|
|
395
395
|
class WrappedError extends Error {
|
|
396
396
|
constructor(message) {
|
|
397
397
|
super(stringify(message));
|
|
398
|
+
this.name = "WrappedError";
|
|
398
399
|
}
|
|
399
400
|
}
|
|
400
401
|
|
|
@@ -409,8 +410,7 @@ function ensureError(value) {
|
|
|
409
410
|
class NestedError extends Error {
|
|
410
411
|
constructor(message, nested) {
|
|
411
412
|
super(message);
|
|
412
|
-
|
|
413
|
-
this.name = NestedError.name;
|
|
413
|
+
this.name = "NestedError";
|
|
414
414
|
if (nested?.stack) {
|
|
415
415
|
this.stack ??= "";
|
|
416
416
|
this.stack += `
|
|
@@ -422,8 +422,7 @@ Caused by: ${nested.stack}`;
|
|
|
422
422
|
class UserError extends NestedError {
|
|
423
423
|
constructor(message, nested) {
|
|
424
424
|
super(message, nested);
|
|
425
|
-
|
|
426
|
-
this.name = UserError.name;
|
|
425
|
+
this.name = "UserError";
|
|
427
426
|
Object.defineProperty(this, "isUserError", {
|
|
428
427
|
value: true,
|
|
429
428
|
enumerable: false,
|
|
@@ -446,8 +445,7 @@ class InheritError extends UserError {
|
|
|
446
445
|
constructor({ tagName, inherit }) {
|
|
447
446
|
const message = `Element <${tagName}> cannot inherit from <${inherit}>: no such element`;
|
|
448
447
|
super(message);
|
|
449
|
-
|
|
450
|
-
this.name = InheritError.name;
|
|
448
|
+
this.name = "InheritError";
|
|
451
449
|
this.tagName = tagName;
|
|
452
450
|
this.inherit = inherit;
|
|
453
451
|
this.filename = null;
|
|
@@ -489,6 +487,7 @@ class SchemaValidationError extends UserError {
|
|
|
489
487
|
constructor(filename, message, obj, schema, errors) {
|
|
490
488
|
const summary = getSummary(schema, obj, errors);
|
|
491
489
|
super(`${message}: ${summary}`);
|
|
490
|
+
this.name = "SchemaValidationError";
|
|
492
491
|
this.filename = filename;
|
|
493
492
|
this.obj = obj;
|
|
494
493
|
this.schema = schema;
|
|
@@ -636,6 +635,18 @@ const patternProperties = {
|
|
|
636
635
|
}
|
|
637
636
|
]
|
|
638
637
|
},
|
|
638
|
+
submitButton: {
|
|
639
|
+
title: "Mark this element as a submit button",
|
|
640
|
+
description: "This element can be used to submit forms.",
|
|
641
|
+
anyOf: [
|
|
642
|
+
{
|
|
643
|
+
type: "boolean"
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
"function": true
|
|
647
|
+
}
|
|
648
|
+
]
|
|
649
|
+
},
|
|
639
650
|
templateRoot: {
|
|
640
651
|
title: "Mark element as an element ignoring DOM ancestry, i.e. <template>.",
|
|
641
652
|
description: "The <template> element can contain any elements.",
|
|
@@ -1019,6 +1030,7 @@ const MetaCopyableProperty = [
|
|
|
1019
1030
|
"form",
|
|
1020
1031
|
"formAssociated",
|
|
1021
1032
|
"labelable",
|
|
1033
|
+
"submitButton",
|
|
1022
1034
|
"attributes",
|
|
1023
1035
|
"aria",
|
|
1024
1036
|
"permittedContent",
|
|
@@ -1033,7 +1045,7 @@ function setMetaProperty(dst, key, value) {
|
|
|
1033
1045
|
}
|
|
1034
1046
|
|
|
1035
1047
|
function isSet(value) {
|
|
1036
|
-
return
|
|
1048
|
+
return value !== void 0;
|
|
1037
1049
|
}
|
|
1038
1050
|
function flag(value) {
|
|
1039
1051
|
return value ? true : void 0;
|
|
@@ -1048,7 +1060,7 @@ function migrateSingleAttribute(src, key) {
|
|
|
1048
1060
|
result.required = flag(src.requiredAttributes?.includes(key));
|
|
1049
1061
|
result.omit = void 0;
|
|
1050
1062
|
const attr = src.attributes ? src.attributes[key] : void 0;
|
|
1051
|
-
if (
|
|
1063
|
+
if (attr === void 0) {
|
|
1052
1064
|
return stripUndefined(result);
|
|
1053
1065
|
}
|
|
1054
1066
|
if (attr === null) {
|
|
@@ -1075,7 +1087,7 @@ function migrateAttributes(src) {
|
|
|
1075
1087
|
...src.requiredAttributes ?? [],
|
|
1076
1088
|
...src.deprecatedAttributes ?? []
|
|
1077
1089
|
/* eslint-disable-next-line sonarjs/no-alphabetical-sort -- not really needed in this case, this is a-z anyway */
|
|
1078
|
-
].
|
|
1090
|
+
].toSorted();
|
|
1079
1091
|
const entries = keys.map((key) => {
|
|
1080
1092
|
return [key, migrateSingleAttribute(src, key)];
|
|
1081
1093
|
});
|
|
@@ -1103,9 +1115,7 @@ function migrateElement(src) {
|
|
|
1103
1115
|
const implicitRole = normalizeAriaImplicitRole(src.implicitRole ?? src.aria?.implicitRole);
|
|
1104
1116
|
const result = {
|
|
1105
1117
|
...src,
|
|
1106
|
-
|
|
1107
|
-
formAssociated: void 0
|
|
1108
|
-
},
|
|
1118
|
+
formAssociated: void 0,
|
|
1109
1119
|
attributes: migrateAttributes(src),
|
|
1110
1120
|
textContent: src.textContent,
|
|
1111
1121
|
focusable: src.focusable ?? false,
|
|
@@ -1140,7 +1150,8 @@ const dynamicKeys = [
|
|
|
1140
1150
|
"phrasing",
|
|
1141
1151
|
"embedded",
|
|
1142
1152
|
"interactive",
|
|
1143
|
-
"labelable"
|
|
1153
|
+
"labelable",
|
|
1154
|
+
"submitButton"
|
|
1144
1155
|
];
|
|
1145
1156
|
const schemaCache = /* @__PURE__ */ new Map();
|
|
1146
1157
|
function clone(src) {
|
|
@@ -1410,13 +1421,10 @@ class Attribute {
|
|
|
1410
1421
|
*/
|
|
1411
1422
|
constructor(key, value, keyLocation, valueLocation, originalAttribute) {
|
|
1412
1423
|
this.key = key;
|
|
1413
|
-
this.value = value;
|
|
1424
|
+
this.value = value ?? null;
|
|
1414
1425
|
this.keyLocation = keyLocation;
|
|
1415
1426
|
this.valueLocation = valueLocation;
|
|
1416
1427
|
this.originalAttribute = originalAttribute;
|
|
1417
|
-
if (typeof this.value === "undefined") {
|
|
1418
|
-
this.value = null;
|
|
1419
|
-
}
|
|
1420
1428
|
}
|
|
1421
1429
|
/**
|
|
1422
1430
|
* Flag set to true if the attribute value is static.
|
|
@@ -1560,11 +1568,11 @@ class Context {
|
|
|
1560
1568
|
while ((offset = consumed.indexOf("\n")) >= 0) {
|
|
1561
1569
|
this.line++;
|
|
1562
1570
|
this.column = 1;
|
|
1563
|
-
consumed = consumed.
|
|
1571
|
+
consumed = consumed.slice(offset + 1);
|
|
1564
1572
|
}
|
|
1565
1573
|
this.column += consumed.length;
|
|
1566
1574
|
this.offset += n;
|
|
1567
|
-
this.string = this.string.
|
|
1575
|
+
this.string = this.string.slice(n);
|
|
1568
1576
|
this.state = state;
|
|
1569
1577
|
}
|
|
1570
1578
|
getLocation(size) {
|
|
@@ -1742,7 +1750,7 @@ class DOMNode {
|
|
|
1742
1750
|
* node has no children.
|
|
1743
1751
|
*/
|
|
1744
1752
|
get lastChild() {
|
|
1745
|
-
return this.childNodes
|
|
1753
|
+
return this.childNodes.at(-1) ?? null;
|
|
1746
1754
|
}
|
|
1747
1755
|
/**
|
|
1748
1756
|
* @internal
|
|
@@ -1836,7 +1844,7 @@ class DOMNode {
|
|
|
1836
1844
|
}
|
|
1837
1845
|
_removeChild(node) {
|
|
1838
1846
|
const index = this.childNodes.findIndex((it) => it.isSameNode(node));
|
|
1839
|
-
if (index
|
|
1847
|
+
if (index !== -1) {
|
|
1840
1848
|
this.childNodes.splice(index, 1);
|
|
1841
1849
|
} else {
|
|
1842
1850
|
throw new Error("DOMException: _removeChild(..) could not find child to remove");
|
|
@@ -1857,7 +1865,7 @@ function parse(text, baseLocation) {
|
|
|
1857
1865
|
begin++;
|
|
1858
1866
|
continue;
|
|
1859
1867
|
}
|
|
1860
|
-
const token = text.
|
|
1868
|
+
const token = text.slice(begin, end);
|
|
1861
1869
|
tokens.push(token);
|
|
1862
1870
|
if (locations && baseLocation) {
|
|
1863
1871
|
const location = sliceLocation(baseLocation, begin, end);
|
|
@@ -1872,7 +1880,7 @@ class DOMTokenList extends Array {
|
|
|
1872
1880
|
locations;
|
|
1873
1881
|
constructor(value, location) {
|
|
1874
1882
|
if (value && typeof value === "string") {
|
|
1875
|
-
const normalized = value.
|
|
1883
|
+
const normalized = value.replaceAll(/[\t\r\n]/g, " ");
|
|
1876
1884
|
const { tokens, locations } = parse(normalized, location);
|
|
1877
1885
|
super(...tokens);
|
|
1878
1886
|
this.locations = locations;
|
|
@@ -1962,7 +1970,7 @@ function nthChild(node, args) {
|
|
|
1962
1970
|
if (!args) {
|
|
1963
1971
|
throw new Error("Missing argument to nth-child");
|
|
1964
1972
|
}
|
|
1965
|
-
const n = parseInt(args.trim(), 10);
|
|
1973
|
+
const n = Number.parseInt(args.trim(), 10);
|
|
1966
1974
|
const cur = getNthChild(node);
|
|
1967
1975
|
return cur === n;
|
|
1968
1976
|
}
|
|
@@ -1987,7 +1995,7 @@ function factory(name, context) {
|
|
|
1987
1995
|
}
|
|
1988
1996
|
|
|
1989
1997
|
function stripslashes(value) {
|
|
1990
|
-
return value.
|
|
1998
|
+
return value.replaceAll(/\\(.)/g, "$1");
|
|
1991
1999
|
}
|
|
1992
2000
|
class Condition {
|
|
1993
2001
|
}
|
|
@@ -2186,7 +2194,7 @@ function candidatesFromCombinator(element, combinator) {
|
|
|
2186
2194
|
}
|
|
2187
2195
|
}
|
|
2188
2196
|
function matchElement(element, compounds, context) {
|
|
2189
|
-
const last = compounds
|
|
2197
|
+
const last = compounds.at(-1);
|
|
2190
2198
|
if (!last.match(element, context)) {
|
|
2191
2199
|
return false;
|
|
2192
2200
|
}
|
|
@@ -2203,7 +2211,7 @@ function matchElement(element, compounds, context) {
|
|
|
2203
2211
|
return false;
|
|
2204
2212
|
}
|
|
2205
2213
|
|
|
2206
|
-
const escapedCodepoints = ["9", "a", "d"];
|
|
2214
|
+
const escapedCodepoints = /* @__PURE__ */ new Set(["9", "a", "d"]);
|
|
2207
2215
|
function* splitSelectorElements(selector) {
|
|
2208
2216
|
let begin = 0;
|
|
2209
2217
|
let end = 0;
|
|
@@ -2218,7 +2226,7 @@ function* splitSelectorElements(selector) {
|
|
|
2218
2226
|
return 0 /* INITIAL */;
|
|
2219
2227
|
}
|
|
2220
2228
|
function escapedState(ch) {
|
|
2221
|
-
if (escapedCodepoints.
|
|
2229
|
+
if (escapedCodepoints.has(ch)) {
|
|
2222
2230
|
return 1 /* ESCAPED */;
|
|
2223
2231
|
}
|
|
2224
2232
|
return 0 /* INITIAL */;
|
|
@@ -2258,7 +2266,7 @@ function unescapeCodepoint(value) {
|
|
|
2258
2266
|
"\\a ": "\n",
|
|
2259
2267
|
"\\d ": "\r"
|
|
2260
2268
|
};
|
|
2261
|
-
return value.
|
|
2269
|
+
return value.replaceAll(
|
|
2262
2270
|
/(\\[\u0039\u0061\u0064] )/g,
|
|
2263
2271
|
(_, codepoint) => replacement[codepoint]
|
|
2264
2272
|
);
|
|
@@ -2269,7 +2277,7 @@ function escapeSelectorComponent(text) {
|
|
|
2269
2277
|
"\n": "\\a ",
|
|
2270
2278
|
"\r": "\\d "
|
|
2271
2279
|
};
|
|
2272
|
-
return text.toString().
|
|
2280
|
+
return text.toString().replaceAll(/([\t\n\r]|[^a-z0-9_-])/gi, (_, ch) => {
|
|
2273
2281
|
if (codepoints[ch]) {
|
|
2274
2282
|
return codepoints[ch];
|
|
2275
2283
|
} else {
|
|
@@ -2318,7 +2326,7 @@ class Selector {
|
|
|
2318
2326
|
}
|
|
2319
2327
|
}
|
|
2320
2328
|
static parse(selector) {
|
|
2321
|
-
selector = selector.
|
|
2329
|
+
selector = selector.replaceAll(/([+~>]) /g, "$1");
|
|
2322
2330
|
return Array.from(splitSelectorElements(selector), (element) => {
|
|
2323
2331
|
return new Compound(unescapeCodepoint(element));
|
|
2324
2332
|
});
|
|
@@ -2559,7 +2567,7 @@ class HtmlElement extends DOMNode {
|
|
|
2559
2567
|
return attr.value;
|
|
2560
2568
|
}
|
|
2561
2569
|
const list = new DOMTokenList(attr.value, attr.valueLocation);
|
|
2562
|
-
return list.length ? Array.from(list) : null;
|
|
2570
|
+
return list.length > 0 ? Array.from(list) : null;
|
|
2563
2571
|
}
|
|
2564
2572
|
/**
|
|
2565
2573
|
* Similar to childNodes but only elements.
|
|
@@ -2614,7 +2622,7 @@ class HtmlElement extends DOMNode {
|
|
|
2614
2622
|
}
|
|
2615
2623
|
parts.push(`${cur.tagName.toLowerCase()}:nth-child(${String(index + 1)})`);
|
|
2616
2624
|
}
|
|
2617
|
-
return parts.
|
|
2625
|
+
return parts.toReversed().join(" > ");
|
|
2618
2626
|
}
|
|
2619
2627
|
/**
|
|
2620
2628
|
* Tests if this element has given tagname.
|
|
@@ -2656,7 +2664,7 @@ class HtmlElement extends DOMNode {
|
|
|
2656
2664
|
this.metaElement ??= {};
|
|
2657
2665
|
for (const key of MetaCopyableProperty) {
|
|
2658
2666
|
const value = meta[key];
|
|
2659
|
-
if (
|
|
2667
|
+
if (value !== void 0) {
|
|
2660
2668
|
setMetaProperty(this.metaElement, key, value);
|
|
2661
2669
|
} else {
|
|
2662
2670
|
delete this.metaElement[key];
|
|
@@ -2760,8 +2768,8 @@ class HtmlElement extends DOMNode {
|
|
|
2760
2768
|
if (tabindex.value instanceof DynamicValue) {
|
|
2761
2769
|
return this.cacheSet(TABINDEX, 0);
|
|
2762
2770
|
}
|
|
2763
|
-
const parsed = parseInt(tabindex.value, 10);
|
|
2764
|
-
if (isNaN(parsed)) {
|
|
2771
|
+
const parsed = Number.parseInt(tabindex.value, 10);
|
|
2772
|
+
if (Number.isNaN(parsed)) {
|
|
2765
2773
|
return this.cacheSet(TABINDEX, null);
|
|
2766
2774
|
}
|
|
2767
2775
|
return this.cacheSet(TABINDEX, parsed);
|
|
@@ -2865,7 +2873,10 @@ class HtmlElement extends DOMNode {
|
|
|
2865
2873
|
*/
|
|
2866
2874
|
get lastElementChild() {
|
|
2867
2875
|
const children = this.childElements;
|
|
2868
|
-
return children.length > 0 ?
|
|
2876
|
+
return children.length > 0 ? (
|
|
2877
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- it is checked right before this */
|
|
2878
|
+
children.at(-1)
|
|
2879
|
+
) : null;
|
|
2869
2880
|
}
|
|
2870
2881
|
get siblings() {
|
|
2871
2882
|
return this.parent ? this.parent.childElements : [this];
|
|
@@ -2988,7 +2999,9 @@ function depthFirst(root, callback) {
|
|
|
2988
2999
|
root = root.root;
|
|
2989
3000
|
}
|
|
2990
3001
|
function visit(node) {
|
|
2991
|
-
node.childElements
|
|
3002
|
+
for (const child of node.childElements) {
|
|
3003
|
+
visit(child);
|
|
3004
|
+
}
|
|
2992
3005
|
if (!node.isRootElement()) {
|
|
2993
3006
|
callback(node);
|
|
2994
3007
|
}
|
|
@@ -3077,7 +3090,7 @@ class DOMTree {
|
|
|
3077
3090
|
}
|
|
3078
3091
|
}
|
|
3079
3092
|
|
|
3080
|
-
const allowedKeys = ["exclude"];
|
|
3093
|
+
const allowedKeys = /* @__PURE__ */ new Set(["exclude"]);
|
|
3081
3094
|
class Validator {
|
|
3082
3095
|
/**
|
|
3083
3096
|
* Test if element is used in a proper context.
|
|
@@ -3316,7 +3329,7 @@ class Validator {
|
|
|
3316
3329
|
}
|
|
3317
3330
|
function validateKeys(rule) {
|
|
3318
3331
|
for (const key of Object.keys(rule)) {
|
|
3319
|
-
if (!allowedKeys.
|
|
3332
|
+
if (!allowedKeys.has(key)) {
|
|
3320
3333
|
const str = JSON.stringify(rule);
|
|
3321
3334
|
throw new Error(`Permitted rule "${str}" contains unknown property "${key}"`);
|
|
3322
3335
|
}
|
|
@@ -3358,7 +3371,7 @@ function parseSeverity(value) {
|
|
|
3358
3371
|
|
|
3359
3372
|
const cacheKey = /* @__PURE__ */ Symbol("aria-naming");
|
|
3360
3373
|
const defaultValue = "allowed";
|
|
3361
|
-
const prohibitedRoles = [
|
|
3374
|
+
const prohibitedRoles = /* @__PURE__ */ new Set([
|
|
3362
3375
|
"caption",
|
|
3363
3376
|
"code",
|
|
3364
3377
|
"deletion",
|
|
@@ -3370,9 +3383,9 @@ const prohibitedRoles = [
|
|
|
3370
3383
|
"strong",
|
|
3371
3384
|
"subscript",
|
|
3372
3385
|
"superscript"
|
|
3373
|
-
];
|
|
3386
|
+
]);
|
|
3374
3387
|
function byRole(role) {
|
|
3375
|
-
return prohibitedRoles.
|
|
3388
|
+
return prohibitedRoles.has(role) ? "prohibited" : "allowed";
|
|
3376
3389
|
}
|
|
3377
3390
|
function byMeta(element, meta) {
|
|
3378
3391
|
return meta.aria.naming(element._adapter);
|
|
@@ -3424,7 +3437,7 @@ function isInputDisabledImpl(node) {
|
|
|
3424
3437
|
|
|
3425
3438
|
const patternCache = /* @__PURE__ */ new Map();
|
|
3426
3439
|
function compileStringPattern(pattern) {
|
|
3427
|
-
const regexp = pattern.
|
|
3440
|
+
const regexp = pattern.replaceAll(/[*]+/g, ".+");
|
|
3428
3441
|
return new RegExp(`^${regexp}$`);
|
|
3429
3442
|
}
|
|
3430
3443
|
function compileRegExpPattern(pattern) {
|
|
@@ -3699,8 +3712,8 @@ function format(value, quote = false) {
|
|
|
3699
3712
|
return String(value);
|
|
3700
3713
|
}
|
|
3701
3714
|
function interpolate(text, data) {
|
|
3702
|
-
return text.
|
|
3703
|
-
return
|
|
3715
|
+
return text.replaceAll(/{{\s*([^\s{}]+)\s*}}/g, (match, key) => {
|
|
3716
|
+
return data[key] !== void 0 ? format(data[key]) : match;
|
|
3704
3717
|
});
|
|
3705
3718
|
}
|
|
3706
3719
|
|
|
@@ -3908,7 +3921,14 @@ class Rule {
|
|
|
3908
3921
|
});
|
|
3909
3922
|
if (enabled && !blocked) {
|
|
3910
3923
|
const interpolated = interpolate(message, context ?? {});
|
|
3911
|
-
this.reporter.add(
|
|
3924
|
+
this.reporter.add({
|
|
3925
|
+
rule: this,
|
|
3926
|
+
message: interpolated,
|
|
3927
|
+
severity: this.severity,
|
|
3928
|
+
node,
|
|
3929
|
+
location: where,
|
|
3930
|
+
context
|
|
3931
|
+
});
|
|
3912
3932
|
}
|
|
3913
3933
|
}
|
|
3914
3934
|
findLocation(src) {
|
|
@@ -3999,7 +4019,7 @@ class Rule {
|
|
|
3999
4019
|
}
|
|
4000
4020
|
}
|
|
4001
4021
|
|
|
4002
|
-
const defaults$
|
|
4022
|
+
const defaults$C = {
|
|
4003
4023
|
allowExternal: true,
|
|
4004
4024
|
allowRelative: true,
|
|
4005
4025
|
allowAbsolute: true,
|
|
@@ -4043,7 +4063,7 @@ class AllowedLinks extends Rule {
|
|
|
4043
4063
|
allowRelative;
|
|
4044
4064
|
allowAbsolute;
|
|
4045
4065
|
constructor(options) {
|
|
4046
|
-
super({ ...defaults$
|
|
4066
|
+
super({ ...defaults$C, ...options });
|
|
4047
4067
|
this.allowExternal = parseAllow(this.options.allowExternal);
|
|
4048
4068
|
this.allowRelative = parseAllow(this.options.allowRelative);
|
|
4049
4069
|
this.allowAbsolute = parseAllow(this.options.allowAbsolute);
|
|
@@ -4211,7 +4231,7 @@ class AllowedLinks extends Rule {
|
|
|
4211
4231
|
}
|
|
4212
4232
|
}
|
|
4213
4233
|
|
|
4214
|
-
const defaults$
|
|
4234
|
+
const defaults$B = {
|
|
4215
4235
|
accessible: true
|
|
4216
4236
|
};
|
|
4217
4237
|
function findByTarget(target, siblings) {
|
|
@@ -4241,7 +4261,7 @@ function getDescription$1(context) {
|
|
|
4241
4261
|
}
|
|
4242
4262
|
class AreaAlt extends Rule {
|
|
4243
4263
|
constructor(options) {
|
|
4244
|
-
super({ ...defaults$
|
|
4264
|
+
super({ ...defaults$B, ...options });
|
|
4245
4265
|
}
|
|
4246
4266
|
static schema() {
|
|
4247
4267
|
return {
|
|
@@ -4320,7 +4340,7 @@ class AriaHiddenBody extends Rule {
|
|
|
4320
4340
|
}
|
|
4321
4341
|
}
|
|
4322
4342
|
|
|
4323
|
-
const defaults$
|
|
4343
|
+
const defaults$A = {
|
|
4324
4344
|
allowAnyNamable: false,
|
|
4325
4345
|
elements: {
|
|
4326
4346
|
include: null,
|
|
@@ -4368,7 +4388,7 @@ function isValidUsage(target, meta) {
|
|
|
4368
4388
|
}
|
|
4369
4389
|
class AriaLabelMisuse extends Rule {
|
|
4370
4390
|
constructor(options) {
|
|
4371
|
-
super({ ...defaults$
|
|
4391
|
+
super({ ...defaults$A, ...options });
|
|
4372
4392
|
}
|
|
4373
4393
|
static schema() {
|
|
4374
4394
|
return {
|
|
@@ -4480,8 +4500,7 @@ class AriaLabelMisuse extends Rule {
|
|
|
4480
4500
|
class ConfigError extends UserError {
|
|
4481
4501
|
constructor(message, nested) {
|
|
4482
4502
|
super(message, nested);
|
|
4483
|
-
|
|
4484
|
-
this.name = ConfigError.name;
|
|
4503
|
+
this.name = "ConfigError";
|
|
4485
4504
|
}
|
|
4486
4505
|
}
|
|
4487
4506
|
|
|
@@ -4537,14 +4556,14 @@ class CaseStyle {
|
|
|
4537
4556
|
}
|
|
4538
4557
|
}
|
|
4539
4558
|
|
|
4540
|
-
const defaults$
|
|
4559
|
+
const defaults$z = {
|
|
4541
4560
|
style: "lowercase",
|
|
4542
4561
|
ignoreForeign: true
|
|
4543
4562
|
};
|
|
4544
4563
|
class AttrCase extends Rule {
|
|
4545
4564
|
style;
|
|
4546
4565
|
constructor(options) {
|
|
4547
|
-
super({ ...defaults$
|
|
4566
|
+
super({ ...defaults$z, ...options });
|
|
4548
4567
|
this.style = new CaseStyle(this.options.style, "attr-case");
|
|
4549
4568
|
}
|
|
4550
4569
|
static schema() {
|
|
@@ -4585,7 +4604,7 @@ class AttrCase extends Rule {
|
|
|
4585
4604
|
if (event.originalAttribute) {
|
|
4586
4605
|
return;
|
|
4587
4606
|
}
|
|
4588
|
-
const letters = event.key.
|
|
4607
|
+
const letters = event.key.replaceAll(/[^a-z]+/gi, "");
|
|
4589
4608
|
if (this.style.match(letters)) {
|
|
4590
4609
|
return;
|
|
4591
4610
|
}
|
|
@@ -4658,6 +4677,7 @@ class InvalidTokenError extends Error {
|
|
|
4658
4677
|
location;
|
|
4659
4678
|
constructor(location, message) {
|
|
4660
4679
|
super(message);
|
|
4680
|
+
this.name = "InvalidTokenError";
|
|
4661
4681
|
this.location = location;
|
|
4662
4682
|
}
|
|
4663
4683
|
}
|
|
@@ -4767,16 +4787,26 @@ class Lexer {
|
|
|
4767
4787
|
*/
|
|
4768
4788
|
enter(context, state, data) {
|
|
4769
4789
|
if (state === State.TAG && data?.[0].startsWith("<")) {
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4790
|
+
switch (data[0]) {
|
|
4791
|
+
case "<script": {
|
|
4792
|
+
context.contentModel = ContentModel.SCRIPT;
|
|
4793
|
+
break;
|
|
4794
|
+
}
|
|
4795
|
+
case "<style": {
|
|
4796
|
+
context.contentModel = ContentModel.STYLE;
|
|
4797
|
+
break;
|
|
4798
|
+
}
|
|
4799
|
+
case "<textarea": {
|
|
4800
|
+
context.contentModel = ContentModel.TEXTAREA;
|
|
4801
|
+
break;
|
|
4802
|
+
}
|
|
4803
|
+
case "<title": {
|
|
4804
|
+
context.contentModel = ContentModel.TITLE;
|
|
4805
|
+
break;
|
|
4806
|
+
}
|
|
4807
|
+
default: {
|
|
4808
|
+
context.contentModel = ContentModel.TEXT;
|
|
4809
|
+
}
|
|
4780
4810
|
}
|
|
4781
4811
|
}
|
|
4782
4812
|
}
|
|
@@ -4949,7 +4979,7 @@ class AttrDelimiter extends Rule {
|
|
|
4949
4979
|
}
|
|
4950
4980
|
|
|
4951
4981
|
const DEFAULT_PATTERN = "[a-z0-9-:]+";
|
|
4952
|
-
const defaults$
|
|
4982
|
+
const defaults$y = {
|
|
4953
4983
|
pattern: DEFAULT_PATTERN,
|
|
4954
4984
|
ignoreForeign: true
|
|
4955
4985
|
};
|
|
@@ -4982,7 +5012,7 @@ function generateDescription(name, pattern) {
|
|
|
4982
5012
|
class AttrPattern extends Rule {
|
|
4983
5013
|
pattern;
|
|
4984
5014
|
constructor(options) {
|
|
4985
|
-
super({ ...defaults$
|
|
5015
|
+
super({ ...defaults$y, ...options });
|
|
4986
5016
|
this.pattern = generateRegexp(this.options.pattern);
|
|
4987
5017
|
}
|
|
4988
5018
|
static schema() {
|
|
@@ -5029,7 +5059,7 @@ class AttrPattern extends Rule {
|
|
|
5029
5059
|
}
|
|
5030
5060
|
}
|
|
5031
5061
|
|
|
5032
|
-
const defaults$
|
|
5062
|
+
const defaults$x = {
|
|
5033
5063
|
style: "auto",
|
|
5034
5064
|
unquoted: false
|
|
5035
5065
|
};
|
|
@@ -5095,7 +5125,7 @@ class AttrQuotes extends Rule {
|
|
|
5095
5125
|
};
|
|
5096
5126
|
}
|
|
5097
5127
|
constructor(options) {
|
|
5098
|
-
super({ ...defaults$
|
|
5128
|
+
super({ ...defaults$x, ...options });
|
|
5099
5129
|
this.style = parseStyle$3(this.options.style);
|
|
5100
5130
|
}
|
|
5101
5131
|
setup() {
|
|
@@ -5177,10 +5207,10 @@ class AttrSpacing extends Rule {
|
|
|
5177
5207
|
|
|
5178
5208
|
function pick(attr) {
|
|
5179
5209
|
const result = {};
|
|
5180
|
-
if (
|
|
5210
|
+
if (attr.enum !== void 0) {
|
|
5181
5211
|
result.enum = attr.enum;
|
|
5182
5212
|
}
|
|
5183
|
-
if (
|
|
5213
|
+
if (attr.boolean !== void 0) {
|
|
5184
5214
|
result.boolean = attr.boolean;
|
|
5185
5215
|
}
|
|
5186
5216
|
return result;
|
|
@@ -5251,13 +5281,13 @@ class AttributeAllowedValues extends Rule {
|
|
|
5251
5281
|
}
|
|
5252
5282
|
}
|
|
5253
5283
|
|
|
5254
|
-
const defaults$
|
|
5284
|
+
const defaults$w = {
|
|
5255
5285
|
style: "omit"
|
|
5256
5286
|
};
|
|
5257
5287
|
class AttributeBooleanStyle extends Rule {
|
|
5258
5288
|
hasInvalidStyle;
|
|
5259
5289
|
constructor(options) {
|
|
5260
|
-
super({ ...defaults$
|
|
5290
|
+
super({ ...defaults$w, ...options });
|
|
5261
5291
|
this.hasInvalidStyle = parseStyle$2(this.options.style);
|
|
5262
5292
|
}
|
|
5263
5293
|
static schema() {
|
|
@@ -5327,13 +5357,13 @@ function reportMessage$1(attr, style) {
|
|
|
5327
5357
|
return "";
|
|
5328
5358
|
}
|
|
5329
5359
|
|
|
5330
|
-
const defaults$
|
|
5360
|
+
const defaults$v = {
|
|
5331
5361
|
style: "omit"
|
|
5332
5362
|
};
|
|
5333
5363
|
class AttributeEmptyStyle extends Rule {
|
|
5334
5364
|
hasInvalidStyle;
|
|
5335
5365
|
constructor(options) {
|
|
5336
|
-
super({ ...defaults$
|
|
5366
|
+
super({ ...defaults$v, ...options });
|
|
5337
5367
|
this.hasInvalidStyle = parseStyle$1(this.options.style);
|
|
5338
5368
|
}
|
|
5339
5369
|
static schema() {
|
|
@@ -5450,7 +5480,7 @@ class AttributeMisuse extends Rule {
|
|
|
5450
5480
|
}
|
|
5451
5481
|
}
|
|
5452
5482
|
|
|
5453
|
-
const defaults$
|
|
5483
|
+
const defaults$u = {
|
|
5454
5484
|
preferred: void 0
|
|
5455
5485
|
};
|
|
5456
5486
|
function isPasswordInput(event) {
|
|
@@ -5467,7 +5497,7 @@ function isGroupingToken(token) {
|
|
|
5467
5497
|
class AutocompletePassword extends Rule {
|
|
5468
5498
|
preferred;
|
|
5469
5499
|
constructor(options) {
|
|
5470
|
-
super({ ...defaults$
|
|
5500
|
+
super({ ...defaults$u, ...options });
|
|
5471
5501
|
this.preferred = options.preferred?.toLowerCase();
|
|
5472
5502
|
}
|
|
5473
5503
|
static schema() {
|
|
@@ -5546,21 +5576,19 @@ class AutocompletePassword extends Rule {
|
|
|
5546
5576
|
});
|
|
5547
5577
|
return;
|
|
5548
5578
|
}
|
|
5549
|
-
if (preferred) {
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
});
|
|
5563
|
-
}
|
|
5579
|
+
if (preferred && value !== preferred) {
|
|
5580
|
+
const context = {
|
|
5581
|
+
kind: "preferred-mismatch",
|
|
5582
|
+
value,
|
|
5583
|
+
preferred
|
|
5584
|
+
};
|
|
5585
|
+
this.report({
|
|
5586
|
+
node: target,
|
|
5587
|
+
message: `<input type="password"> should use autocomplete="${preferred}"`,
|
|
5588
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- location must be present if value is */
|
|
5589
|
+
location,
|
|
5590
|
+
context
|
|
5591
|
+
});
|
|
5564
5592
|
}
|
|
5565
5593
|
});
|
|
5566
5594
|
}
|
|
@@ -5697,7 +5725,7 @@ class BasePatternRule extends Rule {
|
|
|
5697
5725
|
}
|
|
5698
5726
|
}
|
|
5699
5727
|
|
|
5700
|
-
const defaults$
|
|
5728
|
+
const defaults$t = {
|
|
5701
5729
|
pattern: "kebabcase"
|
|
5702
5730
|
};
|
|
5703
5731
|
class ClassPattern extends BasePatternRule {
|
|
@@ -5705,7 +5733,7 @@ class ClassPattern extends BasePatternRule {
|
|
|
5705
5733
|
super({
|
|
5706
5734
|
ruleId: "class-pattern",
|
|
5707
5735
|
attr: "class",
|
|
5708
|
-
options: { ...defaults$
|
|
5736
|
+
options: { ...defaults$t, ...options },
|
|
5709
5737
|
allowedPatterns: patternNames
|
|
5710
5738
|
// allow all patterns
|
|
5711
5739
|
});
|
|
@@ -5855,13 +5883,13 @@ class CloseOrder extends Rule {
|
|
|
5855
5883
|
}
|
|
5856
5884
|
}
|
|
5857
5885
|
|
|
5858
|
-
const defaults$
|
|
5886
|
+
const defaults$s = {
|
|
5859
5887
|
include: null,
|
|
5860
5888
|
exclude: null
|
|
5861
5889
|
};
|
|
5862
5890
|
class Deprecated extends Rule {
|
|
5863
5891
|
constructor(options) {
|
|
5864
|
-
super({ ...defaults$
|
|
5892
|
+
super({ ...defaults$s, ...options });
|
|
5865
5893
|
}
|
|
5866
5894
|
static schema() {
|
|
5867
5895
|
return {
|
|
@@ -5907,7 +5935,7 @@ class Deprecated extends Rule {
|
|
|
5907
5935
|
text.push(context.documentation);
|
|
5908
5936
|
}
|
|
5909
5937
|
const doc = {
|
|
5910
|
-
description: text.map((cur) => cur.
|
|
5938
|
+
description: text.map((cur) => cur.replaceAll("$tagname", context.tagName)).join("\n\n"),
|
|
5911
5939
|
url: "https://html-validate.org/rules/deprecated.html"
|
|
5912
5940
|
};
|
|
5913
5941
|
return doc;
|
|
@@ -5973,7 +6001,7 @@ function quote(value, char = '"') {
|
|
|
5973
6001
|
return `${char}${value}${char}`;
|
|
5974
6002
|
}
|
|
5975
6003
|
|
|
5976
|
-
const defaults$
|
|
6004
|
+
const defaults$r = {
|
|
5977
6005
|
classes: []
|
|
5978
6006
|
};
|
|
5979
6007
|
function isRelevant$6(event) {
|
|
@@ -6027,7 +6055,7 @@ ${listItems.join("\n")}`);
|
|
|
6027
6055
|
class DeprecatedClass extends Rule {
|
|
6028
6056
|
deprecatedMap;
|
|
6029
6057
|
constructor(options) {
|
|
6030
|
-
super({ ...defaults$
|
|
6058
|
+
super({ ...defaults$r, ...options });
|
|
6031
6059
|
const { classes } = this.options;
|
|
6032
6060
|
this.deprecatedMap = new Map(classes.map((entry) => [entry.class, normalizeEntry(entry)]));
|
|
6033
6061
|
}
|
|
@@ -6146,12 +6174,12 @@ let NoStyleTag$1 = class NoStyleTag extends Rule {
|
|
|
6146
6174
|
}
|
|
6147
6175
|
};
|
|
6148
6176
|
|
|
6149
|
-
const defaults$
|
|
6177
|
+
const defaults$q = {
|
|
6150
6178
|
style: "uppercase"
|
|
6151
6179
|
};
|
|
6152
6180
|
class DoctypeStyle extends Rule {
|
|
6153
6181
|
constructor(options) {
|
|
6154
|
-
super({ ...defaults$
|
|
6182
|
+
super({ ...defaults$q, ...options });
|
|
6155
6183
|
}
|
|
6156
6184
|
static schema() {
|
|
6157
6185
|
return {
|
|
@@ -6179,13 +6207,13 @@ class DoctypeStyle extends Rule {
|
|
|
6179
6207
|
}
|
|
6180
6208
|
}
|
|
6181
6209
|
|
|
6182
|
-
const defaults$
|
|
6210
|
+
const defaults$p = {
|
|
6183
6211
|
style: "lowercase"
|
|
6184
6212
|
};
|
|
6185
6213
|
class ElementCase extends Rule {
|
|
6186
6214
|
style;
|
|
6187
6215
|
constructor(options) {
|
|
6188
|
-
super({ ...defaults$
|
|
6216
|
+
super({ ...defaults$p, ...options });
|
|
6189
6217
|
this.style = new CaseStyle(this.options.style, "element-case");
|
|
6190
6218
|
}
|
|
6191
6219
|
static schema() {
|
|
@@ -6226,7 +6254,7 @@ class ElementCase extends Rule {
|
|
|
6226
6254
|
});
|
|
6227
6255
|
}
|
|
6228
6256
|
validateCase(target, targetLocation) {
|
|
6229
|
-
const letters = target.tagName.
|
|
6257
|
+
const letters = target.tagName.replaceAll(/[^a-z]+/gi, "");
|
|
6230
6258
|
if (!this.style.match(letters)) {
|
|
6231
6259
|
const location = sliceLocation(targetLocation, 1);
|
|
6232
6260
|
this.report(target, `Element "${target.tagName}" should be ${this.style.name}`, location);
|
|
@@ -6245,7 +6273,7 @@ class ElementCase extends Rule {
|
|
|
6245
6273
|
}
|
|
6246
6274
|
}
|
|
6247
6275
|
|
|
6248
|
-
const defaults$
|
|
6276
|
+
const defaults$o = {
|
|
6249
6277
|
pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
|
|
6250
6278
|
whitelist: [],
|
|
6251
6279
|
blacklist: []
|
|
@@ -6253,7 +6281,7 @@ const defaults$n = {
|
|
|
6253
6281
|
class ElementName extends Rule {
|
|
6254
6282
|
pattern;
|
|
6255
6283
|
constructor(options) {
|
|
6256
|
-
super({ ...defaults$
|
|
6284
|
+
super({ ...defaults$o, ...options });
|
|
6257
6285
|
this.pattern = new RegExp(this.options.pattern);
|
|
6258
6286
|
}
|
|
6259
6287
|
static schema() {
|
|
@@ -6290,7 +6318,7 @@ class ElementName extends Rule {
|
|
|
6290
6318
|
...context.blacklist.map((cur) => `- ${cur}`)
|
|
6291
6319
|
];
|
|
6292
6320
|
}
|
|
6293
|
-
if (context.pattern !== defaults$
|
|
6321
|
+
if (context.pattern !== defaults$o.pattern) {
|
|
6294
6322
|
return [
|
|
6295
6323
|
`<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
|
|
6296
6324
|
"",
|
|
@@ -6807,7 +6835,7 @@ class EmptyTitle extends Rule {
|
|
|
6807
6835
|
}
|
|
6808
6836
|
}
|
|
6809
6837
|
|
|
6810
|
-
const defaults$
|
|
6838
|
+
const defaults$n = {
|
|
6811
6839
|
allowArrayBrackets: true,
|
|
6812
6840
|
allowCheckboxDefault: true,
|
|
6813
6841
|
shared: ["radio", "button", "reset", "submit"]
|
|
@@ -6830,8 +6858,8 @@ function haveName(name) {
|
|
|
6830
6858
|
return typeof name === "string" && name !== "";
|
|
6831
6859
|
}
|
|
6832
6860
|
function allowSharedName(node, shared) {
|
|
6833
|
-
const type = node
|
|
6834
|
-
return
|
|
6861
|
+
const type = getControlType(node);
|
|
6862
|
+
return shared.includes(type);
|
|
6835
6863
|
}
|
|
6836
6864
|
function isInputHidden(element) {
|
|
6837
6865
|
return element.is("input") && element.getAttributeValue("type") === "hidden";
|
|
@@ -6839,6 +6867,13 @@ function isInputHidden(element) {
|
|
|
6839
6867
|
function isInputCheckbox(element) {
|
|
6840
6868
|
return element.is("input") && element.getAttributeValue("type") === "checkbox";
|
|
6841
6869
|
}
|
|
6870
|
+
function getControlType(element) {
|
|
6871
|
+
const type = element.getAttributeValue("type") ?? "";
|
|
6872
|
+
if (element.is("button") && type === "") {
|
|
6873
|
+
return "submit";
|
|
6874
|
+
}
|
|
6875
|
+
return type;
|
|
6876
|
+
}
|
|
6842
6877
|
function isCheckboxWithDefault(control, previous, options) {
|
|
6843
6878
|
const { allowCheckboxDefault } = options;
|
|
6844
6879
|
if (!allowCheckboxDefault) {
|
|
@@ -6867,7 +6902,7 @@ function getDocumentation(context) {
|
|
|
6867
6902
|
}
|
|
6868
6903
|
class FormDupName extends Rule {
|
|
6869
6904
|
constructor(options) {
|
|
6870
|
-
super({ ...defaults$
|
|
6905
|
+
super({ ...defaults$n, ...options });
|
|
6871
6906
|
}
|
|
6872
6907
|
static schema() {
|
|
6873
6908
|
return {
|
|
@@ -6976,7 +7011,7 @@ class FormDupName extends Rule {
|
|
|
6976
7011
|
validateSharedName(control, group, attr, name) {
|
|
6977
7012
|
const uniqueElements = this.getUniqueElements(group);
|
|
6978
7013
|
const sharedElements = this.getSharedElements(group);
|
|
6979
|
-
const type = control
|
|
7014
|
+
const type = getControlType(control);
|
|
6980
7015
|
if (uniqueElements.has(name) || sharedElements.has(name) && sharedElements.get(name) !== type) {
|
|
6981
7016
|
const context = {
|
|
6982
7017
|
name,
|
|
@@ -7026,7 +7061,7 @@ class FormDupName extends Rule {
|
|
|
7026
7061
|
}
|
|
7027
7062
|
}
|
|
7028
7063
|
|
|
7029
|
-
const defaults$
|
|
7064
|
+
const defaults$m = {
|
|
7030
7065
|
allowMultipleH1: false,
|
|
7031
7066
|
minInitialRank: "h1",
|
|
7032
7067
|
sectioningRoots: ["dialog", '[role="dialog"]', '[role="alertdialog"]']
|
|
@@ -7038,7 +7073,7 @@ function isRelevant$5(event) {
|
|
|
7038
7073
|
function extractLevel(node) {
|
|
7039
7074
|
const match = /^[hH](\d)$/.exec(node.tagName);
|
|
7040
7075
|
if (match) {
|
|
7041
|
-
return parseInt(match[1], 10);
|
|
7076
|
+
return Number.parseInt(match[1], 10);
|
|
7042
7077
|
} else {
|
|
7043
7078
|
return null;
|
|
7044
7079
|
}
|
|
@@ -7051,14 +7086,14 @@ function parseMaxInitial(value) {
|
|
|
7051
7086
|
if (!match) {
|
|
7052
7087
|
return 1;
|
|
7053
7088
|
}
|
|
7054
|
-
return parseInt(match[1], 10);
|
|
7089
|
+
return Number.parseInt(match[1], 10);
|
|
7055
7090
|
}
|
|
7056
7091
|
class HeadingLevel extends Rule {
|
|
7057
7092
|
minInitialRank;
|
|
7058
7093
|
sectionRoots;
|
|
7059
7094
|
stack = [];
|
|
7060
7095
|
constructor(options) {
|
|
7061
|
-
super({ ...defaults$
|
|
7096
|
+
super({ ...defaults$m, ...options });
|
|
7062
7097
|
this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
|
|
7063
7098
|
this.sectionRoots = this.options.sectioningRoots.map((it) => new Compound(it));
|
|
7064
7099
|
this.stack.push({
|
|
@@ -7200,10 +7235,10 @@ class HeadingLevel extends Rule {
|
|
|
7200
7235
|
this.stack.pop();
|
|
7201
7236
|
}
|
|
7202
7237
|
getPrevRoot() {
|
|
7203
|
-
return this.stack
|
|
7238
|
+
return this.stack.at(-2);
|
|
7204
7239
|
}
|
|
7205
7240
|
getCurrentRoot() {
|
|
7206
|
-
return this.stack
|
|
7241
|
+
return this.stack.at(-1);
|
|
7207
7242
|
}
|
|
7208
7243
|
isSectioningRoot(node) {
|
|
7209
7244
|
const context = {
|
|
@@ -7297,7 +7332,7 @@ class HiddenFocusable extends Rule {
|
|
|
7297
7332
|
}
|
|
7298
7333
|
}
|
|
7299
7334
|
|
|
7300
|
-
const defaults$
|
|
7335
|
+
const defaults$l = {
|
|
7301
7336
|
pattern: "kebabcase"
|
|
7302
7337
|
};
|
|
7303
7338
|
function exclude$1(set, ...values) {
|
|
@@ -7313,7 +7348,7 @@ class IdPattern extends BasePatternRule {
|
|
|
7313
7348
|
super({
|
|
7314
7349
|
ruleId: "id-pattern",
|
|
7315
7350
|
attr: "id",
|
|
7316
|
-
options: { ...defaults$
|
|
7351
|
+
options: { ...defaults$l, ...options },
|
|
7317
7352
|
allowedPatterns
|
|
7318
7353
|
});
|
|
7319
7354
|
}
|
|
@@ -7635,13 +7670,13 @@ function findLabelByParent(el) {
|
|
|
7635
7670
|
return [];
|
|
7636
7671
|
}
|
|
7637
7672
|
|
|
7638
|
-
const defaults$
|
|
7673
|
+
const defaults$k = {
|
|
7639
7674
|
maxlength: 70
|
|
7640
7675
|
};
|
|
7641
7676
|
class LongTitle extends Rule {
|
|
7642
7677
|
maxlength;
|
|
7643
7678
|
constructor(options) {
|
|
7644
|
-
super({ ...defaults$
|
|
7679
|
+
super({ ...defaults$k, ...options });
|
|
7645
7680
|
this.maxlength = this.options.maxlength;
|
|
7646
7681
|
}
|
|
7647
7682
|
static schema() {
|
|
@@ -7745,12 +7780,12 @@ class MapIdName extends Rule {
|
|
|
7745
7780
|
}
|
|
7746
7781
|
}
|
|
7747
7782
|
|
|
7748
|
-
const defaults$
|
|
7783
|
+
const defaults$j = {
|
|
7749
7784
|
allowLongDelay: false
|
|
7750
7785
|
};
|
|
7751
7786
|
class MetaRefresh extends Rule {
|
|
7752
7787
|
constructor(options) {
|
|
7753
|
-
super({ ...defaults$
|
|
7788
|
+
super({ ...defaults$j, ...options });
|
|
7754
7789
|
}
|
|
7755
7790
|
documentation() {
|
|
7756
7791
|
return {
|
|
@@ -7800,7 +7835,7 @@ function parseContent(text) {
|
|
|
7800
7835
|
const match = /^(\d+)(?:\s*;\s*url=(.*))?/i.exec(text);
|
|
7801
7836
|
if (match) {
|
|
7802
7837
|
return {
|
|
7803
|
-
delay: parseInt(match[1], 10),
|
|
7838
|
+
delay: Number.parseInt(match[1], 10),
|
|
7804
7839
|
url: match[2]
|
|
7805
7840
|
};
|
|
7806
7841
|
} else {
|
|
@@ -7861,7 +7896,7 @@ class MultipleLabeledControls extends Rule {
|
|
|
7861
7896
|
}
|
|
7862
7897
|
}
|
|
7863
7898
|
|
|
7864
|
-
const defaults$
|
|
7899
|
+
const defaults$i = {
|
|
7865
7900
|
pattern: "camelcase"
|
|
7866
7901
|
};
|
|
7867
7902
|
function exclude(set, ...values) {
|
|
@@ -7877,7 +7912,7 @@ class NamePattern extends BasePatternRule {
|
|
|
7877
7912
|
super({
|
|
7878
7913
|
ruleId: "name-pattern",
|
|
7879
7914
|
attr: "name",
|
|
7880
|
-
options: { ...defaults$
|
|
7915
|
+
options: { ...defaults$i, ...options },
|
|
7881
7916
|
allowedPatterns
|
|
7882
7917
|
});
|
|
7883
7918
|
}
|
|
@@ -7968,13 +8003,13 @@ class NoAbstractRole extends Rule {
|
|
|
7968
8003
|
}
|
|
7969
8004
|
}
|
|
7970
8005
|
|
|
7971
|
-
const defaults$
|
|
8006
|
+
const defaults$h = {
|
|
7972
8007
|
include: null,
|
|
7973
8008
|
exclude: null
|
|
7974
8009
|
};
|
|
7975
8010
|
class NoAutoplay extends Rule {
|
|
7976
8011
|
constructor(options) {
|
|
7977
|
-
super({ ...defaults$
|
|
8012
|
+
super({ ...defaults$h, ...options });
|
|
7978
8013
|
}
|
|
7979
8014
|
documentation(context) {
|
|
7980
8015
|
return {
|
|
@@ -8124,13 +8159,12 @@ class NoDupClass extends Rule {
|
|
|
8124
8159
|
}
|
|
8125
8160
|
const classes = new DOMTokenList(event.value, event.valueLocation);
|
|
8126
8161
|
const unique = /* @__PURE__ */ new Set();
|
|
8127
|
-
classes.
|
|
8128
|
-
if (unique.has(
|
|
8129
|
-
|
|
8130
|
-
this.report(event.target, `Class "${cur}" duplicated`, location);
|
|
8162
|
+
for (const { item, location } of classes.iterator()) {
|
|
8163
|
+
if (unique.has(item)) {
|
|
8164
|
+
this.report(event.target, `Class "${item}" duplicated`, location);
|
|
8131
8165
|
}
|
|
8132
|
-
unique.add(
|
|
8133
|
-
}
|
|
8166
|
+
unique.add(item);
|
|
8167
|
+
}
|
|
8134
8168
|
});
|
|
8135
8169
|
}
|
|
8136
8170
|
}
|
|
@@ -8296,14 +8330,14 @@ class NoImplicitInputType extends Rule {
|
|
|
8296
8330
|
}
|
|
8297
8331
|
}
|
|
8298
8332
|
|
|
8299
|
-
const defaults$
|
|
8333
|
+
const defaults$g = {
|
|
8300
8334
|
include: null,
|
|
8301
8335
|
exclude: null,
|
|
8302
8336
|
allowedProperties: ["display"]
|
|
8303
8337
|
};
|
|
8304
8338
|
class NoInlineStyle extends Rule {
|
|
8305
8339
|
constructor(options) {
|
|
8306
|
-
super({ ...defaults$
|
|
8340
|
+
super({ ...defaults$g, ...options });
|
|
8307
8341
|
}
|
|
8308
8342
|
static schema() {
|
|
8309
8343
|
return {
|
|
@@ -8489,7 +8523,7 @@ class NoMultipleMain extends Rule {
|
|
|
8489
8523
|
}
|
|
8490
8524
|
}
|
|
8491
8525
|
|
|
8492
|
-
const defaults$
|
|
8526
|
+
const defaults$f = {
|
|
8493
8527
|
relaxed: false
|
|
8494
8528
|
};
|
|
8495
8529
|
const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
|
|
@@ -8507,7 +8541,7 @@ const replacementTable = {
|
|
|
8507
8541
|
class NoRawCharacters extends Rule {
|
|
8508
8542
|
relaxed;
|
|
8509
8543
|
constructor(options) {
|
|
8510
|
-
super({ ...defaults$
|
|
8544
|
+
super({ ...defaults$f, ...options });
|
|
8511
8545
|
this.relaxed = this.options.relaxed;
|
|
8512
8546
|
}
|
|
8513
8547
|
static schema() {
|
|
@@ -8646,7 +8680,14 @@ class NoRedundantFor extends Rule {
|
|
|
8646
8680
|
}
|
|
8647
8681
|
}
|
|
8648
8682
|
|
|
8683
|
+
const defaults$e = {
|
|
8684
|
+
include: null,
|
|
8685
|
+
exclude: null
|
|
8686
|
+
};
|
|
8649
8687
|
class NoRedundantRole extends Rule {
|
|
8688
|
+
constructor(options) {
|
|
8689
|
+
super({ ...defaults$e, ...options });
|
|
8690
|
+
}
|
|
8650
8691
|
documentation(context) {
|
|
8651
8692
|
const { role, tagName } = context;
|
|
8652
8693
|
return {
|
|
@@ -8654,6 +8695,36 @@ class NoRedundantRole extends Rule {
|
|
|
8654
8695
|
url: "https://html-validate.org/rules/no-redundant-role.html"
|
|
8655
8696
|
};
|
|
8656
8697
|
}
|
|
8698
|
+
static schema() {
|
|
8699
|
+
return {
|
|
8700
|
+
exclude: {
|
|
8701
|
+
anyOf: [
|
|
8702
|
+
{
|
|
8703
|
+
items: {
|
|
8704
|
+
type: "string"
|
|
8705
|
+
},
|
|
8706
|
+
type: "array"
|
|
8707
|
+
},
|
|
8708
|
+
{
|
|
8709
|
+
type: "null"
|
|
8710
|
+
}
|
|
8711
|
+
]
|
|
8712
|
+
},
|
|
8713
|
+
include: {
|
|
8714
|
+
anyOf: [
|
|
8715
|
+
{
|
|
8716
|
+
items: {
|
|
8717
|
+
type: "string"
|
|
8718
|
+
},
|
|
8719
|
+
type: "array"
|
|
8720
|
+
},
|
|
8721
|
+
{
|
|
8722
|
+
type: "null"
|
|
8723
|
+
}
|
|
8724
|
+
]
|
|
8725
|
+
}
|
|
8726
|
+
};
|
|
8727
|
+
}
|
|
8657
8728
|
setup() {
|
|
8658
8729
|
this.on("tag:ready", (event) => {
|
|
8659
8730
|
const { target } = event;
|
|
@@ -8672,6 +8743,9 @@ class NoRedundantRole extends Rule {
|
|
|
8672
8743
|
if (role.value !== implicitRole) {
|
|
8673
8744
|
return;
|
|
8674
8745
|
}
|
|
8746
|
+
if (this.isKeywordIgnored(role.value)) {
|
|
8747
|
+
return;
|
|
8748
|
+
}
|
|
8675
8749
|
const context = {
|
|
8676
8750
|
tagName: target.tagName,
|
|
8677
8751
|
role: role.value
|
|
@@ -8862,10 +8936,10 @@ class NoUnusedDisable extends Rule {
|
|
|
8862
8936
|
setup() {
|
|
8863
8937
|
}
|
|
8864
8938
|
reportUnused(unused, options, location) {
|
|
8865
|
-
const tokens = new DOMTokenList(options.
|
|
8939
|
+
const tokens = new DOMTokenList(options.replaceAll(",", " "), location);
|
|
8866
8940
|
for (const ruleId of unused) {
|
|
8867
8941
|
const index = tokens.indexOf(ruleId);
|
|
8868
|
-
const tokenLocation = index
|
|
8942
|
+
const tokenLocation = index !== -1 ? tokens.location(index) : location;
|
|
8869
8943
|
this.report({
|
|
8870
8944
|
node: null,
|
|
8871
8945
|
message: '"{{ ruleId }}" rule is disabled but no error was reported',
|
|
@@ -9113,7 +9187,7 @@ class PreferTbody extends Rule {
|
|
|
9113
9187
|
continue;
|
|
9114
9188
|
}
|
|
9115
9189
|
const tr = table.querySelectorAll("> tr");
|
|
9116
|
-
if (tr.length
|
|
9190
|
+
if (tr.length > 0) {
|
|
9117
9191
|
this.report(tr[0], "Prefer to wrap <tr> elements in <tbody>");
|
|
9118
9192
|
}
|
|
9119
9193
|
}
|
|
@@ -9183,19 +9257,19 @@ const supportSri = {
|
|
|
9183
9257
|
link: "href",
|
|
9184
9258
|
script: "src"
|
|
9185
9259
|
};
|
|
9186
|
-
const supportedRel = ["stylesheet", "preload", "modulepreload"];
|
|
9187
|
-
const supportedPreload = ["style", "script"];
|
|
9260
|
+
const supportedRel = /* @__PURE__ */ new Set(["stylesheet", "preload", "modulepreload"]);
|
|
9261
|
+
const supportedPreload = /* @__PURE__ */ new Set(["style", "script"]);
|
|
9188
9262
|
function linkSupportsSri(node) {
|
|
9189
9263
|
const rel = node.getAttribute("rel");
|
|
9190
9264
|
if (typeof rel?.value !== "string") {
|
|
9191
9265
|
return false;
|
|
9192
9266
|
}
|
|
9193
|
-
if (!supportedRel.
|
|
9267
|
+
if (!supportedRel.has(rel.value)) {
|
|
9194
9268
|
return false;
|
|
9195
9269
|
}
|
|
9196
9270
|
if (rel.value === "preload") {
|
|
9197
9271
|
const as = node.getAttribute("as");
|
|
9198
|
-
return typeof as?.value === "string" && supportedPreload.
|
|
9272
|
+
return typeof as?.value === "string" && supportedPreload.has(as.value);
|
|
9199
9273
|
}
|
|
9200
9274
|
return true;
|
|
9201
9275
|
}
|
|
@@ -9312,13 +9386,13 @@ class ScriptElement extends Rule {
|
|
|
9312
9386
|
}
|
|
9313
9387
|
}
|
|
9314
9388
|
|
|
9315
|
-
const javascript = [
|
|
9389
|
+
const javascript = /* @__PURE__ */ new Set([
|
|
9316
9390
|
"",
|
|
9317
9391
|
"application/ecmascript",
|
|
9318
9392
|
"application/javascript",
|
|
9319
9393
|
"text/ecmascript",
|
|
9320
9394
|
"text/javascript"
|
|
9321
|
-
];
|
|
9395
|
+
]);
|
|
9322
9396
|
class ScriptType extends Rule {
|
|
9323
9397
|
documentation() {
|
|
9324
9398
|
return {
|
|
@@ -9349,7 +9423,7 @@ class ScriptType extends Rule {
|
|
|
9349
9423
|
}
|
|
9350
9424
|
isJavascript(mime) {
|
|
9351
9425
|
const type = mime.replace(/;.*/, "");
|
|
9352
|
-
return javascript.
|
|
9426
|
+
return javascript.has(type);
|
|
9353
9427
|
}
|
|
9354
9428
|
}
|
|
9355
9429
|
|
|
@@ -9925,7 +9999,7 @@ class UnknownCharReference extends Rule {
|
|
|
9925
9999
|
}
|
|
9926
10000
|
|
|
9927
10001
|
const expectedOrder = ["section", "hint", "contact", "field1", "field2", "webauthn"];
|
|
9928
|
-
const fieldNames1 = [
|
|
10002
|
+
const fieldNames1 = /* @__PURE__ */ new Set([
|
|
9929
10003
|
"name",
|
|
9930
10004
|
"honorific-prefix",
|
|
9931
10005
|
"given-name",
|
|
@@ -9970,8 +10044,8 @@ const fieldNames1 = [
|
|
|
9970
10044
|
"sex",
|
|
9971
10045
|
"url",
|
|
9972
10046
|
"photo"
|
|
9973
|
-
];
|
|
9974
|
-
const fieldNames2 = [
|
|
10047
|
+
]);
|
|
10048
|
+
const fieldNames2 = /* @__PURE__ */ new Set([
|
|
9975
10049
|
"tel",
|
|
9976
10050
|
"tel-country-code",
|
|
9977
10051
|
"tel-national",
|
|
@@ -9982,7 +10056,7 @@ const fieldNames2 = [
|
|
|
9982
10056
|
"tel-extension",
|
|
9983
10057
|
"email",
|
|
9984
10058
|
"impp"
|
|
9985
|
-
];
|
|
10059
|
+
]);
|
|
9986
10060
|
const fieldNameGroup = {
|
|
9987
10061
|
name: "text",
|
|
9988
10062
|
"honorific-prefix": "text",
|
|
@@ -10047,14 +10121,14 @@ function matchHint(token) {
|
|
|
10047
10121
|
return token === "shipping" || token === "billing";
|
|
10048
10122
|
}
|
|
10049
10123
|
function matchFieldNames1(token) {
|
|
10050
|
-
return fieldNames1.
|
|
10124
|
+
return fieldNames1.has(token);
|
|
10051
10125
|
}
|
|
10052
10126
|
function matchContact(token) {
|
|
10053
10127
|
const haystack = ["home", "work", "mobile", "fax", "pager"];
|
|
10054
10128
|
return haystack.includes(token);
|
|
10055
10129
|
}
|
|
10056
10130
|
function matchFieldNames2(token) {
|
|
10057
|
-
return fieldNames2.
|
|
10131
|
+
return fieldNames2.has(token);
|
|
10058
10132
|
}
|
|
10059
10133
|
function matchWebauthn(token) {
|
|
10060
10134
|
return token === "webauthn";
|
|
@@ -10725,11 +10799,13 @@ class H32 extends Rule {
|
|
|
10725
10799
|
setup() {
|
|
10726
10800
|
const formTags = this.getTagsWithProperty("form");
|
|
10727
10801
|
const formSelector = formTags.join(",");
|
|
10802
|
+
const submitButtonTags = this.getTagsWithProperty("submitButton");
|
|
10803
|
+
const submitButtonSelector = submitButtonTags.join(",");
|
|
10728
10804
|
this.on("dom:ready", (event) => {
|
|
10729
10805
|
const { document } = event;
|
|
10730
10806
|
const forms = document.querySelectorAll(formSelector);
|
|
10731
10807
|
for (const form of forms) {
|
|
10732
|
-
if (hasNestedSubmit(form)) {
|
|
10808
|
+
if (hasNestedSubmit(form, submitButtonSelector)) {
|
|
10733
10809
|
continue;
|
|
10734
10810
|
}
|
|
10735
10811
|
if (hasAssociatedSubmit(document, form)) {
|
|
@@ -10741,15 +10817,15 @@ class H32 extends Rule {
|
|
|
10741
10817
|
}
|
|
10742
10818
|
}
|
|
10743
10819
|
function isSubmit(node) {
|
|
10744
|
-
const
|
|
10745
|
-
return
|
|
10820
|
+
const meta = node.meta;
|
|
10821
|
+
return Boolean(meta?.submitButton);
|
|
10746
10822
|
}
|
|
10747
10823
|
function isAssociated(id, node) {
|
|
10748
10824
|
const form = node.getAttribute("form");
|
|
10749
10825
|
return Boolean(form?.valueMatches(id, true));
|
|
10750
10826
|
}
|
|
10751
|
-
function hasNestedSubmit(form) {
|
|
10752
|
-
const matches = form.querySelectorAll(
|
|
10827
|
+
function hasNestedSubmit(form, submitButtonSelector) {
|
|
10828
|
+
const matches = form.querySelectorAll(submitButtonSelector).filter(isSubmit).filter((node) => !node.hasAttribute("form"));
|
|
10753
10829
|
return matches.length > 0;
|
|
10754
10830
|
}
|
|
10755
10831
|
function hasAssociatedSubmit(document, form) {
|
|
@@ -10895,7 +10971,7 @@ function isSimpleTable(table) {
|
|
|
10895
10971
|
}
|
|
10896
10972
|
const shape = getShape(cells);
|
|
10897
10973
|
const headersPerRow = cells.map((row) => row.reduce((sum, cell) => sum + cell, 0));
|
|
10898
|
-
const headersPerColumn = Array(shape.cols).fill(0).map((_, index) => {
|
|
10974
|
+
const headersPerColumn = new Array(shape.cols).fill(0).map((_, index) => {
|
|
10899
10975
|
return cells.reduce((sum, it) => sum + it[index], 0);
|
|
10900
10976
|
});
|
|
10901
10977
|
const [firstRow, ...otherRows] = headersPerRow;
|
|
@@ -11298,11 +11374,11 @@ function dumpTree(root) {
|
|
|
11298
11374
|
} else {
|
|
11299
11375
|
lines.push("(root)");
|
|
11300
11376
|
}
|
|
11301
|
-
node.childElements.
|
|
11377
|
+
for (const [index, child] of node.childElements.entries()) {
|
|
11302
11378
|
const s = lastSibling ? " " : "\u2502";
|
|
11303
11379
|
const i = level > 0 ? `${indent}${s} ` : "";
|
|
11304
11380
|
writeNode(child, level + 1, i, index);
|
|
11305
|
-
}
|
|
11381
|
+
}
|
|
11306
11382
|
}
|
|
11307
11383
|
writeNode(root, 0, "", 0);
|
|
11308
11384
|
return lines;
|
|
@@ -12417,7 +12493,7 @@ class EventHandler {
|
|
|
12417
12493
|
}
|
|
12418
12494
|
|
|
12419
12495
|
const name = "html-validate";
|
|
12420
|
-
const version = "10.
|
|
12496
|
+
const version = "10.11.0";
|
|
12421
12497
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12422
12498
|
|
|
12423
12499
|
function freeze(src) {
|
|
@@ -12433,7 +12509,13 @@ function isThenableArray(value) {
|
|
|
12433
12509
|
return isThenable(value[0]);
|
|
12434
12510
|
}
|
|
12435
12511
|
class Reporter {
|
|
12512
|
+
/**
|
|
12513
|
+
* @internal
|
|
12514
|
+
*/
|
|
12436
12515
|
result;
|
|
12516
|
+
/**
|
|
12517
|
+
* @internal
|
|
12518
|
+
*/
|
|
12437
12519
|
constructor() {
|
|
12438
12520
|
this.result = {};
|
|
12439
12521
|
}
|
|
@@ -12446,16 +12528,16 @@ class Reporter {
|
|
|
12446
12528
|
}
|
|
12447
12529
|
const valid = reports.every((report) => report.valid);
|
|
12448
12530
|
const merged = {};
|
|
12449
|
-
|
|
12450
|
-
report.results
|
|
12531
|
+
for (const report of reports) {
|
|
12532
|
+
for (const result of report.results) {
|
|
12451
12533
|
const key = result.filePath;
|
|
12452
12534
|
if (key in merged) {
|
|
12453
12535
|
merged[key].messages = [...merged[key].messages, ...result.messages];
|
|
12454
12536
|
} else {
|
|
12455
12537
|
merged[key] = { ...result };
|
|
12456
12538
|
}
|
|
12457
|
-
}
|
|
12458
|
-
}
|
|
12539
|
+
}
|
|
12540
|
+
}
|
|
12459
12541
|
const results = Object.values(merged).map((result) => {
|
|
12460
12542
|
result.errorCount = countErrors(result.messages);
|
|
12461
12543
|
result.warningCount = countWarnings(result.messages);
|
|
@@ -12468,8 +12550,11 @@ class Reporter {
|
|
|
12468
12550
|
warningCount: sumWarnings(results)
|
|
12469
12551
|
};
|
|
12470
12552
|
}
|
|
12471
|
-
|
|
12472
|
-
|
|
12553
|
+
/**
|
|
12554
|
+
* @internal
|
|
12555
|
+
*/
|
|
12556
|
+
add(options) {
|
|
12557
|
+
const { rule, message, severity, node, location, context } = options;
|
|
12473
12558
|
if (!(location.filename in this.result)) {
|
|
12474
12559
|
this.result[location.filename] = [];
|
|
12475
12560
|
}
|
|
@@ -12494,17 +12579,23 @@ class Reporter {
|
|
|
12494
12579
|
}
|
|
12495
12580
|
this.result[location.filename].push(entry);
|
|
12496
12581
|
}
|
|
12582
|
+
/**
|
|
12583
|
+
* @internal
|
|
12584
|
+
*/
|
|
12497
12585
|
addManual(filename, message) {
|
|
12498
12586
|
if (!(filename in this.result)) {
|
|
12499
12587
|
this.result[filename] = [];
|
|
12500
12588
|
}
|
|
12501
12589
|
this.result[filename].push(message);
|
|
12502
12590
|
}
|
|
12591
|
+
/**
|
|
12592
|
+
* @internal
|
|
12593
|
+
*/
|
|
12503
12594
|
save(sources) {
|
|
12504
12595
|
const report = {
|
|
12505
12596
|
valid: this.isValid(),
|
|
12506
12597
|
results: Object.keys(this.result).map((filePath) => {
|
|
12507
|
-
const messages = Array.from(this.result[filePath], freeze).
|
|
12598
|
+
const messages = Array.from(this.result[filePath], freeze).toSorted(messageSort);
|
|
12508
12599
|
const source = (sources ?? []).find((source2) => filePath === source2.filename);
|
|
12509
12600
|
return {
|
|
12510
12601
|
filePath,
|
|
@@ -12521,6 +12612,9 @@ class Reporter {
|
|
|
12521
12612
|
report.warningCount = sumWarnings(report.results);
|
|
12522
12613
|
return report;
|
|
12523
12614
|
}
|
|
12615
|
+
/**
|
|
12616
|
+
* @internal
|
|
12617
|
+
*/
|
|
12524
12618
|
isValid() {
|
|
12525
12619
|
const numErrors = Object.values(this.result).reduce((sum, messages) => {
|
|
12526
12620
|
return sum + countErrors(messages);
|
|
@@ -12583,6 +12677,7 @@ class ParserError extends Error {
|
|
|
12583
12677
|
location;
|
|
12584
12678
|
constructor(location, message) {
|
|
12585
12679
|
super(message);
|
|
12680
|
+
this.name = "ParserError";
|
|
12586
12681
|
this.location = location;
|
|
12587
12682
|
}
|
|
12588
12683
|
}
|
|
@@ -12739,7 +12834,7 @@ class Parser {
|
|
|
12739
12834
|
const tokens = Array.from(
|
|
12740
12835
|
this.consumeUntil(tokenStream, TokenType.TAG_CLOSE, startToken.location)
|
|
12741
12836
|
);
|
|
12742
|
-
const endToken = tokens.
|
|
12837
|
+
const endToken = tokens.at(-1);
|
|
12743
12838
|
const closeOptional = this.closeOptional(startToken);
|
|
12744
12839
|
const parent = closeOptional ? this.dom.getActive().parent : this.dom.getActive();
|
|
12745
12840
|
const node = HtmlElement.fromTokens(
|
|
@@ -12857,7 +12952,7 @@ class Parser {
|
|
|
12857
12952
|
const endTokens = Array.from(
|
|
12858
12953
|
this.consumeUntil(tokenStream, TokenType.TAG_CLOSE, last.location)
|
|
12859
12954
|
);
|
|
12860
|
-
endToken = endTokens.
|
|
12955
|
+
endToken = endTokens.at(-1);
|
|
12861
12956
|
const selfClosed = endToken.data[0] === "/>";
|
|
12862
12957
|
if (tagClosed) {
|
|
12863
12958
|
startToken = last;
|
|
@@ -13139,7 +13234,7 @@ class Parser {
|
|
|
13139
13234
|
this.event.once("*", cb);
|
|
13140
13235
|
}
|
|
13141
13236
|
trigger(event, data) {
|
|
13142
|
-
if (
|
|
13237
|
+
if (data.location === void 0) {
|
|
13143
13238
|
throw new Error("Triggered event must contain location");
|
|
13144
13239
|
}
|
|
13145
13240
|
this.event.trigger(event, data);
|
|
@@ -13267,7 +13362,9 @@ class Engine {
|
|
|
13267
13362
|
}
|
|
13268
13363
|
lines.push({ event, data });
|
|
13269
13364
|
});
|
|
13270
|
-
|
|
13365
|
+
for (const src of source) {
|
|
13366
|
+
parser.parseHtml(src);
|
|
13367
|
+
}
|
|
13271
13368
|
return lines;
|
|
13272
13369
|
}
|
|
13273
13370
|
dumpTokens(source) {
|
|
@@ -13732,7 +13829,7 @@ const entities = {
|
|
|
13732
13829
|
"&": "&"
|
|
13733
13830
|
};
|
|
13734
13831
|
function xmlescape(src) {
|
|
13735
|
-
return src.toString().
|
|
13832
|
+
return src.toString().replaceAll(/[><'"&]/g, (match) => {
|
|
13736
13833
|
return entities[match];
|
|
13737
13834
|
});
|
|
13738
13835
|
}
|
|
@@ -13752,11 +13849,11 @@ function checkstyleFormatter(results) {
|
|
|
13752
13849
|
`;
|
|
13753
13850
|
output += `<checkstyle version="4.3">
|
|
13754
13851
|
`;
|
|
13755
|
-
|
|
13852
|
+
for (const result of results) {
|
|
13756
13853
|
const messages = result.messages;
|
|
13757
13854
|
output += ` <file name="${xmlescape(result.filePath)}">
|
|
13758
13855
|
`;
|
|
13759
|
-
|
|
13856
|
+
for (const message of messages) {
|
|
13760
13857
|
const ruleId = xmlescape(`htmlvalidate.rules.${message.ruleId}`);
|
|
13761
13858
|
output += " ";
|
|
13762
13859
|
output += [
|
|
@@ -13767,9 +13864,9 @@ function checkstyleFormatter(results) {
|
|
|
13767
13864
|
`source="${ruleId}" />`
|
|
13768
13865
|
].join(" ");
|
|
13769
13866
|
output += "\n";
|
|
13770
|
-
}
|
|
13867
|
+
}
|
|
13771
13868
|
output += " </file>\n";
|
|
13772
|
-
}
|
|
13869
|
+
}
|
|
13773
13870
|
output += "</checkstyle>\n";
|
|
13774
13871
|
return output;
|
|
13775
13872
|
}
|
|
@@ -13839,11 +13936,11 @@ function codeFrameColumns(rawLines, loc) {
|
|
|
13839
13936
|
if (hasMarker) {
|
|
13840
13937
|
let markerLine = "";
|
|
13841
13938
|
if (Array.isArray(hasMarker)) {
|
|
13842
|
-
const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).
|
|
13939
|
+
const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replaceAll(/[^\t]/g, " ");
|
|
13843
13940
|
const numberOfMarkers = hasMarker[1] || 1;
|
|
13844
13941
|
markerLine = [
|
|
13845
13942
|
"\n ",
|
|
13846
|
-
gutter.
|
|
13943
|
+
gutter.replaceAll(/\d/g, " "),
|
|
13847
13944
|
" ",
|
|
13848
13945
|
markerSpacing,
|
|
13849
13946
|
"^".repeat(numberOfMarkers)
|
|
@@ -13981,10 +14078,10 @@ function stylish(results) {
|
|
|
13981
14078
|
function textFormatter(results) {
|
|
13982
14079
|
let output = "";
|
|
13983
14080
|
let total = 0;
|
|
13984
|
-
|
|
14081
|
+
for (const result of results) {
|
|
13985
14082
|
const messages = result.messages;
|
|
13986
14083
|
if (messages.length === 0) {
|
|
13987
|
-
|
|
14084
|
+
continue;
|
|
13988
14085
|
}
|
|
13989
14086
|
total += messages.length;
|
|
13990
14087
|
output += messages.map((message) => {
|
|
@@ -14000,7 +14097,7 @@ function textFormatter(results) {
|
|
|
14000
14097
|
return `${location}: ${messageType} [${message.ruleId}] ${message.message}
|
|
14001
14098
|
`;
|
|
14002
14099
|
}).join("");
|
|
14003
|
-
}
|
|
14100
|
+
}
|
|
14004
14101
|
return total > 0 ? output : "";
|
|
14005
14102
|
}
|
|
14006
14103
|
const formatter = textFormatter;
|
|
@@ -14832,7 +14929,7 @@ var ignoreExports = /*@__PURE__*/ requireIgnore();
|
|
|
14832
14929
|
var ignore = /*@__PURE__*/getDefaultExportFromCjs(ignoreExports);
|
|
14833
14930
|
|
|
14834
14931
|
const engines = {
|
|
14835
|
-
node: "^20.19.0 || >= 22.
|
|
14932
|
+
node: "^20.19.0 || >= 22.16.0"
|
|
14836
14933
|
};
|
|
14837
14934
|
|
|
14838
14935
|
var workerPath = "./jest-worker.js";
|