html-validate 8.0.5 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/cjs/browser.js +4 -2
  2. package/dist/cjs/browser.js.map +1 -1
  3. package/dist/cjs/cli.js +41 -15
  4. package/dist/cjs/cli.js.map +1 -1
  5. package/dist/cjs/core-browser.js +31 -0
  6. package/dist/cjs/core-browser.js.map +1 -0
  7. package/dist/cjs/{nodejs.js → core-nodejs.js} +54 -4
  8. package/dist/cjs/core-nodejs.js.map +1 -0
  9. package/dist/cjs/core.js +306 -269
  10. package/dist/cjs/core.js.map +1 -1
  11. package/dist/cjs/elements.js +24 -3
  12. package/dist/cjs/elements.js.map +1 -1
  13. package/dist/cjs/html-validate.js +6 -6
  14. package/dist/cjs/html-validate.js.map +1 -1
  15. package/dist/cjs/index.js +6 -6
  16. package/dist/cjs/jest-lib.js +6 -6
  17. package/dist/cjs/jest-lib.js.map +1 -1
  18. package/dist/cjs/jest.js +3 -3
  19. package/dist/cjs/meta-helper.js +16 -2
  20. package/dist/cjs/meta-helper.js.map +1 -1
  21. package/dist/cjs/test-utils.js +1 -1
  22. package/dist/cjs/test-utils.js.map +1 -1
  23. package/dist/cjs/tsdoc-metadata.json +1 -1
  24. package/dist/es/browser.js +4 -3
  25. package/dist/es/browser.js.map +1 -1
  26. package/dist/es/cli.js +39 -13
  27. package/dist/es/cli.js.map +1 -1
  28. package/dist/es/core-browser.js +29 -0
  29. package/dist/es/core-browser.js.map +1 -0
  30. package/dist/es/{nodejs.js → core-nodejs.js} +53 -5
  31. package/dist/es/core-nodejs.js.map +1 -0
  32. package/dist/es/core.js +304 -266
  33. package/dist/es/core.js.map +1 -1
  34. package/dist/es/elements.js +24 -3
  35. package/dist/es/elements.js.map +1 -1
  36. package/dist/es/html-validate.js +7 -7
  37. package/dist/es/html-validate.js.map +1 -1
  38. package/dist/es/index.js +4 -4
  39. package/dist/es/jest-lib.js +4 -4
  40. package/dist/es/jest-lib.js.map +1 -1
  41. package/dist/es/jest.js +3 -3
  42. package/dist/es/meta-helper.js +16 -2
  43. package/dist/es/meta-helper.js.map +1 -1
  44. package/dist/es/test-utils.js +1 -1
  45. package/dist/es/test-utils.js.map +1 -1
  46. package/dist/tsdoc-metadata.json +1 -1
  47. package/dist/types/browser.d.ts +66 -74
  48. package/dist/types/index.d.ts +45 -77
  49. package/dist/types/jest.d.ts +4 -8
  50. package/package.json +22 -22
  51. package/dist/cjs/nodejs.js.map +0 -1
  52. package/dist/es/nodejs.js.map +0 -1
package/dist/es/core.js CHANGED
@@ -2,12 +2,12 @@ import Ajv from 'ajv';
2
2
  import deepmerge from 'deepmerge';
3
3
  import { e as entities$1, h as html5, b as bundledElements } from './elements.js';
4
4
  import fs from 'fs';
5
- import semver from 'semver';
6
- import kleur from 'kleur';
7
5
  import betterAjvErrors from '@sidvind/better-ajv-errors';
8
6
  import { n as naturalJoin } from './utils/natural-join.js';
9
7
  import { codeFrameColumns } from '@babel/code-frame';
8
+ import kleur from 'kleur';
10
9
  import { stylish as stylish$2 } from '@html-validate/stylish';
10
+ import semver from 'semver';
11
11
 
12
12
  const $schema$2 = "http://json-schema.org/draft-06/schema#";
13
13
  const $id$2 = "http://json-schema.org/draft-06/schema#";
