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/cjs/core.js
CHANGED
|
@@ -397,11 +397,11 @@ var deepmerge = /*@__PURE__*/getDefaultExportFromCjs(cjsExports);
|
|
|
397
397
|
function stringify(value) {
|
|
398
398
|
if (typeof value === "string") {
|
|
399
399
|
return value;
|
|
400
|
-
} else {
|
|
401
|
-
return JSON.stringify(value);
|
|
402
400
|
}
|
|
401
|
+
return JSON.stringify(value);
|
|
403
402
|
}
|
|
404
403
|
class WrappedError extends Error {
|
|
404
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
405
405
|
constructor(message) {
|
|
406
406
|
super(stringify(message));
|
|
407
407
|
this.name = "WrappedError";
|
|
@@ -411,12 +411,12 @@ class WrappedError extends Error {
|
|
|
411
411
|
function ensureError(value) {
|
|
412
412
|
if (value instanceof Error) {
|
|
413
413
|
return value;
|
|
414
|
-
} else {
|
|
415
|
-
return new WrappedError(value);
|
|
416
414
|
}
|
|
415
|
+
return new WrappedError(value);
|
|
417
416
|
}
|
|
418
417
|
|
|
419
418
|
class NestedError extends Error {
|
|
419
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
420
420
|
constructor(message, nested) {
|
|
421
421
|
super(message);
|
|
422
422
|
this.name = "NestedError";
|
|
@@ -429,6 +429,7 @@ Caused by: ${nested.stack}`;
|
|
|
429
429
|
}
|
|
430
430
|
|
|
431
431
|
class UserError extends NestedError {
|
|
432
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
432
433
|
constructor(message, nested) {
|
|
433
434
|
super(message, nested);
|
|
434
435
|
this.name = "UserError";
|
|
@@ -1129,11 +1130,11 @@ const CONTROL_ESCAPES = /* @__PURE__ */ new Map([
|
|
|
1129
1130
|
["\r", "r"]
|
|
1130
1131
|
]);
|
|
1131
1132
|
const OTHER_PUNCTUATORS = /^[!"#%&',:;<=>@`~-]$/;
|
|
1132
|
-
const WHITE_SPACE = /^[\t\v\f\
|
|
1133
|
+
const WHITE_SPACE = /^[\t\v\f\u{FEFF}\p{Zs}]$/u;
|
|
1133
1134
|
const LINE_TERMINATOR = /^[\n\r\u2028\u2029]$/;
|
|
1134
1135
|
const SURROGATE = /^[\uD800-\uDFFF]$/;
|
|
1135
1136
|
function isDecimalDigitOrASCIILetter(ch) {
|
|
1136
|
-
return /^[\dA-
|
|
1137
|
+
return /^[\dA-Z]$/i.test(ch);
|
|
1137
1138
|
}
|
|
1138
1139
|
function needEscape(ch) {
|
|
1139
1140
|
return OTHER_PUNCTUATORS.test(ch) || WHITE_SPACE.test(ch) || LINE_TERMINATOR.test(ch) || SURROGATE.test(ch);
|
|
@@ -1201,9 +1202,8 @@ function migrateSingleAttribute(src, key) {
|
|
|
1201
1202
|
}
|
|
1202
1203
|
}
|
|
1203
1204
|
return stripUndefined(result);
|
|
1204
|
-
} else {
|
|
1205
|
-
return stripUndefined({ ...result, ...attr });
|
|
1206
1205
|
}
|
|
1206
|
+
return stripUndefined({ ...result, ...attr });
|
|
1207
1207
|
}
|
|
1208
1208
|
function isPatternAttribute$1(key) {
|
|
1209
1209
|
return key.includes("*");
|
|
@@ -1217,7 +1217,7 @@ function migrateAttributes(src) {
|
|
|
1217
1217
|
...Object.keys(src.attributes ?? {}),
|
|
1218
1218
|
...src.requiredAttributes ?? [],
|
|
1219
1219
|
...src.deprecatedAttributes ?? []
|
|
1220
|
-
].filter((key) => !isPatternAttribute$1(key)).toSorted();
|
|
1220
|
+
].filter((key) => !isPatternAttribute$1(key)).toSorted((a, b) => a.localeCompare(b));
|
|
1221
1221
|
const entries = keys.map((key) => {
|
|
1222
1222
|
return [key, migrateSingleAttribute(src, key)];
|
|
1223
1223
|
});
|
|
@@ -1297,11 +1297,10 @@ const dynamicKeys = [
|
|
|
1297
1297
|
];
|
|
1298
1298
|
const schemaCache = /* @__PURE__ */ new Map();
|
|
1299
1299
|
function clone(value) {
|
|
1300
|
-
if (globalThis
|
|
1301
|
-
return
|
|
1302
|
-
} else {
|
|
1303
|
-
return JSON.parse(JSON.stringify(value));
|
|
1300
|
+
if (Object.hasOwn(globalThis, "structuredClone")) {
|
|
1301
|
+
return structuredClone(value);
|
|
1304
1302
|
}
|
|
1303
|
+
return JSON.parse(JSON.stringify(value));
|
|
1305
1304
|
}
|
|
1306
1305
|
class MetaTable {
|
|
1307
1306
|
elements;
|
|
@@ -1391,9 +1390,8 @@ class MetaTable {
|
|
|
1391
1390
|
const meta = this.elements[tagName.toLowerCase()] ?? this.elements["*"];
|
|
1392
1391
|
if (meta) {
|
|
1393
1392
|
return { ...meta };
|
|
1394
|
-
} else {
|
|
1395
|
-
return null;
|
|
1396
1393
|
}
|
|
1394
|
+
return null;
|
|
1397
1395
|
}
|
|
1398
1396
|
/**
|
|
1399
1397
|
* Find all tags which has enabled given property.
|
|
@@ -1435,16 +1433,15 @@ class MetaTable {
|
|
|
1435
1433
|
const cached = schemaCache.get(hash);
|
|
1436
1434
|
if (cached) {
|
|
1437
1435
|
return cached;
|
|
1438
|
-
} else {
|
|
1439
|
-
const ajv = new Ajv__default.default({ strict: true, strictTuples: true, strictTypes: true });
|
|
1440
|
-
ajv.addMetaSchema(ajvSchemaDraft);
|
|
1441
|
-
ajv.addKeyword(ajvFunctionKeyword);
|
|
1442
|
-
ajv.addKeyword(ajvRegexpKeyword);
|
|
1443
|
-
ajv.addKeyword({ keyword: "copyable" });
|
|
1444
|
-
const validate = ajv.compile(this.schema);
|
|
1445
|
-
schemaCache.set(hash, validate);
|
|
1446
|
-
return validate;
|
|
1447
1436
|
}
|
|
1437
|
+
const ajv = new Ajv__default.default({ strict: true, strictTuples: true, strictTypes: true });
|
|
1438
|
+
ajv.addMetaSchema(ajvSchemaDraft);
|
|
1439
|
+
ajv.addKeyword(ajvFunctionKeyword);
|
|
1440
|
+
ajv.addKeyword(ajvRegexpKeyword);
|
|
1441
|
+
ajv.addKeyword({ keyword: "copyable" });
|
|
1442
|
+
const validate = ajv.compile(this.schema);
|
|
1443
|
+
schemaCache.set(hash, validate);
|
|
1444
|
+
return validate;
|
|
1448
1445
|
}
|
|
1449
1446
|
/**
|
|
1450
1447
|
* @public
|
|
@@ -1526,14 +1523,13 @@ function expandProperties(node, entry) {
|
|
|
1526
1523
|
}
|
|
1527
1524
|
}
|
|
1528
1525
|
function compileRegexString(value) {
|
|
1529
|
-
const match = /^\/(.*
|
|
1526
|
+
const match = /^\/(.*)\/(i?)$/.exec(value);
|
|
1530
1527
|
if (match) {
|
|
1531
1528
|
const [, expr, flags] = match;
|
|
1532
1529
|
if (expr.startsWith("^") || expr.endsWith("$")) {
|
|
1533
1530
|
return new RegExp(expr, flags);
|
|
1534
|
-
} else {
|
|
1535
|
-
return new RegExp(`^${expr}$`, flags);
|
|
1536
1531
|
}
|
|
1532
|
+
return new RegExp(`^${expr}$`, flags);
|
|
1537
1533
|
}
|
|
1538
1534
|
return null;
|
|
1539
1535
|
}
|
|
@@ -1594,7 +1590,7 @@ class Attribute {
|
|
|
1594
1590
|
* @param keyLocation - Source location of attribute name.
|
|
1595
1591
|
* @param valueLocation - Source location of attribute value.
|
|
1596
1592
|
* @param originalAttribute - If this attribute was dynamically added via a
|
|
1597
|
-
* transformation (e.g.
|
|
1593
|
+
* transformation (e.g. Vue.js `:id` generating the `id` attribute) this
|
|
1598
1594
|
* parameter should be set to the attribute name of the source attribute (`:id`).
|
|
1599
1595
|
*/
|
|
1600
1596
|
constructor(key, value, keyLocation, valueLocation, originalAttribute) {
|
|
@@ -1638,9 +1634,8 @@ class Attribute {
|
|
|
1638
1634
|
}
|
|
1639
1635
|
if (pattern instanceof RegExp) {
|
|
1640
1636
|
return this.value.match(pattern) !== null;
|
|
1641
|
-
} else {
|
|
1642
|
-
return this.value === pattern;
|
|
1643
1637
|
}
|
|
1638
|
+
return this.value === pattern;
|
|
1644
1639
|
}
|
|
1645
1640
|
}
|
|
1646
1641
|
|
|
@@ -1716,7 +1711,9 @@ const Node = {
|
|
|
1716
1711
|
|
|
1717
1712
|
const DOCUMENT_NODE_NAME = "#document";
|
|
1718
1713
|
const TEXT_CONTENT = /* @__PURE__ */ Symbol("textContent");
|
|
1719
|
-
|
|
1714
|
+
const state$1 = {
|
|
1715
|
+
counter: 0
|
|
1716
|
+
};
|
|
1720
1717
|
class DOMNode {
|
|
1721
1718
|
nodeName;
|
|
1722
1719
|
nodeType;
|
|
@@ -1755,7 +1752,7 @@ class DOMNode {
|
|
|
1755
1752
|
this.disabledRules = /* @__PURE__ */ new Set();
|
|
1756
1753
|
this.blockedRules = /* @__PURE__ */ new Map();
|
|
1757
1754
|
this.childNodes = [];
|
|
1758
|
-
this.unique = counter++;
|
|
1755
|
+
this.unique = state$1.counter++;
|
|
1759
1756
|
this.cache = null;
|
|
1760
1757
|
}
|
|
1761
1758
|
/**
|
|
@@ -1771,9 +1768,8 @@ class DOMNode {
|
|
|
1771
1768
|
cacheGet(key) {
|
|
1772
1769
|
if (this.cache) {
|
|
1773
1770
|
return this.cache.get(key);
|
|
1774
|
-
} else {
|
|
1775
|
-
return void 0;
|
|
1776
1771
|
}
|
|
1772
|
+
return void 0;
|
|
1777
1773
|
}
|
|
1778
1774
|
cacheSet(key, value) {
|
|
1779
1775
|
if (this.cache) {
|
|
@@ -1789,9 +1785,8 @@ class DOMNode {
|
|
|
1789
1785
|
cacheRemove(key) {
|
|
1790
1786
|
if (this.cache) {
|
|
1791
1787
|
return this.cache.delete(key);
|
|
1792
|
-
} else {
|
|
1793
|
-
return false;
|
|
1794
1788
|
}
|
|
1789
|
+
return false;
|
|
1795
1790
|
}
|
|
1796
1791
|
/**
|
|
1797
1792
|
* Check if key exists in cache.
|
|
@@ -2011,9 +2006,8 @@ class DOMTokenList extends Array {
|
|
|
2011
2006
|
location(n) {
|
|
2012
2007
|
if (this.locations) {
|
|
2013
2008
|
return this.locations[n];
|
|
2014
|
-
} else {
|
|
2015
|
-
throw new Error("Trying to access DOMTokenList location when base location isn't set");
|
|
2016
2009
|
}
|
|
2010
|
+
throw new Error("Trying to access DOMTokenList location when base location isn't set");
|
|
2017
2011
|
}
|
|
2018
2012
|
contains(token) {
|
|
2019
2013
|
return this.includes(token);
|
|
@@ -2063,25 +2057,25 @@ function lastChild(node) {
|
|
|
2063
2057
|
return node.nextSibling === null;
|
|
2064
2058
|
}
|
|
2065
2059
|
|
|
2066
|
-
const cache = {};
|
|
2060
|
+
const cache$1 = {};
|
|
2067
2061
|
function getNthChild(node) {
|
|
2068
2062
|
if (!node.parent) {
|
|
2069
2063
|
return -1;
|
|
2070
2064
|
}
|
|
2071
|
-
if (!cache[node.unique]) {
|
|
2065
|
+
if (!cache$1[node.unique]) {
|
|
2072
2066
|
const parent = node.parent;
|
|
2073
2067
|
const index = parent.childElements.findIndex((cur) => {
|
|
2074
2068
|
return cur.unique === node.unique;
|
|
2075
2069
|
});
|
|
2076
|
-
cache[node.unique] = index + 1;
|
|
2070
|
+
cache$1[node.unique] = index + 1;
|
|
2077
2071
|
}
|
|
2078
|
-
return cache[node.unique];
|
|
2072
|
+
return cache$1[node.unique];
|
|
2079
2073
|
}
|
|
2080
2074
|
function nthChild(node, args) {
|
|
2081
2075
|
if (!args) {
|
|
2082
2076
|
throw new Error("Missing argument to nth-child");
|
|
2083
2077
|
}
|
|
2084
|
-
const n =
|
|
2078
|
+
const n = Math.trunc(Number(args.trim()));
|
|
2085
2079
|
const cur = getNthChild(node);
|
|
2086
2080
|
return cur === n;
|
|
2087
2081
|
}
|
|
@@ -2100,9 +2094,8 @@ function factory(name, context) {
|
|
|
2100
2094
|
const fn = table[name];
|
|
2101
2095
|
if (fn) {
|
|
2102
2096
|
return fn.bind(context);
|
|
2103
|
-
} else {
|
|
2104
|
-
throw new Error(`Pseudo-class "${name}" is not implemented`);
|
|
2105
2097
|
}
|
|
2098
|
+
throw new Error(`Pseudo-class "${name}" is not implemented`);
|
|
2106
2099
|
}
|
|
2107
2100
|
|
|
2108
2101
|
function stripslashes(value) {
|
|
@@ -2128,7 +2121,7 @@ function createIdCondition(raw) {
|
|
|
2128
2121
|
};
|
|
2129
2122
|
}
|
|
2130
2123
|
function createAttributeCondition(attr) {
|
|
2131
|
-
const match = /^(.+?)(?:([$*^|~]?=)"([^"]
|
|
2124
|
+
const match = /^(.+?)(?:([$*^|~]?=)"([^"]+)")?$/.exec(attr);
|
|
2132
2125
|
const key = match[1];
|
|
2133
2126
|
const op = match[2];
|
|
2134
2127
|
const rawValue = match[3];
|
|
@@ -2191,7 +2184,6 @@ function* splitCompound(pattern) {
|
|
|
2191
2184
|
let quoted = false;
|
|
2192
2185
|
while (cur < end) {
|
|
2193
2186
|
const ch = pattern[cur];
|
|
2194
|
-
const buffer = pattern.slice(begin, cur);
|
|
2195
2187
|
if (ch === "\\") {
|
|
2196
2188
|
cur += 2;
|
|
2197
2189
|
continue;
|
|
@@ -2208,6 +2200,7 @@ function* splitCompound(pattern) {
|
|
|
2208
2200
|
cur += 1;
|
|
2209
2201
|
continue;
|
|
2210
2202
|
}
|
|
2203
|
+
const buffer = pattern.slice(begin, cur);
|
|
2211
2204
|
if (isPseudoElement(ch, buffer)) {
|
|
2212
2205
|
cur += 1;
|
|
2213
2206
|
continue;
|
|
@@ -2228,7 +2221,7 @@ class Compound {
|
|
|
2228
2221
|
selector;
|
|
2229
2222
|
conditions;
|
|
2230
2223
|
constructor(pattern) {
|
|
2231
|
-
const match = /^([+>~-]?)((?:\*|[^#.:[]+)?)([
|
|
2224
|
+
const match = /^([+>~-]?)((?:\*|[^#.:[]+)?)([\s\S]*)$/.exec(pattern);
|
|
2232
2225
|
if (!match) {
|
|
2233
2226
|
throw new Error(`Failed to create selector pattern from "${pattern}"`);
|
|
2234
2227
|
}
|
|
@@ -2242,7 +2235,7 @@ class Compound {
|
|
|
2242
2235
|
return node.is(this.tagName) && this.conditions.every((cur) => cur.match(node, context));
|
|
2243
2236
|
}
|
|
2244
2237
|
createCondition(pattern) {
|
|
2245
|
-
switch (pattern
|
|
2238
|
+
switch (pattern.at(0)) {
|
|
2246
2239
|
case ".":
|
|
2247
2240
|
return createClassCondition(pattern.slice(1));
|
|
2248
2241
|
case "#":
|
|
@@ -2435,9 +2428,9 @@ class ComplexSelector {
|
|
|
2435
2428
|
case Combinator.CHILD:
|
|
2436
2429
|
return root.childElements.filter((node) => node.is(pattern.tagName));
|
|
2437
2430
|
case Combinator.ADJACENT_SIBLING:
|
|
2438
|
-
return
|
|
2431
|
+
return this.findAdjacentSibling(root);
|
|
2439
2432
|
case Combinator.GENERAL_SIBLING:
|
|
2440
|
-
return
|
|
2433
|
+
return this.findGeneralSibling(root);
|
|
2441
2434
|
case Combinator.SCOPE:
|
|
2442
2435
|
return [root];
|
|
2443
2436
|
}
|
|
@@ -2475,12 +2468,11 @@ const codepoints = {
|
|
|
2475
2468
|
"\r": "\\d "
|
|
2476
2469
|
};
|
|
2477
2470
|
function escapeSelectorComponent(text) {
|
|
2478
|
-
return text.toString().replaceAll(/([
|
|
2479
|
-
if (codepoints
|
|
2471
|
+
return text.toString().replaceAll(/([^\w-])/g, (_, ch) => {
|
|
2472
|
+
if (Object.hasOwn(codepoints, ch)) {
|
|
2480
2473
|
return codepoints[ch];
|
|
2481
|
-
} else {
|
|
2482
|
-
return `\\${ch}`;
|
|
2483
2474
|
}
|
|
2475
|
+
return `\\${ch}`;
|
|
2484
2476
|
});
|
|
2485
2477
|
}
|
|
2486
2478
|
|
|
@@ -2489,9 +2481,16 @@ function generateIdSelector(id) {
|
|
|
2489
2481
|
return /^\d/.test(escaped) ? `[id="${escaped}"]` : `#${escaped}`;
|
|
2490
2482
|
}
|
|
2491
2483
|
|
|
2484
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2492
2485
|
function parseSelector(selector) {
|
|
2486
|
+
const cached = cache.get(selector);
|
|
2487
|
+
if (cached) {
|
|
2488
|
+
return cached;
|
|
2489
|
+
}
|
|
2493
2490
|
const compounds = getCompounds(selector);
|
|
2494
|
-
|
|
2491
|
+
const result = ComplexSelector.fromCompounds(compounds);
|
|
2492
|
+
cache.set(selector, result);
|
|
2493
|
+
return result;
|
|
2495
2494
|
}
|
|
2496
2495
|
|
|
2497
2496
|
const TEXT_NODE_NAME = "#text";
|
|
@@ -2636,10 +2635,10 @@ class HtmlElement extends DOMNode {
|
|
|
2636
2635
|
*/
|
|
2637
2636
|
static fromTokens(startToken, endToken, parent, metaTable, namespace = "") {
|
|
2638
2637
|
const name = startToken.data[2];
|
|
2639
|
-
const tagName = namespace ? `${namespace}:${name}` : name;
|
|
2640
2638
|
if (!name) {
|
|
2641
2639
|
throw new Error("tagName cannot be empty");
|
|
2642
2640
|
}
|
|
2641
|
+
const tagName = namespace ? `${namespace}:${name}` : name;
|
|
2643
2642
|
const meta = metaTable ? metaTable.getMetaFor(tagName) : null;
|
|
2644
2643
|
const open = startToken.data[1] !== "/";
|
|
2645
2644
|
const closed = isClosed(endToken, meta);
|
|
@@ -2661,9 +2660,8 @@ class HtmlElement extends DOMNode {
|
|
|
2661
2660
|
get annotatedName() {
|
|
2662
2661
|
if (this.annotation) {
|
|
2663
2662
|
return this.annotation;
|
|
2664
|
-
} else {
|
|
2665
|
-
return `<${this.tagName}>`;
|
|
2666
2663
|
}
|
|
2664
|
+
return `<${this.tagName}>`;
|
|
2667
2665
|
}
|
|
2668
2666
|
/**
|
|
2669
2667
|
* Get list of IDs referenced by `aria-labelledby`.
|
|
@@ -2882,13 +2880,13 @@ class HtmlElement extends DOMNode {
|
|
|
2882
2880
|
if (!tabindex) {
|
|
2883
2881
|
return this.cacheSet(TABINDEX, null);
|
|
2884
2882
|
}
|
|
2885
|
-
if (tabindex.value === null) {
|
|
2883
|
+
if (tabindex.value === null || tabindex.value === "") {
|
|
2886
2884
|
return this.cacheSet(TABINDEX, null);
|
|
2887
2885
|
}
|
|
2888
2886
|
if (tabindex.value instanceof DynamicValue) {
|
|
2889
2887
|
return this.cacheSet(TABINDEX, 0);
|
|
2890
2888
|
}
|
|
2891
|
-
const parsed =
|
|
2889
|
+
const parsed = Math.trunc(Number(tabindex.value));
|
|
2892
2890
|
if (Number.isNaN(parsed)) {
|
|
2893
2891
|
return this.cacheSet(TABINDEX, null);
|
|
2894
2892
|
}
|
|
@@ -2904,11 +2902,11 @@ class HtmlElement extends DOMNode {
|
|
|
2904
2902
|
const tagName = this.tagName.toLowerCase();
|
|
2905
2903
|
if (tagName === "script") {
|
|
2906
2904
|
return "script";
|
|
2907
|
-
}
|
|
2905
|
+
}
|
|
2906
|
+
if (tagName === "style") {
|
|
2908
2907
|
return "css";
|
|
2909
|
-
} else {
|
|
2910
|
-
return "text";
|
|
2911
2908
|
}
|
|
2909
|
+
return "text";
|
|
2912
2910
|
}
|
|
2913
2911
|
/**
|
|
2914
2912
|
* Get a list of all attributes on this node.
|
|
@@ -2920,16 +2918,15 @@ class HtmlElement extends DOMNode {
|
|
|
2920
2918
|
}
|
|
2921
2919
|
hasAttribute(key) {
|
|
2922
2920
|
key = key.toLowerCase();
|
|
2923
|
-
return
|
|
2921
|
+
return Object.hasOwn(this.attr, key);
|
|
2924
2922
|
}
|
|
2925
2923
|
getAttribute(key, all = false) {
|
|
2926
2924
|
key = key.toLowerCase();
|
|
2927
|
-
if (
|
|
2925
|
+
if (Object.hasOwn(this.attr, key)) {
|
|
2928
2926
|
const matches = this.attr[key];
|
|
2929
2927
|
return all ? matches : matches[0];
|
|
2930
|
-
} else {
|
|
2931
|
-
return all ? [] : null;
|
|
2932
2928
|
}
|
|
2929
|
+
return all ? [] : null;
|
|
2933
2930
|
}
|
|
2934
2931
|
/**
|
|
2935
2932
|
* Get attribute value.
|
|
@@ -2947,17 +2944,13 @@ class HtmlElement extends DOMNode {
|
|
|
2947
2944
|
const attr = this.getAttribute(key);
|
|
2948
2945
|
if (attr) {
|
|
2949
2946
|
return attr.value !== null ? attr.value.toString() : null;
|
|
2950
|
-
} else {
|
|
2951
|
-
return null;
|
|
2952
2947
|
}
|
|
2948
|
+
return null;
|
|
2953
2949
|
}
|
|
2954
|
-
/**
|
|
2955
|
-
* Add text as a child node to this element.
|
|
2956
|
-
*
|
|
2957
|
-
* @param text - Text to add.
|
|
2958
|
-
* @param location - Source code location of this text.
|
|
2959
|
-
*/
|
|
2960
2950
|
appendText(text, location) {
|
|
2951
|
+
if (typeof text === "object" && "dynamic" in text) {
|
|
2952
|
+
text = new DynamicValue(text.dynamic);
|
|
2953
|
+
}
|
|
2961
2954
|
this.childNodes.push(new TextNode(text, location));
|
|
2962
2955
|
}
|
|
2963
2956
|
/**
|
|
@@ -3010,23 +3003,30 @@ class HtmlElement extends DOMNode {
|
|
|
3010
3003
|
return i <= this.siblings.length - 2 ? this.siblings[i + 1] : null;
|
|
3011
3004
|
}
|
|
3012
3005
|
getElementsByTagName(tagName) {
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3006
|
+
const matches = [];
|
|
3007
|
+
this.collectByTagName(tagName, matches);
|
|
3008
|
+
return matches;
|
|
3009
|
+
}
|
|
3010
|
+
collectByTagName(tagName, matches) {
|
|
3011
|
+
for (const node of this.childElements) {
|
|
3012
|
+
if (node.is(tagName)) {
|
|
3013
|
+
matches.push(node);
|
|
3014
|
+
}
|
|
3015
|
+
node.collectByTagName(tagName, matches);
|
|
3016
|
+
}
|
|
3016
3017
|
}
|
|
3017
3018
|
querySelector(selector) {
|
|
3018
3019
|
const it = this.querySelectorImpl(selector);
|
|
3019
3020
|
const next = it.next();
|
|
3020
3021
|
if (next.done) {
|
|
3021
3022
|
return null;
|
|
3022
|
-
} else {
|
|
3023
|
-
return next.value;
|
|
3024
3023
|
}
|
|
3024
|
+
return next.value;
|
|
3025
3025
|
}
|
|
3026
3026
|
querySelectorAll(selector) {
|
|
3027
3027
|
const it = this.querySelectorImpl(selector);
|
|
3028
3028
|
const unique = new Set(it);
|
|
3029
|
-
return Array.from(unique
|
|
3029
|
+
return Array.from(unique);
|
|
3030
3030
|
}
|
|
3031
3031
|
*querySelectorImpl(selectorList) {
|
|
3032
3032
|
if (!selectorList) {
|
|
@@ -3047,9 +3047,8 @@ class HtmlElement extends DOMNode {
|
|
|
3047
3047
|
function visit(node) {
|
|
3048
3048
|
if (callback(node)) {
|
|
3049
3049
|
return true;
|
|
3050
|
-
} else {
|
|
3051
|
-
return node.childElements.some(visit);
|
|
3052
3050
|
}
|
|
3051
|
+
return node.childElements.some(visit);
|
|
3053
3052
|
}
|
|
3054
3053
|
}
|
|
3055
3054
|
/**
|
|
@@ -3224,7 +3223,7 @@ class Validator {
|
|
|
3224
3223
|
return true;
|
|
3225
3224
|
}
|
|
3226
3225
|
return rules.some((rule) => {
|
|
3227
|
-
return
|
|
3226
|
+
return this.validatePermittedRule(node, rule);
|
|
3228
3227
|
});
|
|
3229
3228
|
}
|
|
3230
3229
|
/**
|
|
@@ -3251,9 +3250,7 @@ class Validator {
|
|
|
3251
3250
|
const [, category, quantifier] = /^(@?.*?)([*?]?)$/.exec(rule);
|
|
3252
3251
|
const limit = category && quantifier && parseQuantifier(quantifier);
|
|
3253
3252
|
if (limit) {
|
|
3254
|
-
const siblings = children.filter(
|
|
3255
|
-
(cur) => Validator.validatePermittedCategory(cur, rule, true)
|
|
3256
|
-
);
|
|
3253
|
+
const siblings = children.filter((cur) => this.validatePermittedCategory(cur, rule, true));
|
|
3257
3254
|
if (siblings.length > limit) {
|
|
3258
3255
|
for (const child of siblings.slice(limit)) {
|
|
3259
3256
|
cb(child, category);
|
|
@@ -3284,12 +3281,12 @@ class Validator {
|
|
|
3284
3281
|
let prev = null;
|
|
3285
3282
|
for (const node of children) {
|
|
3286
3283
|
const old = i;
|
|
3287
|
-
while (rules[i] && !
|
|
3284
|
+
while (rules[i] && !this.validatePermittedCategory(node, rules[i], true)) {
|
|
3288
3285
|
i++;
|
|
3289
3286
|
}
|
|
3290
3287
|
if (i >= rules.length) {
|
|
3291
|
-
const orderSpecified = rules.
|
|
3292
|
-
(cur) =>
|
|
3288
|
+
const orderSpecified = rules.some(
|
|
3289
|
+
(cur) => this.validatePermittedCategory(node, cur, true)
|
|
3293
3290
|
);
|
|
3294
3291
|
if (orderSpecified) {
|
|
3295
3292
|
cb(node, prev);
|
|
@@ -3328,7 +3325,7 @@ class Validator {
|
|
|
3328
3325
|
}
|
|
3329
3326
|
return rules.filter((tagName) => {
|
|
3330
3327
|
const haveMatchingChild = node.childElements.some(
|
|
3331
|
-
(child) =>
|
|
3328
|
+
(child) => this.validatePermittedCategory(child, tagName, false)
|
|
3332
3329
|
);
|
|
3333
3330
|
return !haveMatchingChild;
|
|
3334
3331
|
});
|
|
@@ -3375,36 +3372,35 @@ class Validator {
|
|
|
3375
3372
|
return rule.enum.some((entry) => {
|
|
3376
3373
|
if (typeof entry === "string") {
|
|
3377
3374
|
return caseInsensitiveValue === entry;
|
|
3378
|
-
}
|
|
3375
|
+
}
|
|
3376
|
+
if (entry instanceof RegExp) {
|
|
3379
3377
|
return entry.test(value);
|
|
3380
|
-
}
|
|
3378
|
+
}
|
|
3379
|
+
if (entry.pattern instanceof RegExp) {
|
|
3381
3380
|
return entry.pattern.test(value);
|
|
3382
|
-
} else {
|
|
3383
|
-
throw new TypeError("RegExp was not precompiled when it should have been");
|
|
3384
3381
|
}
|
|
3382
|
+
throw new TypeError("RegExp was not precompiled when it should have been");
|
|
3385
3383
|
});
|
|
3386
3384
|
}
|
|
3387
3385
|
static validatePermittedRule(node, rule, isExclude = false) {
|
|
3388
3386
|
if (typeof rule === "string") {
|
|
3389
|
-
return
|
|
3390
|
-
}
|
|
3387
|
+
return this.validatePermittedCategory(node, rule, !isExclude);
|
|
3388
|
+
}
|
|
3389
|
+
if (Array.isArray(rule)) {
|
|
3391
3390
|
return rule.every((inner) => {
|
|
3392
|
-
return
|
|
3391
|
+
return this.validatePermittedRule(node, inner, isExclude);
|
|
3393
3392
|
});
|
|
3394
|
-
}
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
} else {
|
|
3402
|
-
return !Validator.validatePermittedRule(node, rule.exclude, true);
|
|
3403
|
-
}
|
|
3404
|
-
} else {
|
|
3405
|
-
return true;
|
|
3393
|
+
}
|
|
3394
|
+
validateKeys(rule);
|
|
3395
|
+
if (rule.exclude) {
|
|
3396
|
+
if (Array.isArray(rule.exclude)) {
|
|
3397
|
+
return rule.exclude.every((inner) => {
|
|
3398
|
+
return !this.validatePermittedRule(node, inner, true);
|
|
3399
|
+
});
|
|
3406
3400
|
}
|
|
3401
|
+
return !this.validatePermittedRule(node, rule.exclude, true);
|
|
3407
3402
|
}
|
|
3403
|
+
return true;
|
|
3408
3404
|
}
|
|
3409
3405
|
/**
|
|
3410
3406
|
* Validate node against a content category.
|
|
@@ -3420,7 +3416,7 @@ class Validator {
|
|
|
3420
3416
|
*/
|
|
3421
3417
|
/* eslint-disable-next-line complexity -- rule does not like switch */
|
|
3422
3418
|
static validatePermittedCategory(node, category, defaultMatch) {
|
|
3423
|
-
const [, rawCategory] = /^(@?.*?)
|
|
3419
|
+
const [, rawCategory] = /^(@?.*?)[*?]?$/.exec(category);
|
|
3424
3420
|
if (!rawCategory.startsWith("@")) {
|
|
3425
3421
|
return node.matches(rawCategory);
|
|
3426
3422
|
}
|
|
@@ -3453,10 +3449,11 @@ class Validator {
|
|
|
3453
3449
|
}
|
|
3454
3450
|
function validateKeys(rule) {
|
|
3455
3451
|
for (const key of Object.keys(rule)) {
|
|
3456
|
-
if (
|
|
3457
|
-
|
|
3458
|
-
throw new Error(`Permitted rule "${str}" contains unknown property "${key}"`);
|
|
3452
|
+
if (allowedKeys.has(key)) {
|
|
3453
|
+
continue;
|
|
3459
3454
|
}
|
|
3455
|
+
const str = JSON.stringify(rule);
|
|
3456
|
+
throw new Error(`Permitted rule "${str}" contains unknown property "${key}"`);
|
|
3460
3457
|
}
|
|
3461
3458
|
}
|
|
3462
3459
|
function parseQuantifier(quantifier) {
|
|
@@ -3523,9 +3520,8 @@ function ariaNaming(element) {
|
|
|
3523
3520
|
if (role) {
|
|
3524
3521
|
if (role instanceof DynamicValue) {
|
|
3525
3522
|
return element.cacheSet(cacheKey, defaultValue);
|
|
3526
|
-
} else {
|
|
3527
|
-
return element.cacheSet(cacheKey, byRole(role));
|
|
3528
3523
|
}
|
|
3524
|
+
return element.cacheSet(cacheKey, byRole(role));
|
|
3529
3525
|
}
|
|
3530
3526
|
const meta = element.meta;
|
|
3531
3527
|
if (!meta) {
|
|
@@ -3710,9 +3706,8 @@ function isPresentation(node) {
|
|
|
3710
3706
|
const role = node.getAttribute("role");
|
|
3711
3707
|
if (role && (role.value === "presentation" || role.value === "none")) {
|
|
3712
3708
|
return node.cacheSet(ROLE_PRESENTATION_CACHE, true);
|
|
3713
|
-
} else {
|
|
3714
|
-
return node.cacheSet(ROLE_PRESENTATION_CACHE, false);
|
|
3715
3709
|
}
|
|
3710
|
+
return node.cacheSet(ROLE_PRESENTATION_CACHE, false);
|
|
3716
3711
|
}
|
|
3717
3712
|
|
|
3718
3713
|
const cachePrefix = classifyNodeText.name;
|
|
@@ -3730,13 +3725,14 @@ function getCachekey(options) {
|
|
|
3730
3725
|
const { accessible = false, ignoreHiddenRoot = false } = options;
|
|
3731
3726
|
if (accessible && ignoreHiddenRoot) {
|
|
3732
3727
|
return IGNORE_HIDDEN_ROOT_A11Y_CACHE_KEY;
|
|
3733
|
-
}
|
|
3728
|
+
}
|
|
3729
|
+
if (ignoreHiddenRoot) {
|
|
3734
3730
|
return IGNORE_HIDDEN_ROOT_HTML_CACHE_KEY;
|
|
3735
|
-
}
|
|
3731
|
+
}
|
|
3732
|
+
if (accessible) {
|
|
3736
3733
|
return A11Y_CACHE_KEY;
|
|
3737
|
-
} else {
|
|
3738
|
-
return HTML_CACHE_KEY;
|
|
3739
3734
|
}
|
|
3735
|
+
return HTML_CACHE_KEY;
|
|
3740
3736
|
}
|
|
3741
3737
|
function isSpecialEmpty(node) {
|
|
3742
3738
|
return node.is("select") || node.is("textarea");
|
|
@@ -3768,7 +3764,7 @@ function classifyNodeText(node, options = {}) {
|
|
|
3768
3764
|
}
|
|
3769
3765
|
function findTextNodes(node, options) {
|
|
3770
3766
|
const { accessible = false } = options;
|
|
3771
|
-
|
|
3767
|
+
const text = [];
|
|
3772
3768
|
for (const child of node.childNodes) {
|
|
3773
3769
|
if (isTextNode(child)) {
|
|
3774
3770
|
text.push(child);
|
|
@@ -3779,7 +3775,7 @@ function findTextNodes(node, options) {
|
|
|
3779
3775
|
if (accessible && isAriaHidden(child, true).bySelf) {
|
|
3780
3776
|
continue;
|
|
3781
3777
|
}
|
|
3782
|
-
text
|
|
3778
|
+
text.push(...findTextNodes(child, options));
|
|
3783
3779
|
}
|
|
3784
3780
|
}
|
|
3785
3781
|
return text;
|
|
@@ -3840,14 +3836,17 @@ function format(value, quote = false) {
|
|
|
3840
3836
|
return String(value);
|
|
3841
3837
|
}
|
|
3842
3838
|
function interpolate(text, data) {
|
|
3843
|
-
return text.replaceAll(
|
|
3839
|
+
return text.replaceAll(/\{\{\s*([^\s{}]+)\s*\}\}/g, (match, key) => {
|
|
3844
3840
|
return data[key] !== void 0 ? format(data[key]) : match;
|
|
3845
3841
|
});
|
|
3846
3842
|
}
|
|
3847
3843
|
|
|
3848
|
-
const ajv$1 =
|
|
3849
|
-
|
|
3850
|
-
|
|
3844
|
+
const ajv$1 = (() => {
|
|
3845
|
+
const ajv2 = new Ajv__default.default({ strict: true, strictTuples: true, strictTypes: true });
|
|
3846
|
+
ajv2.addMetaSchema(ajvSchemaDraft);
|
|
3847
|
+
ajv2.addKeyword(ajvRegexpKeyword);
|
|
3848
|
+
return ajv2;
|
|
3849
|
+
})();
|
|
3851
3850
|
function getSchemaValidator(ruleId, properties) {
|
|
3852
3851
|
const $id = `rule/${ruleId}`;
|
|
3853
3852
|
const cached = ajv$1.getSchema($id);
|
|
@@ -3868,10 +3867,9 @@ function isErrorDescriptor(value) {
|
|
|
3868
3867
|
function unpackErrorDescriptor(value) {
|
|
3869
3868
|
if (isErrorDescriptor(value)) {
|
|
3870
3869
|
return value[0];
|
|
3871
|
-
} else {
|
|
3872
|
-
const [node, message, location, context] = value;
|
|
3873
|
-
return { node, message, location, context };
|
|
3874
3870
|
}
|
|
3871
|
+
const [node, message, location, context] = value;
|
|
3872
|
+
return { node, message, location, context };
|
|
3875
3873
|
}
|
|
3876
3874
|
class Rule {
|
|
3877
3875
|
reporter;
|
|
@@ -4077,17 +4075,18 @@ class Rule {
|
|
|
4077
4075
|
const callback = args.pop();
|
|
4078
4076
|
const filter = args.pop() ?? (() => true);
|
|
4079
4077
|
return this.parser.on(event, (_event, data) => {
|
|
4080
|
-
if (this.isEnabled()
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4078
|
+
if (!this.isEnabled() || !filter(data)) {
|
|
4079
|
+
return;
|
|
4080
|
+
}
|
|
4081
|
+
this.event = data;
|
|
4082
|
+
const { tracker } = this;
|
|
4083
|
+
if (tracker) {
|
|
4084
|
+
const start = performance.now();
|
|
4085
|
+
callback(data);
|
|
4086
|
+
const end = performance.now();
|
|
4087
|
+
tracker.trackRule(this.name, end - start);
|
|
4088
|
+
} else {
|
|
4089
|
+
callback(data);
|
|
4091
4090
|
}
|
|
4092
4091
|
});
|
|
4093
4092
|
}
|
|
@@ -4157,7 +4156,7 @@ class Rule {
|
|
|
4157
4156
|
* @public
|
|
4158
4157
|
* @virtual
|
|
4159
4158
|
* @param context - Error context given by a reported error.
|
|
4160
|
-
* @returns Rule documentation and
|
|
4159
|
+
* @returns Rule documentation and URL with additional details or `null` if no
|
|
4161
4160
|
* additional documentation is available.
|
|
4162
4161
|
*/
|
|
4163
4162
|
documentation(_context) {
|
|
@@ -4196,7 +4195,7 @@ function parseAllow(value) {
|
|
|
4196
4195
|
};
|
|
4197
4196
|
}
|
|
4198
4197
|
function matchList(value, list) {
|
|
4199
|
-
if (list.include
|
|
4198
|
+
if (list.include?.every((it) => !it.test(value))) {
|
|
4200
4199
|
return false;
|
|
4201
4200
|
}
|
|
4202
4201
|
if (list.exclude?.some((it) => it.test(value))) {
|
|
@@ -4281,10 +4280,10 @@ class AllowedLinks extends Rule {
|
|
|
4281
4280
|
return Boolean(attr && attr === key);
|
|
4282
4281
|
}
|
|
4283
4282
|
getStyle(value) {
|
|
4284
|
-
if (/^([a-z]+:)
|
|
4283
|
+
if (/^(?:[a-z]+:)?\/\//.test(value)) {
|
|
4285
4284
|
return "external" /* EXTERNAL */;
|
|
4286
4285
|
}
|
|
4287
|
-
switch (value
|
|
4286
|
+
switch (value.at(0)) {
|
|
4288
4287
|
/* /foo/bar */
|
|
4289
4288
|
case "/":
|
|
4290
4289
|
return "absolute" /* ABSOLUTE */;
|
|
@@ -4303,7 +4302,8 @@ class AllowedLinks extends Rule {
|
|
|
4303
4302
|
const { allowAbsolute } = this;
|
|
4304
4303
|
if (allowAbsolute === true) {
|
|
4305
4304
|
return;
|
|
4306
|
-
}
|
|
4305
|
+
}
|
|
4306
|
+
if (allowAbsolute === false) {
|
|
4307
4307
|
this.report(
|
|
4308
4308
|
event.target,
|
|
4309
4309
|
"Link destination must not be absolute url",
|
|
@@ -4323,7 +4323,8 @@ class AllowedLinks extends Rule {
|
|
|
4323
4323
|
const { allowExternal } = this;
|
|
4324
4324
|
if (allowExternal === true) {
|
|
4325
4325
|
return;
|
|
4326
|
-
}
|
|
4326
|
+
}
|
|
4327
|
+
if (allowExternal === false) {
|
|
4327
4328
|
this.report(
|
|
4328
4329
|
event.target,
|
|
4329
4330
|
"Link destination must not be external url",
|
|
@@ -4343,7 +4344,8 @@ class AllowedLinks extends Rule {
|
|
|
4343
4344
|
const { allowRelative } = this;
|
|
4344
4345
|
if (allowRelative === true) {
|
|
4345
4346
|
return false;
|
|
4346
|
-
}
|
|
4347
|
+
}
|
|
4348
|
+
if (allowRelative === false) {
|
|
4347
4349
|
this.report(
|
|
4348
4350
|
event.target,
|
|
4349
4351
|
"Link destination must not be relative url",
|
|
@@ -4351,7 +4353,8 @@ class AllowedLinks extends Rule {
|
|
|
4351
4353
|
style
|
|
4352
4354
|
);
|
|
4353
4355
|
return true;
|
|
4354
|
-
}
|
|
4356
|
+
}
|
|
4357
|
+
if (!matchList(target, allowRelative)) {
|
|
4355
4358
|
this.report(
|
|
4356
4359
|
event.target,
|
|
4357
4360
|
"Relative link to this destination is not allowed by current configuration",
|
|
@@ -4366,7 +4369,8 @@ class AllowedLinks extends Rule {
|
|
|
4366
4369
|
const { allowBase } = this.options;
|
|
4367
4370
|
if (this.handleRelativePath(target, event, style)) {
|
|
4368
4371
|
return;
|
|
4369
|
-
}
|
|
4372
|
+
}
|
|
4373
|
+
if (!allowBase) {
|
|
4370
4374
|
this.report(
|
|
4371
4375
|
event.target,
|
|
4372
4376
|
"Relative links must be relative to current folder",
|
|
@@ -4584,12 +4588,11 @@ class AriaLabelMisuse extends Rule {
|
|
|
4584
4588
|
].join("\n"),
|
|
4585
4589
|
url
|
|
4586
4590
|
};
|
|
4587
|
-
} else {
|
|
4588
|
-
return {
|
|
4589
|
-
description: [`\`${context.attr}\` can only be used on:`, "", ...lines].join("\n"),
|
|
4590
|
-
url
|
|
4591
|
-
};
|
|
4592
4591
|
}
|
|
4592
|
+
return {
|
|
4593
|
+
description: [`\`${context.attr}\` can only be used on:`, "", ...lines].join("\n"),
|
|
4594
|
+
url
|
|
4595
|
+
};
|
|
4593
4596
|
}
|
|
4594
4597
|
setup() {
|
|
4595
4598
|
this.on("dom:ready", (event) => {
|
|
@@ -4647,6 +4650,7 @@ class AriaLabelMisuse extends Rule {
|
|
|
4647
4650
|
}
|
|
4648
4651
|
|
|
4649
4652
|
class ConfigError extends UserError {
|
|
4653
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
4650
4654
|
constructor(message, nested) {
|
|
4651
4655
|
super(message, nested);
|
|
4652
4656
|
this.name = "ConfigError";
|
|
@@ -4767,9 +4771,8 @@ class AttrCase extends Rule {
|
|
|
4767
4771
|
isIgnored(node) {
|
|
4768
4772
|
if (this.options.ignoreForeign) {
|
|
4769
4773
|
return Boolean(node.meta?.foreign);
|
|
4770
|
-
} else {
|
|
4771
|
-
return false;
|
|
4772
4774
|
}
|
|
4775
|
+
return false;
|
|
4773
4776
|
}
|
|
4774
4777
|
}
|
|
4775
4778
|
|
|
@@ -4816,14 +4819,21 @@ class Context {
|
|
|
4816
4819
|
return JSON.stringify(this.string.length > n ? `${this.string.slice(0, 10)}...` : this.string);
|
|
4817
4820
|
}
|
|
4818
4821
|
consume(n, state) {
|
|
4819
|
-
let
|
|
4820
|
-
let
|
|
4821
|
-
|
|
4822
|
-
this.
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4822
|
+
let lastNewline = -1;
|
|
4823
|
+
let newlines = 0;
|
|
4824
|
+
for (let i = 0; i < n; i++) {
|
|
4825
|
+
if (this.string[i] !== "\n") {
|
|
4826
|
+
continue;
|
|
4827
|
+
}
|
|
4828
|
+
newlines++;
|
|
4829
|
+
lastNewline = i;
|
|
4830
|
+
}
|
|
4831
|
+
if (newlines > 0) {
|
|
4832
|
+
this.line += newlines;
|
|
4833
|
+
this.column = n - lastNewline;
|
|
4834
|
+
} else {
|
|
4835
|
+
this.column += n;
|
|
4836
|
+
}
|
|
4827
4837
|
this.offset += n;
|
|
4828
4838
|
this.string = this.string.slice(n);
|
|
4829
4839
|
this.state = state;
|
|
@@ -4878,28 +4888,29 @@ const MATCH_DOCTYPE_CLOSE = /^>/;
|
|
|
4878
4888
|
const MATCH_XML_TAG = /^<\?xml.*?\?>\s+/;
|
|
4879
4889
|
const MATCH_TAG_OPEN = /^<(\/?)([\w:\-]+)/;
|
|
4880
4890
|
const MATCH_TAG_CLOSE = /^\/?>/;
|
|
4881
|
-
const MATCH_TEXT = /^[
|
|
4891
|
+
const MATCH_TEXT = /^[\s\S]*?(?=[\t ]*(?:\r\n|\r|\n)|<[^ ]|$)/;
|
|
4882
4892
|
const MATCH_TEMPLATING = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)/s;
|
|
4883
|
-
const MATCH_TAG_LOOKAHEAD = /^[
|
|
4893
|
+
const MATCH_TAG_LOOKAHEAD = /^[\s\S]*?(?=<|$)/;
|
|
4884
4894
|
const MATCH_ATTR_START = /^([^\t\n\f\r "'/<=>]+)/;
|
|
4885
|
-
const MATCH_ATTR_SINGLE = /^(\s*=\s*)'([^']
|
|
4886
|
-
const MATCH_ATTR_DOUBLE = /^(\s*=\s*)"([^"]
|
|
4895
|
+
const MATCH_ATTR_SINGLE = /^(\s*=\s*)'([^']*)(')/;
|
|
4896
|
+
const MATCH_ATTR_DOUBLE = /^(\s*=\s*)"([^"]*)(")/;
|
|
4887
4897
|
const MATCH_ATTR_UNQUOTED = /^(\s*=\s*)([^\t\n\f\r "'<>][^\t\n\f\r <>]*)/;
|
|
4888
4898
|
const MATCH_CDATA_BEGIN = /^<!\[CDATA\[/;
|
|
4889
|
-
const MATCH_CDATA_END = /^[
|
|
4890
|
-
const MATCH_SCRIPT_DATA = /^[
|
|
4899
|
+
const MATCH_CDATA_END = /^[\s\S]*?\]\]>/;
|
|
4900
|
+
const MATCH_SCRIPT_DATA = /^[\s\S]*?(?=<\/script)/;
|
|
4891
4901
|
const MATCH_SCRIPT_END = /^<(\/)(script)/;
|
|
4892
|
-
const MATCH_STYLE_DATA = /^[
|
|
4902
|
+
const MATCH_STYLE_DATA = /^[\s\S]*?(?=<\/style)/;
|
|
4893
4903
|
const MATCH_STYLE_END = /^<(\/)(style)/;
|
|
4894
|
-
const MATCH_TEXTAREA_DATA = /^[
|
|
4904
|
+
const MATCH_TEXTAREA_DATA = /^[\s\S]*?(?=<\/textarea)/;
|
|
4895
4905
|
const MATCH_TEXTAREA_END = /^<(\/)(textarea)/;
|
|
4896
|
-
const MATCH_TITLE_DATA = /^[
|
|
4906
|
+
const MATCH_TITLE_DATA = /^[\s\S]*?(?=<\/title)/;
|
|
4897
4907
|
const MATCH_TITLE_END = /^<(\/)(title)/;
|
|
4898
|
-
const MATCH_DIRECTIVE = /^(<!--\s*\[?)(html-validate-)([\da-z-]+)(\s*)(.*?)(]?\s*-->)/;
|
|
4899
|
-
const MATCH_COMMENT = /^<!--([
|
|
4900
|
-
const MATCH_CONDITIONAL = /^<!\[([^\]]
|
|
4908
|
+
const MATCH_DIRECTIVE = /^(<!--\s*\[?)(html-validate-)([\da-z-]+)(\s*)(.*?)(\]?\s*-->)/;
|
|
4909
|
+
const MATCH_COMMENT = /^<!--([\s\S]*?)-->/;
|
|
4910
|
+
const MATCH_CONDITIONAL = /^<!\[([^\]]*)\]>/;
|
|
4901
4911
|
class InvalidTokenError extends Error {
|
|
4902
4912
|
location;
|
|
4913
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
4903
4914
|
constructor(location, message) {
|
|
4904
4915
|
super(message);
|
|
4905
4916
|
this.name = "InvalidTokenError";
|
|
@@ -4983,9 +4994,8 @@ class Lexer {
|
|
|
4983
4994
|
evalNextState(nextState, token) {
|
|
4984
4995
|
if (typeof nextState === "function") {
|
|
4985
4996
|
return nextState(token);
|
|
4986
|
-
} else {
|
|
4987
|
-
return nextState;
|
|
4988
4997
|
}
|
|
4998
|
+
return nextState;
|
|
4989
4999
|
}
|
|
4990
5000
|
*match(context, tests, error) {
|
|
4991
5001
|
const n = tests.length;
|
|
@@ -5072,27 +5082,26 @@ class Lexer {
|
|
|
5072
5082
|
case ContentModel.SCRIPT:
|
|
5073
5083
|
if (selfClosed) {
|
|
5074
5084
|
return State.SCRIPT;
|
|
5075
|
-
} else {
|
|
5076
|
-
return State.TEXT;
|
|
5077
5085
|
}
|
|
5086
|
+
return State.TEXT;
|
|
5087
|
+
/* <script/> (not legal but handle it anyway so the lexer doesn't choke on it) */
|
|
5078
5088
|
case ContentModel.STYLE:
|
|
5079
5089
|
if (selfClosed) {
|
|
5080
5090
|
return State.STYLE;
|
|
5081
|
-
} else {
|
|
5082
|
-
return State.TEXT;
|
|
5083
5091
|
}
|
|
5092
|
+
return State.TEXT;
|
|
5093
|
+
/* <style/> */
|
|
5084
5094
|
case ContentModel.TEXTAREA:
|
|
5085
5095
|
if (selfClosed) {
|
|
5086
5096
|
return State.TEXTAREA;
|
|
5087
|
-
} else {
|
|
5088
|
-
return State.TEXT;
|
|
5089
5097
|
}
|
|
5098
|
+
return State.TEXT;
|
|
5099
|
+
/* <textarea/> */
|
|
5090
5100
|
case ContentModel.TITLE:
|
|
5091
5101
|
if (selfClosed) {
|
|
5092
5102
|
return State.TITLE;
|
|
5093
|
-
} else {
|
|
5094
|
-
return State.TEXT;
|
|
5095
5103
|
}
|
|
5104
|
+
return State.TEXT;
|
|
5096
5105
|
}
|
|
5097
5106
|
}
|
|
5098
5107
|
yield* this.match(
|
|
@@ -5179,7 +5188,7 @@ class Lexer {
|
|
|
5179
5188
|
}
|
|
5180
5189
|
}
|
|
5181
5190
|
|
|
5182
|
-
const whitespace =
|
|
5191
|
+
const whitespace = /\s+/;
|
|
5183
5192
|
class AttrDelimiter extends Rule {
|
|
5184
5193
|
documentation() {
|
|
5185
5194
|
return {
|
|
@@ -5211,17 +5220,15 @@ const defaults$y = {
|
|
|
5211
5220
|
function generateRegexp(pattern) {
|
|
5212
5221
|
if (Array.isArray(pattern)) {
|
|
5213
5222
|
return new RegExp(`^(${pattern.join("|")})$`, "i");
|
|
5214
|
-
} else {
|
|
5215
|
-
return new RegExp(`^${pattern}$`, "i");
|
|
5216
5223
|
}
|
|
5224
|
+
return new RegExp(`^${pattern}$`, "i");
|
|
5217
5225
|
}
|
|
5218
5226
|
function generateMessage(name, pattern) {
|
|
5219
5227
|
if (Array.isArray(pattern)) {
|
|
5220
5228
|
const patterns = pattern.map((it) => `/${it}/`).join(", ");
|
|
5221
5229
|
return `Attribute "${name}" should match one of [${patterns}]`;
|
|
5222
|
-
} else {
|
|
5223
|
-
return `Attribute "${name}" should match /${pattern}/`;
|
|
5224
5230
|
}
|
|
5231
|
+
return `Attribute "${name}" should match /${pattern}/`;
|
|
5225
5232
|
}
|
|
5226
5233
|
function generateDescription(name, pattern) {
|
|
5227
5234
|
if (Array.isArray(pattern)) {
|
|
@@ -5230,9 +5237,8 @@ function generateDescription(name, pattern) {
|
|
|
5230
5237
|
"",
|
|
5231
5238
|
...pattern.map((it) => `- \`/${it}/\``)
|
|
5232
5239
|
].join("\n");
|
|
5233
|
-
} else {
|
|
5234
|
-
return `Attribute "${name}" should match the regular expression \`/${pattern}/\``;
|
|
5235
5240
|
}
|
|
5241
|
+
return `Attribute "${name}" should match the regular expression \`/${pattern}/\``;
|
|
5236
5242
|
}
|
|
5237
5243
|
class AttrPattern extends Rule {
|
|
5238
5244
|
pattern;
|
|
@@ -5278,9 +5284,8 @@ class AttrPattern extends Rule {
|
|
|
5278
5284
|
isIgnored(node) {
|
|
5279
5285
|
if (this.options.ignoreForeign) {
|
|
5280
5286
|
return Boolean(node.meta?.foreign);
|
|
5281
|
-
} else {
|
|
5282
|
-
return false;
|
|
5283
5287
|
}
|
|
5288
|
+
return false;
|
|
5284
5289
|
}
|
|
5285
5290
|
}
|
|
5286
5291
|
|
|
@@ -5391,9 +5396,8 @@ class AttrQuotes extends Rule {
|
|
|
5391
5396
|
resolveQuotemark(value, style) {
|
|
5392
5397
|
if (style === "auto" /* AUTO_QUOTE */) {
|
|
5393
5398
|
return value.includes('"') ? "'" : '"';
|
|
5394
|
-
} else {
|
|
5395
|
-
return style;
|
|
5396
5399
|
}
|
|
5400
|
+
return style;
|
|
5397
5401
|
}
|
|
5398
5402
|
}
|
|
5399
5403
|
function parseStyle$3(style) {
|
|
@@ -5451,11 +5455,11 @@ class AttributeAllowedValues extends Rule {
|
|
|
5451
5455
|
const allowedList = allowed.enum.map((value2) => {
|
|
5452
5456
|
if (typeof value2 === "string") {
|
|
5453
5457
|
return `- \`"${value2}"\``;
|
|
5454
|
-
}
|
|
5458
|
+
}
|
|
5459
|
+
if (value2 instanceof RegExp) {
|
|
5455
5460
|
return `- \`${value2.toString()}\``;
|
|
5456
|
-
} else {
|
|
5457
|
-
return `- ${value2.name}`;
|
|
5458
5461
|
}
|
|
5462
|
+
return `- ${value2.name}`;
|
|
5459
5463
|
});
|
|
5460
5464
|
docs.description = [
|
|
5461
5465
|
`The \`<${element}>\` element does not allow the attribute \`${attribute}\` to have the value \`"${value}"\`.`,
|
|
@@ -5499,9 +5503,8 @@ class AttributeAllowedValues extends Rule {
|
|
|
5499
5503
|
const { key, value } = attr;
|
|
5500
5504
|
if (value !== null) {
|
|
5501
5505
|
return `Attribute "${key}" has invalid value "${value.toString()}"`;
|
|
5502
|
-
} else {
|
|
5503
|
-
return `Attribute "${key}" is missing value`;
|
|
5504
5506
|
}
|
|
5507
|
+
return `Attribute "${key}" is missing value`;
|
|
5505
5508
|
}
|
|
5506
5509
|
getLocation(attr) {
|
|
5507
5510
|
return attr.valueLocation ?? attr.keyLocation;
|
|
@@ -5788,10 +5791,10 @@ class AutocompletePassword extends Rule {
|
|
|
5788
5791
|
const tokens = new DOMTokenList(raw, autocomplete.valueLocation);
|
|
5789
5792
|
const index = tokens.findIndex((token) => !isGroupingToken(token));
|
|
5790
5793
|
const value = tokens.item(index);
|
|
5791
|
-
const location = tokens.location(index);
|
|
5792
5794
|
if (!value) {
|
|
5793
5795
|
return;
|
|
5794
5796
|
}
|
|
5797
|
+
const location = tokens.location(index);
|
|
5795
5798
|
if (value === "off") {
|
|
5796
5799
|
const context = { kind: "off" };
|
|
5797
5800
|
this.report({
|
|
@@ -5876,9 +5879,8 @@ function parsePattern(pattern) {
|
|
|
5876
5879
|
function toArray$2(value) {
|
|
5877
5880
|
if (Array.isArray(value)) {
|
|
5878
5881
|
return value;
|
|
5879
|
-
} else {
|
|
5880
|
-
return [value];
|
|
5881
5882
|
}
|
|
5883
|
+
return [value];
|
|
5882
5884
|
}
|
|
5883
5885
|
function validateAllowedPatterns(patterns, allowedPatterns, ruleId) {
|
|
5884
5886
|
const extraneous = patterns.filter(isNamedPattern).filter((p) => !allowedPatterns.has(p));
|
|
@@ -5964,7 +5966,7 @@ class ClassPattern extends BasePatternRule {
|
|
|
5964
5966
|
});
|
|
5965
5967
|
}
|
|
5966
5968
|
static schema() {
|
|
5967
|
-
return
|
|
5969
|
+
return super.schema();
|
|
5968
5970
|
}
|
|
5969
5971
|
documentation(context) {
|
|
5970
5972
|
return {
|
|
@@ -6045,10 +6047,10 @@ class CloseOrder extends Rule {
|
|
|
6045
6047
|
});
|
|
6046
6048
|
this.on("tag:end", (event) => {
|
|
6047
6049
|
const current = event.target;
|
|
6048
|
-
const active = event.previous;
|
|
6049
6050
|
if (current) {
|
|
6050
6051
|
return;
|
|
6051
6052
|
}
|
|
6053
|
+
const active = event.previous;
|
|
6052
6054
|
for (const ancestor of ancestors(active)) {
|
|
6053
6055
|
if (ancestor.isRootElement() || reported.has(ancestor.unique)) {
|
|
6054
6056
|
continue;
|
|
@@ -6059,13 +6061,13 @@ class CloseOrder extends Rule {
|
|
|
6059
6061
|
});
|
|
6060
6062
|
this.on("tag:end", (event) => {
|
|
6061
6063
|
const current = event.target;
|
|
6062
|
-
const active = event.previous;
|
|
6063
6064
|
if (!current) {
|
|
6064
6065
|
return;
|
|
6065
6066
|
}
|
|
6066
6067
|
if (current.voidElement) {
|
|
6067
6068
|
return;
|
|
6068
6069
|
}
|
|
6070
|
+
const active = event.previous;
|
|
6069
6071
|
if (active.closed === Node.CLOSED_IMPLICIT_CLOSED) {
|
|
6070
6072
|
return;
|
|
6071
6073
|
}
|
|
@@ -6160,7 +6162,7 @@ class Deprecated extends Rule {
|
|
|
6160
6162
|
text.push(context.documentation);
|
|
6161
6163
|
}
|
|
6162
6164
|
const doc = {
|
|
6163
|
-
description: text.map((cur) => cur.replaceAll("$tagname", context.tagName)).join("\n\n"),
|
|
6165
|
+
description: text.map((cur) => cur.replaceAll("$tagname", () => context.tagName)).join("\n\n"),
|
|
6164
6166
|
url: "https://html-validate.org/rules/deprecated.html"
|
|
6165
6167
|
};
|
|
6166
6168
|
return doc;
|
|
@@ -6559,7 +6561,7 @@ class ElementName extends Rule {
|
|
|
6559
6561
|
];
|
|
6560
6562
|
}
|
|
6561
6563
|
setup() {
|
|
6562
|
-
const xmlns = /^
|
|
6564
|
+
const xmlns = /^[^:]+:.+$/;
|
|
6563
6565
|
this.on("tag:start", (event) => {
|
|
6564
6566
|
const target = event.target;
|
|
6565
6567
|
const tagName = target.tagName;
|
|
@@ -6598,13 +6600,12 @@ function isNativeTemplate(node) {
|
|
|
6598
6600
|
function getTransparentChildren(node, transparent) {
|
|
6599
6601
|
if (typeof transparent === "boolean") {
|
|
6600
6602
|
return node.childElements;
|
|
6601
|
-
} else {
|
|
6602
|
-
return node.childElements.filter((it) => {
|
|
6603
|
-
return transparent.some((category) => {
|
|
6604
|
-
return Validator.validatePermittedCategory(it, category, false);
|
|
6605
|
-
});
|
|
6606
|
-
});
|
|
6607
6603
|
}
|
|
6604
|
+
return node.childElements.filter((it) => {
|
|
6605
|
+
return transparent.some((category) => {
|
|
6606
|
+
return Validator.validatePermittedCategory(it, category, false);
|
|
6607
|
+
});
|
|
6608
|
+
});
|
|
6608
6609
|
}
|
|
6609
6610
|
function getRuleDescription$2(context) {
|
|
6610
6611
|
switch (context.kind) {
|
|
@@ -6636,6 +6637,7 @@ class ElementPermittedContent extends Rule {
|
|
|
6636
6637
|
[
|
|
6637
6638
|
() => this.validatePermittedContent(node, parent),
|
|
6638
6639
|
() => this.validatePermittedDescendant(node, parent)
|
|
6640
|
+
/* eslint-disable-next-line unicorn/no-unused-array-method-return -- technical debt, should use iterator helpers */
|
|
6639
6641
|
].some((fn) => fn());
|
|
6640
6642
|
});
|
|
6641
6643
|
});
|
|
@@ -6781,14 +6783,12 @@ function getRuleDescription$1(context) {
|
|
|
6781
6783
|
const allowed = rules.filter(isCategoryOrTag).map((it) => {
|
|
6782
6784
|
if (isCategory$1(it)) {
|
|
6783
6785
|
return `- any ${it.slice(1)} element`;
|
|
6784
|
-
} else {
|
|
6785
|
-
return `- \`<${it}>\``;
|
|
6786
6786
|
}
|
|
6787
|
+
return `- \`<${it}>\``;
|
|
6787
6788
|
});
|
|
6788
6789
|
return [preamble, "", "Allowed parents one of:", "", ...allowed];
|
|
6789
|
-
} else {
|
|
6790
|
-
return [preamble];
|
|
6791
6790
|
}
|
|
6791
|
+
return [preamble];
|
|
6792
6792
|
}
|
|
6793
6793
|
function formatMessage$1(node, parent, rules) {
|
|
6794
6794
|
const nodeName = node.annotatedName;
|
|
@@ -6840,7 +6840,7 @@ class ElementPermittedParent extends Rule {
|
|
|
6840
6840
|
}
|
|
6841
6841
|
|
|
6842
6842
|
function isTagnameOnly(value) {
|
|
6843
|
-
return /^[\dA-
|
|
6843
|
+
return /^[\dA-Z-]+$/i.test(value);
|
|
6844
6844
|
}
|
|
6845
6845
|
function getRuleDescription(context) {
|
|
6846
6846
|
const escaped = context.ancestor.map((it) => `\`${it}\``);
|
|
@@ -6903,9 +6903,8 @@ function normalizeRequired(element, attr) {
|
|
|
6903
6903
|
default:
|
|
6904
6904
|
return result;
|
|
6905
6905
|
}
|
|
6906
|
-
} else {
|
|
6907
|
-
return required ? defaultMessage : false;
|
|
6908
6906
|
}
|
|
6907
|
+
return required ? defaultMessage : false;
|
|
6909
6908
|
}
|
|
6910
6909
|
class ElementRequiredAttributes extends Rule {
|
|
6911
6910
|
documentation(context) {
|
|
@@ -6987,7 +6986,8 @@ const selector = ["h1", "h2", "h3", "h4", "h5", "h6"].join(",");
|
|
|
6987
6986
|
function hasImgAltText$1(node) {
|
|
6988
6987
|
if (node.is("img")) {
|
|
6989
6988
|
return hasAltText(node);
|
|
6990
|
-
}
|
|
6989
|
+
}
|
|
6990
|
+
if (node.is("svg")) {
|
|
6991
6991
|
return node.textContent.trim() !== "";
|
|
6992
6992
|
}
|
|
6993
6993
|
return false;
|
|
@@ -7268,21 +7268,19 @@ class FormDupName extends Rule {
|
|
|
7268
7268
|
const existing = group.cacheGet(UNIQUE_CACHE_KEY);
|
|
7269
7269
|
if (existing) {
|
|
7270
7270
|
return existing;
|
|
7271
|
-
} else {
|
|
7272
|
-
const elements = /* @__PURE__ */ new Map();
|
|
7273
|
-
group.cacheSet(UNIQUE_CACHE_KEY, elements);
|
|
7274
|
-
return elements;
|
|
7275
7271
|
}
|
|
7272
|
+
const elements = /* @__PURE__ */ new Map();
|
|
7273
|
+
group.cacheSet(UNIQUE_CACHE_KEY, elements);
|
|
7274
|
+
return elements;
|
|
7276
7275
|
}
|
|
7277
7276
|
getSharedElements(group) {
|
|
7278
7277
|
const existing = group.cacheGet(SHARED_CACHE_KEY);
|
|
7279
7278
|
if (existing) {
|
|
7280
7279
|
return existing;
|
|
7281
|
-
} else {
|
|
7282
|
-
const elements = /* @__PURE__ */ new Map();
|
|
7283
|
-
group.cacheSet(SHARED_CACHE_KEY, elements);
|
|
7284
|
-
return elements;
|
|
7285
7280
|
}
|
|
7281
|
+
const elements = /* @__PURE__ */ new Map();
|
|
7282
|
+
group.cacheSet(SHARED_CACHE_KEY, elements);
|
|
7283
|
+
return elements;
|
|
7286
7284
|
}
|
|
7287
7285
|
}
|
|
7288
7286
|
|
|
@@ -7296,12 +7294,11 @@ function isRelevant$5(event) {
|
|
|
7296
7294
|
return Boolean(node.meta?.heading);
|
|
7297
7295
|
}
|
|
7298
7296
|
function extractLevel(node) {
|
|
7299
|
-
const match = /^
|
|
7297
|
+
const match = /^H(\d)$/i.exec(node.tagName);
|
|
7300
7298
|
if (match) {
|
|
7301
|
-
return
|
|
7302
|
-
} else {
|
|
7303
|
-
return null;
|
|
7299
|
+
return Math.trunc(Number(match[1]));
|
|
7304
7300
|
}
|
|
7301
|
+
return null;
|
|
7305
7302
|
}
|
|
7306
7303
|
function parseMaxInitial(value) {
|
|
7307
7304
|
if (value === false || value === "any") {
|
|
@@ -7311,7 +7308,7 @@ function parseMaxInitial(value) {
|
|
|
7311
7308
|
if (!match) {
|
|
7312
7309
|
return 1;
|
|
7313
7310
|
}
|
|
7314
|
-
return
|
|
7311
|
+
return Math.trunc(Number(match[1]));
|
|
7315
7312
|
}
|
|
7316
7313
|
class HeadingLevel extends Rule {
|
|
7317
7314
|
minInitialRank;
|
|
@@ -7578,7 +7575,7 @@ class IdPattern extends BasePatternRule {
|
|
|
7578
7575
|
});
|
|
7579
7576
|
}
|
|
7580
7577
|
static schema() {
|
|
7581
|
-
return
|
|
7578
|
+
return super.schema();
|
|
7582
7579
|
}
|
|
7583
7580
|
documentation(context) {
|
|
7584
7581
|
return {
|
|
@@ -7800,24 +7797,23 @@ function isHidden(node, context) {
|
|
|
7800
7797
|
const { reference } = context;
|
|
7801
7798
|
if (reference?.isSameNode(node)) {
|
|
7802
7799
|
return false;
|
|
7803
|
-
} else {
|
|
7804
|
-
return !inAccessibilityTree(node);
|
|
7805
7800
|
}
|
|
7801
|
+
return !inAccessibilityTree(node);
|
|
7806
7802
|
}
|
|
7807
7803
|
function hasImgAltText(node, context) {
|
|
7808
7804
|
if (node.is("img")) {
|
|
7809
7805
|
return hasAltText(node);
|
|
7810
|
-
}
|
|
7806
|
+
}
|
|
7807
|
+
if (node.is("svg")) {
|
|
7811
7808
|
return node.textContent.trim() !== "";
|
|
7812
|
-
}
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
}
|
|
7809
|
+
}
|
|
7810
|
+
for (const img of node.querySelectorAll("img, svg")) {
|
|
7811
|
+
const hasName = hasAccessibleNameImpl(img, context);
|
|
7812
|
+
if (hasName) {
|
|
7813
|
+
return true;
|
|
7818
7814
|
}
|
|
7819
|
-
return false;
|
|
7820
7815
|
}
|
|
7816
|
+
return false;
|
|
7821
7817
|
}
|
|
7822
7818
|
function hasLabel(node) {
|
|
7823
7819
|
const value = node.getAttributeValue("aria-label") ?? "";
|
|
@@ -7948,7 +7944,7 @@ class InputMissingLabel extends Rule {
|
|
|
7948
7944
|
this.report(elem, `<${elem.tagName}> element has <label> but <label> element is hidden`);
|
|
7949
7945
|
return;
|
|
7950
7946
|
}
|
|
7951
|
-
if (
|
|
7947
|
+
if (labels.every((label) => !hasAccessibleName(root, label))) {
|
|
7952
7948
|
this.report(elem, `<${elem.tagName}> element has <label> but <label> has no text`);
|
|
7953
7949
|
}
|
|
7954
7950
|
}
|
|
@@ -8135,12 +8131,11 @@ function parseContent(text) {
|
|
|
8135
8131
|
const match = /^(\d+)(?:\s*;\s*url=(.*))?/i.exec(text);
|
|
8136
8132
|
if (match) {
|
|
8137
8133
|
return {
|
|
8138
|
-
delay:
|
|
8134
|
+
delay: Math.trunc(Number(match[1])),
|
|
8139
8135
|
url: match[2]
|
|
8140
8136
|
};
|
|
8141
|
-
} else {
|
|
8142
|
-
return null;
|
|
8143
8137
|
}
|
|
8138
|
+
return null;
|
|
8144
8139
|
}
|
|
8145
8140
|
|
|
8146
8141
|
class MissingDoctype extends Rule {
|
|
@@ -8217,7 +8212,7 @@ class NamePattern extends BasePatternRule {
|
|
|
8217
8212
|
});
|
|
8218
8213
|
}
|
|
8219
8214
|
static schema() {
|
|
8220
|
-
return
|
|
8215
|
+
return super.schema();
|
|
8221
8216
|
}
|
|
8222
8217
|
documentation(context) {
|
|
8223
8218
|
return {
|
|
@@ -8400,10 +8395,10 @@ class NoDeprecatedAttr extends Rule {
|
|
|
8400
8395
|
this.on("attr", (event) => {
|
|
8401
8396
|
const node = event.target;
|
|
8402
8397
|
const meta = node.meta;
|
|
8403
|
-
const attr = event.key.toLowerCase();
|
|
8404
8398
|
if (meta === null) {
|
|
8405
8399
|
return;
|
|
8406
8400
|
}
|
|
8401
|
+
const attr = event.key.toLowerCase();
|
|
8407
8402
|
const metaAttribute = meta.attributes[attr];
|
|
8408
8403
|
if (!metaAttribute) {
|
|
8409
8404
|
return;
|
|
@@ -8437,7 +8432,7 @@ class NoDupAttr extends Rule {
|
|
|
8437
8432
|
return;
|
|
8438
8433
|
}
|
|
8439
8434
|
const name = event.key.toLowerCase();
|
|
8440
|
-
if (name
|
|
8435
|
+
if (Object.hasOwn(attr, name)) {
|
|
8441
8436
|
this.report(event.target, `Attribute "${name}" duplicated`, event.keyLocation);
|
|
8442
8437
|
}
|
|
8443
8438
|
attr[event.key] = true;
|
|
@@ -8510,10 +8505,9 @@ function getExisting(element, root) {
|
|
|
8510
8505
|
const existing = group.cacheGet(CACHE_KEY);
|
|
8511
8506
|
if (existing) {
|
|
8512
8507
|
return existing;
|
|
8513
|
-
} else {
|
|
8514
|
-
const existing2 = /* @__PURE__ */ new Set();
|
|
8515
|
-
return group.cacheSet(CACHE_KEY, existing2);
|
|
8516
8508
|
}
|
|
8509
|
+
const value = /* @__PURE__ */ new Set();
|
|
8510
|
+
return group.cacheSet(CACHE_KEY, value);
|
|
8517
8511
|
}
|
|
8518
8512
|
|
|
8519
8513
|
function isRelevant$2(event) {
|
|
@@ -8784,10 +8778,11 @@ class NoMissingReferences extends Rule {
|
|
|
8784
8778
|
}
|
|
8785
8779
|
}
|
|
8786
8780
|
validateSingle(document, node, attr, id) {
|
|
8787
|
-
if (idMissing(document, id)) {
|
|
8788
|
-
|
|
8789
|
-
this.report(node, `Element references missing id "${id}"`, attr.valueLocation, context);
|
|
8781
|
+
if (!idMissing(document, id)) {
|
|
8782
|
+
return;
|
|
8790
8783
|
}
|
|
8784
|
+
const context = { key: attr.key, value: id };
|
|
8785
|
+
this.report(node, `Element references missing id "${id}"`, attr.valueLocation, context);
|
|
8791
8786
|
}
|
|
8792
8787
|
validateList(document, node, attr, values) {
|
|
8793
8788
|
const parsed = new DOMTokenList(values, attr.valueLocation);
|
|
@@ -8827,9 +8822,9 @@ class NoMultipleMain extends Rule {
|
|
|
8827
8822
|
const defaults$f = {
|
|
8828
8823
|
relaxed: false
|
|
8829
8824
|
};
|
|
8830
|
-
const textRegexp = /(<|&(?![\d#A-
|
|
8831
|
-
const unquotedAttrRegexp = /(["'<=>`]|&(?![\d#A-
|
|
8832
|
-
const matchTemplate = /^(
|
|
8825
|
+
const textRegexp = /(<|&(?![\d#A-Z]+;))/gi;
|
|
8826
|
+
const unquotedAttrRegexp = /(["'<=>`]|&(?![\d#A-Z]+;))/gi;
|
|
8827
|
+
const matchTemplate = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)$/s;
|
|
8833
8828
|
const replacementTable = {
|
|
8834
8829
|
'"': """,
|
|
8835
8830
|
"&": "&",
|
|
@@ -9061,7 +9056,7 @@ class NoRedundantRole extends Rule {
|
|
|
9061
9056
|
}
|
|
9062
9057
|
}
|
|
9063
9058
|
|
|
9064
|
-
const xmlns = /^
|
|
9059
|
+
const xmlns = /^[^:]+:.+$/;
|
|
9065
9060
|
const defaults$d = {
|
|
9066
9061
|
ignoreForeign: true,
|
|
9067
9062
|
ignoreXML: true
|
|
@@ -9183,11 +9178,11 @@ class NoUnknownAttributes extends Rule {
|
|
|
9183
9178
|
this.on("attr", (event) => {
|
|
9184
9179
|
const node = event.target;
|
|
9185
9180
|
const meta = node.meta;
|
|
9186
|
-
const attr = event.key.toLowerCase();
|
|
9187
9181
|
if (meta === null) {
|
|
9188
9182
|
return;
|
|
9189
9183
|
}
|
|
9190
|
-
|
|
9184
|
+
const attr = event.key.toLowerCase();
|
|
9185
|
+
if (Object.hasOwn(meta.attributes, attr)) {
|
|
9191
9186
|
return;
|
|
9192
9187
|
}
|
|
9193
9188
|
if (isPatternAttribute(attr, meta.patternAttributes)) {
|
|
@@ -9594,7 +9589,7 @@ const defaults$7 = {
|
|
|
9594
9589
|
include: null,
|
|
9595
9590
|
exclude: null
|
|
9596
9591
|
};
|
|
9597
|
-
const crossorigin =
|
|
9592
|
+
const crossorigin = /^(?:\w+:\/\/|\/\/)/;
|
|
9598
9593
|
const supportSri = {
|
|
9599
9594
|
link: "href",
|
|
9600
9595
|
script: "src"
|
|
@@ -9807,7 +9802,10 @@ function constructRegex(characters) {
|
|
|
9807
9802
|
return new RegExp(pattern, "g");
|
|
9808
9803
|
}
|
|
9809
9804
|
function getText(node) {
|
|
9810
|
-
const match = /^(\s*)(.*)$/.exec(node.textContent);
|
|
9805
|
+
const match = /^(\s*)(\S.*)$/.exec(node.textContent);
|
|
9806
|
+
if (!match) {
|
|
9807
|
+
return [0, ""];
|
|
9808
|
+
}
|
|
9811
9809
|
const [, leading, text] = match;
|
|
9812
9810
|
return [leading.length, text.trimEnd()];
|
|
9813
9811
|
}
|
|
@@ -9960,9 +9958,8 @@ function hasDefaultText(node) {
|
|
|
9960
9958
|
function isNonEmptyText(node) {
|
|
9961
9959
|
if (isTextNode(node)) {
|
|
9962
9960
|
return node.isDynamic || node.textContent.trim() !== "";
|
|
9963
|
-
} else {
|
|
9964
|
-
return false;
|
|
9965
9961
|
}
|
|
9962
|
+
return false;
|
|
9966
9963
|
}
|
|
9967
9964
|
function haveAccessibleText(node) {
|
|
9968
9965
|
if (!inAccessibilityTree(node)) {
|
|
@@ -10097,15 +10094,14 @@ function getTextFromReference(document, id) {
|
|
|
10097
10094
|
const ref = document.querySelector(selector);
|
|
10098
10095
|
if (ref) {
|
|
10099
10096
|
return ref.textContent;
|
|
10100
|
-
} else {
|
|
10101
|
-
return selector;
|
|
10102
10097
|
}
|
|
10098
|
+
return selector;
|
|
10103
10099
|
}
|
|
10104
10100
|
function groupBy(values, callback) {
|
|
10105
10101
|
const result = {};
|
|
10106
10102
|
for (const value of values) {
|
|
10107
10103
|
const key = callback(value);
|
|
10108
|
-
if (key
|
|
10104
|
+
if (Object.hasOwn(result, key)) {
|
|
10109
10105
|
result[key].push(value);
|
|
10110
10106
|
} else {
|
|
10111
10107
|
result[key] = [value];
|
|
@@ -10205,7 +10201,7 @@ const defaults$5 = {
|
|
|
10205
10201
|
ignoreCase: false,
|
|
10206
10202
|
requireSemicolon: true
|
|
10207
10203
|
};
|
|
10208
|
-
const regexp$1 = /&(?:[\da-z]+|#x?[\da-f]+)(
|
|
10204
|
+
const regexp$1 = /&(?:[\da-z]+|#x?[\da-f]+)([^\da-z]|$)/gi;
|
|
10209
10205
|
const lowercaseEntities = elements.entities.map((it) => it.toLowerCase());
|
|
10210
10206
|
function isNumerical(entity) {
|
|
10211
10207
|
return entity.startsWith("&#");
|
|
@@ -10284,9 +10280,8 @@ class UnknownCharReference extends Rule {
|
|
|
10284
10280
|
get entities() {
|
|
10285
10281
|
if (this.options.ignoreCase) {
|
|
10286
10282
|
return lowercaseEntities;
|
|
10287
|
-
} else {
|
|
10288
|
-
return elements.entities;
|
|
10289
10283
|
}
|
|
10284
|
+
return elements.entities;
|
|
10290
10285
|
}
|
|
10291
10286
|
findCharacterReferences(node, text, location, { isAttribute }) {
|
|
10292
10287
|
const delimiter = text.search(/[#?]/);
|
|
@@ -10652,7 +10647,6 @@ class ValidAutocomplete extends Rule {
|
|
|
10652
10647
|
}
|
|
10653
10648
|
validateControlAutocomplete(node, tokens, keyLocation) {
|
|
10654
10649
|
const type = node.getAttributeValue("type") ?? "text";
|
|
10655
|
-
const mantle = type !== "hidden" ? "expectation" : "anchor";
|
|
10656
10650
|
if (isDisallowedType(node, type)) {
|
|
10657
10651
|
const context = {
|
|
10658
10652
|
msg: 0 /* InvalidAttribute */,
|
|
@@ -10667,6 +10661,7 @@ class ValidAutocomplete extends Rule {
|
|
|
10667
10661
|
return;
|
|
10668
10662
|
}
|
|
10669
10663
|
if (tokens.includes("on") || tokens.includes("off")) {
|
|
10664
|
+
const mantle = type !== "hidden" ? "expectation" : "anchor";
|
|
10670
10665
|
this.validateOnOff(node, mantle, tokens);
|
|
10671
10666
|
return;
|
|
10672
10667
|
}
|
|
@@ -10790,44 +10785,46 @@ class ValidAutocomplete extends Rule {
|
|
|
10790
10785
|
* Ensure contact token is only used with field names from the second list.
|
|
10791
10786
|
*/
|
|
10792
10787
|
validateContact(node, tokens, order) {
|
|
10793
|
-
if (order.includes("contact")
|
|
10794
|
-
|
|
10795
|
-
|
|
10788
|
+
if (!order.includes("contact") || !order.includes("field1")) {
|
|
10789
|
+
return;
|
|
10790
|
+
}
|
|
10791
|
+
const a = order.indexOf("field1");
|
|
10792
|
+
const b = order.indexOf("contact");
|
|
10793
|
+
const context = {
|
|
10794
|
+
msg: 4 /* InvalidCombination */,
|
|
10795
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
10796
|
+
first: tokens.item(a),
|
|
10797
|
+
second: tokens.item(b)
|
|
10798
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
10799
|
+
};
|
|
10800
|
+
this.report({
|
|
10801
|
+
node,
|
|
10802
|
+
message: getTerminalMessage(context),
|
|
10803
|
+
location: tokens.location(b),
|
|
10804
|
+
context
|
|
10805
|
+
});
|
|
10806
|
+
}
|
|
10807
|
+
validateOrder(node, tokens, order) {
|
|
10808
|
+
const indicies = order.map((it) => expectedOrder.indexOf(it));
|
|
10809
|
+
for (let i = 0; i < indicies.length - 1; i++) {
|
|
10810
|
+
if (indicies[0] <= indicies[i + 1]) {
|
|
10811
|
+
continue;
|
|
10812
|
+
}
|
|
10796
10813
|
const context = {
|
|
10797
|
-
msg:
|
|
10814
|
+
msg: 2 /* InvalidOrder */,
|
|
10798
10815
|
/* eslint-disable @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
10799
|
-
first: tokens.item(
|
|
10800
|
-
second: tokens.item(
|
|
10816
|
+
first: tokens.item(i),
|
|
10817
|
+
second: tokens.item(i + 1)
|
|
10801
10818
|
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
10802
10819
|
};
|
|
10803
10820
|
this.report({
|
|
10804
10821
|
node,
|
|
10805
10822
|
message: getTerminalMessage(context),
|
|
10806
|
-
location: tokens.location(
|
|
10823
|
+
location: tokens.location(i + 1),
|
|
10807
10824
|
context
|
|
10808
10825
|
});
|
|
10809
10826
|
}
|
|
10810
10827
|
}
|
|
10811
|
-
validateOrder(node, tokens, order) {
|
|
10812
|
-
const indicies = order.map((it) => expectedOrder.indexOf(it));
|
|
10813
|
-
for (let i = 0; i < indicies.length - 1; i++) {
|
|
10814
|
-
if (indicies[0] > indicies[i + 1]) {
|
|
10815
|
-
const context = {
|
|
10816
|
-
msg: 2 /* InvalidOrder */,
|
|
10817
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
10818
|
-
first: tokens.item(i),
|
|
10819
|
-
second: tokens.item(i + 1)
|
|
10820
|
-
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
10821
|
-
};
|
|
10822
|
-
this.report({
|
|
10823
|
-
node,
|
|
10824
|
-
message: getTerminalMessage(context),
|
|
10825
|
-
location: tokens.location(i + 1),
|
|
10826
|
-
context
|
|
10827
|
-
});
|
|
10828
|
-
}
|
|
10829
|
-
}
|
|
10830
|
-
}
|
|
10831
10828
|
validateControlGroup(node, tokens, fieldTokens) {
|
|
10832
10829
|
const numFields = fieldTokens.filter(Boolean).length;
|
|
10833
10830
|
if (numFields === 0) {
|
|
@@ -10919,7 +10916,7 @@ class ValidID extends Rule {
|
|
|
10919
10916
|
documentation(context) {
|
|
10920
10917
|
const { relaxed } = this.options;
|
|
10921
10918
|
const { kind, id } = context;
|
|
10922
|
-
const message = this.messages[kind].replace(`"{{ id }}"`, "`{{ id }}`").replace("id", "ID").replace(
|
|
10919
|
+
const message = this.messages[kind].replace(`"{{ id }}"`, "`{{ id }}`").replace("id", "ID").replace(/^./, (m) => m.toUpperCase());
|
|
10923
10920
|
const relaxedDescription = relaxed ? [] : [
|
|
10924
10921
|
" - ID must begin with a letter",
|
|
10925
10922
|
" - ID must only contain letters, digits, `-` and `_`"
|
|
@@ -10957,7 +10954,7 @@ class ValidID extends Rule {
|
|
|
10957
10954
|
if (relaxed) {
|
|
10958
10955
|
return;
|
|
10959
10956
|
}
|
|
10960
|
-
if (
|
|
10957
|
+
if (new RegExp("^\\P{L}", "u").test(value)) {
|
|
10961
10958
|
const context = { kind: 3 /* LEADING_CHARACTER */, id: value };
|
|
10962
10959
|
this.report(event.target, this.messages[context.kind], event.valueLocation, context);
|
|
10963
10960
|
return;
|
|
@@ -11318,7 +11315,7 @@ function isSimpleTable(table) {
|
|
|
11318
11315
|
return false;
|
|
11319
11316
|
}
|
|
11320
11317
|
const numColumns = cells[0].length;
|
|
11321
|
-
if (
|
|
11318
|
+
if (cells.some((row) => row.length !== numColumns)) {
|
|
11322
11319
|
return false;
|
|
11323
11320
|
}
|
|
11324
11321
|
const shape = getShape(cells);
|
|
@@ -11972,7 +11969,7 @@ class ResolvedConfig {
|
|
|
11972
11969
|
}
|
|
11973
11970
|
|
|
11974
11971
|
function haveResolver(key, value) {
|
|
11975
|
-
return key
|
|
11972
|
+
return Object.hasOwn(value, key);
|
|
11976
11973
|
}
|
|
11977
11974
|
function haveConfigResolver(value) {
|
|
11978
11975
|
return haveResolver("resolveConfig", value);
|
|
@@ -11987,7 +11984,10 @@ function haveTransformerResolver(value) {
|
|
|
11987
11984
|
return haveResolver("resolveTransformer", value);
|
|
11988
11985
|
}
|
|
11989
11986
|
function resolveConfig(resolvers, id, options) {
|
|
11990
|
-
for (const resolver of resolvers
|
|
11987
|
+
for (const resolver of resolvers) {
|
|
11988
|
+
if (!haveConfigResolver(resolver)) {
|
|
11989
|
+
continue;
|
|
11990
|
+
}
|
|
11991
11991
|
const config = resolver.resolveConfig(id, options);
|
|
11992
11992
|
if (isThenable(config)) {
|
|
11993
11993
|
return resolveConfigAsync(resolvers, id, options);
|
|
@@ -11999,7 +11999,10 @@ function resolveConfig(resolvers, id, options) {
|
|
|
11999
11999
|
throw new UserError(`Failed to load configuration from "${id}"`);
|
|
12000
12000
|
}
|
|
12001
12001
|
async function resolveConfigAsync(resolvers, id, options) {
|
|
12002
|
-
for (const resolver of resolvers
|
|
12002
|
+
for (const resolver of resolvers) {
|
|
12003
|
+
if (!haveConfigResolver(resolver)) {
|
|
12004
|
+
continue;
|
|
12005
|
+
}
|
|
12003
12006
|
const config = await resolver.resolveConfig(id, options);
|
|
12004
12007
|
if (config) {
|
|
12005
12008
|
return config;
|
|
@@ -12008,7 +12011,10 @@ async function resolveConfigAsync(resolvers, id, options) {
|
|
|
12008
12011
|
throw new UserError(`Failed to load configuration from "${id}"`);
|
|
12009
12012
|
}
|
|
12010
12013
|
function resolveElements(resolvers, id, options) {
|
|
12011
|
-
for (const resolver of resolvers
|
|
12014
|
+
for (const resolver of resolvers) {
|
|
12015
|
+
if (!haveElementsResolver(resolver)) {
|
|
12016
|
+
continue;
|
|
12017
|
+
}
|
|
12012
12018
|
const elements = resolver.resolveElements(id, options);
|
|
12013
12019
|
if (isThenable(elements)) {
|
|
12014
12020
|
return resolveElementsAsync(resolvers, id, options);
|
|
@@ -12020,7 +12026,10 @@ function resolveElements(resolvers, id, options) {
|
|
|
12020
12026
|
throw new UserError(`Failed to load elements from "${id}"`);
|
|
12021
12027
|
}
|
|
12022
12028
|
async function resolveElementsAsync(resolvers, id, options) {
|
|
12023
|
-
for (const resolver of resolvers
|
|
12029
|
+
for (const resolver of resolvers) {
|
|
12030
|
+
if (!haveElementsResolver(resolver)) {
|
|
12031
|
+
continue;
|
|
12032
|
+
}
|
|
12024
12033
|
const elements = await resolver.resolveElements(id, options);
|
|
12025
12034
|
if (elements) {
|
|
12026
12035
|
return elements;
|
|
@@ -12029,7 +12038,10 @@ async function resolveElementsAsync(resolvers, id, options) {
|
|
|
12029
12038
|
throw new UserError(`Failed to load elements from "${id}"`);
|
|
12030
12039
|
}
|
|
12031
12040
|
function resolvePlugin(resolvers, id, options) {
|
|
12032
|
-
for (const resolver of resolvers
|
|
12041
|
+
for (const resolver of resolvers) {
|
|
12042
|
+
if (!havePluginResolver(resolver)) {
|
|
12043
|
+
continue;
|
|
12044
|
+
}
|
|
12033
12045
|
const plugin = resolver.resolvePlugin(id, options);
|
|
12034
12046
|
if (isThenable(plugin)) {
|
|
12035
12047
|
return resolvePluginAsync(resolvers, id, options);
|
|
@@ -12041,7 +12053,10 @@ function resolvePlugin(resolvers, id, options) {
|
|
|
12041
12053
|
throw new UserError(`Failed to load plugin from "${id}"`);
|
|
12042
12054
|
}
|
|
12043
12055
|
async function resolvePluginAsync(resolvers, id, options) {
|
|
12044
|
-
for (const resolver of resolvers
|
|
12056
|
+
for (const resolver of resolvers) {
|
|
12057
|
+
if (!havePluginResolver(resolver)) {
|
|
12058
|
+
continue;
|
|
12059
|
+
}
|
|
12045
12060
|
const plugin = await resolver.resolvePlugin(id, options);
|
|
12046
12061
|
if (plugin) {
|
|
12047
12062
|
return plugin;
|
|
@@ -12050,7 +12065,10 @@ async function resolvePluginAsync(resolvers, id, options) {
|
|
|
12050
12065
|
throw new UserError(`Failed to load plugin from "${id}"`);
|
|
12051
12066
|
}
|
|
12052
12067
|
function resolveTransformer(resolvers, id, options) {
|
|
12053
|
-
for (const resolver of resolvers
|
|
12068
|
+
for (const resolver of resolvers) {
|
|
12069
|
+
if (!haveTransformerResolver(resolver)) {
|
|
12070
|
+
continue;
|
|
12071
|
+
}
|
|
12054
12072
|
const transformer = resolver.resolveTransformer(id, options);
|
|
12055
12073
|
if (isThenable(transformer)) {
|
|
12056
12074
|
return resolveTransformerAsync(resolvers, id, options);
|
|
@@ -12062,7 +12080,10 @@ function resolveTransformer(resolvers, id, options) {
|
|
|
12062
12080
|
throw new UserError(`Failed to load transformer from "${id}"`);
|
|
12063
12081
|
}
|
|
12064
12082
|
async function resolveTransformerAsync(resolvers, id, options) {
|
|
12065
|
-
for (const resolver of resolvers
|
|
12083
|
+
for (const resolver of resolvers) {
|
|
12084
|
+
if (!haveTransformerResolver(resolver)) {
|
|
12085
|
+
continue;
|
|
12086
|
+
}
|
|
12066
12087
|
const transformer = await resolver.resolveTransformer(id, options);
|
|
12067
12088
|
if (transformer) {
|
|
12068
12089
|
return transformer;
|
|
@@ -12102,9 +12123,12 @@ function staticResolver(map = {}) {
|
|
|
12102
12123
|
};
|
|
12103
12124
|
}
|
|
12104
12125
|
|
|
12105
|
-
const ajv =
|
|
12106
|
-
|
|
12107
|
-
|
|
12126
|
+
const ajv = (() => {
|
|
12127
|
+
const ajv2 = new Ajv__default.default({ strict: true, strictTuples: true, strictTypes: true });
|
|
12128
|
+
ajv2.addMetaSchema(ajvSchemaDraft);
|
|
12129
|
+
ajv2.addKeyword(ajvFunctionKeyword);
|
|
12130
|
+
return ajv2;
|
|
12131
|
+
})();
|
|
12108
12132
|
const validator = ajv.compile(configurationSchema);
|
|
12109
12133
|
function overwriteMerge(_a, b) {
|
|
12110
12134
|
return b;
|
|
@@ -12123,18 +12147,16 @@ function mergeInternal(base, rhs) {
|
|
|
12123
12147
|
function toArray$1(value) {
|
|
12124
12148
|
if (Array.isArray(value)) {
|
|
12125
12149
|
return value;
|
|
12126
|
-
} else {
|
|
12127
|
-
return [value];
|
|
12128
12150
|
}
|
|
12151
|
+
return [value];
|
|
12129
12152
|
}
|
|
12130
12153
|
function transformerEntries(transform) {
|
|
12131
12154
|
return Object.entries(transform).map(([pattern, value]) => {
|
|
12132
12155
|
const regex = new RegExp(pattern);
|
|
12133
12156
|
if (typeof value === "string") {
|
|
12134
12157
|
return { kind: "import", pattern: regex, name: value };
|
|
12135
|
-
} else {
|
|
12136
|
-
return { kind: "function", pattern: regex, function: value };
|
|
12137
12158
|
}
|
|
12159
|
+
return { kind: "function", pattern: regex, function: value };
|
|
12138
12160
|
});
|
|
12139
12161
|
}
|
|
12140
12162
|
class Config {
|
|
@@ -12159,8 +12181,8 @@ class Config {
|
|
|
12159
12181
|
* Create configuration from object.
|
|
12160
12182
|
*/
|
|
12161
12183
|
static fromObject(resolvers, options, filename = null) {
|
|
12162
|
-
|
|
12163
|
-
return
|
|
12184
|
+
this.validate(options, filename);
|
|
12185
|
+
return this.create(resolvers, options);
|
|
12164
12186
|
}
|
|
12165
12187
|
/**
|
|
12166
12188
|
* Read configuration from filename.
|
|
@@ -12174,10 +12196,9 @@ class Config {
|
|
|
12174
12196
|
static fromFile(resolvers, filename) {
|
|
12175
12197
|
const configData = resolveConfig(toArray$1(resolvers), filename, { cache: false });
|
|
12176
12198
|
if (isThenable(configData)) {
|
|
12177
|
-
return configData.then((configData2) =>
|
|
12178
|
-
} else {
|
|
12179
|
-
return Config.fromObject(resolvers, configData, filename);
|
|
12199
|
+
return configData.then((configData2) => this.fromObject(resolvers, configData2, filename));
|
|
12180
12200
|
}
|
|
12201
|
+
return this.fromObject(resolvers, configData, filename);
|
|
12181
12202
|
}
|
|
12182
12203
|
/**
|
|
12183
12204
|
* Validate configuration data.
|
|
@@ -12199,8 +12220,8 @@ class Config {
|
|
|
12199
12220
|
);
|
|
12200
12221
|
}
|
|
12201
12222
|
if (configData.rules) {
|
|
12202
|
-
const normalizedRules =
|
|
12203
|
-
for (const [ruleId, [, ruleOptions]] of normalizedRules
|
|
12223
|
+
const normalizedRules = this.getRulesObject(configData.rules);
|
|
12224
|
+
for (const [ruleId, [, ruleOptions]] of normalizedRules) {
|
|
12204
12225
|
const cls = bundledRules[ruleId];
|
|
12205
12226
|
const path = `/rules/${ruleId}/1`;
|
|
12206
12227
|
Rule.validateOptions(cls, ruleId, path, ruleOptions, filename, configData);
|
|
@@ -12223,9 +12244,8 @@ class Config {
|
|
|
12223
12244
|
return plugins.then((plugins2) => {
|
|
12224
12245
|
return instance.init(options, plugins2);
|
|
12225
12246
|
});
|
|
12226
|
-
} else {
|
|
12227
|
-
return instance.init(options, plugins);
|
|
12228
12247
|
}
|
|
12248
|
+
return instance.init(options, plugins);
|
|
12229
12249
|
}
|
|
12230
12250
|
init(options, plugins) {
|
|
12231
12251
|
this.plugins = plugins;
|
|
@@ -12242,9 +12262,8 @@ class Config {
|
|
|
12242
12262
|
const extendedConfig = this.extendConfig(this.config.extends ?? []);
|
|
12243
12263
|
if (isThenable(extendedConfig)) {
|
|
12244
12264
|
return extendedConfig.then((extended) => update(extended));
|
|
12245
|
-
} else {
|
|
12246
|
-
return update(extendedConfig);
|
|
12247
12265
|
}
|
|
12266
|
+
return update(extendedConfig);
|
|
12248
12267
|
}
|
|
12249
12268
|
/**
|
|
12250
12269
|
* @internal
|
|
@@ -12286,12 +12305,11 @@ class Config {
|
|
|
12286
12305
|
instance.extendMeta(instance.plugins);
|
|
12287
12306
|
return instance;
|
|
12288
12307
|
});
|
|
12289
|
-
} else {
|
|
12290
|
-
instance.plugins = plugins;
|
|
12291
|
-
instance.configurations = instance.loadConfigurations(instance.plugins);
|
|
12292
|
-
instance.extendMeta(instance.plugins);
|
|
12293
|
-
return instance;
|
|
12294
12308
|
}
|
|
12309
|
+
instance.plugins = plugins;
|
|
12310
|
+
instance.configurations = instance.loadConfigurations(instance.plugins);
|
|
12311
|
+
instance.extendMeta(instance.plugins);
|
|
12312
|
+
return instance;
|
|
12295
12313
|
}
|
|
12296
12314
|
extendConfig(entries) {
|
|
12297
12315
|
if (entries.length === 0) {
|
|
@@ -12347,20 +12365,19 @@ class Config {
|
|
|
12347
12365
|
const result = this.getElementsFromEntry(entry);
|
|
12348
12366
|
if (isThenable(result)) {
|
|
12349
12367
|
return result.then((result2) => {
|
|
12350
|
-
const [
|
|
12351
|
-
metaTable.loadFromObject(
|
|
12352
|
-
const
|
|
12353
|
-
if (
|
|
12354
|
-
return loadEntry(
|
|
12368
|
+
const [obj2, filename2] = result2;
|
|
12369
|
+
metaTable.loadFromObject(obj2, filename2);
|
|
12370
|
+
const next3 = source.shift();
|
|
12371
|
+
if (next3) {
|
|
12372
|
+
return loadEntry(next3);
|
|
12355
12373
|
}
|
|
12356
12374
|
});
|
|
12357
|
-
}
|
|
12358
|
-
|
|
12359
|
-
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12363
|
-
}
|
|
12375
|
+
}
|
|
12376
|
+
const [obj, filename] = result;
|
|
12377
|
+
metaTable.loadFromObject(obj, filename);
|
|
12378
|
+
const next2 = source.shift();
|
|
12379
|
+
if (next2) {
|
|
12380
|
+
return loadEntry(next2);
|
|
12364
12381
|
}
|
|
12365
12382
|
};
|
|
12366
12383
|
const next = source.shift();
|
|
@@ -12390,9 +12407,8 @@ class Config {
|
|
|
12390
12407
|
return obj.then((obj2) => {
|
|
12391
12408
|
return [obj2, entry];
|
|
12392
12409
|
});
|
|
12393
|
-
} else {
|
|
12394
|
-
return [obj, entry];
|
|
12395
12410
|
}
|
|
12411
|
+
return [obj, entry];
|
|
12396
12412
|
} catch (err) {
|
|
12397
12413
|
const message = err instanceof Error ? err.message : String(err);
|
|
12398
12414
|
throw new ConfigError(
|
|
@@ -12454,7 +12470,7 @@ class Config {
|
|
|
12454
12470
|
const loadPlugin = (entry, index) => {
|
|
12455
12471
|
if (typeof entry !== "string") {
|
|
12456
12472
|
const plugin = entry;
|
|
12457
|
-
plugin.name
|
|
12473
|
+
plugin.name ||= `:unnamedPlugin@${String(index + 1)}`;
|
|
12458
12474
|
plugin.originalName = `:unnamedPlugin@${String(index + 1)}`;
|
|
12459
12475
|
loaded.push(plugin);
|
|
12460
12476
|
const next2 = loading.shift();
|
|
@@ -12466,22 +12482,21 @@ class Config {
|
|
|
12466
12482
|
const plugin = resolvePlugin(this.resolvers, entry, { cache: true });
|
|
12467
12483
|
if (isThenable(plugin)) {
|
|
12468
12484
|
return plugin.then((plugin2) => {
|
|
12469
|
-
plugin2.name
|
|
12485
|
+
plugin2.name ||= entry;
|
|
12470
12486
|
plugin2.originalName = entry;
|
|
12471
12487
|
loaded.push(plugin2);
|
|
12472
|
-
const
|
|
12473
|
-
if (
|
|
12474
|
-
return loadPlugin(
|
|
12488
|
+
const next3 = loading.shift();
|
|
12489
|
+
if (next3) {
|
|
12490
|
+
return loadPlugin(next3, index + 1);
|
|
12475
12491
|
}
|
|
12476
12492
|
});
|
|
12477
|
-
}
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
}
|
|
12493
|
+
}
|
|
12494
|
+
plugin.name ||= entry;
|
|
12495
|
+
plugin.originalName = entry;
|
|
12496
|
+
loaded.push(plugin);
|
|
12497
|
+
const next2 = loading.shift();
|
|
12498
|
+
if (next2) {
|
|
12499
|
+
return loadPlugin(next2, index + 1);
|
|
12485
12500
|
}
|
|
12486
12501
|
} catch (err) {
|
|
12487
12502
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -12507,7 +12522,8 @@ class Config {
|
|
|
12507
12522
|
configs.set(name, config);
|
|
12508
12523
|
}
|
|
12509
12524
|
for (const plugin of plugins) {
|
|
12510
|
-
|
|
12525
|
+
const entries = Object.entries(plugin.configs ?? {});
|
|
12526
|
+
for (const [name, config] of entries) {
|
|
12511
12527
|
if (!config) {
|
|
12512
12528
|
continue;
|
|
12513
12529
|
}
|
|
@@ -12551,9 +12567,8 @@ class Config {
|
|
|
12551
12567
|
return resolveData.then((resolveData2) => {
|
|
12552
12568
|
return new ResolvedConfig(resolveData2, this.get());
|
|
12553
12569
|
});
|
|
12554
|
-
} else {
|
|
12555
|
-
return new ResolvedConfig(resolveData, this.get());
|
|
12556
12570
|
}
|
|
12571
|
+
return new ResolvedConfig(resolveData, this.get());
|
|
12557
12572
|
}
|
|
12558
12573
|
/**
|
|
12559
12574
|
* Same as [[resolve]] but returns the raw configuration data instead of
|
|
@@ -12572,14 +12587,13 @@ class Config {
|
|
|
12572
12587
|
transformers: this.transformers
|
|
12573
12588
|
};
|
|
12574
12589
|
});
|
|
12575
|
-
} else {
|
|
12576
|
-
return {
|
|
12577
|
-
metaTable,
|
|
12578
|
-
plugins: this.getPlugins(),
|
|
12579
|
-
rules: this.getRules(),
|
|
12580
|
-
transformers: this.transformers
|
|
12581
|
-
};
|
|
12582
12590
|
}
|
|
12591
|
+
return {
|
|
12592
|
+
metaTable,
|
|
12593
|
+
plugins: this.getPlugins(),
|
|
12594
|
+
rules: this.getRules(),
|
|
12595
|
+
transformers: this.transformers
|
|
12596
|
+
};
|
|
12583
12597
|
}
|
|
12584
12598
|
}
|
|
12585
12599
|
|
|
@@ -12623,10 +12637,9 @@ class ConfigLoader {
|
|
|
12623
12637
|
this._globalConfig = config2;
|
|
12624
12638
|
return this._globalConfig;
|
|
12625
12639
|
});
|
|
12626
|
-
} else {
|
|
12627
|
-
this._globalConfig = config;
|
|
12628
|
-
return this._globalConfig;
|
|
12629
12640
|
}
|
|
12641
|
+
this._globalConfig = config;
|
|
12642
|
+
return this._globalConfig;
|
|
12630
12643
|
}
|
|
12631
12644
|
/**
|
|
12632
12645
|
* Get the global configuration.
|
|
@@ -12708,9 +12721,8 @@ class StaticConfigLoader extends ConfigLoader {
|
|
|
12708
12721
|
const override = this.loadFromObject(configOverride ?? {});
|
|
12709
12722
|
if (isThenable(override)) {
|
|
12710
12723
|
return override.then((override2) => this._resolveConfig(override2));
|
|
12711
|
-
} else {
|
|
12712
|
-
return this._resolveConfig(override);
|
|
12713
12724
|
}
|
|
12725
|
+
return this._resolveConfig(override);
|
|
12714
12726
|
}
|
|
12715
12727
|
flushCache() {
|
|
12716
12728
|
}
|
|
@@ -12727,25 +12739,22 @@ class StaticConfigLoader extends ConfigLoader {
|
|
|
12727
12739
|
const globalConfig = this.getGlobalConfig();
|
|
12728
12740
|
if (isThenable(globalConfig)) {
|
|
12729
12741
|
return globalConfig.then((globalConfig2) => {
|
|
12730
|
-
const
|
|
12731
|
-
if (isThenable(
|
|
12732
|
-
return
|
|
12733
|
-
return
|
|
12742
|
+
const merged2 = globalConfig2.merge(this.resolvers, override);
|
|
12743
|
+
if (isThenable(merged2)) {
|
|
12744
|
+
return merged2.then((merged3) => {
|
|
12745
|
+
return merged3.resolve();
|
|
12734
12746
|
});
|
|
12735
|
-
} else {
|
|
12736
|
-
return merged.resolve();
|
|
12737
12747
|
}
|
|
12748
|
+
return merged2.resolve();
|
|
12738
12749
|
});
|
|
12739
|
-
} else {
|
|
12740
|
-
const merged = globalConfig.merge(this.resolvers, override);
|
|
12741
|
-
if (isThenable(merged)) {
|
|
12742
|
-
return merged.then((merged2) => {
|
|
12743
|
-
return merged2.resolve();
|
|
12744
|
-
});
|
|
12745
|
-
} else {
|
|
12746
|
-
return merged.resolve();
|
|
12747
|
-
}
|
|
12748
12750
|
}
|
|
12751
|
+
const merged = globalConfig.merge(this.resolvers, override);
|
|
12752
|
+
if (isThenable(merged)) {
|
|
12753
|
+
return merged.then((merged2) => {
|
|
12754
|
+
return merged2.resolve();
|
|
12755
|
+
});
|
|
12756
|
+
}
|
|
12757
|
+
return merged.resolve();
|
|
12749
12758
|
}
|
|
12750
12759
|
}
|
|
12751
12760
|
|
|
@@ -12832,7 +12841,7 @@ class EventHandler {
|
|
|
12832
12841
|
}
|
|
12833
12842
|
|
|
12834
12843
|
const name = "html-validate";
|
|
12835
|
-
const version = "11.5.
|
|
12844
|
+
const version = "11.5.4";
|
|
12836
12845
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12837
12846
|
|
|
12838
12847
|
function freeze(src) {
|
|
@@ -12870,7 +12879,7 @@ class Reporter {
|
|
|
12870
12879
|
for (const report of reports) {
|
|
12871
12880
|
for (const result of report.results) {
|
|
12872
12881
|
const key = result.filePath;
|
|
12873
|
-
if (key
|
|
12882
|
+
if (Object.hasOwn(merged, key)) {
|
|
12874
12883
|
merged[key].messages = [...merged[key].messages, ...result.messages];
|
|
12875
12884
|
} else {
|
|
12876
12885
|
merged[key] = { ...result };
|
|
@@ -12894,7 +12903,7 @@ class Reporter {
|
|
|
12894
12903
|
*/
|
|
12895
12904
|
add(options) {
|
|
12896
12905
|
const { rule, message, severity, node, location, context } = options;
|
|
12897
|
-
if (!(location.filename
|
|
12906
|
+
if (!Object.hasOwn(this.result, location.filename)) {
|
|
12898
12907
|
this.result[location.filename] = [];
|
|
12899
12908
|
}
|
|
12900
12909
|
const ruleUrl = rule.documentation(context)?.url;
|
|
@@ -12922,7 +12931,7 @@ class Reporter {
|
|
|
12922
12931
|
* @internal
|
|
12923
12932
|
*/
|
|
12924
12933
|
addManual(filename, message) {
|
|
12925
|
-
if (!(
|
|
12934
|
+
if (!Object.hasOwn(this.result, filename)) {
|
|
12926
12935
|
this.result[filename] = [];
|
|
12927
12936
|
}
|
|
12928
12937
|
this.result[filename].push(message);
|
|
@@ -12933,6 +12942,7 @@ class Reporter {
|
|
|
12933
12942
|
save(sources) {
|
|
12934
12943
|
const report = {
|
|
12935
12944
|
valid: this.isValid(),
|
|
12945
|
+
/* eslint-disable-next-line unicorn/prefer-object-iterable-methods -- technical debt */
|
|
12936
12946
|
results: Object.keys(this.result).map((filePath) => {
|
|
12937
12947
|
const messages = Array.from(this.result[filePath], freeze).toSorted(messageSort);
|
|
12938
12948
|
const source = (sources ?? []).find((source2) => filePath === source2.filename);
|
|
@@ -12997,7 +13007,7 @@ function definePlugin(plugin) {
|
|
|
12997
13007
|
return plugin;
|
|
12998
13008
|
}
|
|
12999
13009
|
|
|
13000
|
-
const regexp = /<!(?:--)?\[(.*?)](?:--)?>/g;
|
|
13010
|
+
const regexp = /<!(?:--)?\[(.*?)\](?:--)?>/g;
|
|
13001
13011
|
function* parseConditionalComment(comment, commentLocation) {
|
|
13002
13012
|
let match;
|
|
13003
13013
|
while ((match = regexp.exec(comment)) !== null) {
|
|
@@ -13014,6 +13024,7 @@ function* parseConditionalComment(comment, commentLocation) {
|
|
|
13014
13024
|
|
|
13015
13025
|
class ParserError extends Error {
|
|
13016
13026
|
location;
|
|
13027
|
+
/* eslint-disable-next-line unicorn/custom-error-definition -- technical debt */
|
|
13017
13028
|
constructor(location, message) {
|
|
13018
13029
|
super(message);
|
|
13019
13030
|
this.name = "ParserError";
|
|
@@ -13177,9 +13188,8 @@ class Parser {
|
|
|
13177
13188
|
const open = !token.data[1];
|
|
13178
13189
|
if (open) {
|
|
13179
13190
|
return this.wouldCloseElement(token, active);
|
|
13180
|
-
} else {
|
|
13181
|
-
return this.closeOptionalEndTag(token, active);
|
|
13182
13191
|
}
|
|
13192
|
+
return this.closeOptionalEndTag(token, active);
|
|
13183
13193
|
}
|
|
13184
13194
|
/**
|
|
13185
13195
|
* Returns `true` if the element’s end tag may be omitted, either because
|
|
@@ -13531,9 +13541,8 @@ class Parser {
|
|
|
13531
13541
|
const quote = token.data[3];
|
|
13532
13542
|
if (quote) {
|
|
13533
13543
|
return sliceLocation(token.location, 2, -1);
|
|
13534
|
-
} else {
|
|
13535
|
-
return sliceLocation(token.location, 1);
|
|
13536
13544
|
}
|
|
13545
|
+
return sliceLocation(token.location, 1);
|
|
13537
13546
|
}
|
|
13538
13547
|
/**
|
|
13539
13548
|
* Take attribute key and value token an returns a new location referring to
|
|
@@ -13821,13 +13830,14 @@ class PerformanceTracker {
|
|
|
13821
13830
|
*/
|
|
13822
13831
|
getResult() {
|
|
13823
13832
|
const events = Array.from(
|
|
13824
|
-
this.eventData
|
|
13833
|
+
this.eventData,
|
|
13825
13834
|
([event, { count, time }]) => ({ event, count, time })
|
|
13826
13835
|
).toSorted((a, b) => b.time - a.time);
|
|
13827
|
-
const rules = Array.from(
|
|
13828
|
-
|
|
13829
|
-
|
|
13830
|
-
|
|
13836
|
+
const rules = Array.from(this.ruleData, ([rule, { count, time }]) => ({
|
|
13837
|
+
rule,
|
|
13838
|
+
count,
|
|
13839
|
+
time
|
|
13840
|
+
})).toSorted((a, b) => b.time - a.time);
|
|
13831
13841
|
return {
|
|
13832
13842
|
events,
|
|
13833
13843
|
rules,
|
|
@@ -13874,9 +13884,11 @@ function dumpTree(root) {
|
|
|
13874
13884
|
return lines;
|
|
13875
13885
|
}
|
|
13876
13886
|
|
|
13877
|
-
|
|
13887
|
+
const state = {
|
|
13888
|
+
blockerCounter: 1
|
|
13889
|
+
};
|
|
13878
13890
|
function createBlocker() {
|
|
13879
|
-
const id = blockerCounter++;
|
|
13891
|
+
const id = state.blockerCounter++;
|
|
13880
13892
|
return id;
|
|
13881
13893
|
}
|
|
13882
13894
|
|
|
@@ -14012,9 +14024,8 @@ class Engine {
|
|
|
14012
14024
|
const [, options] = ruleData;
|
|
14013
14025
|
const rule = this.instantiateRule(ruleId, options);
|
|
14014
14026
|
return rule.documentation(context);
|
|
14015
|
-
} else {
|
|
14016
|
-
return null;
|
|
14017
14027
|
}
|
|
14028
|
+
return null;
|
|
14018
14029
|
}
|
|
14019
14030
|
/**
|
|
14020
14031
|
* Create a new parser instance with the current configuration.
|
|
@@ -14143,7 +14154,8 @@ class Engine {
|
|
|
14143
14154
|
initRules(config) {
|
|
14144
14155
|
const availableRules = {};
|
|
14145
14156
|
for (const plugin of config.getPlugins()) {
|
|
14146
|
-
|
|
14157
|
+
const entries = Object.entries(plugin.rules ?? {});
|
|
14158
|
+
for (const [name, rule] of entries) {
|
|
14147
14159
|
if (!rule) {
|
|
14148
14160
|
continue;
|
|
14149
14161
|
}
|
|
@@ -14171,7 +14183,7 @@ class Engine {
|
|
|
14171
14183
|
*/
|
|
14172
14184
|
setupRules(config, parser) {
|
|
14173
14185
|
const rules = {};
|
|
14174
|
-
for (const [ruleId, [severity, options]] of config.getRules()
|
|
14186
|
+
for (const [ruleId, [severity, options]] of config.getRules()) {
|
|
14175
14187
|
rules[ruleId] = this.loadRule(ruleId, config, severity, options, parser, this.report);
|
|
14176
14188
|
}
|
|
14177
14189
|
return rules;
|
|
@@ -14195,9 +14207,8 @@ class Engine {
|
|
|
14195
14207
|
if (this.availableRules[name]) {
|
|
14196
14208
|
const RuleConstructor = this.availableRules[name];
|
|
14197
14209
|
return new RuleConstructor(options);
|
|
14198
|
-
} else {
|
|
14199
|
-
return this.missingRule(name);
|
|
14200
14210
|
}
|
|
14211
|
+
return this.missingRule(name);
|
|
14201
14212
|
}
|
|
14202
14213
|
missingRule(name) {
|
|
14203
14214
|
return new class MissingRule extends Rule {
|
|
@@ -14293,34 +14304,30 @@ function getTransformerFunction(resolvers, name, plugins) {
|
|
|
14293
14304
|
validateTransformer(transformer2);
|
|
14294
14305
|
return transformer2;
|
|
14295
14306
|
});
|
|
14296
|
-
} else {
|
|
14297
|
-
validateTransformer(transformer);
|
|
14298
|
-
return transformer;
|
|
14299
14307
|
}
|
|
14308
|
+
validateTransformer(transformer);
|
|
14309
|
+
return transformer;
|
|
14300
14310
|
} catch (err) {
|
|
14301
14311
|
if (err instanceof ConfigError) {
|
|
14302
14312
|
throw new ConfigError(`Failed to load transformer "${name}": ${err.message}`, err);
|
|
14303
|
-
} else {
|
|
14304
|
-
throw new ConfigError(`Failed to load transformer "${name}"`, ensureError(err));
|
|
14305
14313
|
}
|
|
14314
|
+
throw new ConfigError(`Failed to load transformer "${name}"`, ensureError(err));
|
|
14306
14315
|
}
|
|
14307
14316
|
}
|
|
14308
14317
|
function getCachedTransformerFunction(cache, resolvers, name, plugins) {
|
|
14309
14318
|
const cached = cache.get(name);
|
|
14310
14319
|
if (cached) {
|
|
14311
14320
|
return cached;
|
|
14312
|
-
} else {
|
|
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
|
-
} else {
|
|
14320
|
-
cache.set(name, transformer);
|
|
14321
|
-
return transformer;
|
|
14322
|
-
}
|
|
14323
14321
|
}
|
|
14322
|
+
const transformer = getTransformerFunction(resolvers, name, plugins);
|
|
14323
|
+
if (isThenable(transformer)) {
|
|
14324
|
+
return transformer.then((transformer2) => {
|
|
14325
|
+
cache.set(name, transformer2);
|
|
14326
|
+
return transformer2;
|
|
14327
|
+
});
|
|
14328
|
+
}
|
|
14329
|
+
cache.set(name, transformer);
|
|
14330
|
+
return transformer;
|
|
14324
14331
|
}
|
|
14325
14332
|
|
|
14326
14333
|
function isIterable(value) {
|
|
@@ -14336,6 +14343,9 @@ const asyncInSyncTransformError = "Cannot use async transformer from sync functi
|
|
|
14336
14343
|
async function transformSource(resolvers, config, source, filename) {
|
|
14337
14344
|
const { cache } = config;
|
|
14338
14345
|
const transformer = config.findTransformer(filename ?? source.filename);
|
|
14346
|
+
if (!transformer) {
|
|
14347
|
+
return [source];
|
|
14348
|
+
}
|
|
14339
14349
|
const context = {
|
|
14340
14350
|
hasChain(filename2) {
|
|
14341
14351
|
return config.canTransform(filename2);
|
|
@@ -14344,9 +14354,6 @@ async function transformSource(resolvers, config, source, filename) {
|
|
|
14344
14354
|
return transformSource(resolvers, config, source2, filename2);
|
|
14345
14355
|
}
|
|
14346
14356
|
};
|
|
14347
|
-
if (!transformer) {
|
|
14348
|
-
return [source];
|
|
14349
|
-
}
|
|
14350
14357
|
const fn = transformer.kind === "import" ? await getCachedTransformerFunction(cache, resolvers, transformer.name, config.getPlugins()) : transformer.function;
|
|
14351
14358
|
const name = transformer.kind === "import" ? transformer.name : transformer.function.name;
|
|
14352
14359
|
try {
|
|
@@ -14365,6 +14372,9 @@ async function transformSource(resolvers, config, source, filename) {
|
|
|
14365
14372
|
function transformSourceSync(resolvers, config, source, filename) {
|
|
14366
14373
|
const { cache } = config;
|
|
14367
14374
|
const transformer = config.findTransformer(filename ?? source.filename);
|
|
14375
|
+
if (!transformer) {
|
|
14376
|
+
return [source];
|
|
14377
|
+
}
|
|
14368
14378
|
const context = {
|
|
14369
14379
|
hasChain(filename2) {
|
|
14370
14380
|
return config.canTransform(filename2);
|
|
@@ -14373,14 +14383,11 @@ function transformSourceSync(resolvers, config, source, filename) {
|
|
|
14373
14383
|
return transformSourceSync(resolvers, config, source2, filename2);
|
|
14374
14384
|
}
|
|
14375
14385
|
};
|
|
14376
|
-
if (!transformer) {
|
|
14377
|
-
return [source];
|
|
14378
|
-
}
|
|
14379
14386
|
const fn = transformer.kind === "import" ? getCachedTransformerFunction(cache, resolvers, transformer.name, config.getPlugins()) : transformer.function;
|
|
14380
|
-
const name = transformer.kind === "import" ? transformer.name : transformer.function.name;
|
|
14381
14387
|
if (isThenable(fn)) {
|
|
14382
14388
|
throw new UserError(asyncInSyncTransformError);
|
|
14383
14389
|
}
|
|
14390
|
+
const name = transformer.kind === "import" ? transformer.name : transformer.function.name;
|
|
14384
14391
|
try {
|
|
14385
14392
|
const result = fn.call(context, source);
|
|
14386
14393
|
if (isThenable(result)) {
|
|
@@ -14482,7 +14489,7 @@ function checkstyleFormatter(results) {
|
|
|
14482
14489
|
`;
|
|
14483
14490
|
for (const message of messages) {
|
|
14484
14491
|
const ruleId = xmlescape(`htmlvalidate.rules.${message.ruleId}`);
|
|
14485
|
-
output += "
|
|
14492
|
+
output += " ".repeat(4);
|
|
14486
14493
|
output += [
|
|
14487
14494
|
`<error line="${xmlescape(message.line)}"`,
|
|
14488
14495
|
`column="${xmlescape(message.column)}"`,
|
|
@@ -14569,9 +14576,8 @@ function codeFrameColumns(rawLines, loc) {
|
|
|
14569
14576
|
].join("");
|
|
14570
14577
|
}
|
|
14571
14578
|
return [">", gutter, line.length > 0 ? ` ${line}` : "", markerLine].join("");
|
|
14572
|
-
} else {
|
|
14573
|
-
return [" ", gutter, line.length > 0 ? ` ${line}` : ""].join("");
|
|
14574
14579
|
}
|
|
14580
|
+
return [" ", gutter, line.length > 0 ? ` ${line}` : ""].join("");
|
|
14575
14581
|
}).join("\n");
|
|
14576
14582
|
}
|
|
14577
14583
|
|