html-validate 11.5.2 → 11.5.4
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 +11 -14
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/core-browser.js +4 -4
- package/dist/cjs/core-browser.js.map +1 -1
- package/dist/cjs/core-nodejs.js +17 -25
- package/dist/cjs/core-nodejs.js.map +1 -1
- package/dist/cjs/core.js +454 -448
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/elements.js +11 -22
- package/dist/cjs/elements.js.map +1 -1
- package/dist/cjs/html-validate.js +1 -1
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/jest-matchers.js +49 -55
- package/dist/cjs/jest-matchers.js.map +1 -1
- package/dist/cjs/jest-utils.js +1 -2
- package/dist/cjs/jest-utils.js.map +1 -1
- package/dist/cjs/jest-worker.js.map +1 -1
- package/dist/cjs/test-utils.js +1 -2
- package/dist/cjs/test-utils.js.map +2 -2
- package/dist/cjs/tsdoc-metadata.json +1 -1
- package/dist/cjs/utils/parse-image-candidate-string.js +2 -2
- package/dist/cjs/utils/parse-image-candidate-string.js.map +1 -1
- package/dist/cjs/vitest-matchers.js +46 -50
- package/dist/cjs/vitest-matchers.js.map +1 -1
- package/dist/cjs/vitest-utils.js +1 -2
- package/dist/cjs/vitest-utils.js.map +1 -1
- package/dist/cjs/vitest-worker.js.map +1 -1
- package/dist/esm/cli.js +11 -14
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/core-browser.js +4 -4
- package/dist/esm/core-browser.js.map +1 -1
- package/dist/esm/core-nodejs.js +17 -25
- package/dist/esm/core-nodejs.js.map +1 -1
- package/dist/esm/core.js +454 -448
- package/dist/esm/core.js.map +1 -1
- package/dist/esm/elements.js +11 -22
- package/dist/esm/elements.js.map +1 -1
- package/dist/esm/html-validate.js +1 -1
- package/dist/esm/html-validate.js.map +1 -1
- package/dist/esm/jest-matchers.js +49 -55
- package/dist/esm/jest-matchers.js.map +1 -1
- package/dist/esm/jest-utils.js +1 -2
- package/dist/esm/jest-utils.js.map +1 -1
- package/dist/esm/jest-worker.js.map +1 -1
- package/dist/esm/test-utils.js +1 -2
- package/dist/esm/test-utils.js.map +2 -2
- package/dist/esm/utils/parse-image-candidate-string.js +2 -2
- package/dist/esm/utils/parse-image-candidate-string.js.map +1 -1
- package/dist/esm/vitest-matchers.js +46 -50
- package/dist/esm/vitest-matchers.js.map +1 -1
- package/dist/esm/vitest-utils.js +1 -2
- package/dist/esm/vitest-utils.js.map +1 -1
- package/dist/esm/vitest-worker.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types/browser.d.ts +22 -11
- package/dist/types/index.d.ts +24 -13
- package/package.json +1 -1
package/dist/esm/core.js
CHANGED
|
@@ -388,11 +388,11 @@ var deepmerge = /*@__PURE__*/getDefaultExportFromCjs(cjsExports);
|
|
|
388
388
|
function stringify(value) {
|
|
389
389
|
if (typeof value === "string") {
|
|
390
390
|
return value;
|
|
391
|
-
} else {
|
|
392
|
-
return JSON.stringify(value);
|
|
393
391
|
}
|
|
392
|
+
return JSON.stringify(value);
|
|
394
393
|
}
|
|
395
394
|
class WrappedError extends Error {
|
|
395
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
396
396
|
constructor(message) {
|
|
397
397
|
super(stringify(message));
|
|
398
398
|
this.name = "WrappedError";
|
|
@@ -402,12 +402,12 @@ class WrappedError extends Error {
|
|
|
402
402
|
function ensureError(value) {
|
|
403
403
|
if (value instanceof Error) {
|
|
404
404
|
return value;
|
|
405
|
-
} else {
|
|
406
|
-
return new WrappedError(value);
|
|
407
405
|
}
|
|
406
|
+
return new WrappedError(value);
|
|
408
407
|
}
|
|
409
408
|
|
|
410
409
|
class NestedError extends Error {
|
|
410
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
411
411
|
constructor(message, nested) {
|
|
412
412
|
super(message);
|
|
413
413
|
this.name = "NestedError";
|
|
@@ -420,6 +420,7 @@ Caused by: ${nested.stack}`;
|
|
|
420
420
|
}
|
|
421
421
|
|
|
422
422
|
class UserError extends NestedError {
|
|
423
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
423
424
|
constructor(message, nested) {
|
|
424
425
|
super(message, nested);
|
|
425
426
|
this.name = "UserError";
|
|
@@ -1120,11 +1121,11 @@ const CONTROL_ESCAPES = /* @__PURE__ */ new Map([
|
|
|
1120
1121
|
["\r", "r"]
|
|
1121
1122
|
]);
|
|
1122
1123
|
const OTHER_PUNCTUATORS = /^[!"#%&',:;<=>@`~-]$/;
|
|
1123
|
-
const WHITE_SPACE = /^[\t\v\f\
|
|
1124
|
+
const WHITE_SPACE = /^[\t\v\f\u{FEFF}\p{Zs}]$/u;
|
|
1124
1125
|
const LINE_TERMINATOR = /^[\n\r\u2028\u2029]$/;
|
|
1125
1126
|
const SURROGATE = /^[\uD800-\uDFFF]$/;
|
|
1126
1127
|
function isDecimalDigitOrASCIILetter(ch) {
|
|
1127
|
-
return /^[\dA-
|
|
1128
|
+
return /^[\dA-Z]$/i.test(ch);
|
|
1128
1129
|
}
|
|
1129
1130
|
function needEscape(ch) {
|
|
1130
1131
|
return OTHER_PUNCTUATORS.test(ch) || WHITE_SPACE.test(ch) || LINE_TERMINATOR.test(ch) || SURROGATE.test(ch);
|
|
@@ -1192,9 +1193,8 @@ function migrateSingleAttribute(src, key) {
|
|
|
1192
1193
|
}
|
|
1193
1194
|
}
|
|
1194
1195
|
return stripUndefined(result);
|
|
1195
|
-
} else {
|
|
1196
|
-
return stripUndefined({ ...result, ...attr });
|
|
1197
1196
|
}
|
|
1197
|
+
return stripUndefined({ ...result, ...attr });
|
|
1198
1198
|
}
|
|
1199
1199
|
function isPatternAttribute$1(key) {
|
|
1200
1200
|
return key.includes("*");
|
|
@@ -1208,7 +1208,7 @@ function migrateAttributes(src) {
|
|
|
1208
1208
|
...Object.keys(src.attributes ?? {}),
|
|
1209
1209
|
...src.requiredAttributes ?? [],
|
|
1210
1210
|
...src.deprecatedAttributes ?? []
|
|
1211
|
-
].filter((key) => !isPatternAttribute$1(key)).toSorted();
|
|
1211
|
+
].filter((key) => !isPatternAttribute$1(key)).toSorted((a, b) => a.localeCompare(b));
|
|
1212
1212
|
const entries = keys.map((key) => {
|
|
1213
1213
|
return [key, migrateSingleAttribute(src, key)];
|
|
1214
1214
|
});
|
|
@@ -1288,11 +1288,10 @@ const dynamicKeys = [
|
|
|
1288
1288
|
];
|
|
1289
1289
|
const schemaCache = /* @__PURE__ */ new Map();
|
|
1290
1290
|
function clone(value) {
|
|
1291
|
-
if (globalThis
|
|
1292
|
-
return
|
|
1293
|
-
} else {
|
|
1294
|
-
return JSON.parse(JSON.stringify(value));
|
|
1291
|
+
if (Object.hasOwn(globalThis, "structuredClone")) {
|
|
1292
|
+
return structuredClone(value);
|
|
1295
1293
|
}
|
|
1294
|
+
return JSON.parse(JSON.stringify(value));
|
|
1296
1295
|
}
|
|
1297
1296
|
class MetaTable {
|
|
1298
1297
|
elements;
|
|
@@ -1382,9 +1381,8 @@ class MetaTable {
|
|
|
1382
1381
|
const meta = this.elements[tagName.toLowerCase()] ?? this.elements["*"];
|
|
1383
1382
|
if (meta) {
|
|
1384
1383
|
return { ...meta };
|
|
1385
|
-
} else {
|
|
1386
|
-
return null;
|
|
1387
1384
|
}
|
|
1385
|
+
return null;
|
|
1388
1386
|
}
|
|
1389
1387
|
/**
|
|
1390
1388
|
* Find all tags which has enabled given property.
|
|
@@ -1426,16 +1424,15 @@ class MetaTable {
|
|
|
1426
1424
|
const cached = schemaCache.get(hash);
|
|
1427
1425
|
if (cached) {
|
|
1428
1426
|
return cached;
|
|
1429
|
-
} else {
|
|
1430
|
-
const ajv = new Ajv({ strict: true, strictTuples: true, strictTypes: true });
|
|
1431
|
-
ajv.addMetaSchema(ajvSchemaDraft);
|
|
1432
|
-
ajv.addKeyword(ajvFunctionKeyword);
|
|
1433
|
-
ajv.addKeyword(ajvRegexpKeyword);
|
|
1434
|
-
ajv.addKeyword({ keyword: "copyable" });
|
|
1435
|
-
const validate = ajv.compile(this.schema);
|
|
1436
|
-
schemaCache.set(hash, validate);
|
|
1437
|
-
return validate;
|
|
1438
1427
|
}
|
|
1428
|
+
const ajv = new Ajv({ strict: true, strictTuples: true, strictTypes: true });
|
|
1429
|
+
ajv.addMetaSchema(ajvSchemaDraft);
|
|
1430
|
+
ajv.addKeyword(ajvFunctionKeyword);
|
|
1431
|
+
ajv.addKeyword(ajvRegexpKeyword);
|
|
1432
|
+
ajv.addKeyword({ keyword: "copyable" });
|
|
1433
|
+
const validate = ajv.compile(this.schema);
|
|
1434
|
+
schemaCache.set(hash, validate);
|
|
1435
|
+
return validate;
|
|
1439
1436
|
}
|
|
1440
1437
|
/**
|
|
1441
1438
|
* @public
|
|
@@ -1517,14 +1514,13 @@ function expandProperties(node, entry) {
|
|
|
1517
1514
|
}
|
|
1518
1515
|
}
|
|
1519
1516
|
function compileRegexString(value) {
|
|
1520
|
-
const match = /^\/(.*
|
|
1517
|
+
const match = /^\/(.*)\/(i?)$/.exec(value);
|
|
1521
1518
|
if (match) {
|
|
1522
1519
|
const [, expr, flags] = match;
|
|
1523
1520
|
if (expr.startsWith("^") || expr.endsWith("$")) {
|
|
1524
1521
|
return new RegExp(expr, flags);
|
|
1525
|
-
} else {
|
|
1526
|
-
return new RegExp(`^${expr}$`, flags);
|
|
1527
1522
|
}
|
|
1523
|
+
return new RegExp(`^${expr}$`, flags);
|
|
1528
1524
|
}
|
|
1529
1525
|
return null;
|
|
1530
1526
|
}
|
|
@@ -1585,7 +1581,7 @@ class Attribute {
|
|
|
1585
1581
|
* @param keyLocation - Source location of attribute name.
|
|
1586
1582
|
* @param valueLocation - Source location of attribute value.
|
|
1587
1583
|
* @param originalAttribute - If this attribute was dynamically added via a
|
|
1588
|
-
* transformation (e.g.
|
|
1584
|
+
* transformation (e.g. Vue.js `:id` generating the `id` attribute) this
|
|
1589
1585
|
* parameter should be set to the attribute name of the source attribute (`:id`).
|
|
1590
1586
|
*/
|
|
1591
1587
|
constructor(key, value, keyLocation, valueLocation, originalAttribute) {
|
|
@@ -1629,9 +1625,8 @@ class Attribute {
|
|
|
1629
1625
|
}
|
|
1630
1626
|
if (pattern instanceof RegExp) {
|
|
1631
1627
|
return this.value.match(pattern) !== null;
|
|
1632
|
-
} else {
|
|
1633
|
-
return this.value === pattern;
|
|
1634
1628
|
}
|
|
1629
|
+
return this.value === pattern;
|
|
1635
1630
|
}
|
|
1636
1631
|
}
|
|
1637
1632
|
|
|
@@ -1707,7 +1702,9 @@ const Node = {
|
|
|
1707
1702
|
|
|
1708
1703
|
const DOCUMENT_NODE_NAME = "#document";
|
|
1709
1704
|
const TEXT_CONTENT = /* @__PURE__ */ Symbol("textContent");
|
|
1710
|
-
|
|
1705
|
+
const state$1 = {
|
|
1706
|
+
counter: 0
|
|
1707
|
+
};
|
|
1711
1708
|
class DOMNode {
|
|
1712
1709
|
nodeName;
|
|
1713
1710
|
nodeType;
|
|
@@ -1746,7 +1743,7 @@ class DOMNode {
|
|
|
1746
1743
|
this.disabledRules = /* @__PURE__ */ new Set();
|
|
1747
1744
|
this.blockedRules = /* @__PURE__ */ new Map();
|
|
1748
1745
|
this.childNodes = [];
|
|
1749
|
-
this.unique = counter++;
|
|
1746
|
+
this.unique = state$1.counter++;
|
|
1750
1747
|
this.cache = null;
|
|
1751
1748
|
}
|
|
1752
1749
|
/**
|
|
@@ -1762,9 +1759,8 @@ class DOMNode {
|
|
|
1762
1759
|
cacheGet(key) {
|
|
1763
1760
|
if (this.cache) {
|
|
1764
1761
|
return this.cache.get(key);
|
|
1765
|
-
} else {
|
|
1766
|
-
return void 0;
|
|
1767
1762
|
}
|
|
1763
|
+
return void 0;
|
|
1768
1764
|
}
|
|
1769
1765
|
cacheSet(key, value) {
|
|
1770
1766
|
if (this.cache) {
|
|
@@ -1780,9 +1776,8 @@ class DOMNode {
|
|
|
1780
1776
|
cacheRemove(key) {
|
|
1781
1777
|
if (this.cache) {
|
|
1782
1778
|
return this.cache.delete(key);
|
|
1783
|
-
} else {
|
|
1784
|
-
return false;
|
|
1785
1779
|
}
|
|
1780
|
+
return false;
|
|
1786
1781
|
}
|
|
1787
1782
|
/**
|
|
1788
1783
|
* Check if key exists in cache.
|
|
@@ -2002,9 +1997,8 @@ class DOMTokenList extends Array {
|
|
|
2002
1997
|
location(n) {
|
|
2003
1998
|
if (this.locations) {
|
|
2004
1999
|
return this.locations[n];
|
|
2005
|
-
} else {
|
|
2006
|
-
throw new Error("Trying to access DOMTokenList location when base location isn't set");
|
|
2007
2000
|
}
|
|
2001
|
+
throw new Error("Trying to access DOMTokenList location when base location isn't set");
|
|
2008
2002
|
}
|
|
2009
2003
|
contains(token) {
|
|
2010
2004
|
return this.includes(token);
|
|
@@ -2054,25 +2048,25 @@ function lastChild(node) {
|
|
|
2054
2048
|
return node.nextSibling === null;
|
|
2055
2049
|
}
|
|
2056
2050
|
|
|
2057
|
-
const cache = {};
|
|
2051
|
+
const cache$1 = {};
|
|
2058
2052
|
function getNthChild(node) {
|
|
2059
2053
|
if (!node.parent) {
|
|
2060
2054
|
return -1;
|
|
2061
2055
|
}
|
|
2062
|
-
if (!cache[node.unique]) {
|
|
2056
|
+
if (!cache$1[node.unique]) {
|
|
2063
2057
|
const parent = node.parent;
|
|
2064
2058
|
const index = parent.childElements.findIndex((cur) => {
|
|
2065
2059
|
return cur.unique === node.unique;
|
|
2066
2060
|
});
|
|
2067
|
-
cache[node.unique] = index + 1;
|
|
2061
|
+
cache$1[node.unique] = index + 1;
|
|
2068
2062
|
}
|
|
2069
|
-
return cache[node.unique];
|
|
2063
|
+
return cache$1[node.unique];
|
|
2070
2064
|
}
|
|
2071
2065
|
function nthChild(node, args) {
|
|
2072
2066
|
if (!args) {
|
|
2073
2067
|
throw new Error("Missing argument to nth-child");
|
|
2074
2068
|
}
|
|
2075
|
-
const n =
|
|
2069
|
+
const n = Math.trunc(Number(args.trim()));
|
|
2076
2070
|
const cur = getNthChild(node);
|
|
2077
2071
|
return cur === n;
|
|
2078
2072
|
}
|
|
@@ -2091,9 +2085,8 @@ function factory(name, context) {
|
|
|
2091
2085
|
const fn = table[name];
|
|
2092
2086
|
if (fn) {
|
|
2093
2087
|
return fn.bind(context);
|
|
2094
|
-
} else {
|
|
2095
|
-
throw new Error(`Pseudo-class "${name}" is not implemented`);
|
|
2096
2088
|
}
|
|
2089
|
+
throw new Error(`Pseudo-class "${name}" is not implemented`);
|
|
2097
2090
|
}
|
|
2098
2091
|
|
|
2099
2092
|
function stripslashes(value) {
|
|
@@ -2119,7 +2112,7 @@ function createIdCondition(raw) {
|
|
|
2119
2112
|
};
|
|
2120
2113
|
}
|
|
2121
2114
|
function createAttributeCondition(attr) {
|
|
2122
|
-
const match = /^(.+?)(?:([$*^|~]?=)"([^"]
|
|
2115
|
+
const match = /^(.+?)(?:([$*^|~]?=)"([^"]+)")?$/.exec(attr);
|
|
2123
2116
|
const key = match[1];
|
|
2124
2117
|
const op = match[2];
|
|
2125
2118
|
const rawValue = match[3];
|
|
@@ -2182,7 +2175,6 @@ function* splitCompound(pattern) {
|
|
|
2182
2175
|
let quoted = false;
|
|
2183
2176
|
while (cur < end) {
|
|
2184
2177
|
const ch = pattern[cur];
|
|
2185
|
-
const buffer = pattern.slice(begin, cur);
|
|
2186
2178
|
if (ch === "\\") {
|
|
2187
2179
|
cur += 2;
|
|
2188
2180
|
continue;
|
|
@@ -2199,6 +2191,7 @@ function* splitCompound(pattern) {
|
|
|
2199
2191
|
cur += 1;
|
|
2200
2192
|
continue;
|
|
2201
2193
|
}
|
|
2194
|
+
const buffer = pattern.slice(begin, cur);
|
|
2202
2195
|
if (isPseudoElement(ch, buffer)) {
|
|
2203
2196
|
cur += 1;
|
|
2204
2197
|
continue;
|
|
@@ -2219,7 +2212,7 @@ class Compound {
|
|
|
2219
2212
|
selector;
|
|
2220
2213
|
conditions;
|
|
2221
2214
|
constructor(pattern) {
|
|
2222
|
-
const match = /^([+>~-]?)((?:\*|[^#.:[]+)?)([
|
|
2215
|
+
const match = /^([+>~-]?)((?:\*|[^#.:[]+)?)([\s\S]*)$/.exec(pattern);
|
|
2223
2216
|
if (!match) {
|
|
2224
2217
|
throw new Error(`Failed to create selector pattern from "${pattern}"`);
|
|
2225
2218
|
}
|
|
@@ -2233,7 +2226,7 @@ class Compound {
|
|
|
2233
2226
|
return node.is(this.tagName) && this.conditions.every((cur) => cur.match(node, context));
|
|
2234
2227
|
}
|
|
2235
2228
|
createCondition(pattern) {
|
|
2236
|
-
switch (pattern
|
|
2229
|
+
switch (pattern.at(0)) {
|
|
2237
2230
|
case ".":
|
|
2238
2231
|
return createClassCondition(pattern.slice(1));
|
|
2239
2232
|
case "#":
|
|
@@ -2426,9 +2419,9 @@ class ComplexSelector {
|
|
|
2426
2419
|
case Combinator.CHILD:
|
|
2427
2420
|
return root.childElements.filter((node) => node.is(pattern.tagName));
|
|
2428
2421
|
case Combinator.ADJACENT_SIBLING:
|
|
2429
|
-
return
|
|
2422
|
+
return this.findAdjacentSibling(root);
|
|
2430
2423
|
case Combinator.GENERAL_SIBLING:
|
|
2431
|
-
return
|
|
2424
|
+
return this.findGeneralSibling(root);
|
|
2432
2425
|
case Combinator.SCOPE:
|
|
2433
2426
|
return [root];
|
|
2434
2427
|
}
|
|
@@ -2466,12 +2459,11 @@ const codepoints = {
|
|
|
2466
2459
|
"\r": "\\d "
|
|
2467
2460
|
};
|
|
2468
2461
|
function escapeSelectorComponent(text) {
|
|
2469
|
-
return text.toString().replaceAll(/([
|
|
2470
|
-
if (codepoints
|
|
2462
|
+
return text.toString().replaceAll(/([^\w-])/g, (_, ch) => {
|
|
2463
|
+
if (Object.hasOwn(codepoints, ch)) {
|
|
2471
2464
|
return codepoints[ch];
|
|
2472
|
-
} else {
|
|
2473
|
-
return `\\${ch}`;
|
|
2474
2465
|
}
|
|
2466
|
+
return `\\${ch}`;
|
|
2475
2467
|
});
|
|
2476
2468
|
}
|
|
2477
2469
|
|
|
@@ -2480,9 +2472,16 @@ function generateIdSelector(id) {
|
|
|
2480
2472
|
return /^\d/.test(escaped) ? `[id="${escaped}"]` : `#${escaped}`;
|
|
2481
2473
|
}
|
|
2482
2474
|
|
|
2475
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2483
2476
|
function parseSelector(selector) {
|
|
2477
|
+
const cached = cache.get(selector);
|
|
2478
|
+
if (cached) {
|
|
2479
|
+
return cached;
|
|
2480
|
+
}
|
|
2484
2481
|
const compounds = getCompounds(selector);
|
|
2485
|
-
|
|
2482
|
+
const result = ComplexSelector.fromCompounds(compounds);
|
|
2483
|
+
cache.set(selector, result);
|
|
2484
|
+
return result;
|
|
2486
2485
|
}
|
|
2487
2486
|
|
|
2488
2487
|
const TEXT_NODE_NAME = "#text";
|
|
@@ -2627,10 +2626,10 @@ class HtmlElement extends DOMNode {
|
|
|
2627
2626
|
*/
|
|
2628
2627
|
static fromTokens(startToken, endToken, parent, metaTable, namespace = "") {
|
|
2629
2628
|
const name = startToken.data[2];
|
|
2630
|
-
const tagName = namespace ? `${namespace}:${name}` : name;
|
|
2631
2629
|
if (!name) {
|
|
2632
2630
|
throw new Error("tagName cannot be empty");
|
|
2633
2631
|
}
|
|
2632
|
+
const tagName = namespace ? `${namespace}:${name}` : name;
|
|
2634
2633
|
const meta = metaTable ? metaTable.getMetaFor(tagName) : null;
|
|
2635
2634
|
const open = startToken.data[1] !== "/";
|
|
2636
2635
|
const closed = isClosed(endToken, meta);
|
|
@@ -2652,9 +2651,8 @@ class HtmlElement extends DOMNode {
|
|
|
2652
2651
|
get annotatedName() {
|
|
2653
2652
|
if (this.annotation) {
|
|
2654
2653
|
return this.annotation;
|
|
2655
|
-
} else {
|
|
2656
|
-
return `<${this.tagName}>`;
|
|
2657
2654
|
}
|
|
2655
|
+
return `<${this.tagName}>`;
|
|
2658
2656
|
}
|
|
2659
2657
|
/**
|
|
2660
2658
|
* Get list of IDs referenced by `aria-labelledby`.
|
|
@@ -2873,13 +2871,13 @@ class HtmlElement extends DOMNode {
|
|
|
2873
2871
|
if (!tabindex) {
|
|
2874
2872
|
return this.cacheSet(TABINDEX, null);
|
|
2875
2873
|
}
|
|
2876
|
-
if (tabindex.value === null) {
|
|
2874
|
+
if (tabindex.value === null || tabindex.value === "") {
|
|
2877
2875
|
return this.cacheSet(TABINDEX, null);
|
|
2878
2876
|
}
|
|
2879
2877
|
if (tabindex.value instanceof DynamicValue) {
|
|
2880
2878
|
return this.cacheSet(TABINDEX, 0);
|
|
2881
2879
|
}
|
|
2882
|
-
const parsed =
|
|
2880
|
+
const parsed = Math.trunc(Number(tabindex.value));
|
|
2883
2881
|
if (Number.isNaN(parsed)) {
|
|
2884
2882
|
return this.cacheSet(TABINDEX, null);
|
|
2885
2883
|
}
|
|
@@ -2895,11 +2893,11 @@ class HtmlElement extends DOMNode {
|
|
|
2895
2893
|
const tagName = this.tagName.toLowerCase();
|
|
2896
2894
|
if (tagName === "script") {
|
|
2897
2895
|
return "script";
|
|
2898
|
-
}
|
|
2896
|
+
}
|
|
2897
|
+
if (tagName === "style") {
|
|
2899
2898
|
return "css";
|
|
2900
|
-
} else {
|
|
2901
|
-
return "text";
|
|
2902
2899
|
}
|
|
2900
|
+
return "text";
|
|
2903
2901
|
}
|
|
2904
2902
|
/**
|
|
2905
2903
|
* Get a list of all attributes on this node.
|
|
@@ -2911,16 +2909,15 @@ class HtmlElement extends DOMNode {
|
|
|
2911
2909
|
}
|
|
2912
2910
|
hasAttribute(key) {
|
|
2913
2911
|
key = key.toLowerCase();
|
|
2914
|
-
return
|
|
2912
|
+
return Object.hasOwn(this.attr, key);
|
|
2915
2913
|
}
|
|
2916
2914
|
getAttribute(key, all = false) {
|
|
2917
2915
|
key = key.toLowerCase();
|
|
2918
|
-
if (
|
|
2916
|
+
if (Object.hasOwn(this.attr, key)) {
|
|
2919
2917
|
const matches = this.attr[key];
|
|
2920
2918
|
return all ? matches : matches[0];
|
|
2921
|
-
} else {
|
|
2922
|
-
return all ? [] : null;
|
|
2923
2919
|
}
|
|
2920
|
+
return all ? [] : null;
|
|
2924
2921
|
}
|
|
2925
2922
|
/**
|
|
2926
2923
|
* Get attribute value.
|
|
@@ -2938,17 +2935,13 @@ class HtmlElement extends DOMNode {
|
|
|
2938
2935
|
const attr = this.getAttribute(key);
|
|
2939
2936
|
if (attr) {
|
|
2940
2937
|
return attr.value !== null ? attr.value.toString() : null;
|
|
2941
|
-
} else {
|
|
2942
|
-
return null;
|
|
2943
2938
|
}
|
|
2939
|
+
return null;
|
|
2944
2940
|
}
|
|
2945
|
-
/**
|
|
2946
|
-
* Add text as a child node to this element.
|
|
2947
|
-
*
|
|
2948
|
-
* @param text - Text to add.
|
|
2949
|
-
* @param location - Source code location of this text.
|
|
2950
|
-
*/
|
|
2951
2941
|
appendText(text, location) {
|
|
2942
|
+
if (typeof text === "object" && "dynamic" in text) {
|
|
2943
|
+
text = new DynamicValue(text.dynamic);
|
|
2944
|
+
}
|
|
2952
2945
|
this.childNodes.push(new TextNode(text, location));
|
|
2953
2946
|
}
|
|
2954
2947
|
/**
|
|
@@ -3001,23 +2994,30 @@ class HtmlElement extends DOMNode {
|
|
|
3001
2994
|
return i <= this.siblings.length - 2 ? this.siblings[i + 1] : null;
|
|
3002
2995
|
}
|
|
3003
2996
|
getElementsByTagName(tagName) {
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
2997
|
+
const matches = [];
|
|
2998
|
+
this.collectByTagName(tagName, matches);
|
|
2999
|
+
return matches;
|
|
3000
|
+
}
|
|
3001
|
+
collectByTagName(tagName, matches) {
|
|
3002
|
+
for (const node of this.childElements) {
|
|
3003
|
+
if (node.is(tagName)) {
|
|
3004
|
+
matches.push(node);
|
|
3005
|
+
}
|
|
3006
|
+
node.collectByTagName(tagName, matches);
|
|
3007
|
+
}
|
|
3007
3008
|
}
|
|
3008
3009
|
querySelector(selector) {
|
|
3009
3010
|
const it = this.querySelectorImpl(selector);
|
|
3010
3011
|
const next = it.next();
|
|
3011
3012
|
if (next.done) {
|
|
3012
3013
|
return null;
|
|
3013
|
-
} else {
|
|
3014
|
-
return next.value;
|
|
3015
3014
|
}
|
|
3015
|
+
return next.value;
|
|
3016
3016
|
}
|
|
3017
3017
|
querySelectorAll(selector) {
|
|
3018
3018
|
const it = this.querySelectorImpl(selector);
|
|
3019
3019
|
const unique = new Set(it);
|
|
3020
|
-
return Array.from(unique
|
|
3020
|
+
return Array.from(unique);
|
|
3021
3021
|
}
|
|
3022
3022
|
*querySelectorImpl(selectorList) {
|
|
3023
3023
|
if (!selectorList) {
|
|
@@ -3038,9 +3038,8 @@ class HtmlElement extends DOMNode {
|
|
|
3038
3038
|
function visit(node) {
|
|
3039
3039
|
if (callback(node)) {
|
|
3040
3040
|
return true;
|
|
3041
|
-
} else {
|
|
3042
|
-
return node.childElements.some(visit);
|
|
3043
3041
|
}
|
|
3042
|
+
return node.childElements.some(visit);
|
|
3044
3043
|
}
|
|
3045
3044
|
}
|
|
3046
3045
|
/**
|
|
@@ -3215,7 +3214,7 @@ class Validator {
|
|
|
3215
3214
|
return true;
|
|
3216
3215
|
}
|
|
3217
3216
|
return rules.some((rule) => {
|
|
3218
|
-
return
|
|
3217
|
+
return this.validatePermittedRule(node, rule);
|
|
3219
3218
|
});
|
|
3220
3219
|
}
|
|
3221
3220
|
/**
|
|
@@ -3242,9 +3241,7 @@ class Validator {
|
|
|
3242
3241
|
const [, category, quantifier] = /^(@?.*?)([*?]?)$/.exec(rule);
|
|
3243
3242
|
const limit = category && quantifier && parseQuantifier(quantifier);
|
|
3244
3243
|
if (limit) {
|
|
3245
|
-
const siblings = children.filter(
|
|
3246
|
-
(cur) => Validator.validatePermittedCategory(cur, rule, true)
|
|
3247
|
-
);
|
|
3244
|
+
const siblings = children.filter((cur) => this.validatePermittedCategory(cur, rule, true));
|
|
3248
3245
|
if (siblings.length > limit) {
|
|
3249
3246
|
for (const child of siblings.slice(limit)) {
|
|
3250
3247
|
cb(child, category);
|
|
@@ -3275,12 +3272,12 @@ class Validator {
|
|
|
3275
3272
|
let prev = null;
|
|
3276
3273
|
for (const node of children) {
|
|
3277
3274
|
const old = i;
|
|
3278
|
-
while (rules[i] && !
|
|
3275
|
+
while (rules[i] && !this.validatePermittedCategory(node, rules[i], true)) {
|
|
3279
3276
|
i++;
|
|
3280
3277
|
}
|
|
3281
3278
|
if (i >= rules.length) {
|
|
3282
|
-
const orderSpecified = rules.
|
|
3283
|
-
(cur) =>
|
|
3279
|
+
const orderSpecified = rules.some(
|
|
3280
|
+
(cur) => this.validatePermittedCategory(node, cur, true)
|
|
3284
3281
|
);
|
|
3285
3282
|
if (orderSpecified) {
|
|
3286
3283
|
cb(node, prev);
|
|
@@ -3319,7 +3316,7 @@ class Validator {
|
|
|
3319
3316
|
}
|
|
3320
3317
|
return rules.filter((tagName) => {
|
|
3321
3318
|
const haveMatchingChild = node.childElements.some(
|
|
3322
|
-
(child) =>
|
|
3319
|
+
(child) => this.validatePermittedCategory(child, tagName, false)
|
|
3323
3320
|
);
|
|
3324
3321
|
return !haveMatchingChild;
|
|
3325
3322
|
});
|
|
@@ -3366,36 +3363,35 @@ class Validator {
|
|
|
3366
3363
|
return rule.enum.some((entry) => {
|
|
3367
3364
|
if (typeof entry === "string") {
|
|
3368
3365
|
return caseInsensitiveValue === entry;
|
|
3369
|
-
}
|
|
3366
|
+
}
|
|
3367
|
+
if (entry instanceof RegExp) {
|
|
3370
3368
|
return entry.test(value);
|
|
3371
|
-
}
|
|
3369
|
+
}
|
|
3370
|
+
if (entry.pattern instanceof RegExp) {
|
|
3372
3371
|
return entry.pattern.test(value);
|
|
3373
|
-
} else {
|
|
3374
|
-
throw new TypeError("RegExp was not precompiled when it should have been");
|
|
3375
3372
|
}
|
|
3373
|
+
throw new TypeError("RegExp was not precompiled when it should have been");
|
|
3376
3374
|
});
|
|
3377
3375
|
}
|
|
3378
3376
|
static validatePermittedRule(node, rule, isExclude = false) {
|
|
3379
3377
|
if (typeof rule === "string") {
|
|
3380
|
-
return
|
|
3381
|
-
}
|
|
3378
|
+
return this.validatePermittedCategory(node, rule, !isExclude);
|
|
3379
|
+
}
|
|
3380
|
+
if (Array.isArray(rule)) {
|
|
3382
3381
|
return rule.every((inner) => {
|
|
3383
|
-
return
|
|
3382
|
+
return this.validatePermittedRule(node, inner, isExclude);
|
|
3384
3383
|
});
|
|
3385
|
-
}
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
} else {
|
|
3393
|
-
return !Validator.validatePermittedRule(node, rule.exclude, true);
|
|
3394
|
-
}
|
|
3395
|
-
} else {
|
|
3396
|
-
return true;
|
|
3384
|
+
}
|
|
3385
|
+
validateKeys(rule);
|
|
3386
|
+
if (rule.exclude) {
|
|
3387
|
+
if (Array.isArray(rule.exclude)) {
|
|
3388
|
+
return rule.exclude.every((inner) => {
|
|
3389
|
+
return !this.validatePermittedRule(node, inner, true);
|
|
3390
|
+
});
|
|
3397
3391
|
}
|
|
3392
|
+
return !this.validatePermittedRule(node, rule.exclude, true);
|
|
3398
3393
|
}
|
|
3394
|
+
return true;
|
|
3399
3395
|
}
|
|
3400
3396
|
/**
|
|
3401
3397
|
* Validate node against a content category.
|
|
@@ -3411,7 +3407,7 @@ class Validator {
|
|
|
3411
3407
|
*/
|
|
3412
3408
|
/* eslint-disable-next-line complexity -- rule does not like switch */
|
|
3413
3409
|
static validatePermittedCategory(node, category, defaultMatch) {
|
|
3414
|
-
const [, rawCategory] = /^(@?.*?)
|
|
3410
|
+
const [, rawCategory] = /^(@?.*?)[*?]?$/.exec(category);
|
|
3415
3411
|
if (!rawCategory.startsWith("@")) {
|
|
3416
3412
|
return node.matches(rawCategory);
|
|
3417
3413
|
}
|
|
@@ -3444,10 +3440,11 @@ class Validator {
|
|
|
3444
3440
|
}
|
|
3445
3441
|
function validateKeys(rule) {
|
|
3446
3442
|
for (const key of Object.keys(rule)) {
|
|
3447
|
-
if (
|
|
3448
|
-
|
|
3449
|
-
throw new Error(`Permitted rule "${str}" contains unknown property "${key}"`);
|
|
3443
|
+
if (allowedKeys.has(key)) {
|
|
3444
|
+
continue;
|
|
3450
3445
|
}
|
|
3446
|
+
const str = JSON.stringify(rule);
|
|
3447
|
+
throw new Error(`Permitted rule "${str}" contains unknown property "${key}"`);
|
|
3451
3448
|
}
|
|
3452
3449
|
}
|
|
3453
3450
|
function parseQuantifier(quantifier) {
|
|
@@ -3514,9 +3511,8 @@ function ariaNaming(element) {
|
|
|
3514
3511
|
if (role) {
|
|
3515
3512
|
if (role instanceof DynamicValue) {
|
|
3516
3513
|
return element.cacheSet(cacheKey, defaultValue);
|
|
3517
|
-
} else {
|
|
3518
|
-
return element.cacheSet(cacheKey, byRole(role));
|
|
3519
3514
|
}
|
|
3515
|
+
return element.cacheSet(cacheKey, byRole(role));
|
|
3520
3516
|
}
|
|
3521
3517
|
const meta = element.meta;
|
|
3522
3518
|
if (!meta) {
|
|
@@ -3701,9 +3697,8 @@ function isPresentation(node) {
|
|
|
3701
3697
|
const role = node.getAttribute("role");
|
|
3702
3698
|
if (role && (role.value === "presentation" || role.value === "none")) {
|
|
3703
3699
|
return node.cacheSet(ROLE_PRESENTATION_CACHE, true);
|
|
3704
|
-
} else {
|
|
3705
|
-
return node.cacheSet(ROLE_PRESENTATION_CACHE, false);
|
|
3706
3700
|
}
|
|
3701
|
+
return node.cacheSet(ROLE_PRESENTATION_CACHE, false);
|
|
3707
3702
|
}
|
|
3708
3703
|
|
|
3709
3704
|
const cachePrefix = classifyNodeText.name;
|
|
@@ -3721,13 +3716,14 @@ function getCachekey(options) {
|
|
|
3721
3716
|
const { accessible = false, ignoreHiddenRoot = false } = options;
|
|
3722
3717
|
if (accessible && ignoreHiddenRoot) {
|
|
3723
3718
|
return IGNORE_HIDDEN_ROOT_A11Y_CACHE_KEY;
|
|
3724
|
-
}
|
|
3719
|
+
}
|
|
3720
|
+
if (ignoreHiddenRoot) {
|
|
3725
3721
|
return IGNORE_HIDDEN_ROOT_HTML_CACHE_KEY;
|
|
3726
|
-
}
|
|
3722
|
+
}
|
|
3723
|
+
if (accessible) {
|
|
3727
3724
|
return A11Y_CACHE_KEY;
|
|
3728
|
-
} else {
|
|
3729
|
-
return HTML_CACHE_KEY;
|
|
3730
3725
|
}
|
|
3726
|
+
return HTML_CACHE_KEY;
|
|
3731
3727
|
}
|
|
3732
3728
|
function isSpecialEmpty(node) {
|
|
3733
3729
|
return node.is("select") || node.is("textarea");
|
|
@@ -3759,7 +3755,7 @@ function classifyNodeText(node, options = {}) {
|
|
|
3759
3755
|
}
|
|
3760
3756
|
function findTextNodes(node, options) {
|
|
3761
3757
|
const { accessible = false } = options;
|
|
3762
|
-
|
|
3758
|
+
const text = [];
|
|
3763
3759
|
for (const child of node.childNodes) {
|
|
3764
3760
|
if (isTextNode(child)) {
|
|
3765
3761
|
text.push(child);
|
|
@@ -3770,7 +3766,7 @@ function findTextNodes(node, options) {
|
|
|
3770
3766
|
if (accessible && isAriaHidden(child, true).bySelf) {
|
|
3771
3767
|
continue;
|
|
3772
3768
|
}
|
|
3773
|
-
text
|
|
3769
|
+
text.push(...findTextNodes(child, options));
|
|
3774
3770
|
}
|
|
3775
3771
|
}
|
|
3776
3772
|
return text;
|
|
@@ -3831,14 +3827,17 @@ function format(value, quote = false) {
|
|
|
3831
3827
|
return String(value);
|
|
3832
3828
|
}
|
|
3833
3829
|
function interpolate(text, data) {
|
|
3834
|
-
return text.replaceAll(
|
|
3830
|
+
return text.replaceAll(/\{\{\s*([^\s{}]+)\s*\}\}/g, (match, key) => {
|
|
3835
3831
|
return data[key] !== void 0 ? format(data[key]) : match;
|
|
3836
3832
|
});
|
|
3837
3833
|
}
|
|
3838
3834
|
|
|
3839
|
-
const ajv$1 =
|
|
3840
|
-
|
|
3841
|
-
|
|
3835
|
+
const ajv$1 = (() => {
|
|
3836
|
+
const ajv2 = new Ajv({ strict: true, strictTuples: true, strictTypes: true });
|
|
3837
|
+
ajv2.addMetaSchema(ajvSchemaDraft);
|
|
3838
|
+
ajv2.addKeyword(ajvRegexpKeyword);
|
|
3839
|
+
return ajv2;
|
|
3840
|
+
})();
|
|
3842
3841
|
function getSchemaValidator(ruleId, properties) {
|
|
3843
3842
|
const $id = `rule/${ruleId}`;
|
|
3844
3843
|
const cached = ajv$1.getSchema($id);
|
|
@@ -3859,10 +3858,9 @@ function isErrorDescriptor(value) {
|
|
|
3859
3858
|
function unpackErrorDescriptor(value) {
|
|
3860
3859
|
if (isErrorDescriptor(value)) {
|
|
3861
3860
|
return value[0];
|
|
3862
|
-
} else {
|
|
3863
|
-
const [node, message, location, context] = value;
|
|
3864
|
-
return { node, message, location, context };
|
|
3865
3861
|
}
|
|
3862
|
+
const [node, message, location, context] = value;
|
|
3863
|
+
return { node, message, location, context };
|
|
3866
3864
|
}
|
|
3867
3865
|
class Rule {
|
|
3868
3866
|
reporter;
|
|
@@ -4068,17 +4066,18 @@ class Rule {
|
|
|
4068
4066
|
const callback = args.pop();
|
|
4069
4067
|
const filter = args.pop() ?? (() => true);
|
|
4070
4068
|
return this.parser.on(event, (_event, data) => {
|
|
4071
|
-
if (this.isEnabled()
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4069
|
+
if (!this.isEnabled() || !filter(data)) {
|
|
4070
|
+
return;
|
|
4071
|
+
}
|
|
4072
|
+
this.event = data;
|
|
4073
|
+
const { tracker } = this;
|
|
4074
|
+
if (tracker) {
|
|
4075
|
+
const start = performance.now();
|
|
4076
|
+
callback(data);
|
|
4077
|
+
const end = performance.now();
|
|
4078
|
+
tracker.trackRule(this.name, end - start);
|
|
4079
|
+
} else {
|
|
4080
|
+
callback(data);
|
|
4082
4081
|
}
|
|
4083
4082
|
});
|
|
4084
4083
|
}
|
|
@@ -4148,7 +4147,7 @@ class Rule {
|
|
|
4148
4147
|
* @public
|
|
4149
4148
|
* @virtual
|
|
4150
4149
|
* @param context - Error context given by a reported error.
|
|
4151
|
-
* @returns Rule documentation and
|
|
4150
|
+
* @returns Rule documentation and URL with additional details or `null` if no
|
|
4152
4151
|
* additional documentation is available.
|
|
4153
4152
|
*/
|
|
4154
4153
|
documentation(_context) {
|
|
@@ -4187,7 +4186,7 @@ function parseAllow(value) {
|
|
|
4187
4186
|
};
|
|
4188
4187
|
}
|
|
4189
4188
|
function matchList(value, list) {
|
|
4190
|
-
if (list.include
|
|
4189
|
+
if (list.include?.every((it) => !it.test(value))) {
|
|
4191
4190
|
return false;
|
|
4192
4191
|
}
|
|
4193
4192
|
if (list.exclude?.some((it) => it.test(value))) {
|
|
@@ -4272,10 +4271,10 @@ class AllowedLinks extends Rule {
|
|
|
4272
4271
|
return Boolean(attr && attr === key);
|
|
4273
4272
|
}
|
|
4274
4273
|
getStyle(value) {
|
|
4275
|
-
if (/^([a-z]+:)
|
|
4274
|
+
if (/^(?:[a-z]+:)?\/\//.test(value)) {
|
|
4276
4275
|
return "external" /* EXTERNAL */;
|
|
4277
4276
|
}
|
|
4278
|
-
switch (value
|
|
4277
|
+
switch (value.at(0)) {
|
|
4279
4278
|
/* /foo/bar */
|
|
4280
4279
|
case "/":
|
|
4281
4280
|
return "absolute" /* ABSOLUTE */;
|
|
@@ -4294,7 +4293,8 @@ class AllowedLinks extends Rule {
|
|
|
4294
4293
|
const { allowAbsolute } = this;
|
|
4295
4294
|
if (allowAbsolute === true) {
|
|
4296
4295
|
return;
|
|
4297
|
-
}
|
|
4296
|
+
}
|
|
4297
|
+
if (allowAbsolute === false) {
|
|
4298
4298
|
this.report(
|
|
4299
4299
|
event.target,
|
|
4300
4300
|
"Link destination must not be absolute url",
|
|
@@ -4314,7 +4314,8 @@ class AllowedLinks extends Rule {
|
|
|
4314
4314
|
const { allowExternal } = this;
|
|
4315
4315
|
if (allowExternal === true) {
|
|
4316
4316
|
return;
|
|
4317
|
-
}
|
|
4317
|
+
}
|
|
4318
|
+
if (allowExternal === false) {
|
|
4318
4319
|
this.report(
|
|
4319
4320
|
event.target,
|
|
4320
4321
|
"Link destination must not be external url",
|
|
@@ -4334,7 +4335,8 @@ class AllowedLinks extends Rule {
|
|
|
4334
4335
|
const { allowRelative } = this;
|
|
4335
4336
|
if (allowRelative === true) {
|
|
4336
4337
|
return false;
|
|
4337
|
-
}
|
|
4338
|
+
}
|
|
4339
|
+
if (allowRelative === false) {
|
|
4338
4340
|
this.report(
|
|
4339
4341
|
event.target,
|
|
4340
4342
|
"Link destination must not be relative url",
|
|
@@ -4342,7 +4344,8 @@ class AllowedLinks extends Rule {
|
|
|
4342
4344
|
style
|
|
4343
4345
|
);
|
|
4344
4346
|
return true;
|
|
4345
|
-
}
|
|
4347
|
+
}
|
|
4348
|
+
if (!matchList(target, allowRelative)) {
|
|
4346
4349
|
this.report(
|
|
4347
4350
|
event.target,
|
|
4348
4351
|
"Relative link to this destination is not allowed by current configuration",
|
|
@@ -4357,7 +4360,8 @@ class AllowedLinks extends Rule {
|
|
|
4357
4360
|
const { allowBase } = this.options;
|
|
4358
4361
|
if (this.handleRelativePath(target, event, style)) {
|
|
4359
4362
|
return;
|
|
4360
|
-
}
|
|
4363
|
+
}
|
|
4364
|
+
if (!allowBase) {
|
|
4361
4365
|
this.report(
|
|
4362
4366
|
event.target,
|
|
4363
4367
|
"Relative links must be relative to current folder",
|
|
@@ -4575,12 +4579,11 @@ class AriaLabelMisuse extends Rule {
|
|
|
4575
4579
|
].join("\n"),
|
|
4576
4580
|
url
|
|
4577
4581
|
};
|
|
4578
|
-
} else {
|
|
4579
|
-
return {
|
|
4580
|
-
description: [`\`${context.attr}\` can only be used on:`, "", ...lines].join("\n"),
|
|
4581
|
-
url
|
|
4582
|
-
};
|
|
4583
4582
|
}
|
|
4583
|
+
return {
|
|
4584
|
+
description: [`\`${context.attr}\` can only be used on:`, "", ...lines].join("\n"),
|
|
4585
|
+
url
|
|
4586
|
+
};
|
|
4584
4587
|
}
|
|
4585
4588
|
setup() {
|
|
4586
4589
|
this.on("dom:ready", (event) => {
|
|
@@ -4638,6 +4641,7 @@ class AriaLabelMisuse extends Rule {
|
|
|
4638
4641
|
}
|
|
4639
4642
|
|
|
4640
4643
|
class ConfigError extends UserError {
|
|
4644
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
4641
4645
|
constructor(message, nested) {
|
|
4642
4646
|
super(message, nested);
|
|
4643
4647
|
this.name = "ConfigError";
|
|
@@ -4758,9 +4762,8 @@ class AttrCase extends Rule {
|
|
|
4758
4762
|
isIgnored(node) {
|
|
4759
4763
|
if (this.options.ignoreForeign) {
|
|
4760
4764
|
return Boolean(node.meta?.foreign);
|
|
4761
|
-
} else {
|
|
4762
|
-
return false;
|
|
4763
4765
|
}
|
|
4766
|
+
return false;
|
|
4764
4767
|
}
|
|
4765
4768
|
}
|
|
4766
4769
|
|
|
@@ -4807,14 +4810,21 @@ class Context {
|
|
|
4807
4810
|
return JSON.stringify(this.string.length > n ? `${this.string.slice(0, 10)}...` : this.string);
|
|
4808
4811
|
}
|
|
4809
4812
|
consume(n, state) {
|
|
4810
|
-
let
|
|
4811
|
-
let
|
|
4812
|
-
|
|
4813
|
-
this.
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4813
|
+
let lastNewline = -1;
|
|
4814
|
+
let newlines = 0;
|
|
4815
|
+
for (let i = 0; i < n; i++) {
|
|
4816
|
+
if (this.string[i] !== "\n") {
|
|
4817
|
+
continue;
|
|
4818
|
+
}
|
|
4819
|
+
newlines++;
|
|
4820
|
+
lastNewline = i;
|
|
4821
|
+
}
|
|
4822
|
+
if (newlines > 0) {
|
|
4823
|
+
this.line += newlines;
|
|
4824
|
+
this.column = n - lastNewline;
|
|
4825
|
+
} else {
|
|
4826
|
+
this.column += n;
|
|
4827
|
+
}
|
|
4818
4828
|
this.offset += n;
|
|
4819
4829
|
this.string = this.string.slice(n);
|
|
4820
4830
|
this.state = state;
|
|
@@ -4869,28 +4879,29 @@ const MATCH_DOCTYPE_CLOSE = /^>/;
|
|
|
4869
4879
|
const MATCH_XML_TAG = /^<\?xml.*?\?>\s+/;
|
|
4870
4880
|
const MATCH_TAG_OPEN = /^<(\/?)([\w:\-]+)/;
|
|
4871
4881
|
const MATCH_TAG_CLOSE = /^\/?>/;
|
|
4872
|
-
const MATCH_TEXT = /^[
|
|
4882
|
+
const MATCH_TEXT = /^[\s\S]*?(?=[\t ]*(?:\r\n|\r|\n)|<[^ ]|$)/;
|
|
4873
4883
|
const MATCH_TEMPLATING = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)/s;
|
|
4874
|
-
const MATCH_TAG_LOOKAHEAD = /^[
|
|
4884
|
+
const MATCH_TAG_LOOKAHEAD = /^[\s\S]*?(?=<|$)/;
|
|
4875
4885
|
const MATCH_ATTR_START = /^([^\t\n\f\r "'/<=>]+)/;
|
|
4876
|
-
const MATCH_ATTR_SINGLE = /^(\s*=\s*)'([^']
|
|
4877
|
-
const MATCH_ATTR_DOUBLE = /^(\s*=\s*)"([^"]
|
|
4886
|
+
const MATCH_ATTR_SINGLE = /^(\s*=\s*)'([^']*)(')/;
|
|
4887
|
+
const MATCH_ATTR_DOUBLE = /^(\s*=\s*)"([^"]*)(")/;
|
|
4878
4888
|
const MATCH_ATTR_UNQUOTED = /^(\s*=\s*)([^\t\n\f\r "'<>][^\t\n\f\r <>]*)/;
|
|
4879
4889
|
const MATCH_CDATA_BEGIN = /^<!\[CDATA\[/;
|
|
4880
|
-
const MATCH_CDATA_END = /^[
|
|
4881
|
-
const MATCH_SCRIPT_DATA = /^[
|
|
4890
|
+
const MATCH_CDATA_END = /^[\s\S]*?\]\]>/;
|
|
4891
|
+
const MATCH_SCRIPT_DATA = /^[\s\S]*?(?=<\/script)/;
|
|
4882
4892
|
const MATCH_SCRIPT_END = /^<(\/)(script)/;
|
|
4883
|
-
const MATCH_STYLE_DATA = /^[
|
|
4893
|
+
const MATCH_STYLE_DATA = /^[\s\S]*?(?=<\/style)/;
|
|
4884
4894
|
const MATCH_STYLE_END = /^<(\/)(style)/;
|
|
4885
|
-
const MATCH_TEXTAREA_DATA = /^[
|
|
4895
|
+
const MATCH_TEXTAREA_DATA = /^[\s\S]*?(?=<\/textarea)/;
|
|
4886
4896
|
const MATCH_TEXTAREA_END = /^<(\/)(textarea)/;
|
|
4887
|
-
const MATCH_TITLE_DATA = /^[
|
|
4897
|
+
const MATCH_TITLE_DATA = /^[\s\S]*?(?=<\/title)/;
|
|
4888
4898
|
const MATCH_TITLE_END = /^<(\/)(title)/;
|
|
4889
|
-
const MATCH_DIRECTIVE = /^(<!--\s*\[?)(html-validate-)([\da-z-]+)(\s*)(.*?)(]?\s*-->)/;
|
|
4890
|
-
const MATCH_COMMENT = /^<!--([
|
|
4891
|
-
const MATCH_CONDITIONAL = /^<!\[([^\]]
|
|
4899
|
+
const MATCH_DIRECTIVE = /^(<!--\s*\[?)(html-validate-)([\da-z-]+)(\s*)(.*?)(\]?\s*-->)/;
|
|
4900
|
+
const MATCH_COMMENT = /^<!--([\s\S]*?)-->/;
|
|
4901
|
+
const MATCH_CONDITIONAL = /^<!\[([^\]]*)\]>/;
|
|
4892
4902
|
class InvalidTokenError extends Error {
|
|
4893
4903
|
location;
|
|
4904
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
4894
4905
|
constructor(location, message) {
|
|
4895
4906
|
super(message);
|
|
4896
4907
|
this.name = "InvalidTokenError";
|
|
@@ -4974,9 +4985,8 @@ class Lexer {
|
|
|
4974
4985
|
evalNextState(nextState, token) {
|
|
4975
4986
|
if (typeof nextState === "function") {
|
|
4976
4987
|
return nextState(token);
|
|
4977
|
-
} else {
|
|
4978
|
-
return nextState;
|
|
4979
4988
|
}
|
|
4989
|
+
return nextState;
|
|
4980
4990
|
}
|
|
4981
4991
|
*match(context, tests, error) {
|
|
4982
4992
|
const n = tests.length;
|
|
@@ -5063,27 +5073,26 @@ class Lexer {
|
|
|
5063
5073
|
case ContentModel.SCRIPT:
|
|
5064
5074
|
if (selfClosed) {
|
|
5065
5075
|
return State.SCRIPT;
|
|
5066
|
-
} else {
|
|
5067
|
-
return State.TEXT;
|
|
5068
5076
|
}
|
|
5077
|
+
return State.TEXT;
|
|
5078
|
+
/* <script/> (not legal but handle it anyway so the lexer doesn't choke on it) */
|
|
5069
5079
|
case ContentModel.STYLE:
|
|
5070
5080
|
if (selfClosed) {
|
|
5071
5081
|
return State.STYLE;
|
|
5072
|
-
} else {
|
|
5073
|
-
return State.TEXT;
|
|
5074
5082
|
}
|
|
5083
|
+
return State.TEXT;
|
|
5084
|
+
/* <style/> */
|
|
5075
5085
|
case ContentModel.TEXTAREA:
|
|
5076
5086
|
if (selfClosed) {
|
|
5077
5087
|
return State.TEXTAREA;
|
|
5078
|
-
} else {
|
|
5079
|
-
return State.TEXT;
|
|
5080
5088
|
}
|
|
5089
|
+
return State.TEXT;
|
|
5090
|
+
/* <textarea/> */
|
|
5081
5091
|
case ContentModel.TITLE:
|
|
5082
5092
|
if (selfClosed) {
|
|
5083
5093
|
return State.TITLE;
|
|
5084
|
-
} else {
|
|
5085
|
-
return State.TEXT;
|
|
5086
5094
|
}
|
|
5095
|
+
return State.TEXT;
|
|
5087
5096
|
}
|
|
5088
5097
|
}
|
|
5089
5098
|
yield* this.match(
|
|
@@ -5170,7 +5179,7 @@ class Lexer {
|
|
|
5170
5179
|
}
|
|
5171
5180
|
}
|
|
5172
5181
|
|
|
5173
|
-
const whitespace =
|
|
5182
|
+
const whitespace = /\s+/;
|
|
5174
5183
|
class AttrDelimiter extends Rule {
|
|
5175
5184
|
documentation() {
|
|
5176
5185
|
return {
|
|
@@ -5202,17 +5211,15 @@ const defaults$y = {
|
|
|
5202
5211
|
function generateRegexp(pattern) {
|
|
5203
5212
|
if (Array.isArray(pattern)) {
|
|
5204
5213
|
return new RegExp(`^(${pattern.join("|")})$`, "i");
|
|
5205
|
-
} else {
|
|
5206
|
-
return new RegExp(`^${pattern}$`, "i");
|
|
5207
5214
|
}
|
|
5215
|
+
return new RegExp(`^${pattern}$`, "i");
|
|
5208
5216
|
}
|
|
5209
5217
|
function generateMessage(name, pattern) {
|
|
5210
5218
|
if (Array.isArray(pattern)) {
|
|
5211
5219
|
const patterns = pattern.map((it) => `/${it}/`).join(", ");
|
|
5212
5220
|
return `Attribute "${name}" should match one of [${patterns}]`;
|
|
5213
|
-
} else {
|
|
5214
|
-
return `Attribute "${name}" should match /${pattern}/`;
|
|
5215
5221
|
}
|
|
5222
|
+
return `Attribute "${name}" should match /${pattern}/`;
|
|
5216
5223
|
}
|
|
5217
5224
|
function generateDescription(name, pattern) {
|
|
5218
5225
|
if (Array.isArray(pattern)) {
|
|
@@ -5221,9 +5228,8 @@ function generateDescription(name, pattern) {
|
|
|
5221
5228
|
"",
|
|
5222
5229
|
...pattern.map((it) => `- \`/${it}/\``)
|
|
5223
5230
|
].join("\n");
|
|
5224
|
-
} else {
|
|
5225
|
-
return `Attribute "${name}" should match the regular expression \`/${pattern}/\``;
|
|
5226
5231
|
}
|
|
5232
|
+
return `Attribute "${name}" should match the regular expression \`/${pattern}/\``;
|
|
5227
5233
|
}
|
|
5228
5234
|
class AttrPattern extends Rule {
|
|
5229
5235
|
pattern;
|
|
@@ -5269,9 +5275,8 @@ class AttrPattern extends Rule {
|
|
|
5269
5275
|
isIgnored(node) {
|
|
5270
5276
|
if (this.options.ignoreForeign) {
|
|
5271
5277
|
return Boolean(node.meta?.foreign);
|
|
5272
|
-
} else {
|
|
5273
|
-
return false;
|
|
5274
5278
|
}
|
|
5279
|
+
return false;
|
|
5275
5280
|
}
|
|
5276
5281
|
}
|
|
5277
5282
|
|
|
@@ -5382,9 +5387,8 @@ class AttrQuotes extends Rule {
|
|
|
5382
5387
|
resolveQuotemark(value, style) {
|
|
5383
5388
|
if (style === "auto" /* AUTO_QUOTE */) {
|
|
5384
5389
|
return value.includes('"') ? "'" : '"';
|
|
5385
|
-
} else {
|
|
5386
|
-
return style;
|
|
5387
5390
|
}
|
|
5391
|
+
return style;
|
|
5388
5392
|
}
|
|
5389
5393
|
}
|
|
5390
5394
|
function parseStyle$3(style) {
|
|
@@ -5442,11 +5446,11 @@ class AttributeAllowedValues extends Rule {
|
|
|
5442
5446
|
const allowedList = allowed.enum.map((value2) => {
|
|
5443
5447
|
if (typeof value2 === "string") {
|
|
5444
5448
|
return `- \`"${value2}"\``;
|
|
5445
|
-
}
|
|
5449
|
+
}
|
|
5450
|
+
if (value2 instanceof RegExp) {
|
|
5446
5451
|
return `- \`${value2.toString()}\``;
|
|
5447
|
-
} else {
|
|
5448
|
-
return `- ${value2.name}`;
|
|
5449
5452
|
}
|
|
5453
|
+
return `- ${value2.name}`;
|
|
5450
5454
|
});
|
|
5451
5455
|
docs.description = [
|
|
5452
5456
|
`The \`<${element}>\` element does not allow the attribute \`${attribute}\` to have the value \`"${value}"\`.`,
|
|
@@ -5490,9 +5494,8 @@ class AttributeAllowedValues extends Rule {
|
|
|
5490
5494
|
const { key, value } = attr;
|
|
5491
5495
|
if (value !== null) {
|
|
5492
5496
|
return `Attribute "${key}" has invalid value "${value.toString()}"`;
|
|
5493
|
-
} else {
|
|
5494
|
-
return `Attribute "${key}" is missing value`;
|
|
5495
5497
|
}
|
|
5498
|
+
return `Attribute "${key}" is missing value`;
|
|
5496
5499
|
}
|
|
5497
5500
|
getLocation(attr) {
|
|
5498
5501
|
return attr.valueLocation ?? attr.keyLocation;
|
|
@@ -5779,10 +5782,10 @@ class AutocompletePassword extends Rule {
|
|
|
5779
5782
|
const tokens = new DOMTokenList(raw, autocomplete.valueLocation);
|
|
5780
5783
|
const index = tokens.findIndex((token) => !isGroupingToken(token));
|
|
5781
5784
|
const value = tokens.item(index);
|
|
5782
|
-
const location = tokens.location(index);
|
|
5783
5785
|
if (!value) {
|
|
5784
5786
|
return;
|
|
5785
5787
|
}
|
|
5788
|
+
const location = tokens.location(index);
|
|
5786
5789
|
if (value === "off") {
|
|
5787
5790
|
const context = { kind: "off" };
|
|
5788
5791
|
this.report({
|
|
@@ -5867,9 +5870,8 @@ function parsePattern(pattern) {
|
|
|
5867
5870
|
function toArray$2(value) {
|
|
5868
5871
|
if (Array.isArray(value)) {
|
|
5869
5872
|
return value;
|
|
5870
|
-
} else {
|
|
5871
|
-
return [value];
|
|
5872
5873
|
}
|
|
5874
|
+
return [value];
|
|
5873
5875
|
}
|
|
5874
5876
|
function validateAllowedPatterns(patterns, allowedPatterns, ruleId) {
|
|
5875
5877
|
const extraneous = patterns.filter(isNamedPattern).filter((p) => !allowedPatterns.has(p));
|
|
@@ -5955,7 +5957,7 @@ class ClassPattern extends BasePatternRule {
|
|
|
5955
5957
|
});
|
|
5956
5958
|
}
|
|
5957
5959
|
static schema() {
|
|
5958
|
-
return
|
|
5960
|
+
return super.schema();
|
|
5959
5961
|
}
|
|
5960
5962
|
documentation(context) {
|
|
5961
5963
|
return {
|
|
@@ -6036,10 +6038,10 @@ class CloseOrder extends Rule {
|
|
|
6036
6038
|
});
|
|
6037
6039
|
this.on("tag:end", (event) => {
|
|
6038
6040
|
const current = event.target;
|
|
6039
|
-
const active = event.previous;
|
|
6040
6041
|
if (current) {
|
|
6041
6042
|
return;
|
|
6042
6043
|
}
|
|
6044
|
+
const active = event.previous;
|
|
6043
6045
|
for (const ancestor of ancestors(active)) {
|
|
6044
6046
|
if (ancestor.isRootElement() || reported.has(ancestor.unique)) {
|
|
6045
6047
|
continue;
|
|
@@ -6050,13 +6052,13 @@ class CloseOrder extends Rule {
|
|
|
6050
6052
|
});
|
|
6051
6053
|
this.on("tag:end", (event) => {
|
|
6052
6054
|
const current = event.target;
|
|
6053
|
-
const active = event.previous;
|
|
6054
6055
|
if (!current) {
|
|
6055
6056
|
return;
|
|
6056
6057
|
}
|
|
6057
6058
|
if (current.voidElement) {
|
|
6058
6059
|
return;
|
|
6059
6060
|
}
|
|
6061
|
+
const active = event.previous;
|
|
6060
6062
|
if (active.closed === Node.CLOSED_IMPLICIT_CLOSED) {
|
|
6061
6063
|
return;
|
|
6062
6064
|
}
|
|
@@ -6151,7 +6153,7 @@ class Deprecated extends Rule {
|
|
|
6151
6153
|
text.push(context.documentation);
|
|
6152
6154
|
}
|
|
6153
6155
|
const doc = {
|
|
6154
|
-
description: text.map((cur) => cur.replaceAll("$tagname", context.tagName)).join("\n\n"),
|
|
6156
|
+
description: text.map((cur) => cur.replaceAll("$tagname", () => context.tagName)).join("\n\n"),
|
|
6155
6157
|
url: "https://html-validate.org/rules/deprecated.html"
|
|
6156
6158
|
};
|
|
6157
6159
|
return doc;
|
|
@@ -6550,7 +6552,7 @@ class ElementName extends Rule {
|
|
|
6550
6552
|
];
|
|
6551
6553
|
}
|
|
6552
6554
|
setup() {
|
|
6553
|
-
const xmlns = /^
|
|
6555
|
+
const xmlns = /^[^:]+:.+$/;
|
|
6554
6556
|
this.on("tag:start", (event) => {
|
|
6555
6557
|
const target = event.target;
|
|
6556
6558
|
const tagName = target.tagName;
|
|
@@ -6589,13 +6591,12 @@ function isNativeTemplate(node) {
|
|
|
6589
6591
|
function getTransparentChildren(node, transparent) {
|
|
6590
6592
|
if (typeof transparent === "boolean") {
|
|
6591
6593
|
return node.childElements;
|
|
6592
|
-
} else {
|
|
6593
|
-
return node.childElements.filter((it) => {
|
|
6594
|
-
return transparent.some((category) => {
|
|
6595
|
-
return Validator.validatePermittedCategory(it, category, false);
|
|
6596
|
-
});
|
|
6597
|
-
});
|
|
6598
6594
|
}
|
|
6595
|
+
return node.childElements.filter((it) => {
|
|
6596
|
+
return transparent.some((category) => {
|
|
6597
|
+
return Validator.validatePermittedCategory(it, category, false);
|
|
6598
|
+
});
|
|
6599
|
+
});
|
|
6599
6600
|
}
|
|
6600
6601
|
function getRuleDescription$2(context) {
|
|
6601
6602
|
switch (context.kind) {
|
|
@@ -6627,6 +6628,7 @@ class ElementPermittedContent extends Rule {
|
|
|
6627
6628
|
[
|
|
6628
6629
|
() => this.validatePermittedContent(node, parent),
|
|
6629
6630
|
() => this.validatePermittedDescendant(node, parent)
|
|
6631
|
+
/* eslint-disable-next-line unicorn/no-unused-array-method-return -- technical debt, should use iterator helpers */
|
|
6630
6632
|
].some((fn) => fn());
|
|
6631
6633
|
});
|
|
6632
6634
|
});
|
|
@@ -6772,14 +6774,12 @@ function getRuleDescription$1(context) {
|
|
|
6772
6774
|
const allowed = rules.filter(isCategoryOrTag).map((it) => {
|
|
6773
6775
|
if (isCategory$1(it)) {
|
|
6774
6776
|
return `- any ${it.slice(1)} element`;
|
|
6775
|
-
} else {
|
|
6776
|
-
return `- \`<${it}>\``;
|
|
6777
6777
|
}
|
|
6778
|
+
return `- \`<${it}>\``;
|
|
6778
6779
|
});
|
|
6779
6780
|
return [preamble, "", "Allowed parents one of:", "", ...allowed];
|
|
6780
|
-
} else {
|
|
6781
|
-
return [preamble];
|
|
6782
6781
|
}
|
|
6782
|
+
return [preamble];
|
|
6783
6783
|
}
|
|
6784
6784
|
function formatMessage$1(node, parent, rules) {
|
|
6785
6785
|
const nodeName = node.annotatedName;
|
|
@@ -6831,7 +6831,7 @@ class ElementPermittedParent extends Rule {
|
|
|
6831
6831
|
}
|
|
6832
6832
|
|
|
6833
6833
|
function isTagnameOnly(value) {
|
|
6834
|
-
return /^[\dA-
|
|
6834
|
+
return /^[\dA-Z-]+$/i.test(value);
|
|
6835
6835
|
}
|
|
6836
6836
|
function getRuleDescription(context) {
|
|
6837
6837
|
const escaped = context.ancestor.map((it) => `\`${it}\``);
|
|
@@ -6894,9 +6894,8 @@ function normalizeRequired(element, attr) {
|
|
|
6894
6894
|
default:
|
|
6895
6895
|
return result;
|
|
6896
6896
|
}
|
|
6897
|
-
} else {
|
|
6898
|
-
return required ? defaultMessage : false;
|
|
6899
6897
|
}
|
|
6898
|
+
return required ? defaultMessage : false;
|
|
6900
6899
|
}
|
|
6901
6900
|
class ElementRequiredAttributes extends Rule {
|
|
6902
6901
|
documentation(context) {
|
|
@@ -6978,7 +6977,8 @@ const selector = ["h1", "h2", "h3", "h4", "h5", "h6"].join(",");
|
|
|
6978
6977
|
function hasImgAltText$1(node) {
|
|
6979
6978
|
if (node.is("img")) {
|
|
6980
6979
|
return hasAltText(node);
|
|
6981
|
-
}
|
|
6980
|
+
}
|
|
6981
|
+
if (node.is("svg")) {
|
|
6982
6982
|
return node.textContent.trim() !== "";
|
|
6983
6983
|
}
|
|
6984
6984
|
return false;
|
|
@@ -7259,21 +7259,19 @@ class FormDupName extends Rule {
|
|
|
7259
7259
|
const existing = group.cacheGet(UNIQUE_CACHE_KEY);
|
|
7260
7260
|
if (existing) {
|
|
7261
7261
|
return existing;
|
|
7262
|
-
} else {
|
|
7263
|
-
const elements = /* @__PURE__ */ new Map();
|
|
7264
|
-
group.cacheSet(UNIQUE_CACHE_KEY, elements);
|
|
7265
|
-
return elements;
|
|
7266
7262
|
}
|
|
7263
|
+
const elements = /* @__PURE__ */ new Map();
|
|
7264
|
+
group.cacheSet(UNIQUE_CACHE_KEY, elements);
|
|
7265
|
+
return elements;
|
|
7267
7266
|
}
|
|
7268
7267
|
getSharedElements(group) {
|
|
7269
7268
|
const existing = group.cacheGet(SHARED_CACHE_KEY);
|
|
7270
7269
|
if (existing) {
|
|
7271
7270
|
return existing;
|
|
7272
|
-
} else {
|
|
7273
|
-
const elements = /* @__PURE__ */ new Map();
|
|
7274
|
-
group.cacheSet(SHARED_CACHE_KEY, elements);
|
|
7275
|
-
return elements;
|
|
7276
7271
|
}
|
|
7272
|
+
const elements = /* @__PURE__ */ new Map();
|
|
7273
|
+
group.cacheSet(SHARED_CACHE_KEY, elements);
|
|
7274
|
+
return elements;
|
|
7277
7275
|
}
|
|
7278
7276
|
}
|
|
7279
7277
|
|
|
@@ -7287,12 +7285,11 @@ function isRelevant$5(event) {
|
|
|
7287
7285
|
return Boolean(node.meta?.heading);
|
|
7288
7286
|
}
|
|
7289
7287
|
function extractLevel(node) {
|
|
7290
|
-
const match = /^
|
|
7288
|
+
const match = /^H(\d)$/i.exec(node.tagName);
|
|
7291
7289
|
if (match) {
|
|
7292
|
-
return
|
|
7293
|
-
} else {
|
|
7294
|
-
return null;
|
|
7290
|
+
return Math.trunc(Number(match[1]));
|
|
7295
7291
|
}
|
|
7292
|
+
return null;
|
|
7296
7293
|
}
|
|
7297
7294
|
function parseMaxInitial(value) {
|
|
7298
7295
|
if (value === false || value === "any") {
|
|
@@ -7302,7 +7299,7 @@ function parseMaxInitial(value) {
|
|
|
7302
7299
|
if (!match) {
|
|
7303
7300
|
return 1;
|
|
7304
7301
|
}
|
|
7305
|
-
return
|
|
7302
|
+
return Math.trunc(Number(match[1]));
|
|
7306
7303
|
}
|
|
7307
7304
|
class HeadingLevel extends Rule {
|
|
7308
7305
|
minInitialRank;
|
|
@@ -7569,7 +7566,7 @@ class IdPattern extends BasePatternRule {
|
|
|
7569
7566
|
});
|
|
7570
7567
|
}
|
|
7571
7568
|
static schema() {
|
|
7572
|
-
return
|
|
7569
|
+
return super.schema();
|
|
7573
7570
|
}
|
|
7574
7571
|
documentation(context) {
|
|
7575
7572
|
return {
|
|
@@ -7791,24 +7788,23 @@ function isHidden(node, context) {
|
|
|
7791
7788
|
const { reference } = context;
|
|
7792
7789
|
if (reference?.isSameNode(node)) {
|
|
7793
7790
|
return false;
|
|
7794
|
-
} else {
|
|
7795
|
-
return !inAccessibilityTree(node);
|
|
7796
7791
|
}
|
|
7792
|
+
return !inAccessibilityTree(node);
|
|
7797
7793
|
}
|
|
7798
7794
|
function hasImgAltText(node, context) {
|
|
7799
7795
|
if (node.is("img")) {
|
|
7800
7796
|
return hasAltText(node);
|
|
7801
|
-
}
|
|
7797
|
+
}
|
|
7798
|
+
if (node.is("svg")) {
|
|
7802
7799
|
return node.textContent.trim() !== "";
|
|
7803
|
-
}
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
}
|
|
7800
|
+
}
|
|
7801
|
+
for (const img of node.querySelectorAll("img, svg")) {
|
|
7802
|
+
const hasName = hasAccessibleNameImpl(img, context);
|
|
7803
|
+
if (hasName) {
|
|
7804
|
+
return true;
|
|
7809
7805
|
}
|
|
7810
|
-
return false;
|
|
7811
7806
|
}
|
|
7807
|
+
return false;
|
|
7812
7808
|
}
|
|
7813
7809
|
function hasLabel(node) {
|
|
7814
7810
|
const value = node.getAttributeValue("aria-label") ?? "";
|
|
@@ -7939,7 +7935,7 @@ class InputMissingLabel extends Rule {
|
|
|
7939
7935
|
this.report(elem, `<${elem.tagName}> element has <label> but <label> element is hidden`);
|
|
7940
7936
|
return;
|
|
7941
7937
|
}
|
|
7942
|
-
if (
|
|
7938
|
+
if (labels.every((label) => !hasAccessibleName(root, label))) {
|
|
7943
7939
|
this.report(elem, `<${elem.tagName}> element has <label> but <label> has no text`);
|
|
7944
7940
|
}
|
|
7945
7941
|
}
|
|
@@ -8126,12 +8122,11 @@ function parseContent(text) {
|
|
|
8126
8122
|
const match = /^(\d+)(?:\s*;\s*url=(.*))?/i.exec(text);
|
|
8127
8123
|
if (match) {
|
|
8128
8124
|
return {
|
|
8129
|
-
delay:
|
|
8125
|
+
delay: Math.trunc(Number(match[1])),
|
|
8130
8126
|
url: match[2]
|
|
8131
8127
|
};
|
|
8132
|
-
} else {
|
|
8133
|
-
return null;
|
|
8134
8128
|
}
|
|
8129
|
+
return null;
|
|
8135
8130
|
}
|
|
8136
8131
|
|
|
8137
8132
|
class MissingDoctype extends Rule {
|
|
@@ -8208,7 +8203,7 @@ class NamePattern extends BasePatternRule {
|
|
|
8208
8203
|
});
|
|
8209
8204
|
}
|
|
8210
8205
|
static schema() {
|
|
8211
|
-
return
|
|
8206
|
+
return super.schema();
|
|
8212
8207
|
}
|
|
8213
8208
|
documentation(context) {
|
|
8214
8209
|
return {
|
|
@@ -8391,10 +8386,10 @@ class NoDeprecatedAttr extends Rule {
|
|
|
8391
8386
|
this.on("attr", (event) => {
|
|
8392
8387
|
const node = event.target;
|
|
8393
8388
|
const meta = node.meta;
|
|
8394
|
-
const attr = event.key.toLowerCase();
|
|
8395
8389
|
if (meta === null) {
|
|
8396
8390
|
return;
|
|
8397
8391
|
}
|
|
8392
|
+
const attr = event.key.toLowerCase();
|
|
8398
8393
|
const metaAttribute = meta.attributes[attr];
|
|
8399
8394
|
if (!metaAttribute) {
|
|
8400
8395
|
return;
|
|
@@ -8428,7 +8423,7 @@ class NoDupAttr extends Rule {
|
|
|
8428
8423
|
return;
|
|
8429
8424
|
}
|
|
8430
8425
|
const name = event.key.toLowerCase();
|
|
8431
|
-
if (name
|
|
8426
|
+
if (Object.hasOwn(attr, name)) {
|
|
8432
8427
|
this.report(event.target, `Attribute "${name}" duplicated`, event.keyLocation);
|
|
8433
8428
|
}
|
|
8434
8429
|
attr[event.key] = true;
|
|
@@ -8501,10 +8496,9 @@ function getExisting(element, root) {
|
|
|
8501
8496
|
const existing = group.cacheGet(CACHE_KEY);
|
|
8502
8497
|
if (existing) {
|
|
8503
8498
|
return existing;
|
|
8504
|
-
} else {
|
|
8505
|
-
const existing2 = /* @__PURE__ */ new Set();
|
|
8506
|
-
return group.cacheSet(CACHE_KEY, existing2);
|
|
8507
8499
|
}
|
|
8500
|
+
const value = /* @__PURE__ */ new Set();
|
|
8501
|
+
return group.cacheSet(CACHE_KEY, value);
|
|
8508
8502
|
}
|
|
8509
8503
|
|
|
8510
8504
|
function isRelevant$2(event) {
|
|
@@ -8775,10 +8769,11 @@ class NoMissingReferences extends Rule {
|
|
|
8775
8769
|
}
|
|
8776
8770
|
}
|
|
8777
8771
|
validateSingle(document, node, attr, id) {
|
|
8778
|
-
if (idMissing(document, id)) {
|
|
8779
|
-
|
|
8780
|
-
this.report(node, `Element references missing id "${id}"`, attr.valueLocation, context);
|
|
8772
|
+
if (!idMissing(document, id)) {
|
|
8773
|
+
return;
|
|
8781
8774
|
}
|
|
8775
|
+
const context = { key: attr.key, value: id };
|
|
8776
|
+
this.report(node, `Element references missing id "${id}"`, attr.valueLocation, context);
|
|
8782
8777
|
}
|
|
8783
8778
|
validateList(document, node, attr, values) {
|
|
8784
8779
|
const parsed = new DOMTokenList(values, attr.valueLocation);
|
|
@@ -8818,9 +8813,9 @@ class NoMultipleMain extends Rule {
|
|
|
8818
8813
|
const defaults$f = {
|
|
8819
8814
|
relaxed: false
|
|
8820
8815
|
};
|
|
8821
|
-
const textRegexp = /(<|&(?![\d#A-
|
|
8822
|
-
const unquotedAttrRegexp = /(["'<=>`]|&(?![\d#A-
|
|
8823
|
-
const matchTemplate = /^(
|
|
8816
|
+
const textRegexp = /(<|&(?![\d#A-Z]+;))/gi;
|
|
8817
|
+
const unquotedAttrRegexp = /(["'<=>`]|&(?![\d#A-Z]+;))/gi;
|
|
8818
|
+
const matchTemplate = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)$/s;
|
|
8824
8819
|
const replacementTable = {
|
|
8825
8820
|
'"': """,
|
|
8826
8821
|
"&": "&",
|
|
@@ -9052,7 +9047,7 @@ class NoRedundantRole extends Rule {
|
|
|
9052
9047
|
}
|
|
9053
9048
|
}
|
|
9054
9049
|
|
|
9055
|
-
const xmlns = /^
|
|
9050
|
+
const xmlns = /^[^:]+:.+$/;
|
|
9056
9051
|
const defaults$d = {
|
|
9057
9052
|
ignoreForeign: true,
|
|
9058
9053
|
ignoreXML: true
|
|
@@ -9174,11 +9169,11 @@ class NoUnknownAttributes extends Rule {
|
|
|
9174
9169
|
this.on("attr", (event) => {
|
|
9175
9170
|
const node = event.target;
|
|
9176
9171
|
const meta = node.meta;
|
|
9177
|
-
const attr = event.key.toLowerCase();
|
|
9178
9172
|
if (meta === null) {
|
|
9179
9173
|
return;
|
|
9180
9174
|
}
|
|
9181
|
-
|
|
9175
|
+
const attr = event.key.toLowerCase();
|
|
9176
|
+
if (Object.hasOwn(meta.attributes, attr)) {
|
|
9182
9177
|
return;
|
|
9183
9178
|
}
|
|
9184
9179
|
if (isPatternAttribute(attr, meta.patternAttributes)) {
|
|
@@ -9585,7 +9580,7 @@ const defaults$7 = {
|
|
|
9585
9580
|
include: null,
|
|
9586
9581
|
exclude: null
|
|
9587
9582
|
};
|
|
9588
|
-
const crossorigin =
|
|
9583
|
+
const crossorigin = /^(?:\w+:\/\/|\/\/)/;
|
|
9589
9584
|
const supportSri = {
|
|
9590
9585
|
link: "href",
|
|
9591
9586
|
script: "src"
|
|
@@ -9798,7 +9793,10 @@ function constructRegex(characters) {
|
|
|
9798
9793
|
return new RegExp(pattern, "g");
|
|
9799
9794
|
}
|
|
9800
9795
|
function getText(node) {
|
|
9801
|
-
const match = /^(\s*)(.*)$/.exec(node.textContent);
|
|
9796
|
+
const match = /^(\s*)(\S.*)$/.exec(node.textContent);
|
|
9797
|
+
if (!match) {
|
|
9798
|
+
return [0, ""];
|
|
9799
|
+
}
|
|
9802
9800
|
const [, leading, text] = match;
|
|
9803
9801
|
return [leading.length, text.trimEnd()];
|
|
9804
9802
|
}
|
|
@@ -9951,9 +9949,8 @@ function hasDefaultText(node) {
|
|
|
9951
9949
|
function isNonEmptyText(node) {
|
|
9952
9950
|
if (isTextNode(node)) {
|
|
9953
9951
|
return node.isDynamic || node.textContent.trim() !== "";
|
|
9954
|
-
} else {
|
|
9955
|
-
return false;
|
|
9956
9952
|
}
|
|
9953
|
+
return false;
|
|
9957
9954
|
}
|
|
9958
9955
|
function haveAccessibleText(node) {
|
|
9959
9956
|
if (!inAccessibilityTree(node)) {
|
|
@@ -10088,15 +10085,14 @@ function getTextFromReference(document, id) {
|
|
|
10088
10085
|
const ref = document.querySelector(selector);
|
|
10089
10086
|
if (ref) {
|
|
10090
10087
|
return ref.textContent;
|
|
10091
|
-
} else {
|
|
10092
|
-
return selector;
|
|
10093
10088
|
}
|
|
10089
|
+
return selector;
|
|
10094
10090
|
}
|
|
10095
10091
|
function groupBy(values, callback) {
|
|
10096
10092
|
const result = {};
|
|
10097
10093
|
for (const value of values) {
|
|
10098
10094
|
const key = callback(value);
|
|
10099
|
-
if (key
|
|
10095
|
+
if (Object.hasOwn(result, key)) {
|
|
10100
10096
|
result[key].push(value);
|
|
10101
10097
|
} else {
|
|
10102
10098
|
result[key] = [value];
|
|
@@ -10196,7 +10192,7 @@ const defaults$5 = {
|
|
|
10196
10192
|
ignoreCase: false,
|
|
10197
10193
|
requireSemicolon: true
|
|
10198
10194
|
};
|
|
10199
|
-
const regexp$1 = /&(?:[\da-z]+|#x?[\da-f]+)(
|
|
10195
|
+
const regexp$1 = /&(?:[\da-z]+|#x?[\da-f]+)([^\da-z]|$)/gi;
|
|
10200
10196
|
const lowercaseEntities = entities$1.map((it) => it.toLowerCase());
|
|
10201
10197
|
function isNumerical(entity) {
|
|
10202
10198
|
return entity.startsWith("&#");
|
|
@@ -10275,9 +10271,8 @@ class UnknownCharReference extends Rule {
|
|
|
10275
10271
|
get entities() {
|
|
10276
10272
|
if (this.options.ignoreCase) {
|
|
10277
10273
|
return lowercaseEntities;
|
|
10278
|
-
} else {
|
|
10279
|
-
return entities$1;
|
|
10280
10274
|
}
|
|
10275
|
+
return entities$1;
|
|
10281
10276
|
}
|
|
10282
10277
|
findCharacterReferences(node, text, location, { isAttribute }) {
|
|
10283
10278
|
const delimiter = text.search(/[#?]/);
|
|
@@ -10643,7 +10638,6 @@ class ValidAutocomplete extends Rule {
|
|
|
10643
10638
|
}
|
|
10644
10639
|
validateControlAutocomplete(node, tokens, keyLocation) {
|
|
10645
10640
|
const type = node.getAttributeValue("type") ?? "text";
|
|
10646
|
-
const mantle = type !== "hidden" ? "expectation" : "anchor";
|
|
10647
10641
|
if (isDisallowedType(node, type)) {
|
|
10648
10642
|
const context = {
|
|
10649
10643
|
msg: 0 /* InvalidAttribute */,
|
|
@@ -10658,6 +10652,7 @@ class ValidAutocomplete extends Rule {
|
|
|
10658
10652
|
return;
|
|
10659
10653
|
}
|
|
10660
10654
|
if (tokens.includes("on") || tokens.includes("off")) {
|
|
10655
|
+
const mantle = type !== "hidden" ? "expectation" : "anchor";
|
|
10661
10656
|
this.validateOnOff(node, mantle, tokens);
|
|
10662
10657
|
return;
|
|
10663
10658
|
}
|
|
@@ -10781,44 +10776,46 @@ class ValidAutocomplete extends Rule {
|
|
|
10781
10776
|
* Ensure contact token is only used with field names from the second list.
|
|
10782
10777
|
*/
|
|
10783
10778
|
validateContact(node, tokens, order) {
|
|
10784
|
-
if (order.includes("contact")
|
|
10785
|
-
|
|
10786
|
-
|
|
10779
|
+
if (!order.includes("contact") || !order.includes("field1")) {
|
|
10780
|
+
return;
|
|
10781
|
+
}
|
|
10782
|
+
const a = order.indexOf("field1");
|
|
10783
|
+
const b = order.indexOf("contact");
|
|
10784
|
+
const context = {
|
|
10785
|
+
msg: 4 /* InvalidCombination */,
|
|
10786
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
10787
|
+
first: tokens.item(a),
|
|
10788
|
+
second: tokens.item(b)
|
|
10789
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
10790
|
+
};
|
|
10791
|
+
this.report({
|
|
10792
|
+
node,
|
|
10793
|
+
message: getTerminalMessage(context),
|
|
10794
|
+
location: tokens.location(b),
|
|
10795
|
+
context
|
|
10796
|
+
});
|
|
10797
|
+
}
|
|
10798
|
+
validateOrder(node, tokens, order) {
|
|
10799
|
+
const indicies = order.map((it) => expectedOrder.indexOf(it));
|
|
10800
|
+
for (let i = 0; i < indicies.length - 1; i++) {
|
|
10801
|
+
if (indicies[0] <= indicies[i + 1]) {
|
|
10802
|
+
continue;
|
|
10803
|
+
}
|
|
10787
10804
|
const context = {
|
|
10788
|
-
msg:
|
|
10805
|
+
msg: 2 /* InvalidOrder */,
|
|
10789
10806
|
/* eslint-disable @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
10790
|
-
first: tokens.item(
|
|
10791
|
-
second: tokens.item(
|
|
10807
|
+
first: tokens.item(i),
|
|
10808
|
+
second: tokens.item(i + 1)
|
|
10792
10809
|
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
10793
10810
|
};
|
|
10794
10811
|
this.report({
|
|
10795
10812
|
node,
|
|
10796
10813
|
message: getTerminalMessage(context),
|
|
10797
|
-
location: tokens.location(
|
|
10814
|
+
location: tokens.location(i + 1),
|
|
10798
10815
|
context
|
|
10799
10816
|
});
|
|
10800
10817
|
}
|
|
10801
10818
|
}
|
|
10802
|
-
validateOrder(node, tokens, order) {
|
|
10803
|
-
const indicies = order.map((it) => expectedOrder.indexOf(it));
|
|
10804
|
-
for (let i = 0; i < indicies.length - 1; i++) {
|
|
10805
|
-
if (indicies[0] > indicies[i + 1]) {
|
|
10806
|
-
const context = {
|
|
10807
|
-
msg: 2 /* InvalidOrder */,
|
|
10808
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
10809
|
-
first: tokens.item(i),
|
|
10810
|
-
second: tokens.item(i + 1)
|
|
10811
|
-
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
10812
|
-
};
|
|
10813
|
-
this.report({
|
|
10814
|
-
node,
|
|
10815
|
-
message: getTerminalMessage(context),
|
|
10816
|
-
location: tokens.location(i + 1),
|
|
10817
|
-
context
|
|
10818
|
-
});
|
|
10819
|
-
}
|
|
10820
|
-
}
|
|
10821
|
-
}
|
|
10822
10819
|
validateControlGroup(node, tokens, fieldTokens) {
|
|
10823
10820
|
const numFields = fieldTokens.filter(Boolean).length;
|
|
10824
10821
|
if (numFields === 0) {
|
|
@@ -10910,7 +10907,7 @@ class ValidID extends Rule {
|
|
|
10910
10907
|
documentation(context) {
|
|
10911
10908
|
const { relaxed } = this.options;
|
|
10912
10909
|
const { kind, id } = context;
|
|
10913
|
-
const message = this.messages[kind].replace(`"{{ id }}"`, "`{{ id }}`").replace("id", "ID").replace(
|
|
10910
|
+
const message = this.messages[kind].replace(`"{{ id }}"`, "`{{ id }}`").replace("id", "ID").replace(/^./, (m) => m.toUpperCase());
|
|
10914
10911
|
const relaxedDescription = relaxed ? [] : [
|
|
10915
10912
|
" - ID must begin with a letter",
|
|
10916
10913
|
" - ID must only contain letters, digits, `-` and `_`"
|
|
@@ -10948,7 +10945,7 @@ class ValidID extends Rule {
|
|
|
10948
10945
|
if (relaxed) {
|
|
10949
10946
|
return;
|
|
10950
10947
|
}
|
|
10951
|
-
if (
|
|
10948
|
+
if (new RegExp("^\\P{L}", "u").test(value)) {
|
|
10952
10949
|
const context = { kind: 3 /* LEADING_CHARACTER */, id: value };
|
|
10953
10950
|
this.report(event.target, this.messages[context.kind], event.valueLocation, context);
|
|
10954
10951
|
return;
|
|
@@ -11309,7 +11306,7 @@ function isSimpleTable(table) {
|
|
|
11309
11306
|
return false;
|
|
11310
11307
|
}
|
|
11311
11308
|
const numColumns = cells[0].length;
|
|
11312
|
-
if (
|
|
11309
|
+
if (cells.some((row) => row.length !== numColumns)) {
|
|
11313
11310
|
return false;
|
|
11314
11311
|
}
|
|
11315
11312
|
const shape = getShape(cells);
|
|
@@ -11963,7 +11960,7 @@ class ResolvedConfig {
|
|
|
11963
11960
|
}
|
|
11964
11961
|
|
|
11965
11962
|
function haveResolver(key, value) {
|
|
11966
|
-
return key
|
|
11963
|
+
return Object.hasOwn(value, key);
|
|
11967
11964
|
}
|
|
11968
11965
|
function haveConfigResolver(value) {
|
|
11969
11966
|
return haveResolver("resolveConfig", value);
|
|
@@ -11978,7 +11975,10 @@ function haveTransformerResolver(value) {
|
|
|
11978
11975
|
return haveResolver("resolveTransformer", value);
|
|
11979
11976
|
}
|
|
11980
11977
|
function resolveConfig(resolvers, id, options) {
|
|
11981
|
-
for (const resolver of resolvers
|
|
11978
|
+
for (const resolver of resolvers) {
|
|
11979
|
+
if (!haveConfigResolver(resolver)) {
|
|
11980
|
+
continue;
|
|
11981
|
+
}
|
|
11982
11982
|
const config = resolver.resolveConfig(id, options);
|
|
11983
11983
|
if (isThenable(config)) {
|
|
11984
11984
|
return resolveConfigAsync(resolvers, id, options);
|
|
@@ -11990,7 +11990,10 @@ function resolveConfig(resolvers, id, options) {
|
|
|
11990
11990
|
throw new UserError(`Failed to load configuration from "${id}"`);
|
|
11991
11991
|
}
|
|
11992
11992
|
async function resolveConfigAsync(resolvers, id, options) {
|
|
11993
|
-
for (const resolver of resolvers
|
|
11993
|
+
for (const resolver of resolvers) {
|
|
11994
|
+
if (!haveConfigResolver(resolver)) {
|
|
11995
|
+
continue;
|
|
11996
|
+
}
|
|
11994
11997
|
const config = await resolver.resolveConfig(id, options);
|
|
11995
11998
|
if (config) {
|
|
11996
11999
|
return config;
|
|
@@ -11999,7 +12002,10 @@ async function resolveConfigAsync(resolvers, id, options) {
|
|
|
11999
12002
|
throw new UserError(`Failed to load configuration from "${id}"`);
|
|
12000
12003
|
}
|
|
12001
12004
|
function resolveElements(resolvers, id, options) {
|
|
12002
|
-
for (const resolver of resolvers
|
|
12005
|
+
for (const resolver of resolvers) {
|
|
12006
|
+
if (!haveElementsResolver(resolver)) {
|
|
12007
|
+
continue;
|
|
12008
|
+
}
|
|
12003
12009
|
const elements = resolver.resolveElements(id, options);
|
|
12004
12010
|
if (isThenable(elements)) {
|
|
12005
12011
|
return resolveElementsAsync(resolvers, id, options);
|
|
@@ -12011,7 +12017,10 @@ function resolveElements(resolvers, id, options) {
|
|
|
12011
12017
|
throw new UserError(`Failed to load elements from "${id}"`);
|
|
12012
12018
|
}
|
|
12013
12019
|
async function resolveElementsAsync(resolvers, id, options) {
|
|
12014
|
-
for (const resolver of resolvers
|
|
12020
|
+
for (const resolver of resolvers) {
|
|
12021
|
+
if (!haveElementsResolver(resolver)) {
|
|
12022
|
+
continue;
|
|
12023
|
+
}
|
|
12015
12024
|
const elements = await resolver.resolveElements(id, options);
|
|
12016
12025
|
if (elements) {
|
|
12017
12026
|
return elements;
|
|
@@ -12020,7 +12029,10 @@ async function resolveElementsAsync(resolvers, id, options) {
|
|
|
12020
12029
|
throw new UserError(`Failed to load elements from "${id}"`);
|
|
12021
12030
|
}
|
|
12022
12031
|
function resolvePlugin(resolvers, id, options) {
|
|
12023
|
-
for (const resolver of resolvers
|
|
12032
|
+
for (const resolver of resolvers) {
|
|
12033
|
+
if (!havePluginResolver(resolver)) {
|
|
12034
|
+
continue;
|
|
12035
|
+
}
|
|
12024
12036
|
const plugin = resolver.resolvePlugin(id, options);
|
|
12025
12037
|
if (isThenable(plugin)) {
|
|
12026
12038
|
return resolvePluginAsync(resolvers, id, options);
|
|
@@ -12032,7 +12044,10 @@ function resolvePlugin(resolvers, id, options) {
|
|
|
12032
12044
|
throw new UserError(`Failed to load plugin from "${id}"`);
|
|
12033
12045
|
}
|
|
12034
12046
|
async function resolvePluginAsync(resolvers, id, options) {
|
|
12035
|
-
for (const resolver of resolvers
|
|
12047
|
+
for (const resolver of resolvers) {
|
|
12048
|
+
if (!havePluginResolver(resolver)) {
|
|
12049
|
+
continue;
|
|
12050
|
+
}
|
|
12036
12051
|
const plugin = await resolver.resolvePlugin(id, options);
|
|
12037
12052
|
if (plugin) {
|
|
12038
12053
|
return plugin;
|
|
@@ -12041,7 +12056,10 @@ async function resolvePluginAsync(resolvers, id, options) {
|
|
|
12041
12056
|
throw new UserError(`Failed to load plugin from "${id}"`);
|
|
12042
12057
|
}
|
|
12043
12058
|
function resolveTransformer(resolvers, id, options) {
|
|
12044
|
-
for (const resolver of resolvers
|
|
12059
|
+
for (const resolver of resolvers) {
|
|
12060
|
+
if (!haveTransformerResolver(resolver)) {
|
|
12061
|
+
continue;
|
|
12062
|
+
}
|
|
12045
12063
|
const transformer = resolver.resolveTransformer(id, options);
|
|
12046
12064
|
if (isThenable(transformer)) {
|
|
12047
12065
|
return resolveTransformerAsync(resolvers, id, options);
|
|
@@ -12053,7 +12071,10 @@ function resolveTransformer(resolvers, id, options) {
|
|
|
12053
12071
|
throw new UserError(`Failed to load transformer from "${id}"`);
|
|
12054
12072
|
}
|
|
12055
12073
|
async function resolveTransformerAsync(resolvers, id, options) {
|
|
12056
|
-
for (const resolver of resolvers
|
|
12074
|
+
for (const resolver of resolvers) {
|
|
12075
|
+
if (!haveTransformerResolver(resolver)) {
|
|
12076
|
+
continue;
|
|
12077
|
+
}
|
|
12057
12078
|
const transformer = await resolver.resolveTransformer(id, options);
|
|
12058
12079
|
if (transformer) {
|
|
12059
12080
|
return transformer;
|
|
@@ -12093,9 +12114,12 @@ function staticResolver(map = {}) {
|
|
|
12093
12114
|
};
|
|
12094
12115
|
}
|
|
12095
12116
|
|
|
12096
|
-
const ajv =
|
|
12097
|
-
|
|
12098
|
-
|
|
12117
|
+
const ajv = (() => {
|
|
12118
|
+
const ajv2 = new Ajv({ strict: true, strictTuples: true, strictTypes: true });
|
|
12119
|
+
ajv2.addMetaSchema(ajvSchemaDraft);
|
|
12120
|
+
ajv2.addKeyword(ajvFunctionKeyword);
|
|
12121
|
+
return ajv2;
|
|
12122
|
+
})();
|
|
12099
12123
|
const validator = ajv.compile(configurationSchema);
|
|
12100
12124
|
function overwriteMerge(_a, b) {
|
|
12101
12125
|
return b;
|
|
@@ -12114,18 +12138,16 @@ function mergeInternal(base, rhs) {
|
|
|
12114
12138
|
function toArray$1(value) {
|
|
12115
12139
|
if (Array.isArray(value)) {
|
|
12116
12140
|
return value;
|
|
12117
|
-
} else {
|
|
12118
|
-
return [value];
|
|
12119
12141
|
}
|
|
12142
|
+
return [value];
|
|
12120
12143
|
}
|
|
12121
12144
|
function transformerEntries(transform) {
|
|
12122
12145
|
return Object.entries(transform).map(([pattern, value]) => {
|
|
12123
12146
|
const regex = new RegExp(pattern);
|
|
12124
12147
|
if (typeof value === "string") {
|
|
12125
12148
|
return { kind: "import", pattern: regex, name: value };
|
|
12126
|
-
} else {
|
|
12127
|
-
return { kind: "function", pattern: regex, function: value };
|
|
12128
12149
|
}
|
|
12150
|
+
return { kind: "function", pattern: regex, function: value };
|
|
12129
12151
|
});
|
|
12130
12152
|
}
|
|
12131
12153
|
class Config {
|
|
@@ -12150,8 +12172,8 @@ class Config {
|
|
|
12150
12172
|
* Create configuration from object.
|
|
12151
12173
|
*/
|
|
12152
12174
|
static fromObject(resolvers, options, filename = null) {
|
|
12153
|
-
|
|
12154
|
-
return
|
|
12175
|
+
this.validate(options, filename);
|
|
12176
|
+
return this.create(resolvers, options);
|
|
12155
12177
|
}
|
|
12156
12178
|
/**
|
|
12157
12179
|
* Read configuration from filename.
|
|
@@ -12165,10 +12187,9 @@ class Config {
|
|
|
12165
12187
|
static fromFile(resolvers, filename) {
|
|
12166
12188
|
const configData = resolveConfig(toArray$1(resolvers), filename, { cache: false });
|
|
12167
12189
|
if (isThenable(configData)) {
|
|
12168
|
-
return configData.then((configData2) =>
|
|
12169
|
-
} else {
|
|
12170
|
-
return Config.fromObject(resolvers, configData, filename);
|
|
12190
|
+
return configData.then((configData2) => this.fromObject(resolvers, configData2, filename));
|
|
12171
12191
|
}
|
|
12192
|
+
return this.fromObject(resolvers, configData, filename);
|
|
12172
12193
|
}
|
|
12173
12194
|
/**
|
|
12174
12195
|
* Validate configuration data.
|
|
@@ -12190,8 +12211,8 @@ class Config {
|
|
|
12190
12211
|
);
|
|
12191
12212
|
}
|
|
12192
12213
|
if (configData.rules) {
|
|
12193
|
-
const normalizedRules =
|
|
12194
|
-
for (const [ruleId, [, ruleOptions]] of normalizedRules
|
|
12214
|
+
const normalizedRules = this.getRulesObject(configData.rules);
|
|
12215
|
+
for (const [ruleId, [, ruleOptions]] of normalizedRules) {
|
|
12195
12216
|
const cls = bundledRules[ruleId];
|
|
12196
12217
|
const path = `/rules/${ruleId}/1`;
|
|
12197
12218
|
Rule.validateOptions(cls, ruleId, path, ruleOptions, filename, configData);
|
|
@@ -12214,9 +12235,8 @@ class Config {
|
|
|
12214
12235
|
return plugins.then((plugins2) => {
|
|
12215
12236
|
return instance.init(options, plugins2);
|
|
12216
12237
|
});
|
|
12217
|
-
} else {
|
|
12218
|
-
return instance.init(options, plugins);
|
|
12219
12238
|
}
|
|
12239
|
+
return instance.init(options, plugins);
|
|
12220
12240
|
}
|
|
12221
12241
|
init(options, plugins) {
|
|
12222
12242
|
this.plugins = plugins;
|
|
@@ -12233,9 +12253,8 @@ class Config {
|
|
|
12233
12253
|
const extendedConfig = this.extendConfig(this.config.extends ?? []);
|
|
12234
12254
|
if (isThenable(extendedConfig)) {
|
|
12235
12255
|
return extendedConfig.then((extended) => update(extended));
|
|
12236
|
-
} else {
|
|
12237
|
-
return update(extendedConfig);
|
|
12238
12256
|
}
|
|
12257
|
+
return update(extendedConfig);
|
|
12239
12258
|
}
|
|
12240
12259
|
/**
|
|
12241
12260
|
* @internal
|
|
@@ -12277,12 +12296,11 @@ class Config {
|
|
|
12277
12296
|
instance.extendMeta(instance.plugins);
|
|
12278
12297
|
return instance;
|
|
12279
12298
|
});
|
|
12280
|
-
} else {
|
|
12281
|
-
instance.plugins = plugins;
|
|
12282
|
-
instance.configurations = instance.loadConfigurations(instance.plugins);
|
|
12283
|
-
instance.extendMeta(instance.plugins);
|
|
12284
|
-
return instance;
|
|
12285
12299
|
}
|
|
12300
|
+
instance.plugins = plugins;
|
|
12301
|
+
instance.configurations = instance.loadConfigurations(instance.plugins);
|
|
12302
|
+
instance.extendMeta(instance.plugins);
|
|
12303
|
+
return instance;
|
|
12286
12304
|
}
|
|
12287
12305
|
extendConfig(entries) {
|
|
12288
12306
|
if (entries.length === 0) {
|
|
@@ -12338,20 +12356,19 @@ class Config {
|
|
|
12338
12356
|
const result = this.getElementsFromEntry(entry);
|
|
12339
12357
|
if (isThenable(result)) {
|
|
12340
12358
|
return result.then((result2) => {
|
|
12341
|
-
const [
|
|
12342
|
-
metaTable.loadFromObject(
|
|
12343
|
-
const
|
|
12344
|
-
if (
|
|
12345
|
-
return loadEntry(
|
|
12359
|
+
const [obj2, filename2] = result2;
|
|
12360
|
+
metaTable.loadFromObject(obj2, filename2);
|
|
12361
|
+
const next3 = source.shift();
|
|
12362
|
+
if (next3) {
|
|
12363
|
+
return loadEntry(next3);
|
|
12346
12364
|
}
|
|
12347
12365
|
});
|
|
12348
|
-
}
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
}
|
|
12366
|
+
}
|
|
12367
|
+
const [obj, filename] = result;
|
|
12368
|
+
metaTable.loadFromObject(obj, filename);
|
|
12369
|
+
const next2 = source.shift();
|
|
12370
|
+
if (next2) {
|
|
12371
|
+
return loadEntry(next2);
|
|
12355
12372
|
}
|
|
12356
12373
|
};
|
|
12357
12374
|
const next = source.shift();
|
|
@@ -12381,9 +12398,8 @@ class Config {
|
|
|
12381
12398
|
return obj.then((obj2) => {
|
|
12382
12399
|
return [obj2, entry];
|
|
12383
12400
|
});
|
|
12384
|
-
} else {
|
|
12385
|
-
return [obj, entry];
|
|
12386
12401
|
}
|
|
12402
|
+
return [obj, entry];
|
|
12387
12403
|
} catch (err) {
|
|
12388
12404
|
const message = err instanceof Error ? err.message : String(err);
|
|
12389
12405
|
throw new ConfigError(
|
|
@@ -12445,7 +12461,7 @@ class Config {
|
|
|
12445
12461
|
const loadPlugin = (entry, index) => {
|
|
12446
12462
|
if (typeof entry !== "string") {
|
|
12447
12463
|
const plugin = entry;
|
|
12448
|
-
plugin.name
|
|
12464
|
+
plugin.name ||= `:unnamedPlugin@${String(index + 1)}`;
|
|
12449
12465
|
plugin.originalName = `:unnamedPlugin@${String(index + 1)}`;
|
|
12450
12466
|
loaded.push(plugin);
|
|
12451
12467
|
const next2 = loading.shift();
|
|
@@ -12457,22 +12473,21 @@ class Config {
|
|
|
12457
12473
|
const plugin = resolvePlugin(this.resolvers, entry, { cache: true });
|
|
12458
12474
|
if (isThenable(plugin)) {
|
|
12459
12475
|
return plugin.then((plugin2) => {
|
|
12460
|
-
plugin2.name
|
|
12476
|
+
plugin2.name ||= entry;
|
|
12461
12477
|
plugin2.originalName = entry;
|
|
12462
12478
|
loaded.push(plugin2);
|
|
12463
|
-
const
|
|
12464
|
-
if (
|
|
12465
|
-
return loadPlugin(
|
|
12479
|
+
const next3 = loading.shift();
|
|
12480
|
+
if (next3) {
|
|
12481
|
+
return loadPlugin(next3, index + 1);
|
|
12466
12482
|
}
|
|
12467
12483
|
});
|
|
12468
|
-
}
|
|
12469
|
-
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
}
|
|
12484
|
+
}
|
|
12485
|
+
plugin.name ||= entry;
|
|
12486
|
+
plugin.originalName = entry;
|
|
12487
|
+
loaded.push(plugin);
|
|
12488
|
+
const next2 = loading.shift();
|
|
12489
|
+
if (next2) {
|
|
12490
|
+
return loadPlugin(next2, index + 1);
|
|
12476
12491
|
}
|
|
12477
12492
|
} catch (err) {
|
|
12478
12493
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -12498,7 +12513,8 @@ class Config {
|
|
|
12498
12513
|
configs.set(name, config);
|
|
12499
12514
|
}
|
|
12500
12515
|
for (const plugin of plugins) {
|
|
12501
|
-
|
|
12516
|
+
const entries = Object.entries(plugin.configs ?? {});
|
|
12517
|
+
for (const [name, config] of entries) {
|
|
12502
12518
|
if (!config) {
|
|
12503
12519
|
continue;
|
|
12504
12520
|
}
|
|
@@ -12542,9 +12558,8 @@ class Config {
|
|
|
12542
12558
|
return resolveData.then((resolveData2) => {
|
|
12543
12559
|
return new ResolvedConfig(resolveData2, this.get());
|
|
12544
12560
|
});
|
|
12545
|
-
} else {
|
|
12546
|
-
return new ResolvedConfig(resolveData, this.get());
|
|
12547
12561
|
}
|
|
12562
|
+
return new ResolvedConfig(resolveData, this.get());
|
|
12548
12563
|
}
|
|
12549
12564
|
/**
|
|
12550
12565
|
* Same as [[resolve]] but returns the raw configuration data instead of
|
|
@@ -12563,14 +12578,13 @@ class Config {
|
|
|
12563
12578
|
transformers: this.transformers
|
|
12564
12579
|
};
|
|
12565
12580
|
});
|
|
12566
|
-
} else {
|
|
12567
|
-
return {
|
|
12568
|
-
metaTable,
|
|
12569
|
-
plugins: this.getPlugins(),
|
|
12570
|
-
rules: this.getRules(),
|
|
12571
|
-
transformers: this.transformers
|
|
12572
|
-
};
|
|
12573
12581
|
}
|
|
12582
|
+
return {
|
|
12583
|
+
metaTable,
|
|
12584
|
+
plugins: this.getPlugins(),
|
|
12585
|
+
rules: this.getRules(),
|
|
12586
|
+
transformers: this.transformers
|
|
12587
|
+
};
|
|
12574
12588
|
}
|
|
12575
12589
|
}
|
|
12576
12590
|
|
|
@@ -12614,10 +12628,9 @@ class ConfigLoader {
|
|
|
12614
12628
|
this._globalConfig = config2;
|
|
12615
12629
|
return this._globalConfig;
|
|
12616
12630
|
});
|
|
12617
|
-
} else {
|
|
12618
|
-
this._globalConfig = config;
|
|
12619
|
-
return this._globalConfig;
|
|
12620
12631
|
}
|
|
12632
|
+
this._globalConfig = config;
|
|
12633
|
+
return this._globalConfig;
|
|
12621
12634
|
}
|
|
12622
12635
|
/**
|
|
12623
12636
|
* Get the global configuration.
|
|
@@ -12699,9 +12712,8 @@ class StaticConfigLoader extends ConfigLoader {
|
|
|
12699
12712
|
const override = this.loadFromObject(configOverride ?? {});
|
|
12700
12713
|
if (isThenable(override)) {
|
|
12701
12714
|
return override.then((override2) => this._resolveConfig(override2));
|
|
12702
|
-
} else {
|
|
12703
|
-
return this._resolveConfig(override);
|
|
12704
12715
|
}
|
|
12716
|
+
return this._resolveConfig(override);
|
|
12705
12717
|
}
|
|
12706
12718
|
flushCache() {
|
|
12707
12719
|
}
|
|
@@ -12718,25 +12730,22 @@ class StaticConfigLoader extends ConfigLoader {
|
|
|
12718
12730
|
const globalConfig = this.getGlobalConfig();
|
|
12719
12731
|
if (isThenable(globalConfig)) {
|
|
12720
12732
|
return globalConfig.then((globalConfig2) => {
|
|
12721
|
-
const
|
|
12722
|
-
if (isThenable(
|
|
12723
|
-
return
|
|
12724
|
-
return
|
|
12733
|
+
const merged2 = globalConfig2.merge(this.resolvers, override);
|
|
12734
|
+
if (isThenable(merged2)) {
|
|
12735
|
+
return merged2.then((merged3) => {
|
|
12736
|
+
return merged3.resolve();
|
|
12725
12737
|
});
|
|
12726
|
-
} else {
|
|
12727
|
-
return merged.resolve();
|
|
12728
12738
|
}
|
|
12739
|
+
return merged2.resolve();
|
|
12729
12740
|
});
|
|
12730
|
-
} else {
|
|
12731
|
-
const merged = globalConfig.merge(this.resolvers, override);
|
|
12732
|
-
if (isThenable(merged)) {
|
|
12733
|
-
return merged.then((merged2) => {
|
|
12734
|
-
return merged2.resolve();
|
|
12735
|
-
});
|
|
12736
|
-
} else {
|
|
12737
|
-
return merged.resolve();
|
|
12738
|
-
}
|
|
12739
12741
|
}
|
|
12742
|
+
const merged = globalConfig.merge(this.resolvers, override);
|
|
12743
|
+
if (isThenable(merged)) {
|
|
12744
|
+
return merged.then((merged2) => {
|
|
12745
|
+
return merged2.resolve();
|
|
12746
|
+
});
|
|
12747
|
+
}
|
|
12748
|
+
return merged.resolve();
|
|
12740
12749
|
}
|
|
12741
12750
|
}
|
|
12742
12751
|
|
|
@@ -12823,7 +12832,7 @@ class EventHandler {
|
|
|
12823
12832
|
}
|
|
12824
12833
|
|
|
12825
12834
|
const name = "html-validate";
|
|
12826
|
-
const version = "11.5.
|
|
12835
|
+
const version = "11.5.4";
|
|
12827
12836
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12828
12837
|
|
|
12829
12838
|
function freeze(src) {
|
|
@@ -12861,7 +12870,7 @@ class Reporter {
|
|
|
12861
12870
|
for (const report of reports) {
|
|
12862
12871
|
for (const result of report.results) {
|
|
12863
12872
|
const key = result.filePath;
|
|
12864
|
-
if (key
|
|
12873
|
+
if (Object.hasOwn(merged, key)) {
|
|
12865
12874
|
merged[key].messages = [...merged[key].messages, ...result.messages];
|
|
12866
12875
|
} else {
|
|
12867
12876
|
merged[key] = { ...result };
|
|
@@ -12885,7 +12894,7 @@ class Reporter {
|
|
|
12885
12894
|
*/
|
|
12886
12895
|
add(options) {
|
|
12887
12896
|
const { rule, message, severity, node, location, context } = options;
|
|
12888
|
-
if (!(location.filename
|
|
12897
|
+
if (!Object.hasOwn(this.result, location.filename)) {
|
|
12889
12898
|
this.result[location.filename] = [];
|
|
12890
12899
|
}
|
|
12891
12900
|
const ruleUrl = rule.documentation(context)?.url;
|
|
@@ -12913,7 +12922,7 @@ class Reporter {
|
|
|
12913
12922
|
* @internal
|
|
12914
12923
|
*/
|
|
12915
12924
|
addManual(filename, message) {
|
|
12916
|
-
if (!(
|
|
12925
|
+
if (!Object.hasOwn(this.result, filename)) {
|
|
12917
12926
|
this.result[filename] = [];
|
|
12918
12927
|
}
|
|
12919
12928
|
this.result[filename].push(message);
|
|
@@ -12924,6 +12933,7 @@ class Reporter {
|
|
|
12924
12933
|
save(sources) {
|
|
12925
12934
|
const report = {
|
|
12926
12935
|
valid: this.isValid(),
|
|
12936
|
+
/* eslint-disable-next-line unicorn/prefer-object-iterable-methods -- technical debt */
|
|
12927
12937
|
results: Object.keys(this.result).map((filePath) => {
|
|
12928
12938
|
const messages = Array.from(this.result[filePath], freeze).toSorted(messageSort);
|
|
12929
12939
|
const source = (sources ?? []).find((source2) => filePath === source2.filename);
|
|
@@ -12988,7 +12998,7 @@ function definePlugin(plugin) {
|
|
|
12988
12998
|
return plugin;
|
|
12989
12999
|
}
|
|
12990
13000
|
|
|
12991
|
-
const regexp = /<!(?:--)?\[(.*?)](?:--)?>/g;
|
|
13001
|
+
const regexp = /<!(?:--)?\[(.*?)\](?:--)?>/g;
|
|
12992
13002
|
function* parseConditionalComment(comment, commentLocation) {
|
|
12993
13003
|
let match;
|
|
12994
13004
|
while ((match = regexp.exec(comment)) !== null) {
|
|
@@ -13005,6 +13015,7 @@ function* parseConditionalComment(comment, commentLocation) {
|
|
|
13005
13015
|
|
|
13006
13016
|
class ParserError extends Error {
|
|
13007
13017
|
location;
|
|
13018
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
13008
13019
|
constructor(location, message) {
|
|
13009
13020
|
super(message);
|
|
13010
13021
|
this.name = "ParserError";
|
|
@@ -13168,9 +13179,8 @@ class Parser {
|
|
|
13168
13179
|
const open = !token.data[1];
|
|
13169
13180
|
if (open) {
|
|
13170
13181
|
return this.wouldCloseElement(token, active);
|
|
13171
|
-
} else {
|
|
13172
|
-
return this.closeOptionalEndTag(token, active);
|
|
13173
13182
|
}
|
|
13183
|
+
return this.closeOptionalEndTag(token, active);
|
|
13174
13184
|
}
|
|
13175
13185
|
/**
|
|
13176
13186
|
* Returns `true` if the element’s end tag may be omitted, either because
|
|
@@ -13522,9 +13532,8 @@ class Parser {
|
|
|
13522
13532
|
const quote = token.data[3];
|
|
13523
13533
|
if (quote) {
|
|
13524
13534
|
return sliceLocation(token.location, 2, -1);
|
|
13525
|
-
} else {
|
|
13526
|
-
return sliceLocation(token.location, 1);
|
|
13527
13535
|
}
|
|
13536
|
+
return sliceLocation(token.location, 1);
|
|
13528
13537
|
}
|
|
13529
13538
|
/**
|
|
13530
13539
|
* Take attribute key and value token an returns a new location referring to
|
|
@@ -13812,13 +13821,14 @@ class PerformanceTracker {
|
|
|
13812
13821
|
*/
|
|
13813
13822
|
getResult() {
|
|
13814
13823
|
const events = Array.from(
|
|
13815
|
-
this.eventData
|
|
13824
|
+
this.eventData,
|
|
13816
13825
|
([event, { count, time }]) => ({ event, count, time })
|
|
13817
13826
|
).toSorted((a, b) => b.time - a.time);
|
|
13818
|
-
const rules = Array.from(
|
|
13819
|
-
|
|
13820
|
-
|
|
13821
|
-
|
|
13827
|
+
const rules = Array.from(this.ruleData, ([rule, { count, time }]) => ({
|
|
13828
|
+
rule,
|
|
13829
|
+
count,
|
|
13830
|
+
time
|
|
13831
|
+
})).toSorted((a, b) => b.time - a.time);
|
|
13822
13832
|
return {
|
|
13823
13833
|
events,
|
|
13824
13834
|
rules,
|
|
@@ -13865,9 +13875,11 @@ function dumpTree(root) {
|
|
|
13865
13875
|
return lines;
|
|
13866
13876
|
}
|
|
13867
13877
|
|
|
13868
|
-
|
|
13878
|
+
const state = {
|
|
13879
|
+
blockerCounter: 1
|
|
13880
|
+
};
|
|
13869
13881
|
function createBlocker() {
|
|
13870
|
-
const id = blockerCounter++;
|
|
13882
|
+
const id = state.blockerCounter++;
|
|
13871
13883
|
return id;
|
|
13872
13884
|
}
|
|
13873
13885
|
|
|
@@ -14003,9 +14015,8 @@ class Engine {
|
|
|
14003
14015
|
const [, options] = ruleData;
|
|
14004
14016
|
const rule = this.instantiateRule(ruleId, options);
|
|
14005
14017
|
return rule.documentation(context);
|
|
14006
|
-
} else {
|
|
14007
|
-
return null;
|
|
14008
14018
|
}
|
|
14019
|
+
return null;
|
|
14009
14020
|
}
|
|
14010
14021
|
/**
|
|
14011
14022
|
* Create a new parser instance with the current configuration.
|
|
@@ -14134,7 +14145,8 @@ class Engine {
|
|
|
14134
14145
|
initRules(config) {
|
|
14135
14146
|
const availableRules = {};
|
|
14136
14147
|
for (const plugin of config.getPlugins()) {
|
|
14137
|
-
|
|
14148
|
+
const entries = Object.entries(plugin.rules ?? {});
|
|
14149
|
+
for (const [name, rule] of entries) {
|
|
14138
14150
|
if (!rule) {
|
|
14139
14151
|
continue;
|
|
14140
14152
|
}
|
|
@@ -14162,7 +14174,7 @@ class Engine {
|
|
|
14162
14174
|
*/
|
|
14163
14175
|
setupRules(config, parser) {
|
|
14164
14176
|
const rules = {};
|
|
14165
|
-
for (const [ruleId, [severity, options]] of config.getRules()
|
|
14177
|
+
for (const [ruleId, [severity, options]] of config.getRules()) {
|
|
14166
14178
|
rules[ruleId] = this.loadRule(ruleId, config, severity, options, parser, this.report);
|
|
14167
14179
|
}
|
|
14168
14180
|
return rules;
|
|
@@ -14186,9 +14198,8 @@ class Engine {
|
|
|
14186
14198
|
if (this.availableRules[name]) {
|
|
14187
14199
|
const RuleConstructor = this.availableRules[name];
|
|
14188
14200
|
return new RuleConstructor(options);
|
|
14189
|
-
} else {
|
|
14190
|
-
return this.missingRule(name);
|
|
14191
14201
|
}
|
|
14202
|
+
return this.missingRule(name);
|
|
14192
14203
|
}
|
|
14193
14204
|
missingRule(name) {
|
|
14194
14205
|
return new class MissingRule extends Rule {
|
|
@@ -14284,34 +14295,30 @@ function getTransformerFunction(resolvers, name, plugins) {
|
|
|
14284
14295
|
validateTransformer(transformer2);
|
|
14285
14296
|
return transformer2;
|
|
14286
14297
|
});
|
|
14287
|
-
} else {
|
|
14288
|
-
validateTransformer(transformer);
|
|
14289
|
-
return transformer;
|
|
14290
14298
|
}
|
|
14299
|
+
validateTransformer(transformer);
|
|
14300
|
+
return transformer;
|
|
14291
14301
|
} catch (err) {
|
|
14292
14302
|
if (err instanceof ConfigError) {
|
|
14293
14303
|
throw new ConfigError(`Failed to load transformer "${name}": ${err.message}`, err);
|
|
14294
|
-
} else {
|
|
14295
|
-
throw new ConfigError(`Failed to load transformer "${name}"`, ensureError(err));
|
|
14296
14304
|
}
|
|
14305
|
+
throw new ConfigError(`Failed to load transformer "${name}"`, ensureError(err));
|
|
14297
14306
|
}
|
|
14298
14307
|
}
|
|
14299
14308
|
function getCachedTransformerFunction(cache, resolvers, name, plugins) {
|
|
14300
14309
|
const cached = cache.get(name);
|
|
14301
14310
|
if (cached) {
|
|
14302
14311
|
return cached;
|
|
14303
|
-
} else {
|
|
14304
|
-
const transformer = getTransformerFunction(resolvers, name, plugins);
|
|
14305
|
-
if (isThenable(transformer)) {
|
|
14306
|
-
return transformer.then((transformer2) => {
|
|
14307
|
-
cache.set(name, transformer2);
|
|
14308
|
-
return transformer2;
|
|
14309
|
-
});
|
|
14310
|
-
} else {
|
|
14311
|
-
cache.set(name, transformer);
|
|
14312
|
-
return transformer;
|
|
14313
|
-
}
|
|
14314
14312
|
}
|
|
14313
|
+
const transformer = getTransformerFunction(resolvers, name, plugins);
|
|
14314
|
+
if (isThenable(transformer)) {
|
|
14315
|
+
return transformer.then((transformer2) => {
|
|
14316
|
+
cache.set(name, transformer2);
|
|
14317
|
+
return transformer2;
|
|
14318
|
+
});
|
|
14319
|
+
}
|
|
14320
|
+
cache.set(name, transformer);
|
|
14321
|
+
return transformer;
|
|
14315
14322
|
}
|
|
14316
14323
|
|
|
14317
14324
|
function isIterable(value) {
|
|
@@ -14327,6 +14334,9 @@ const asyncInSyncTransformError = "Cannot use async transformer from sync functi
|
|
|
14327
14334
|
async function transformSource(resolvers, config, source, filename) {
|
|
14328
14335
|
const { cache } = config;
|
|
14329
14336
|
const transformer = config.findTransformer(filename ?? source.filename);
|
|
14337
|
+
if (!transformer) {
|
|
14338
|
+
return [source];
|
|
14339
|
+
}
|
|
14330
14340
|
const context = {
|
|
14331
14341
|
hasChain(filename2) {
|
|
14332
14342
|
return config.canTransform(filename2);
|
|
@@ -14335,9 +14345,6 @@ async function transformSource(resolvers, config, source, filename) {
|
|
|
14335
14345
|
return transformSource(resolvers, config, source2, filename2);
|
|
14336
14346
|
}
|
|
14337
14347
|
};
|
|
14338
|
-
if (!transformer) {
|
|
14339
|
-
return [source];
|
|
14340
|
-
}
|
|
14341
14348
|
const fn = transformer.kind === "import" ? await getCachedTransformerFunction(cache, resolvers, transformer.name, config.getPlugins()) : transformer.function;
|
|
14342
14349
|
const name = transformer.kind === "import" ? transformer.name : transformer.function.name;
|
|
14343
14350
|
try {
|
|
@@ -14356,6 +14363,9 @@ async function transformSource(resolvers, config, source, filename) {
|
|
|
14356
14363
|
function transformSourceSync(resolvers, config, source, filename) {
|
|
14357
14364
|
const { cache } = config;
|
|
14358
14365
|
const transformer = config.findTransformer(filename ?? source.filename);
|
|
14366
|
+
if (!transformer) {
|
|
14367
|
+
return [source];
|
|
14368
|
+
}
|
|
14359
14369
|
const context = {
|
|
14360
14370
|
hasChain(filename2) {
|
|
14361
14371
|
return config.canTransform(filename2);
|
|
@@ -14364,14 +14374,11 @@ function transformSourceSync(resolvers, config, source, filename) {
|
|
|
14364
14374
|
return transformSourceSync(resolvers, config, source2, filename2);
|
|
14365
14375
|
}
|
|
14366
14376
|
};
|
|
14367
|
-
if (!transformer) {
|
|
14368
|
-
return [source];
|
|
14369
|
-
}
|
|
14370
14377
|
const fn = transformer.kind === "import" ? getCachedTransformerFunction(cache, resolvers, transformer.name, config.getPlugins()) : transformer.function;
|
|
14371
|
-
const name = transformer.kind === "import" ? transformer.name : transformer.function.name;
|
|
14372
14378
|
if (isThenable(fn)) {
|
|
14373
14379
|
throw new UserError(asyncInSyncTransformError);
|
|
14374
14380
|
}
|
|
14381
|
+
const name = transformer.kind === "import" ? transformer.name : transformer.function.name;
|
|
14375
14382
|
try {
|
|
14376
14383
|
const result = fn.call(context, source);
|
|
14377
14384
|
if (isThenable(result)) {
|
|
@@ -14473,7 +14480,7 @@ function checkstyleFormatter(results) {
|
|
|
14473
14480
|
`;
|
|
14474
14481
|
for (const message of messages) {
|
|
14475
14482
|
const ruleId = xmlescape(`htmlvalidate.rules.${message.ruleId}`);
|
|
14476
|
-
output += "
|
|
14483
|
+
output += " ".repeat(4);
|
|
14477
14484
|
output += [
|
|
14478
14485
|
`<error line="${xmlescape(message.line)}"`,
|
|
14479
14486
|
`column="${xmlescape(message.column)}"`,
|
|
@@ -14560,9 +14567,8 @@ function codeFrameColumns(rawLines, loc) {
|
|
|
14560
14567
|
].join("");
|
|
14561
14568
|
}
|
|
14562
14569
|
return [">", gutter, line.length > 0 ? ` ${line}` : "", markerLine].join("");
|
|
14563
|
-
} else {
|
|
14564
|
-
return [" ", gutter, line.length > 0 ? ` ${line}` : ""].join("");
|
|
14565
14570
|
}
|
|
14571
|
+
return [" ", gutter, line.length > 0 ? ` ${line}` : ""].join("");
|
|
14566
14572
|
}).join("\n");
|
|
14567
14573
|
}
|
|
14568
14574
|
|