@@ -284,7 +284,7 @@ class NestedError extends Error {
284
284
  super(message);
285
285
  Error.captureStackTrace(this, NestedError);
286
286
  this.name = NestedError.name;
287
- if (nested && nested.stack) {
287
+ if (nested === null || nested === void 0 ? void 0 : nested.stack) {
288
288
  this.stack += `\nCaused by: ${nested.stack}`;
289
289
  }
290
290
  }
@@ -1019,7 +1019,8 @@ function hasAttribute(node, attr) {
1019
1019
  * Matches attribute against value.
1020
1020
  */
1021
1021
  function matchAttribute(node, key, op, value) {
1022
- const nodeValue = (node.getAttributeValue(key) || "").toLowerCase();
1022
+ var _a;
1023
+ const nodeValue = ((_a = node.getAttributeValue(key)) !== null && _a !== void 0 ? _a : "").toLowerCase();
1023
1024
  switch (op) {
1024
1025
  case "!=":
1025
1026
  return nodeValue !== value;
@@ -1381,6 +1382,16 @@ class Attribute {
1381
1382
  get isDynamic() {
1382
1383
  return this.value instanceof DynamicValue;
1383
1384
  }
1385
+ /**
1386
+ * Test attribute value.
1387
+ *
1388
+ * @param pattern - Pattern to match value against. Can be a RegExp, literal
1389
+ * string or an array of strings (returns true if any value matches the
1390
+ * array).
1391
+ * @param dynamicMatches - If true `DynamicValue` will always match, if false
1392
+ * it never matches.
1393
+ * @returns `true` if attribute value matches pattern.
1394
+ */
1384
1395
  valueMatches(pattern, dynamicMatches = true) {
1385
1396
  if (this.value === null) {
1386
1397
  return false;
@@ -1766,7 +1777,7 @@ class DOMTokenList extends Array {
1766
1777
  this.value = value.expr;
1767
1778
  }
1768
1779
  else {
1769
- this.value = value || "";
1780
+ this.value = value !== null && value !== void 0 ? value : "";
1770
1781
  }
1771
1782
  }
1772
1783
  item(n) {
@@ -1991,7 +2002,7 @@ class IdMatcher extends Matcher {
1991
2002
  class AttrMatcher extends Matcher {
1992
2003
  constructor(attr) {
1993
2004
  super();
1994
- const [, key, op, value] = attr.match(/^(.+?)(?:([~^$*|]?=)"([^"]+?)")?$/);
2005
+ const [, key, op, value] = attr.match(/^(.+?)(?:([~^$*|]?=)"([^"]+?)")?$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
1995
2006
  this.key = key;
1996
2007
  this.op = op;
1997
2008
  this.value = value;
@@ -2028,11 +2039,11 @@ class PseudoClassMatcher extends Matcher {
2028
2039
  }
2029
2040
  class Pattern {
2030
2041
  constructor(pattern) {
2031
- const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)(.*)$/);
2042
+ const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)(.*)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2032
2043
  match.shift(); /* remove full matched string */
2033
2044
  this.selector = pattern;
2034
2045
  this.combinator = parseCombinator(match.shift(), pattern);
2035
- this.tagName = match.shift() || "*";
2046
+ this.tagName = match.shift() || "*"; // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing -- empty string */
2036
2047
  this.pattern = Array.from(splitPattern(match[0]), (it) => this.createMatcher(it));
2037
2048
  }
2038
2049
  match(node, context) {
@@ -2206,6 +2217,21 @@ function isElementNode(node) {
2206
2217
  function isValidTagName(tagName) {
2207
2218
  return Boolean(tagName !== "" && tagName !== "*");
2208
2219
  }
2220
+ function createAdapter(node) {
2221
+ return {
2222
+ closest(selectors) {
2223
+ var _a;
2224
+ return (_a = node.closest(selectors)) === null || _a === void 0 ? void 0 : _a._adapter;
2225
+ },
2226
+ getAttribute(name) {
2227
+ var _a;
2228
+ return (_a = node.getAttribute(name)) === null || _a === void 0 ? void 0 : _a.value;
2229
+ },
2230
+ hasAttribute(name) {
2231
+ return node.hasAttribute(name);
2232
+ },
2233
+ };
2234
+ }
2209
2235
  /**
2210
2236
  * @public
2211
2237
  */
@@ -2214,9 +2240,9 @@ class HtmlElement extends DOMNode {
2214
2240
  const nodeType = tagName ? NodeType.ELEMENT_NODE : NodeType.DOCUMENT_NODE;
2215
2241
  super(nodeType, tagName, location);
2216
2242
  if (!isValidTagName(tagName)) {
2217
- throw new Error(`The tag name provided ('${tagName || ""}') is not a valid name`);
2243
+ throw new Error(`The tag name provided ('${tagName !== null && tagName !== void 0 ? tagName : ""}') is not a valid name`);
2218
2244
  }
2219
- this.tagName = tagName || "#document";
2245
+ this.tagName = tagName !== null && tagName !== void 0 ? tagName : "#document";
2220
2246
  this.parent = parent !== null && parent !== void 0 ? parent : null;
2221
2247
  this.attr = {};
2222
2248
  this.metaElement = meta !== null && meta !== void 0 ? meta : null;
@@ -2224,6 +2250,7 @@ class HtmlElement extends DOMNode {
2224
2250
  this.voidElement = meta ? Boolean(meta.void) : false;
2225
2251
  this.depth = 0;
2226
2252
  this.annotation = null;
2253
+ this._adapter = createAdapter(this);
2227
2254
  if (parent) {
2228
2255
  parent.childNodes.push(this);
2229
2256
  /* calculate depth in domtree */
@@ -2283,7 +2310,7 @@ class HtmlElement extends DOMNode {
2283
2310
  */
2284
2311
  get ariaLabelledby() {
2285
2312
  const attr = this.getAttribute("aria-labelledby");
2286
- if (!attr || !attr.value) {
2313
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value)) {
2287
2314
  return null;
2288
2315
  }
2289
2316
  if (attr.value instanceof DynamicValue) {
@@ -2401,6 +2428,7 @@ class HtmlElement extends DOMNode {
2401
2428
  setMetaProperty(this.metaElement, key, value);
2402
2429
  }
2403
2430
  else {
2431
+ /* eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- technical debt */
2404
2432
  delete this.metaElement[key];
2405
2433
  }
2406
2434
  }
@@ -2676,11 +2704,12 @@ class DOMTree {
2676
2704
  this.active = node;
2677
2705
  }
2678
2706
  popActive() {
2707
+ var _a;
2679
2708
  if (this.active.isRootElement()) {
2680
2709
  /* root element should never be popped, continue as if nothing happened */
2681
2710
  return;
2682
2711
  }
2683
- this.active = this.active.parent || this.root;
2712
+ this.active = (_a = this.active.parent) !== null && _a !== void 0 ? _a : this.root;
2684
2713
  }
2685
2714
  getActive() {
2686
2715
  return this.active;
@@ -2689,7 +2718,9 @@ class DOMTree {
2689
2718
  * Resolve dynamic meta expressions.
2690
2719
  */
2691
2720
  resolveMeta(table) {
2692
- this.visitDepthFirst((node) => table.resolve(node));
2721
+ this.visitDepthFirst((node) => {
2722
+ table.resolve(node);
2723
+ });
2693
2724
  }
2694
2725
  getElementsByTagName(tagName) {
2695
2726
  return this.root.getElementsByTagName(tagName);
@@ -2714,6 +2745,7 @@ const allowedKeys = ["exclude"];
2714
2745
  *
2715
2746
  * @public
2716
2747
  */
2748
+ /* eslint-disable-next-line @typescript-eslint/no-extraneous-class -- technical debt, should probably be plain functions maybe in an object */
2717
2749
  class Validator {
2718
2750
  /**
2719
2751
  * Test if element is used in a proper context.
@@ -2755,7 +2787,7 @@ class Validator {
2755
2787
  return false;
2756
2788
  }
2757
2789
  // Check if the rule has a quantifier
2758
- const [, category, quantifier] = rule.match(/^(@?.*?)([?*]?)$/);
2790
+ const [, category, quantifier] = rule.match(/^(@?.*?)([?*]?)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2759
2791
  const limit = category && quantifier && parseQuantifier(quantifier);
2760
2792
  if (limit) {
2761
2793
  const siblings = children.filter((cur) => Validator.validatePermittedCategory(cur, rule, true));
@@ -2801,6 +2833,7 @@ class Validator {
2801
2833
  * In both of these cases no error should be reported. */
2802
2834
  const orderSpecified = rules.find((cur) => Validator.validatePermittedCategory(node, cur, true));
2803
2835
  if (orderSpecified) {
2836
+ /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt, should never happen */
2804
2837
  cb(node, prev);
2805
2838
  return false;
2806
2839
  }
@@ -2941,9 +2974,9 @@ class Validator {
2941
2974
  */
2942
2975
  /* eslint-disable-next-line complexity -- rule does not like switch */
2943
2976
  static validatePermittedCategory(node, category, defaultMatch) {
2944
- const [, rawCategory] = category.match(/^(@?.*?)([?*]?)$/);
2977
+ const [, rawCategory] = category.match(/^(@?.*?)([?*]?)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2945
2978
  /* match tagName when an explicit name is given */
2946
- if (rawCategory[0] !== "@") {
2979
+ if (!rawCategory.startsWith("@")) {
2947
2980
  return node.tagName === rawCategory;
2948
2981
  }
2949
2982
  /* if the meta entry is missing assume any content model would match */
@@ -2966,9 +2999,9 @@ class Validator {
2966
2999
  case "@interactive":
2967
3000
  return node.meta.interactive;
2968
3001
  case "@script":
2969
- return node.meta.scriptSupporting;
3002
+ return Boolean(node.meta.scriptSupporting);
2970
3003
  case "@form":
2971
- return node.meta.form;
3004
+ return Boolean(node.meta.form);
2972
3005
  default:
2973
3006
  throw new Error(`Invalid content category "${category}"`);
2974
3007
  }
@@ -3153,10 +3186,12 @@ var configurationSchema = {
3153
3186
  properties: properties
3154
3187
  };
3155
3188
 
3156
- var TRANSFORMER_API;
3157
- (function (TRANSFORMER_API) {
3158
- TRANSFORMER_API[TRANSFORMER_API["VERSION"] = 1] = "VERSION";
3159
- })(TRANSFORMER_API || (TRANSFORMER_API = {}));
3189
+ /**
3190
+ * @internal
3191
+ */
3192
+ const TRANSFORMER_API = {
3193
+ VERSION: 1,
3194
+ };
3160
3195
 
3161
3196
  /**
3162
3197
  * @public
@@ -3403,7 +3438,7 @@ function classifyNodeText(node, options = {}) {
3403
3438
  const { accessible = false, ignoreHiddenRoot = false } = options;
3404
3439
  const cacheKey = getCachekey(options);
3405
3440
  if (node.cacheExists(cacheKey)) {
3406
- return node.cacheGet(cacheKey);
3441
+ return node.cacheGet(cacheKey); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- has/get combo
3407
3442
  }
3408
3443
  if (!ignoreHiddenRoot && isHTMLHidden(node)) {
3409
3444
  return node.cacheSet(cacheKey, TextClassification.EMPTY_TEXT);
@@ -3451,8 +3486,12 @@ function findTextNodes(node, options) {
3451
3486
 
3452
3487
  function hasAltText(image) {
3453
3488
  const alt = image.getAttribute("alt");
3454
- /* missing or boolean */
3455
- if (alt === null || alt.value === null) {
3489
+ /* missing attribute */
3490
+ if (!alt) {
3491
+ return false;
3492
+ }
3493
+ /* (incorrectly) set as boolean value */
3494
+ if (alt.value === null) {
3456
3495
  return false;
3457
3496
  }
3458
3497
  return alt.isDynamic || alt.value.toString() !== "";
@@ -3460,8 +3499,12 @@ function hasAltText(image) {
3460
3499
 
3461
3500
  function hasAriaLabel(node) {
3462
3501
  const label = node.getAttribute("aria-label");
3463
- /* missing or boolean */
3464
- if (label === null || label.value === null) {
3502
+ /* missing attribute */
3503
+ if (!label) {
3504
+ return false;
3505
+ }
3506
+ /* (incorrectly) set as boolean value */
3507
+ if (label.value === null) {
3465
3508
  return false;
3466
3509
  }
3467
3510
  return label.isDynamic || label.value.toString() !== "";
@@ -3542,7 +3585,7 @@ class Rule {
3542
3585
  this.options = options;
3543
3586
  this.enabled = true;
3544
3587
  this.blockers = [];
3545
- this.severity = 0;
3588
+ this.severity = Severity.DISABLED;
3546
3589
  this.name = "";
3547
3590
  }
3548
3591
  getSeverity() {
@@ -3695,13 +3738,14 @@ class Rule {
3695
3738
  }
3696
3739
  }
3697
3740
  findLocation(src) {
3741
+ var _a, _b;
3698
3742
  if (src.location) {
3699
3743
  return src.location;
3700
3744
  }
3701
- if (src.event && src.event.location) {
3745
+ if ((_a = src.event) === null || _a === void 0 ? void 0 : _a.location) {
3702
3746
  return src.event.location;
3703
3747
  }
3704
- if (src.node && src.node.location) {
3748
+ if ((_b = src.node) === null || _b === void 0 ? void 0 : _b.location) {
3705
3749
  return src.node.location;
3706
3750
  }
3707
3751
  return {};
@@ -3798,7 +3842,7 @@ var Style$1;
3798
3842
  Style["ABSOLUTE"] = "absolute";
3799
3843
  Style["ANCHOR"] = "anchor";
3800
3844
  })(Style$1 || (Style$1 = {}));
3801
- const defaults$v = {
3845
+ const defaults$u = {
3802
3846
  allowExternal: true,
3803
3847
  allowRelative: true,
3804
3848
  allowAbsolute: true,
@@ -3842,7 +3886,7 @@ function matchList(value, list) {
3842
3886
  }
3843
3887
  class AllowedLinks extends Rule {
3844
3888
  constructor(options) {
3845
- super({ ...defaults$v, ...options });
3889
+ super({ ...defaults$u, ...options });
3846
3890
  this.allowExternal = parseAllow(this.options.allowExternal);
3847
3891
  this.allowRelative = parseAllow(this.options.allowRelative);
3848
3892
  this.allowAbsolute = parseAllow(this.options.allowAbsolute);
@@ -3874,7 +3918,8 @@ class AllowedLinks extends Rule {
3874
3918
  };
3875
3919
  }
3876
3920
  documentation(context) {
3877
- const message = description[context] || "This link type is not allowed by current configuration";
3921
+ var _a;
3922
+ const message = (_a = description[context]) !== null && _a !== void 0 ? _a : "This link type is not allowed by current configuration";
3878
3923
  return {
3879
3924
  description: message,
3880
3925
  url: "https://html-validate.org/rules/allowed-links.html",
@@ -3990,7 +4035,7 @@ var RuleContext$1;
3990
4035
  RuleContext["MISSING_ALT"] = "missing-alt";
3991
4036
  RuleContext["MISSING_HREF"] = "missing-href";
3992
4037
  })(RuleContext$1 || (RuleContext$1 = {}));
3993
- const defaults$u = {
4038
+ const defaults$t = {
3994
4039
  accessible: true,
3995
4040
  };
3996
4041
  function findByTarget(target, siblings) {
@@ -4016,19 +4061,11 @@ function getDescription$1(context) {
4016
4061
  "",
4017
4062
  "Either add the `href` attribute or remove the `alt` attribute.",
4018
4063
  ];
4019
- default:
4020
- return [
4021
- "The `alt` attribute must only be used together with the `href` attribute.",
4022
- "It must be set if `href` is present and must be omitted if `href` is missing",
4023
- "",
4024
- "The attribute is used to provide an alternative text description for the area of the image map.",
4025
- "The text should describe the purpose of area and the resource referenced by the `href` attribute.",
4026
- ];
4027
4064
  }
4028
4065
  }
4029
4066
  class AreaAlt extends Rule {
4030
4067
  constructor(options) {
4031
- super({ ...defaults$u, ...options });
4068
+ super({ ...defaults$t, ...options });
4032
4069
  }
4033
4070
  static schema() {
4034
4071
  return {
@@ -4146,7 +4183,7 @@ function isValidUsage(target, meta) {
4146
4183
  return true;
4147
4184
  }
4148
4185
  /* interactive and labelable elements are valid */
4149
- if (meta.interactive || meta.labelable) {
4186
+ if (Boolean(meta.interactive) || Boolean(meta.labelable)) {
4150
4187
  return true;
4151
4188
  }
4152
4189
  return false;
@@ -4181,7 +4218,7 @@ class AriaLabelMisuse extends Rule {
4181
4218
  }
4182
4219
  validateElement(target) {
4183
4220
  const attr = target.getAttribute("aria-label");
4184
- if (!attr || !attr.value || attr.valueMatches("", false)) {
4221
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value) || attr.valueMatches("", false)) {
4185
4222
  return;
4186
4223
  }
4187
4224
  /* ignore elements without meta */
@@ -4262,13 +4299,13 @@ class CaseStyle {
4262
4299
  }
4263
4300
  }
4264
4301
 
4265
- const defaults$t = {
4302
+ const defaults$s = {
4266
4303
  style: "lowercase",
4267
4304
  ignoreForeign: true,
4268
4305
  };
4269
4306
  class AttrCase extends Rule {
4270
4307
  constructor(options) {
4271
- super({ ...defaults$t, ...options });
4308
+ super({ ...defaults$s, ...options });
4272
4309
  this.style = new CaseStyle(this.options.style, "attr-case");
4273
4310
  }
4274
4311
  static schema() {
@@ -4494,7 +4531,7 @@ class Lexer {
4494
4531
  */
4495
4532
  enter(context, state, data) {
4496
4533
  /* script/style tags require a different content model */
4497
- if (state === State.TAG && data && data[0][0] === "<") {
4534
+ if (state === State.TAG && data && data[0].startsWith("<")) {
4498
4535
  if (data[0] === "<script") {
4499
4536
  context.contentModel = ContentModel.SCRIPT;
4500
4537
  }
@@ -4532,14 +4569,14 @@ class Lexer {
4532
4569
  case ContentModel.TEXT:
4533
4570
  return State.TEXT;
4534
4571
  case ContentModel.SCRIPT:
4535
- if (tagCloseToken && tagCloseToken.data[0][0] !== "/") {
4572
+ if (tagCloseToken && !tagCloseToken.data[0].startsWith("/")) {
4536
4573
  return State.SCRIPT;
4537
4574
  }
4538
4575
  else {
4539
4576
  return State.TEXT; /* <script/> (not legal but handle it anyway so the lexer doesn't choke on it) */
4540
4577
  }
4541
4578
  case ContentModel.STYLE:
4542
- if (tagCloseToken && tagCloseToken.data[0][0] !== "/") {
4579
+ if (tagCloseToken && !tagCloseToken.data[0].startsWith("/")) {
4543
4580
  return State.STYLE;
4544
4581
  }
4545
4582
  else {
@@ -4616,7 +4653,7 @@ class AttrDelimiter extends Rule {
4616
4653
  }
4617
4654
 
4618
4655
  const DEFAULT_PATTERN = "[a-z0-9-:]+";
4619
- const defaults$s = {
4656
+ const defaults$r = {
4620
4657
  pattern: DEFAULT_PATTERN,
4621
4658
  ignoreForeign: true,
4622
4659
  };
@@ -4653,7 +4690,7 @@ function generateDescription(name, pattern) {
4653
4690
  }
4654
4691
  class AttrPattern extends Rule {
4655
4692
  constructor(options) {
4656
- super({ ...defaults$s, ...options });
4693
+ super({ ...defaults$r, ...options });
4657
4694
  this.pattern = generateRegexp(this.options.pattern);
4658
4695
  }
4659
4696
  static schema() {
@@ -4714,7 +4751,7 @@ var QuoteStyle;
4714
4751
  QuoteStyle["AUTO_QUOTE"] = "auto";
4715
4752
  QuoteStyle["ANY_QUOTE"] = "any";
4716
4753
  })(QuoteStyle || (QuoteStyle = {}));
4717
- const defaults$r = {
4754
+ const defaults$q = {
4718
4755
  style: "auto",
4719
4756
  unquoted: false,
4720
4757
  };
@@ -4781,7 +4818,7 @@ class AttrQuotes extends Rule {
4781
4818
  };
4782
4819
  }
4783
4820
  constructor(options) {
4784
- super({ ...defaults$r, ...options });
4821
+ super({ ...defaults$q, ...options });
4785
4822
  this.style = parseStyle$3(this.options.style);
4786
4823
  }
4787
4824
  setup() {
@@ -4791,7 +4828,7 @@ class AttrQuotes extends Rule {
4791
4828
  return;
4792
4829
  }
4793
4830
  if (!event.quote) {
4794
- if (this.options.unquoted === false) {
4831
+ if (!this.options.unquoted) {
4795
4832
  const message = `Attribute "${event.key}" using unquoted value`;
4796
4833
  const context = {
4797
4834
  error: "unquoted",
@@ -4912,7 +4949,7 @@ class AttributeAllowedValues extends Rule {
4912
4949
  const meta = node.meta;
4913
4950
  /* ignore rule if element has no meta or meta does not specify attribute
4914
4951
  * allowed values */
4915
- if (!meta || !meta.attributes)
4952
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
4916
4953
  return;
4917
4954
  for (const attr of node.attributes) {
4918
4955
  if (Validator.validateAttribute(attr, meta.attributes)) {
@@ -4951,12 +4988,12 @@ class AttributeAllowedValues extends Rule {
4951
4988
  }
4952
4989
  }
4953
4990
 
4954
- const defaults$q = {
4991
+ const defaults$p = {
4955
4992
  style: "omit",
4956
4993
  };
4957
4994
  class AttributeBooleanStyle extends Rule {
4958
4995
  constructor(options) {
4959
- super({ ...defaults$q, ...options });
4996
+ super({ ...defaults$p, ...options });
4960
4997
  this.hasInvalidStyle = parseStyle$2(this.options.style);
4961
4998
  }
4962
4999
  static schema() {
@@ -4980,7 +5017,7 @@ class AttributeBooleanStyle extends Rule {
4980
5017
  const meta = node.meta;
4981
5018
  /* ignore rule if element has no meta or meta does not specify attribute
4982
5019
  * allowed values */
4983
- if (!meta || !meta.attributes)
5020
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
4984
5021
  return;
4985
5022
  /* check all boolean attributes */
4986
5023
  for (const attr of node.attributes) {
@@ -5032,12 +5069,12 @@ function reportMessage$1(attr, style) {
5032
5069
  return "";
5033
5070
  }
5034
5071
 
5035
- const defaults$p = {
5072
+ const defaults$o = {
5036
5073
  style: "omit",
5037
5074
  };
5038
5075
  class AttributeEmptyStyle extends Rule {
5039
5076
  constructor(options) {
5040
- super({ ...defaults$p, ...options });
5077
+ super({ ...defaults$o, ...options });
5041
5078
  this.hasInvalidStyle = parseStyle$1(this.options.style);
5042
5079
  }
5043
5080
  static schema() {
@@ -5061,7 +5098,7 @@ class AttributeEmptyStyle extends Rule {
5061
5098
  const meta = node.meta;
5062
5099
  /* ignore rule if element has no meta or meta does not specify attribute
5063
5100
  * allowed values */
5064
- if (!meta || !meta.attributes)
5101
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
5065
5102
  return;
5066
5103
  /* check all boolean attributes */
5067
5104
  for (const attr of node.attributes) {
@@ -5149,10 +5186,10 @@ class AttributeMisuse extends Rule {
5149
5186
  });
5150
5187
  }
5151
5188
  validateAttr(node, attr, meta) {
5152
- if (!meta || !meta.allowed) {
5189
+ if (!(meta === null || meta === void 0 ? void 0 : meta.allowed)) {
5153
5190
  return;
5154
5191
  }
5155
- const details = meta.allowed(node, attr);
5192
+ const details = meta.allowed(node._adapter, attr.value);
5156
5193
  if (details) {
5157
5194
  this.report({
5158
5195
  node,
@@ -5193,12 +5230,12 @@ function describePattern(pattern) {
5193
5230
  }
5194
5231
  }
5195
5232
 
5196
- const defaults$o = {
5233
+ const defaults$n = {
5197
5234
  pattern: "kebabcase",
5198
5235
  };
5199
5236
  class ClassPattern extends Rule {
5200
5237
  constructor(options) {
5201
- super({ ...defaults$o, ...options });
5238
+ super({ ...defaults$n, ...options });
5202
5239
  this.pattern = parsePattern(this.options.pattern);
5203
5240
  }
5204
5241
  static schema() {
@@ -5307,13 +5344,13 @@ class CloseOrder extends Rule {
5307
5344
  }
5308
5345
  }
5309
5346
 
5310
- const defaults$n = {
5347
+ const defaults$m = {
5311
5348
  include: null,
5312
5349
  exclude: null,
5313
5350
  };
5314
5351
  class Deprecated extends Rule {
5315
5352
  constructor(options) {
5316
- super({ ...defaults$n, ...options });
5353
+ super({ ...defaults$m, ...options });
5317
5354
  }
5318
5355
  static schema() {
5319
5356
  return {
@@ -5476,12 +5513,12 @@ let NoStyleTag$1 = class NoStyleTag extends Rule {
5476
5513
  }
5477
5514
  };
5478
5515
 
5479
- const defaults$m = {
5516
+ const defaults$l = {
5480
5517
  style: "uppercase",
5481
5518
  };
5482
5519
  class DoctypeStyle extends Rule {
5483
5520
  constructor(options) {
5484
- super({ ...defaults$m, ...options });
5521
+ super({ ...defaults$l, ...options });
5485
5522
  }
5486
5523
  static schema() {
5487
5524
  return {
@@ -5513,12 +5550,12 @@ class DoctypeStyle extends Rule {
5513
5550
  }
5514
5551
  }
5515
5552
 
5516
- const defaults$l = {
5553
+ const defaults$k = {
5517
5554
  style: "lowercase",
5518
5555
  };
5519
5556
  class ElementCase extends Rule {
5520
5557
  constructor(options) {
5521
- super({ ...defaults$l, ...options });
5558
+ super({ ...defaults$k, ...options });
5522
5559
  this.style = new CaseStyle(this.options.style, "element-case");
5523
5560
  }
5524
5561
  static schema() {
@@ -5584,14 +5621,14 @@ class ElementCase extends Rule {
5584
5621
  }
5585
5622
  }
5586
5623
 
5587
- const defaults$k = {
5624
+ const defaults$j = {
5588
5625
  pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
5589
5626
  whitelist: [],
5590
5627
  blacklist: [],
5591
5628
  };
5592
5629
  class ElementName extends Rule {
5593
5630
  constructor(options) {
5594
- super({ ...defaults$k, ...options });
5631
+ super({ ...defaults$j, ...options });
5595
5632
  /* eslint-disable-next-line security/detect-non-literal-regexp -- expected to be a regexp */
5596
5633
  this.pattern = new RegExp(this.options.pattern);
5597
5634
  }
@@ -5632,7 +5669,7 @@ class ElementName extends Rule {
5632
5669
  ...context.blacklist.map((cur) => `- ${cur}`),
5633
5670
  ];
5634
5671
  }
5635
- if (context.pattern !== defaults$k.pattern) {
5672
+ if (context.pattern !== defaults$j.pattern) {
5636
5673
  return [
5637
5674
  `<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
5638
5675
  "",
@@ -5823,7 +5860,7 @@ class ElementPermittedOccurrences extends Rule {
5823
5860
  this.on("dom:ready", (event) => {
5824
5861
  const doc = event.document;
5825
5862
  doc.visitDepthFirst((node) => {
5826
- if (!node || !node.meta) {
5863
+ if (!(node === null || node === void 0 ? void 0 : node.meta)) {
5827
5864
  return;
5828
5865
  }
5829
5866
  const rules = node.meta.permittedContent;
@@ -5868,7 +5905,7 @@ function isCategoryOrTag(value) {
5868
5905
  return typeof value === "string";
5869
5906
  }
5870
5907
  function isCategory$1(value) {
5871
- return value[0] === "@";
5908
+ return value.startsWith("@");
5872
5909
  }
5873
5910
  function formatCategoryOrTag(value) {
5874
5911
  return isCategory$1(value) ? value.slice(1) : `<${value}>`;
@@ -6028,7 +6065,7 @@ class ElementRequiredAttributes extends Rule {
6028
6065
  const node = event.previous;
6029
6066
  const meta = node.meta;
6030
6067
  /* handle missing metadata and missing attributes */
6031
- if (!meta || !meta.attributes) {
6068
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes)) {
6032
6069
  return;
6033
6070
  }
6034
6071
  for (const [key, attr] of Object.entries(meta.attributes)) {
@@ -6048,7 +6085,7 @@ class ElementRequiredAttributes extends Rule {
6048
6085
  }
6049
6086
 
6050
6087
  function isCategory(value) {
6051
- return value[0] === "@";
6088
+ return value.startsWith("@");
6052
6089
  }
6053
6090
  class ElementRequiredContent extends Rule {
6054
6091
  documentation(context) {
@@ -6176,7 +6213,7 @@ class EmptyTitle extends Rule {
6176
6213
  }
6177
6214
  }
6178
6215
 
6179
- const defaults$j = {
6216
+ const defaults$i = {
6180
6217
  allowArrayBrackets: true,
6181
6218
  shared: ["radio", "button", "reset", "submit"],
6182
6219
  };
@@ -6209,7 +6246,7 @@ function getDocumentation(context) {
6209
6246
  }
6210
6247
  class FormDupName extends Rule {
6211
6248
  constructor(options) {
6212
- super({ ...defaults$j, ...options });
6249
+ super({ ...defaults$i, ...options });
6213
6250
  }
6214
6251
  static schema() {
6215
6252
  return {
@@ -6340,7 +6377,7 @@ class FormDupName extends Rule {
6340
6377
  const meta = this.getMetaFor(tagName);
6341
6378
  /* istanbul ignore if: the earlier check for getTagsWithProperty ensures
6342
6379
  * these will actually be set so this is just an untestable fallback */
6343
- if (!meta || !meta.formAssociated) {
6380
+ if (!(meta === null || meta === void 0 ? void 0 : meta.formAssociated)) {
6344
6381
  return false;
6345
6382
  }
6346
6383
  return meta.formAssociated.listed;
@@ -6369,7 +6406,7 @@ class FormDupName extends Rule {
6369
6406
  }
6370
6407
  }
6371
6408
 
6372
- const defaults$i = {
6409
+ const defaults$h = {
6373
6410
  allowMultipleH1: false,
6374
6411
  minInitialRank: "h1",
6375
6412
  sectioningRoots: ["dialog", '[role="dialog"]', '[role="alertdialog"]'],
@@ -6400,7 +6437,7 @@ function parseMaxInitial(value) {
6400
6437
  }
6401
6438
  class HeadingLevel extends Rule {
6402
6439
  constructor(options) {
6403
- super({ ...defaults$i, ...options });
6440
+ super({ ...defaults$h, ...options });
6404
6441
  this.stack = [];
6405
6442
  this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
6406
6443
  this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
@@ -6442,9 +6479,15 @@ class HeadingLevel extends Rule {
6442
6479
  };
6443
6480
  }
6444
6481
  setup() {
6445
- this.on("tag:start", isRelevant$3, (event) => this.onTagStart(event));
6446
- this.on("tag:ready", (event) => this.onTagReady(event));
6447
- this.on("tag:close", (event) => this.onTagClose(event));
6482
+ this.on("tag:start", isRelevant$3, (event) => {
6483
+ this.onTagStart(event);
6484
+ });
6485
+ this.on("tag:ready", (event) => {
6486
+ this.onTagReady(event);
6487
+ });
6488
+ this.on("tag:close", (event) => {
6489
+ this.onTagClose(event);
6490
+ });
6448
6491
  }
6449
6492
  onTagStart(event) {
6450
6493
  /* extract heading level from tagName (e.g "h1" -> 1)*/
@@ -6558,12 +6601,12 @@ class HeadingLevel extends Rule {
6558
6601
  }
6559
6602
  }
6560
6603
 
6561
- const defaults$h = {
6604
+ const defaults$g = {
6562
6605
  pattern: "kebabcase",
6563
6606
  };
6564
6607
  class IdPattern extends Rule {
6565
6608
  constructor(options) {
6566
- super({ ...defaults$h, ...options });
6609
+ super({ ...defaults$g, ...options });
6567
6610
  this.pattern = parsePattern(this.options.pattern);
6568
6611
  }
6569
6612
  static schema() {
@@ -6582,7 +6625,7 @@ class IdPattern extends Rule {
6582
6625
  }
6583
6626
  setup() {
6584
6627
  this.on("attr", (event) => {
6585
- var _a;
6628
+ var _a, _b;
6586
6629
  if (event.key.toLowerCase() !== "id") {
6587
6630
  return;
6588
6631
  }
@@ -6590,8 +6633,8 @@ class IdPattern extends Rule {
6590
6633
  if (event.value instanceof DynamicValue) {
6591
6634
  return;
6592
6635
  }
6593
- if (!event.value || !event.value.match(this.pattern)) {
6594
- const value = (_a = event.value) !== null && _a !== void 0 ? _a : "";
6636
+ if (!((_a = event.value) === null || _a === void 0 ? void 0 : _a.match(this.pattern))) {
6637
+ const value = (_b = event.value) !== null && _b !== void 0 ? _b : "";
6595
6638
  const pattern = this.pattern.toString();
6596
6639
  const message = `ID "${value}" does not match required pattern "${pattern}"`;
6597
6640
  this.report(event.target, message, event.valueLocation);
@@ -6965,12 +7008,12 @@ function findLabelByParent(el) {
6965
7008
  return [];
6966
7009
  }
6967
7010
 
6968
- const defaults$g = {
7011
+ const defaults$f = {
6969
7012
  maxlength: 70,
6970
7013
  };
6971
7014
  class LongTitle extends Rule {
6972
7015
  constructor(options) {
6973
- super({ ...defaults$g, ...options });
7016
+ super({ ...defaults$f, ...options });
6974
7017
  this.maxlength = this.options.maxlength;
6975
7018
  }
6976
7019
  static schema() {
@@ -7019,7 +7062,7 @@ class MetaRefresh extends Rule {
7019
7062
  }
7020
7063
  /* ensure content attribute is set */
7021
7064
  const content = target.getAttribute("content");
7022
- if (!content || !content.value || content.isDynamic) {
7065
+ if (!(content === null || content === void 0 ? void 0 : content.value) || content.isDynamic) {
7023
7066
  return;
7024
7067
  }
7025
7068
  /* ensure content attribute is valid */
@@ -7196,13 +7239,13 @@ class MultipleLabeledControls extends Rule {
7196
7239
  }
7197
7240
  }
7198
7241
 
7199
- const defaults$f = {
7242
+ const defaults$e = {
7200
7243
  include: null,
7201
7244
  exclude: null,
7202
7245
  };
7203
7246
  class NoAutoplay extends Rule {
7204
7247
  constructor(options) {
7205
- super({ ...defaults$f, ...options });
7248
+ super({ ...defaults$e, ...options });
7206
7249
  }
7207
7250
  documentation(context) {
7208
7251
  const tagName = context ? ` on <${context.tagName}>` : "";
@@ -7298,7 +7341,7 @@ class NoDeprecatedAttr extends Rule {
7298
7341
  if (meta === null) {
7299
7342
  return;
7300
7343
  }
7301
- const metaAttribute = meta.attributes && meta.attributes[attr];
7344
+ const metaAttribute = meta.attributes[attr];
7302
7345
  if (!metaAttribute) {
7303
7346
  return;
7304
7347
  }
@@ -7378,7 +7421,7 @@ class NoDupID extends Rule {
7378
7421
  for (const el of relevant) {
7379
7422
  const attr = el.getAttribute("id");
7380
7423
  /* istanbul ignore next: this has already been tested in isRelevant once but for type-safety it is checked again */
7381
- if (!attr || !attr.value) {
7424
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value)) {
7382
7425
  continue;
7383
7426
  }
7384
7427
  const id = attr.value.toString();
@@ -7443,14 +7486,14 @@ Omitted end tags can be ambigious for humans to read and many editors have troub
7443
7486
  }
7444
7487
  }
7445
7488
 
7446
- const defaults$e = {
7489
+ const defaults$d = {
7447
7490
  include: null,
7448
7491
  exclude: null,
7449
7492
  allowedProperties: ["display"],
7450
7493
  };
7451
7494
  class NoInlineStyle extends Rule {
7452
7495
  constructor(options) {
7453
- super({ ...defaults$e, ...options });
7496
+ super({ ...defaults$d, ...options });
7454
7497
  }
7455
7498
  static schema() {
7456
7499
  return {
@@ -7512,11 +7555,12 @@ class NoInlineStyle extends Rule {
7512
7555
  });
7513
7556
  }
7514
7557
  isRelevant(event) {
7558
+ var _a;
7515
7559
  if (event.key !== "style") {
7516
7560
  return false;
7517
7561
  }
7518
7562
  const { include, exclude } = this.options;
7519
- const key = event.originalAttribute || event.key;
7563
+ const key = (_a = event.originalAttribute) !== null && _a !== void 0 ? _a : event.key;
7520
7564
  /* ignore attributes not present in "include" */
7521
7565
  if (include && !include.includes(key)) {
7522
7566
  return false;
@@ -7652,7 +7696,7 @@ class NoMultipleMain extends Rule {
7652
7696
  }
7653
7697
  }
7654
7698
 
7655
- const defaults$d = {
7699
+ const defaults$c = {
7656
7700
  relaxed: false,
7657
7701
  };
7658
7702
  const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
@@ -7669,7 +7713,7 @@ const replacementTable = {
7669
7713
  };
7670
7714
  class NoRawCharacters extends Rule {
7671
7715
  constructor(options) {
7672
- super({ ...defaults$d, ...options });
7716
+ super({ ...defaults$c, ...options });
7673
7717
  this.relaxed = this.options.relaxed;
7674
7718
  }
7675
7719
  static schema() {
@@ -7710,7 +7754,8 @@ class NoRawCharacters extends Rule {
7710
7754
  if (event.quote) {
7711
7755
  return;
7712
7756
  }
7713
- this.findRawChars(event.target, event.value.toString(), event.valueLocation, unquotedAttrRegexp);
7757
+ this.findRawChars(event.target, event.value.toString(), event.valueLocation, // eslint-disable-line @typescript-eslint/no-non-null-assertion -- technical debt, valueLocation is always set if a value is provided
7758
+ unquotedAttrRegexp);
7714
7759
  });
7715
7760
  }
7716
7761
  /**
@@ -7743,6 +7788,39 @@ class NoRawCharacters extends Rule {
7743
7788
  }
7744
7789
  }
7745
7790
 
7791
+ const selectors = ["input[aria-label]", "textarea[aria-label]", "select[aria-label]"];
7792
+ class NoRedundantAriaLabel extends Rule {
7793
+ documentation() {
7794
+ return {
7795
+ description: "`aria-label` is redundant when an associated `<label>` element containing the same text exists.",
7796
+ url: "https://html-validate.org/rules/no-redundant-aria-label.html",
7797
+ };
7798
+ }
7799
+ setup() {
7800
+ this.on("dom:ready", (event) => {
7801
+ const { document } = event;
7802
+ const elements = document.querySelectorAll(selectors.join(","));
7803
+ for (const element of elements) {
7804
+ const ariaLabel = element.getAttribute("aria-label");
7805
+ const id = element.id;
7806
+ if (!id) {
7807
+ continue;
7808
+ }
7809
+ const label = document.querySelector(`label[for="${id}"]`);
7810
+ if (!ariaLabel || !label || label.textContent.trim() !== ariaLabel.value) {
7811
+ continue;
7812
+ }
7813
+ const message = "aria-label is redundant when label containing same text exists";
7814
+ this.report({
7815
+ message,
7816
+ node: element,
7817
+ location: ariaLabel.keyLocation,
7818
+ });
7819
+ }
7820
+ });
7821
+ }
7822
+ }
7823
+
7746
7824
  class NoRedundantFor extends Rule {
7747
7825
  documentation() {
7748
7826
  return {
@@ -7847,13 +7925,13 @@ class NoRedundantRole extends Rule {
7847
7925
  }
7848
7926
 
7849
7927
  const xmlns = /^(.+):.+$/;
7850
- const defaults$c = {
7928
+ const defaults$b = {
7851
7929
  ignoreForeign: true,
7852
7930
  ignoreXML: true,
7853
7931
  };
7854
7932
  class NoSelfClosing extends Rule {
7855
7933
  constructor(options) {
7856
- super({ ...defaults$c, ...options });
7934
+ super({ ...defaults$b, ...options });
7857
7935
  }
7858
7936
  static schema() {
7859
7937
  return {
@@ -7891,7 +7969,7 @@ class NoSelfClosing extends Rule {
7891
7969
  function isRelevant(node, options) {
7892
7970
  /* tags in XML namespaces are relevant only if ignoreXml is false, in which
7893
7971
  * case assume all xml elements must not be self-closed */
7894
- if (node.tagName && node.tagName.match(xmlns)) {
7972
+ if (node.tagName.match(xmlns)) {
7895
7973
  return !options.ignoreXML;
7896
7974
  }
7897
7975
  /* nodes with missing metadata is assumed relevant */
@@ -7942,13 +8020,13 @@ class NoTrailingWhitespace extends Rule {
7942
8020
  }
7943
8021
  }
7944
8022
 
7945
- const defaults$b = {
8023
+ const defaults$a = {
7946
8024
  include: null,
7947
8025
  exclude: null,
7948
8026
  };
7949
8027
  class NoUnknownElements extends Rule {
7950
8028
  constructor(options) {
7951
- super({ ...defaults$b, ...options });
8029
+ super({ ...defaults$a, ...options });
7952
8030
  }
7953
8031
  static schema() {
7954
8032
  return {
@@ -8004,9 +8082,7 @@ class NoUnknownElements extends Rule {
8004
8082
  class NoUnusedDisable extends Rule {
8005
8083
  documentation(context) {
8006
8084
  return {
8007
- description: context
8008
- ? `\`${context.ruleId}\` rule is disabled but no error was reported.`
8009
- : "Rule is disabled but no error was reported.",
8085
+ description: `\`${context.ruleId}\` rule is disabled but no error was reported.`,
8010
8086
  url: "https://html-validate.org/rules/no-unused-disable.html",
8011
8087
  };
8012
8088
  }
@@ -8060,13 +8136,13 @@ const replacement = {
8060
8136
  reset: '<button type="reset">',
8061
8137
  image: '<button type="button">',
8062
8138
  };
8063
- const defaults$a = {
8139
+ const defaults$9 = {
8064
8140
  include: null,
8065
8141
  exclude: null,
8066
8142
  };
8067
8143
  class PreferButton extends Rule {
8068
8144
  constructor(options) {
8069
- super({ ...defaults$a, ...options });
8145
+ super({ ...defaults$9, ...options });
8070
8146
  }
8071
8147
  static schema() {
8072
8148
  return {
@@ -8099,16 +8175,12 @@ class PreferButton extends Rule {
8099
8175
  };
8100
8176
  }
8101
8177
  documentation(context) {
8102
- const doc = {
8103
- description: `Prefer to use the generic \`<button>\` element instead of \`<input>\`.`,
8178
+ const src = `<input type="${context.type}">`;
8179
+ const dst = replacement[context.type] || `<button>`;
8180
+ return {
8181
+ description: `Prefer to use \`${dst}\` instead of \`"${src}\`.`,
8104
8182
  url: "https://html-validate.org/rules/prefer-button.html",
8105
8183
  };
8106
- if (context) {
8107
- const src = `<input type="${context.type}">`;
8108
- const dst = replacement[context.type] || `<button>`;
8109
- doc.description = `Prefer to use \`${dst}\` instead of \`"${src}\`.`;
8110
- }
8111
- return doc;
8112
8184
  }
8113
8185
  setup() {
8114
8186
  this.on("attr", (event) => {
@@ -8141,7 +8213,7 @@ class PreferButton extends Rule {
8141
8213
  }
8142
8214
  }
8143
8215
 
8144
- const defaults$9 = {
8216
+ const defaults$8 = {
8145
8217
  mapping: {
8146
8218
  article: "article",
8147
8219
  banner: "header",
@@ -8171,7 +8243,7 @@ const defaults$9 = {
8171
8243
  };
8172
8244
  class PreferNativeElement extends Rule {
8173
8245
  constructor(options) {
8174
- super({ ...defaults$9, ...options });
8246
+ super({ ...defaults$8, ...options });
8175
8247
  }
8176
8248
  static schema() {
8177
8249
  return {
@@ -8207,14 +8279,10 @@ class PreferNativeElement extends Rule {
8207
8279
  };
8208
8280
  }
8209
8281
  documentation(context) {
8210
- const doc = {
8211
- description: `Instead of using WAI-ARIA roles prefer to use the native HTML elements.`,
8282
+ return {
8283
+ description: `Instead of using the WAI-ARIA role "${context.role}" prefer to use the native <${context.replacement}> element.`,
8212
8284
  url: "https://html-validate.org/rules/prefer-native-element.html",
8213
8285
  };
8214
- if (context) {
8215
- doc.description = `Instead of using the WAI-ARIA role "${context.role}" prefer to use the native <${context.replacement}> element.`;
8216
- }
8217
- return doc;
8218
8286
  }
8219
8287
  setup() {
8220
8288
  const { mapping } = this.options;
@@ -8255,7 +8323,7 @@ class PreferNativeElement extends Rule {
8255
8323
  }
8256
8324
  getLocation(event) {
8257
8325
  const begin = event.location;
8258
- const end = event.valueLocation;
8326
+ const end = event.valueLocation; // eslint-disable-line @typescript-eslint/no-non-null-assertion -- technical debt, valueLocation will always be set when a value is provided
8259
8327
  const quote = event.quote ? 1 : 0;
8260
8328
  const size = end.offset + end.size - begin.offset + quote;
8261
8329
  return {
@@ -8291,12 +8359,12 @@ class PreferTbody extends Rule {
8291
8359
  }
8292
8360
  }
8293
8361
 
8294
- const defaults$8 = {
8362
+ const defaults$7 = {
8295
8363
  tags: ["script", "style"],
8296
8364
  };
8297
8365
  class RequireCSPNonce extends Rule {
8298
8366
  constructor(options) {
8299
- super({ ...defaults$8, ...options });
8367
+ super({ ...defaults$7, ...options });
8300
8368
  }
8301
8369
  static schema() {
8302
8370
  return {
@@ -8329,7 +8397,7 @@ class RequireCSPNonce extends Rule {
8329
8397
  const { tags } = this.options;
8330
8398
  const node = event.previous;
8331
8399
  /* ignore other tags */
8332
- if (!node || !tags.includes(node.tagName)) {
8400
+ if (!tags.includes(node.tagName)) {
8333
8401
  return;
8334
8402
  }
8335
8403
  /* ignore if nonce is set to non-empty value (or dynamic) */
@@ -8347,7 +8415,7 @@ class RequireCSPNonce extends Rule {
8347
8415
  }
8348
8416
  }
8349
8417
 
8350
- const defaults$7 = {
8418
+ const defaults$6 = {
8351
8419
  target: "all",
8352
8420
  include: null,
8353
8421
  exclude: null,
@@ -8359,7 +8427,7 @@ const supportSri = {
8359
8427
  };
8360
8428
  class RequireSri extends Rule {
8361
8429
  constructor(options) {
8362
- super({ ...defaults$7, ...options });
8430
+ super({ ...defaults$6, ...options });
8363
8431
  this.target = this.options.target;
8364
8432
  }
8365
8433
  static schema() {
@@ -8421,7 +8489,10 @@ class RequireSri extends Rule {
8421
8489
  }
8422
8490
  needSri(node) {
8423
8491
  const attr = this.elementSourceAttr(node);
8424
- if (!attr || attr.value === null || attr.value === "" || attr.isDynamic) {
8492
+ if (!attr) {
8493
+ return false;
8494
+ }
8495
+ if (attr.value === null || attr.value === "" || attr.isDynamic) {
8425
8496
  return false;
8426
8497
  }
8427
8498
  const url = attr.value.toString();
@@ -8478,7 +8549,7 @@ class ScriptType extends Rule {
8478
8549
  setup() {
8479
8550
  this.on("tag:end", (event) => {
8480
8551
  const node = event.previous;
8481
- if (!node || node.tagName !== "script") {
8552
+ if (node.tagName !== "script") {
8482
8553
  return;
8483
8554
  }
8484
8555
  const attr = node.getAttribute("type");
@@ -8521,7 +8592,7 @@ class SvgFocusable extends Rule {
8521
8592
  }
8522
8593
  }
8523
8594
 
8524
- const defaults$6 = {
8595
+ const defaults$5 = {
8525
8596
  characters: [
8526
8597
  { pattern: " ", replacement: "&nbsp;", description: "non-breaking space" },
8527
8598
  { pattern: "-", replacement: "&#8209;", description: "non-breaking hyphen" },
@@ -8560,7 +8631,7 @@ function matchAll(text, regexp) {
8560
8631
  }
8561
8632
  class TelNonBreaking extends Rule {
8562
8633
  constructor(options) {
8563
- super({ ...defaults$6, ...options });
8634
+ super({ ...defaults$5, ...options });
8564
8635
  this.regex = constructRegex(this.options.characters);
8565
8636
  }
8566
8637
  static schema() {
@@ -8601,9 +8672,7 @@ class TelNonBreaking extends Rule {
8601
8672
  });
8602
8673
  return {
8603
8674
  description: [
8604
- context
8605
- ? `The \`${context.pattern}\` character should be replaced with \`${context.replacement}\` character (${context.description}) when used in a telephone number.`
8606
- : `Replace this character with a non-breaking version.`,
8675
+ `The \`${context.pattern}\` character should be replaced with \`${context.replacement}\` character (${context.description}) when used in a telephone number.`,
8607
8676
  "",
8608
8677
  "Unless non-breaking characters is used there could be a line break inserted at that character.",
8609
8678
  "Line breaks make is harder to read and understand the telephone number.",
@@ -8761,18 +8830,16 @@ class TextContent extends Rule {
8761
8830
  description: `The textual content for this element is not valid.`,
8762
8831
  url: "https://html-validate.org/rules/text-content.html",
8763
8832
  };
8764
- if (context === null || context === void 0 ? void 0 : context.textContent) {
8765
- switch (context.textContent) {
8766
- case TextContent$1.NONE:
8767
- doc.description = `The \`<${context.tagName}>\` element must not have textual content.`;
8768
- break;
8769
- case TextContent$1.REQUIRED:
8770
- doc.description = `The \`<${context.tagName}>\` element must have textual content.`;
8771
- break;
8772
- case TextContent$1.ACCESSIBLE:
8773
- doc.description = `The \`<${context.tagName}>\` element must have accessible text.`;
8774
- break;
8775
- }
8833
+ switch (context.textContent) {
8834
+ case TextContent$1.NONE:
8835
+ doc.description = `The \`<${context.tagName}>\` element must not have textual content.`;
8836
+ break;
8837
+ case TextContent$1.REQUIRED:
8838
+ doc.description = `The \`<${context.tagName}>\` element must have textual content.`;
8839
+ break;
8840
+ case TextContent$1.ACCESSIBLE:
8841
+ doc.description = `The \`<${context.tagName}>\` element must have accessible text.`;
8842
+ break;
8776
8843
  }
8777
8844
  return doc;
8778
8845
  }
@@ -8848,7 +8915,7 @@ class TextContent extends Rule {
8848
8915
  }
8849
8916
  }
8850
8917
 
8851
- const defaults$5 = {
8918
+ const defaults$4 = {
8852
8919
  ignoreCase: false,
8853
8920
  requireSemicolon: true,
8854
8921
  };
@@ -8866,16 +8933,11 @@ function getLocation(location, entity, match) {
8866
8933
  function getDescription(context, options) {
8867
8934
  const url = "https://html.spec.whatwg.org/multipage/named-characters.html";
8868
8935
  let message;
8869
- if (context) {
8870
- if (context.terminated) {
8871
- message = `Unrecognized character reference \`${context.entity}\`.`;
8872
- }
8873
- else {
8874
- message = `Character reference \`${context.entity}\` must be terminated by a semicolon.`;
8875
- }
8936
+ if (context.terminated) {
8937
+ message = `Unrecognized character reference \`${context.entity}\`.`;
8876
8938
  }
8877
8939
  else {
8878
- message = `Unrecognized character reference.`;
8940
+ message = `Character reference \`${context.entity}\` must be terminated by a semicolon.`;
8879
8941
  }
8880
8942
  return [
8881
8943
  message,
@@ -8890,7 +8952,7 @@ function getDescription(context, options) {
8890
8952
  }
8891
8953
  class UnknownCharReference extends Rule {
8892
8954
  constructor(options) {
8893
- super({ ...defaults$5, ...options });
8955
+ super({ ...defaults$4, ...options });
8894
8956
  }
8895
8957
  static schema() {
8896
8958
  return {
@@ -9007,12 +9069,12 @@ var RuleContext;
9007
9069
  RuleContext[RuleContext["LEADING_CHARACTER"] = 3] = "LEADING_CHARACTER";
9008
9070
  RuleContext[RuleContext["DISALLOWED_CHARACTER"] = 4] = "DISALLOWED_CHARACTER";
9009
9071
  })(RuleContext || (RuleContext = {}));
9010
- const defaults$4 = {
9072
+ const defaults$3 = {
9011
9073
  relaxed: false,
9012
9074
  };
9013
9075
  class ValidID extends Rule {
9014
9076
  constructor(options) {
9015
- super({ ...defaults$4, ...options });
9077
+ super({ ...defaults$3, ...options });
9016
9078
  }
9017
9079
  static schema() {
9018
9080
  return {
@@ -9023,9 +9085,9 @@ class ValidID extends Rule {
9023
9085
  }
9024
9086
  documentation(context) {
9025
9087
  const { relaxed } = this.options;
9026
- const message = context
9027
- ? this.messages[context].replace("id", "ID").replace(/^(.)/, (m) => m.toUpperCase())
9028
- : "Element ID is not valid";
9088
+ const message = this.messages[context]
9089
+ .replace("id", "ID")
9090
+ .replace(/^(.)/, (m) => m.toUpperCase());
9029
9091
  const relaxedDescription = relaxed
9030
9092
  ? []
9031
9093
  : [
@@ -9121,12 +9183,12 @@ var Style;
9121
9183
  Style[Style["AlwaysOmit"] = 1] = "AlwaysOmit";
9122
9184
  Style[Style["AlwaysSelfclose"] = 2] = "AlwaysSelfclose";
9123
9185
  })(Style || (Style = {}));
9124
- const defaults$3 = {
9186
+ const defaults$2 = {
9125
9187
  style: "omit",
9126
9188
  };
9127
9189
  class VoidStyle extends Rule {
9128
9190
  constructor(options) {
9129
- super({ ...defaults$3, ...options });
9191
+ super({ ...defaults$2, ...options });
9130
9192
  this.style = parseStyle(this.options.style);
9131
9193
  }
9132
9194
  static schema() {
@@ -9138,20 +9200,16 @@ class VoidStyle extends Rule {
9138
9200
  };
9139
9201
  }
9140
9202
  documentation(context) {
9141
- const doc = {
9142
- description: "The current configuration requires a specific style for ending void elements.",
9203
+ const [desc, end] = styleDescription(context.style);
9204
+ return {
9205
+ description: `The current configuration requires void elements to ${desc}, use <${context.tagName}${end}> instead.`,
9143
9206
  url: "https://html-validate.org/rules/void-style.html",
9144
9207
  };
9145
- if (context) {
9146
- const [desc, end] = styleDescription(context.style);
9147
- doc.description = `The current configuration requires void elements to ${desc}, use <${context.tagName}${end}> instead.`;
9148
- }
9149
- return doc;
9150
9208
  }
9151
9209
  setup() {
9152
9210
  this.on("tag:end", (event) => {
9153
9211
  const active = event.previous; // The current active element (that is, the current element on the stack)
9154
- if (active && active.meta) {
9212
+ if (active.meta) {
9155
9213
  this.validateActive(active);
9156
9214
  }
9157
9215
  });
@@ -9323,7 +9381,7 @@ class H36 extends Rule {
9323
9381
  }
9324
9382
  }
9325
9383
 
9326
- const defaults$2 = {
9384
+ const defaults$1 = {
9327
9385
  allowEmpty: true,
9328
9386
  alias: [],
9329
9387
  };
@@ -9344,7 +9402,7 @@ function getTag(node) {
9344
9402
  }
9345
9403
  class H37 extends Rule {
9346
9404
  constructor(options) {
9347
- super({ ...defaults$2, ...options });
9405
+ super({ ...defaults$1, ...options });
9348
9406
  /* ensure alias is array */
9349
9407
  if (!Array.isArray(this.options.alias)) {
9350
9408
  this.options.alias = [this.options.alias];
@@ -9388,7 +9446,8 @@ class H37 extends Rule {
9388
9446
  return;
9389
9447
  }
9390
9448
  /* validate plain alt-attribute */
9391
- if (node.getAttributeValue("alt") || (node.hasAttribute("alt") && this.options.allowEmpty)) {
9449
+ if (Boolean(node.getAttributeValue("alt")) ||
9450
+ Boolean(node.hasAttribute("alt") && this.options.allowEmpty)) {
9392
9451
  return;
9393
9452
  }
9394
9453
  /* validate if any non-empty alias is present */
@@ -9570,6 +9629,7 @@ const bundledRules = {
9570
9629
  "no-missing-references": NoMissingReferences,
9571
9630
  "no-multiple-main": NoMultipleMain,
9572
9631
  "no-raw-characters": NoRawCharacters,
9632
+ "no-redundant-aria-label": NoRedundantAriaLabel,
9573
9633
  "no-redundant-for": NoRedundantFor,
9574
9634
  "no-redundant-role": NoRedundantRole,
9575
9635
  "no-self-closing": NoSelfClosing,
@@ -9610,6 +9670,7 @@ const config$4 = {
9610
9670
  "multiple-labeled-controls": "error",
9611
9671
  "no-autoplay": ["error", { include: ["audio", "video"] }],
9612
9672
  "no-dup-id": "error",
9673
+ "no-redundant-aria-label": "error",
9613
9674
  "no-redundant-for": "error",
9614
9675
  "no-redundant-role": "error",
9615
9676
  "prefer-native-element": "error",
@@ -9692,6 +9753,7 @@ const config$1 = {
9692
9753
  "no-inline-style": "error",
9693
9754
  "no-multiple-main": "error",
9694
9755
  "no-raw-characters": "error",
9756
+ "no-redundant-aria-label": "error",
9695
9757
  "no-redundant-for": "error",
9696
9758
  "no-redundant-role": "error",
9697
9759
  "no-self-closing": "error",
@@ -9818,7 +9880,7 @@ class ResolvedConfig {
9818
9880
  * @returns A list of transformed sources ready for validation.
9819
9881
  */
9820
9882
  transformSource(source, filename) {
9821
- const transformer = this.findTransformer(filename || source.filename);
9883
+ const transformer = this.findTransformer(filename !== null && filename !== void 0 ? filename : source.filename);
9822
9884
  const context = {
9823
9885
  hasChain: (filename) => {
9824
9886
  return !!this.findTransformer(filename);
@@ -9830,9 +9892,10 @@ class ResolvedConfig {
9830
9892
  if (transformer) {
9831
9893
  try {
9832
9894
  return Array.from(transformer.fn.call(context, source), (cur) => {
9895
+ var _a;
9833
9896
  /* keep track of which transformers that has been run on this source
9834
9897
  * by appending this entry to the transformedBy array */
9835
- cur.transformedBy = cur.transformedBy || [];
9898
+ (_a = cur.transformedBy) !== null && _a !== void 0 ? _a : (cur.transformedBy = []);
9836
9899
  cur.transformedBy.push(transformer.name);
9837
9900
  return cur;
9838
9901
  });
@@ -10004,7 +10067,7 @@ function mergeInternal(base, rhs) {
10004
10067
  }
10005
10068
  /* root property is merged with boolean "or" since it should always be truthy
10006
10069
  * if any config has it set. */
10007
- const root = base.root || rhs.root;
10070
+ const root = Boolean(base.root) || Boolean(rhs.root);
10008
10071
  if (root) {
10009
10072
  dst.root = root;
10010
10073
  }
@@ -10091,7 +10154,7 @@ class Config {
10091
10154
  * @internal
10092
10155
  */
10093
10156
  constructor(resolvers, options) {
10094
- var _a;
10157
+ var _a, _b;
10095
10158
  this.transformers = [];
10096
10159
  const initial = {
10097
10160
  extends: [],
@@ -10104,18 +10167,18 @@ class Config {
10104
10167
  this.initialized = false;
10105
10168
  this.resolvers = toArray(resolvers);
10106
10169
  /* load plugins */
10107
- this.plugins = this.loadPlugins(this.config.plugins || []);
10170
+ this.plugins = this.loadPlugins((_a = this.config.plugins) !== null && _a !== void 0 ? _a : []);
10108
10171
  this.configurations = this.loadConfigurations(this.plugins);
10109
10172
  this.extendMeta(this.plugins);
10110
10173
  /* process extended configs */
10111
- this.config = this.extendConfig((_a = this.config.extends) !== null && _a !== void 0 ? _a : []);
10174
+ this.config = this.extendConfig((_b = this.config.extends) !== null && _b !== void 0 ? _b : []);
10112
10175
  /* reset extends as we already processed them, this prevents the next config
10113
10176
  * from reapplying config from extended config as well as duplicate entries
10114
10177
  * when merging arrays */
10115
10178
  this.config.extends = [];
10116
10179
  /* rules explicitly set by passed options should have precedence over any
10117
10180
  * extended rules, not the other way around. */
10118
- if (options && options.rules) {
10181
+ if (options === null || options === void 0 ? void 0 : options.rules) {
10119
10182
  this.config = mergeInternal(this.config, { rules: options.rules });
10120
10183
  }
10121
10184
  }
@@ -10128,11 +10191,12 @@ class Config {
10128
10191
  * @public
10129
10192
  */
10130
10193
  init() {
10194
+ var _a;
10131
10195
  if (this.initialized) {
10132
10196
  return;
10133
10197
  }
10134
10198
  /* precompile transform patterns */
10135
- this.transformers = this.precompileTransformers(this.config.transform || {});
10199
+ this.transformers = this.precompileTransformers((_a = this.config.transform) !== null && _a !== void 0 ? _a : {});
10136
10200
  this.initialized = true;
10137
10201
  }
10138
10202
  /**
@@ -10156,11 +10220,10 @@ class Config {
10156
10220
  return this.config;
10157
10221
  }
10158
10222
  let base = {};
10159
- for (let i = 0; i < entries.length; i++) {
10160
- const entry = entries[i];
10223
+ for (const entry of entries) {
10161
10224
  let extended;
10162
10225
  if (this.configurations.has(entry)) {
10163
- extended = this.configurations.get(entry);
10226
+ extended = this.configurations.get(entry); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- map has/get combo
10164
10227
  }
10165
10228
  else {
10166
10229
  extended = Config.fromFile(this.resolvers, entry).config;
@@ -10175,12 +10238,13 @@ class Config {
10175
10238
  * @internal
10176
10239
  */
10177
10240
  getMetaTable() {
10241
+ var _a;
10178
10242
  /* use cached table if it exists */
10179
10243
  if (this.metaTable) {
10180
10244
  return this.metaTable;
10181
10245
  }
10182
10246
  const metaTable = new MetaTable();
10183
- const source = this.config.elements || ["html5"];
10247
+ const source = (_a = this.config.elements) !== null && _a !== void 0 ? _a : ["html5"];
10184
10248
  /* extend validation schema from plugins */
10185
10249
  for (const plugin of this.getPlugins()) {
10186
10250
  if (plugin.elementSchema) {
@@ -10278,6 +10342,7 @@ class Config {
10278
10342
  });
10279
10343
  }
10280
10344
  loadConfigurations(plugins) {
10345
+ var _a;
10281
10346
  const configs = new Map();
10282
10347
  /* builtin presets */
10283
10348
  for (const [name, config] of Object.entries(Presets)) {
@@ -10286,7 +10351,7 @@ class Config {
10286
10351
  }
10287
10352
  /* presets from plugins */
10288
10353
  for (const plugin of plugins) {
10289
- for (const [name, config] of Object.entries(plugin.configs || {})) {
10354
+ for (const [name, config] of Object.entries((_a = plugin.configs) !== null && _a !== void 0 ? _a : {})) {
10290
10355
  if (!config)
10291
10356
  continue;
10292
10357
  Config.validate(config, name);
@@ -10651,10 +10716,11 @@ class Parser {
10651
10716
  * stack when is allowed to omit.
10652
10717
  */
10653
10718
  closeOptional(token) {
10719
+ var _a;
10654
10720
  /* if the element doesn't have metadata it cannot have optional end
10655
10721
  * tags. Period. */
10656
10722
  const active = this.dom.getActive();
10657
- if (!(active.meta && active.meta.implicitClosed)) {
10723
+ if (!((_a = active.meta) === null || _a === void 0 ? void 0 : _a.implicitClosed)) {
10658
10724
  return false;
10659
10725
  }
10660
10726
  const tagName = token.data[2];
@@ -10806,9 +10872,10 @@ class Parser {
10806
10872
  }
10807
10873
  }
10808
10874
  processElement(node, source) {
10875
+ var _a;
10809
10876
  /* enable cache on node now that it is fully constructed */
10810
10877
  node.cacheEnable();
10811
- if (source.hooks && source.hooks.processElement) {
10878
+ if ((_a = source.hooks) === null || _a === void 0 ? void 0 : _a.processElement) {
10812
10879
  const processElement = source.hooks.processElement;
10813
10880
  const metaTable = this.metaTable;
10814
10881
  const context = {
@@ -10875,6 +10942,7 @@ class Parser {
10875
10942
  * @internal
10876
10943
  */
10877
10944
  consumeAttribute(source, node, token, next) {
10945
+ var _a;
10878
10946
  const keyLocation = this.getAttributeKeyLocation(token);
10879
10947
  const valueLocation = this.getAttributeValueLocation(next);
10880
10948
  const location = this.getAttributeLocation(token, next);
@@ -10893,7 +10961,7 @@ class Parser {
10893
10961
  * data right away but a transformer may override it to allow aliasing
10894
10962
  * attributes, e.g ng-attr-foo or v-bind:foo */
10895
10963
  let processAttribute = (attr) => [attr];
10896
- if (source.hooks && source.hooks.processAttribute) {
10964
+ if ((_a = source.hooks) === null || _a === void 0 ? void 0 : _a.processAttribute) {
10897
10965
  processAttribute = source.hooks.processAttribute;
10898
10966
  }
10899
10967
  /* handle deprecated callbacks */
@@ -11243,14 +11311,15 @@ class Reporter {
11243
11311
  const report = {
11244
11312
  valid: this.isValid(),
11245
11313
  results: Object.keys(this.result).map((filePath) => {
11314
+ var _a;
11246
11315
  const messages = Array.from(this.result[filePath], freeze).sort(messageSort);
11247
- const source = (sources || []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11316
+ const source = (sources !== null && sources !== void 0 ? sources : []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11248
11317
  return {
11249
11318
  filePath,
11250
11319
  messages,
11251
11320
  errorCount: countErrors(messages),
11252
11321
  warningCount: countWarnings(messages),
11253
- source: source ? source.originalData || source.data : null,
11322
+ source: source ? (_a = source.originalData) !== null && _a !== void 0 ? _a : source.data : null,
11254
11323
  };
11255
11324
  }),
11256
11325
  errorCount: 0,
@@ -11268,10 +11337,10 @@ class Reporter {
11268
11337
  }
11269
11338
  }
11270
11339
  function countErrors(messages) {
11271
- return messages.filter((m) => m.severity === Severity.ERROR).length;
11340
+ return messages.filter((m) => m.severity === Number(Severity.ERROR)).length;
11272
11341
  }
11273
11342
  function countWarnings(messages) {
11274
- return messages.filter((m) => m.severity === Severity.WARN).length;
11343
+ return messages.filter((m) => m.severity === Number(Severity.WARN)).length;
11275
11344
  }
11276
11345
  function sumErrors(results) {
11277
11346
  return results.reduce((sum, result) => {
@@ -11449,7 +11518,9 @@ class Engine {
11449
11518
  else {
11450
11519
  lines.push("(root)");
11451
11520
  }
11452
- node.childElements.forEach((child, index) => writeNode(child, level + 1, index));
11521
+ node.childElements.forEach((child, index) => {
11522
+ writeNode(child, level + 1, index);
11523
+ });
11453
11524
  }
11454
11525
  writeNode(document, 0, 0);
11455
11526
  return lines;
@@ -11614,9 +11685,10 @@ class Engine {
11614
11685
  * between rule name and its constructor.
11615
11686
  */
11616
11687
  initRules(config) {
11688
+ var _a;
11617
11689
  const availableRules = {};
11618
11690
  for (const plugin of config.getPlugins()) {
11619
- for (const [name, rule] of Object.entries(plugin.rules || {})) {
11691
+ for (const [name, rule] of Object.entries((_a = plugin.rules) !== null && _a !== void 0 ? _a : {})) {
11620
11692
  if (!rule)
11621
11693
  continue;
11622
11694
  availableRules[name] = rule;
@@ -11719,7 +11791,7 @@ class StaticConfigLoader extends ConfigLoader {
11719
11791
  }
11720
11792
  }
11721
11793
  getConfigFor(_handle, configOverride) {
11722
- const override = this.loadFromObject(configOverride || {});
11794
+ const override = this.loadFromObject(configOverride !== null && configOverride !== void 0 ? configOverride : {});
11723
11795
  if (override.isRootFound()) {
11724
11796
  override.init();
11725
11797
  return override.resolve();
@@ -11763,6 +11835,7 @@ class HtmlValidate {
11763
11835
  const [loader, config] = arg instanceof ConfigLoader ? [arg, undefined] : [undefined, arg];
11764
11836
  this.configLoader = loader !== null && loader !== void 0 ? loader : new StaticConfigLoader(config);
11765
11837
  }
11838
+ /* eslint-enable @typescript-eslint/unified-signatures */
11766
11839
  validateString(str, arg1, arg2, arg3) {
11767
11840
  const filename = typeof arg1 === "string" ? arg1 : "inline";
11768
11841
  const options = isConfigData(arg1) ? arg1 : isConfigData(arg2) ? arg2 : undefined;
@@ -11777,6 +11850,7 @@ class HtmlValidate {
11777
11850
  };
11778
11851
  return this.validateSource(source, options);
11779
11852
  }
11853
+ /* eslint-enable @typescript-eslint/unified-signatures */
11780
11854
  validateStringSync(str, arg1, arg2, arg3) {
11781
11855
  const filename = typeof arg1 === "string" ? arg1 : "inline";
11782
11856
  const options = isConfigData(arg1) ? arg1 : isConfigData(arg2) ? arg2 : undefined;
@@ -12048,7 +12122,7 @@ class HtmlValidate {
12048
12122
  * contextual details and suggestions.
12049
12123
  */
12050
12124
  async getRuleDocumentation(ruleId, config = null, context = null) {
12051
- const c = config || this.getConfigFor("inline");
12125
+ const c = config !== null && config !== void 0 ? config : this.getConfigFor("inline");
12052
12126
  const engine = new Engine(await c, Parser);
12053
12127
  return engine.getRuleDocumentation({ ruleId, context });
12054
12128
  }
@@ -12077,7 +12151,7 @@ class HtmlValidate {
12077
12151
  * contextual details and suggestions.
12078
12152
  */
12079
12153
  getRuleDocumentationSync(ruleId, config = null, context = null) {
12080
- const c = config || this.getConfigForSync("inline");
12154
+ const c = config !== null && config !== void 0 ? config : this.getConfigForSync("inline");
12081
12155
  const engine = new Engine(c, Parser);
12082
12156
  return engine.getRuleDocumentation({ ruleId, context });
12083
12157
  }
@@ -12133,7 +12207,7 @@ class HtmlValidate {
12133
12207
  /** @public */
12134
12208
  const name = "html-validate";
12135
12209
  /** @public */
12136
- const version = "8.0.5";
12210
+ const version = "8.2.0";
12137
12211
  /** @public */
12138
12212
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
12139
12213
 
@@ -12146,61 +12220,6 @@ function definePlugin(plugin) {
12146
12220
  return plugin;
12147
12221
  }
12148
12222
 
12149
- const defaults$1 = {
12150
- silent: false,
12151
- version,
12152
- logger(text) {
12153
- /* eslint-disable-next-line no-console -- expected to log */
12154
- console.error(kleur.red(text));
12155
- },
12156
- };
12157
- /**
12158
- * Tests if plugin is compatible with html-validate library. Unless the `silent`
12159
- * option is used a warning is displayed on the console.
12160
- *
12161
- * @public
12162
- * @since v5.0.0
12163
- * @param name - Name of plugin
12164
- * @param declared - What library versions the plugin support (e.g. declared peerDependencies)
12165
- * @returns - `true` if version is compatible
12166
- */
12167
- function compatibilityCheck(name, declared, options) {
12168
- const { silent, version: current, logger } = { ...defaults$1, ...options };
12169
- const valid = semver.satisfies(current, declared);
12170
- if (valid || silent) {
12171
- return valid;
12172
- }
12173
- const text = [
12174
- "-----------------------------------------------------------------------------------------------------",
12175
- `${name} requires html-validate version "${declared}" but current installed version is ${current}`,
12176
- "This is not a supported configuration. Please install a supported version before reporting bugs.",
12177
- "-----------------------------------------------------------------------------------------------------",
12178
- ].join("\n");
12179
- logger(text);
12180
- return false;
12181
- }
12182
-
12183
- /**
12184
- * Similar to `require(..)` but removes the cached copy first.
12185
- */
12186
- function requireUncached(require, moduleId) {
12187
- const filename = require.resolve(moduleId);
12188
- /* remove references from the parent module to prevent memory leak */
12189
- const m = require.cache[filename];
12190
- if (m && m.parent) {
12191
- const { parent } = m;
12192
- for (let i = parent.children.length - 1; i >= 0; i--) {
12193
- if (parent.children[i].id === filename) {
12194
- parent.children.splice(i, 1);
12195
- }
12196
- }
12197
- }
12198
- /* remove old module from cache */
12199
- delete require.cache[filename];
12200
- /* eslint-disable-next-line import/no-dynamic-require, security/detect-non-literal-require -- as expected but should be moved to upcoming resolver class */
12201
- return require(filename);
12202
- }
12203
-
12204
12223
  const ruleIds = new Set(Object.keys(rules));
12205
12224
  /**
12206
12225
  * Returns true if given ruleId is an existing builtin rule. It does not handle
@@ -12467,5 +12486,24 @@ function getFormatter(name) {
12467
12486
  return (_a = availableFormatters[name]) !== null && _a !== void 0 ? _a : null;
12468
12487
  }
12469
12488
 
12470
- export { Attribute as A, codeframe as B, Config as C, DynamicValue as D, EventHandler as E, requireUncached as F, name as G, HtmlValidate as H, bugs as I, MetaTable as M, NodeClosed as N, Presets as P, ResolvedConfig as R, Severity as S, TextNode as T, UserError as U, Validator as V, WrappedError as W, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, DOMTokenList as d, HtmlElement as e, DOMNode as f, DOMTree as g, NodeType as h, SchemaValidationError as i, NestedError as j, TextContent$1 as k, MetaCopyableProperty as l, Rule as m, TextClassification as n, classifyNodeText as o, keywordPatternMatcher as p, sliceLocation as q, Reporter as r, staticResolver as s, definePlugin as t, Parser as u, version as v, ruleExists as w, getFormatter as x, ensureError as y, compatibilityCheck as z };
12489
+ /**
12490
+ * @internal
12491
+ */
12492
+ function compatibilityCheckImpl(name, declared, options) {
12493
+ const { silent, version: current, logger } = options;
12494
+ const valid = semver.satisfies(current, declared);
12495
+ if (valid || silent) {
12496
+ return valid;
12497
+ }
12498
+ const text = [
12499
+ "-----------------------------------------------------------------------------------------------------",
12500
+ `${name} requires html-validate version "${declared}" but current installed version is ${current}`,
12501
+ "This is not a supported configuration. Please install a supported version before reporting bugs.",
12502
+ "-----------------------------------------------------------------------------------------------------",
12503
+ ].join("\n");
12504
+ logger(text);
12505
+ return false;
12506
+ }
12507
+
12508
+ export { Attribute as A, codeframe as B, Config as C, DOMNode as D, EventHandler as E, name as F, bugs as G, HtmlValidate as H, MetaCopyableProperty as M, NodeClosed as N, Presets as P, ResolvedConfig as R, Severity as S, TextNode as T, UserError as U, Validator as V, WrappedError as W, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, DOMTokenList as d, ensureError as e, DOMTree as f, getFormatter as g, DynamicValue as h, HtmlElement as i, NodeType as j, NestedError as k, SchemaValidationError as l, MetaTable as m, TextContent$1 as n, Rule as o, TextClassification as p, classifyNodeText as q, keywordPatternMatcher as r, staticResolver as s, sliceLocation as t, Reporter as u, version as v, definePlugin as w, Parser as x, ruleExists as y, compatibilityCheckImpl as z };
12471
12509
  //# sourceMappingURL=core.js.map