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/cjs/core.js CHANGED
@@ -4,21 +4,21 @@ var Ajv = require('ajv');
4
4
  var deepmerge = require('deepmerge');
5
5
  var elements = require('./elements.js');
6
6
  var fs = require('fs');
7
- var semver = require('semver');
8
- var kleur = require('kleur');
9
7
  var betterAjvErrors = require('@sidvind/better-ajv-errors');
10
8
  var utils_naturalJoin = require('./utils/natural-join.js');
11
9
  var codeFrame = require('@babel/code-frame');
10
+ var kleur = require('kleur');
12
11
  var stylish$2 = require('@html-validate/stylish');
12
+ var semver = require('semver');
13
13
 
14
14
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
15
 
16
16
  var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
17
17
  var deepmerge__default = /*#__PURE__*/_interopDefault(deepmerge);
18
18
  var fs__default = /*#__PURE__*/_interopDefault(fs);
19
- var semver__default = /*#__PURE__*/_interopDefault(semver);
20
- var kleur__default = /*#__PURE__*/_interopDefault(kleur);
21
19
  var betterAjvErrors__default = /*#__PURE__*/_interopDefault(betterAjvErrors);
20
+ var kleur__default = /*#__PURE__*/_interopDefault(kleur);
21
+ var semver__default = /*#__PURE__*/_interopDefault(semver);
22
22
 
23
23
  const $schema$2 = "http://json-schema.org/draft-06/schema#";
24
24
  const $id$2 = "http://json-schema.org/draft-06/schema#";
@@ -295,7 +295,7 @@ class NestedError extends Error {
295
295
  super(message);
296
296
  Error.captureStackTrace(this, NestedError);
297
297
  this.name = NestedError.name;
298
- if (nested && nested.stack) {
298
+ if (nested === null || nested === void 0 ? void 0 : nested.stack) {
299
299
  this.stack += `\nCaused by: ${nested.stack}`;
300
300
  }
301
301
  }
@@ -1030,7 +1030,8 @@ function hasAttribute(node, attr) {
1030
1030
  * Matches attribute against value.
1031
1031
  */
1032
1032
  function matchAttribute(node, key, op, value) {
1033
- const nodeValue = (node.getAttributeValue(key) || "").toLowerCase();
1033
+ var _a;
1034
+ const nodeValue = ((_a = node.getAttributeValue(key)) !== null && _a !== void 0 ? _a : "").toLowerCase();
1034
1035
  switch (op) {
1035
1036
  case "!=":
1036
1037
  return nodeValue !== value;
@@ -1392,6 +1393,16 @@ class Attribute {
1392
1393
  get isDynamic() {
1393
1394
  return this.value instanceof DynamicValue;
1394
1395
  }
1396
+ /**
1397
+ * Test attribute value.
1398
+ *
1399
+ * @param pattern - Pattern to match value against. Can be a RegExp, literal
1400
+ * string or an array of strings (returns true if any value matches the
1401
+ * array).
1402
+ * @param dynamicMatches - If true `DynamicValue` will always match, if false
1403
+ * it never matches.
1404
+ * @returns `true` if attribute value matches pattern.
1405
+ */
1395
1406
  valueMatches(pattern, dynamicMatches = true) {
1396
1407
  if (this.value === null) {
1397
1408
  return false;
@@ -1777,7 +1788,7 @@ class DOMTokenList extends Array {
1777
1788
  this.value = value.expr;
1778
1789
  }
1779
1790
  else {
1780
- this.value = value || "";
1791
+ this.value = value !== null && value !== void 0 ? value : "";
1781
1792
  }
1782
1793
  }
1783
1794
  item(n) {
@@ -2002,7 +2013,7 @@ class IdMatcher extends Matcher {
2002
2013
  class AttrMatcher extends Matcher {
2003
2014
  constructor(attr) {
2004
2015
  super();
2005
- const [, key, op, value] = attr.match(/^(.+?)(?:([~^$*|]?=)"([^"]+?)")?$/);
2016
+ const [, key, op, value] = attr.match(/^(.+?)(?:([~^$*|]?=)"([^"]+?)")?$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2006
2017
  this.key = key;
2007
2018
  this.op = op;
2008
2019
  this.value = value;
@@ -2039,11 +2050,11 @@ class PseudoClassMatcher extends Matcher {
2039
2050
  }
2040
2051
  class Pattern {
2041
2052
  constructor(pattern) {
2042
- const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)(.*)$/);
2053
+ const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)(.*)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2043
2054
  match.shift(); /* remove full matched string */
2044
2055
  this.selector = pattern;
2045
2056
  this.combinator = parseCombinator(match.shift(), pattern);
2046
- this.tagName = match.shift() || "*";
2057
+ this.tagName = match.shift() || "*"; // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing -- empty string */
2047
2058
  this.pattern = Array.from(splitPattern(match[0]), (it) => this.createMatcher(it));
2048
2059
  }
2049
2060
  match(node, context) {
@@ -2217,6 +2228,21 @@ function isElementNode(node) {
2217
2228
  function isValidTagName(tagName) {
2218
2229
  return Boolean(tagName !== "" && tagName !== "*");
2219
2230
  }
2231
+ function createAdapter(node) {
2232
+ return {
2233
+ closest(selectors) {
2234
+ var _a;
2235
+ return (_a = node.closest(selectors)) === null || _a === void 0 ? void 0 : _a._adapter;
2236
+ },
2237
+ getAttribute(name) {
2238
+ var _a;
2239
+ return (_a = node.getAttribute(name)) === null || _a === void 0 ? void 0 : _a.value;
2240
+ },
2241
+ hasAttribute(name) {
2242
+ return node.hasAttribute(name);
2243
+ },
2244
+ };
2245
+ }
2220
2246
  /**
2221
2247
  * @public
2222
2248
  */
@@ -2225,9 +2251,9 @@ class HtmlElement extends DOMNode {
2225
2251
  const nodeType = tagName ? exports.NodeType.ELEMENT_NODE : exports.NodeType.DOCUMENT_NODE;
2226
2252
  super(nodeType, tagName, location);
2227
2253
  if (!isValidTagName(tagName)) {
2228
- throw new Error(`The tag name provided ('${tagName || ""}') is not a valid name`);
2254
+ throw new Error(`The tag name provided ('${tagName !== null && tagName !== void 0 ? tagName : ""}') is not a valid name`);
2229
2255
  }
2230
- this.tagName = tagName || "#document";
2256
+ this.tagName = tagName !== null && tagName !== void 0 ? tagName : "#document";
2231
2257
  this.parent = parent !== null && parent !== void 0 ? parent : null;
2232
2258
  this.attr = {};
2233
2259
  this.metaElement = meta !== null && meta !== void 0 ? meta : null;
@@ -2235,6 +2261,7 @@ class HtmlElement extends DOMNode {
2235
2261
  this.voidElement = meta ? Boolean(meta.void) : false;
2236
2262
  this.depth = 0;
2237
2263
  this.annotation = null;
2264
+ this._adapter = createAdapter(this);
2238
2265
  if (parent) {
2239
2266
  parent.childNodes.push(this);
2240
2267
  /* calculate depth in domtree */
@@ -2294,7 +2321,7 @@ class HtmlElement extends DOMNode {
2294
2321
  */
2295
2322
  get ariaLabelledby() {
2296
2323
  const attr = this.getAttribute("aria-labelledby");
2297
- if (!attr || !attr.value) {
2324
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value)) {
2298
2325
  return null;
2299
2326
  }
2300
2327
  if (attr.value instanceof DynamicValue) {
@@ -2412,6 +2439,7 @@ class HtmlElement extends DOMNode {
2412
2439
  setMetaProperty(this.metaElement, key, value);
2413
2440
  }
2414
2441
  else {
2442
+ /* eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- technical debt */
2415
2443
  delete this.metaElement[key];
2416
2444
  }
2417
2445
  }
@@ -2687,11 +2715,12 @@ class DOMTree {
2687
2715
  this.active = node;
2688
2716
  }
2689
2717
  popActive() {
2718
+ var _a;
2690
2719
  if (this.active.isRootElement()) {
2691
2720
  /* root element should never be popped, continue as if nothing happened */
2692
2721
  return;
2693
2722
  }
2694
- this.active = this.active.parent || this.root;
2723
+ this.active = (_a = this.active.parent) !== null && _a !== void 0 ? _a : this.root;
2695
2724
  }
2696
2725
  getActive() {
2697
2726
  return this.active;
@@ -2700,7 +2729,9 @@ class DOMTree {
2700
2729
  * Resolve dynamic meta expressions.
2701
2730
  */
2702
2731
  resolveMeta(table) {
2703
- this.visitDepthFirst((node) => table.resolve(node));
2732
+ this.visitDepthFirst((node) => {
2733
+ table.resolve(node);
2734
+ });
2704
2735
  }
2705
2736
  getElementsByTagName(tagName) {
2706
2737
  return this.root.getElementsByTagName(tagName);
@@ -2725,6 +2756,7 @@ const allowedKeys = ["exclude"];
2725
2756
  *
2726
2757
  * @public
2727
2758
  */
2759
+ /* eslint-disable-next-line @typescript-eslint/no-extraneous-class -- technical debt, should probably be plain functions maybe in an object */
2728
2760
  class Validator {
2729
2761
  /**
2730
2762
  * Test if element is used in a proper context.
@@ -2766,7 +2798,7 @@ class Validator {
2766
2798
  return false;
2767
2799
  }
2768
2800
  // Check if the rule has a quantifier
2769
- const [, category, quantifier] = rule.match(/^(@?.*?)([?*]?)$/);
2801
+ const [, category, quantifier] = rule.match(/^(@?.*?)([?*]?)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2770
2802
  const limit = category && quantifier && parseQuantifier(quantifier);
2771
2803
  if (limit) {
2772
2804
  const siblings = children.filter((cur) => Validator.validatePermittedCategory(cur, rule, true));
@@ -2812,6 +2844,7 @@ class Validator {
2812
2844
  * In both of these cases no error should be reported. */
2813
2845
  const orderSpecified = rules.find((cur) => Validator.validatePermittedCategory(node, cur, true));
2814
2846
  if (orderSpecified) {
2847
+ /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt, should never happen */
2815
2848
  cb(node, prev);
2816
2849
  return false;
2817
2850
  }
@@ -2952,9 +2985,9 @@ class Validator {
2952
2985
  */
2953
2986
  /* eslint-disable-next-line complexity -- rule does not like switch */
2954
2987
  static validatePermittedCategory(node, category, defaultMatch) {
2955
- const [, rawCategory] = category.match(/^(@?.*?)([?*]?)$/);
2988
+ const [, rawCategory] = category.match(/^(@?.*?)([?*]?)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2956
2989
  /* match tagName when an explicit name is given */
2957
- if (rawCategory[0] !== "@") {
2990
+ if (!rawCategory.startsWith("@")) {
2958
2991
  return node.tagName === rawCategory;
2959
2992
  }
2960
2993
  /* if the meta entry is missing assume any content model would match */
@@ -2977,9 +3010,9 @@ class Validator {
2977
3010
  case "@interactive":
2978
3011
  return node.meta.interactive;
2979
3012
  case "@script":
2980
- return node.meta.scriptSupporting;
3013
+ return Boolean(node.meta.scriptSupporting);
2981
3014
  case "@form":
2982
- return node.meta.form;
3015
+ return Boolean(node.meta.form);
2983
3016
  default:
2984
3017
  throw new Error(`Invalid content category "${category}"`);
2985
3018
  }
@@ -3164,10 +3197,12 @@ var configurationSchema = {
3164
3197
  properties: properties
3165
3198
  };
3166
3199
 
3167
- var TRANSFORMER_API;
3168
- (function (TRANSFORMER_API) {
3169
- TRANSFORMER_API[TRANSFORMER_API["VERSION"] = 1] = "VERSION";
3170
- })(TRANSFORMER_API || (TRANSFORMER_API = {}));
3200
+ /**
3201
+ * @internal
3202
+ */
3203
+ const TRANSFORMER_API = {
3204
+ VERSION: 1,
3205
+ };
3171
3206
 
3172
3207
  /**
3173
3208
  * @public
@@ -3414,7 +3449,7 @@ function classifyNodeText(node, options = {}) {
3414
3449
  const { accessible = false, ignoreHiddenRoot = false } = options;
3415
3450
  const cacheKey = getCachekey(options);
3416
3451
  if (node.cacheExists(cacheKey)) {
3417
- return node.cacheGet(cacheKey);
3452
+ return node.cacheGet(cacheKey); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- has/get combo
3418
3453
  }
3419
3454
  if (!ignoreHiddenRoot && isHTMLHidden(node)) {
3420
3455
  return node.cacheSet(cacheKey, exports.TextClassification.EMPTY_TEXT);
@@ -3462,8 +3497,12 @@ function findTextNodes(node, options) {
3462
3497
 
3463
3498
  function hasAltText(image) {
3464
3499
  const alt = image.getAttribute("alt");
3465
- /* missing or boolean */
3466
- if (alt === null || alt.value === null) {
3500
+ /* missing attribute */
3501
+ if (!alt) {
3502
+ return false;
3503
+ }
3504
+ /* (incorrectly) set as boolean value */
3505
+ if (alt.value === null) {
3467
3506
  return false;
3468
3507
  }
3469
3508
  return alt.isDynamic || alt.value.toString() !== "";
@@ -3471,8 +3510,12 @@ function hasAltText(image) {
3471
3510
 
3472
3511
  function hasAriaLabel(node) {
3473
3512
  const label = node.getAttribute("aria-label");
3474
- /* missing or boolean */
3475
- if (label === null || label.value === null) {
3513
+ /* missing attribute */
3514
+ if (!label) {
3515
+ return false;
3516
+ }
3517
+ /* (incorrectly) set as boolean value */
3518
+ if (label.value === null) {
3476
3519
  return false;
3477
3520
  }
3478
3521
  return label.isDynamic || label.value.toString() !== "";
@@ -3553,7 +3596,7 @@ class Rule {
3553
3596
  this.options = options;
3554
3597
  this.enabled = true;
3555
3598
  this.blockers = [];
3556
- this.severity = 0;
3599
+ this.severity = exports.Severity.DISABLED;
3557
3600
  this.name = "";
3558
3601
  }
3559
3602
  getSeverity() {
@@ -3706,13 +3749,14 @@ class Rule {
3706
3749
  }
3707
3750
  }
3708
3751
  findLocation(src) {
3752
+ var _a, _b;
3709
3753
  if (src.location) {
3710
3754
  return src.location;
3711
3755
  }
3712
- if (src.event && src.event.location) {
3756
+ if ((_a = src.event) === null || _a === void 0 ? void 0 : _a.location) {
3713
3757
  return src.event.location;
3714
3758
  }
3715
- if (src.node && src.node.location) {
3759
+ if ((_b = src.node) === null || _b === void 0 ? void 0 : _b.location) {
3716
3760
  return src.node.location;
3717
3761
  }
3718
3762
  return {};
@@ -3809,7 +3853,7 @@ var Style$1;
3809
3853
  Style["ABSOLUTE"] = "absolute";
3810
3854
  Style["ANCHOR"] = "anchor";
3811
3855
  })(Style$1 || (Style$1 = {}));
3812
- const defaults$v = {
3856
+ const defaults$u = {
3813
3857
  allowExternal: true,
3814
3858
  allowRelative: true,
3815
3859
  allowAbsolute: true,
@@ -3853,7 +3897,7 @@ function matchList(value, list) {
3853
3897
  }
3854
3898
  class AllowedLinks extends Rule {
3855
3899
  constructor(options) {
3856
- super({ ...defaults$v, ...options });
3900
+ super({ ...defaults$u, ...options });
3857
3901
  this.allowExternal = parseAllow(this.options.allowExternal);
3858
3902
  this.allowRelative = parseAllow(this.options.allowRelative);
3859
3903
  this.allowAbsolute = parseAllow(this.options.allowAbsolute);
@@ -3885,7 +3929,8 @@ class AllowedLinks extends Rule {
3885
3929
  };
3886
3930
  }
3887
3931
  documentation(context) {
3888
- const message = description[context] || "This link type is not allowed by current configuration";
3932
+ var _a;
3933
+ const message = (_a = description[context]) !== null && _a !== void 0 ? _a : "This link type is not allowed by current configuration";
3889
3934
  return {
3890
3935
  description: message,
3891
3936
  url: "https://html-validate.org/rules/allowed-links.html",
@@ -4001,7 +4046,7 @@ var RuleContext$1;
4001
4046
  RuleContext["MISSING_ALT"] = "missing-alt";
4002
4047
  RuleContext["MISSING_HREF"] = "missing-href";
4003
4048
  })(RuleContext$1 || (RuleContext$1 = {}));
4004
- const defaults$u = {
4049
+ const defaults$t = {
4005
4050
  accessible: true,
4006
4051
  };
4007
4052
  function findByTarget(target, siblings) {
@@ -4027,19 +4072,11 @@ function getDescription$1(context) {
4027
4072
  "",
4028
4073
  "Either add the `href` attribute or remove the `alt` attribute.",
4029
4074
  ];
4030
- default:
4031
- return [
4032
- "The `alt` attribute must only be used together with the `href` attribute.",
4033
- "It must be set if `href` is present and must be omitted if `href` is missing",
4034
- "",
4035
- "The attribute is used to provide an alternative text description for the area of the image map.",
4036
- "The text should describe the purpose of area and the resource referenced by the `href` attribute.",
4037
- ];
4038
4075
  }
4039
4076
  }
4040
4077
  class AreaAlt extends Rule {
4041
4078
  constructor(options) {
4042
- super({ ...defaults$u, ...options });
4079
+ super({ ...defaults$t, ...options });
4043
4080
  }
4044
4081
  static schema() {
4045
4082
  return {
@@ -4157,7 +4194,7 @@ function isValidUsage(target, meta) {
4157
4194
  return true;
4158
4195
  }
4159
4196
  /* interactive and labelable elements are valid */
4160
- if (meta.interactive || meta.labelable) {
4197
+ if (Boolean(meta.interactive) || Boolean(meta.labelable)) {
4161
4198
  return true;
4162
4199
  }
4163
4200
  return false;
@@ -4192,7 +4229,7 @@ class AriaLabelMisuse extends Rule {
4192
4229
  }
4193
4230
  validateElement(target) {
4194
4231
  const attr = target.getAttribute("aria-label");
4195
- if (!attr || !attr.value || attr.valueMatches("", false)) {
4232
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value) || attr.valueMatches("", false)) {
4196
4233
  return;
4197
4234
  }
4198
4235
  /* ignore elements without meta */
@@ -4273,13 +4310,13 @@ class CaseStyle {
4273
4310
  }
4274
4311
  }
4275
4312
 
4276
- const defaults$t = {
4313
+ const defaults$s = {
4277
4314
  style: "lowercase",
4278
4315
  ignoreForeign: true,
4279
4316
  };
4280
4317
  class AttrCase extends Rule {
4281
4318
  constructor(options) {
4282
- super({ ...defaults$t, ...options });
4319
+ super({ ...defaults$s, ...options });
4283
4320
  this.style = new CaseStyle(this.options.style, "attr-case");
4284
4321
  }
4285
4322
  static schema() {
@@ -4505,7 +4542,7 @@ class Lexer {
4505
4542
  */
4506
4543
  enter(context, state, data) {
4507
4544
  /* script/style tags require a different content model */
4508
- if (state === State.TAG && data && data[0][0] === "<") {
4545
+ if (state === State.TAG && data && data[0].startsWith("<")) {
4509
4546
  if (data[0] === "<script") {
4510
4547
  context.contentModel = ContentModel.SCRIPT;
4511
4548
  }
@@ -4543,14 +4580,14 @@ class Lexer {
4543
4580
  case ContentModel.TEXT:
4544
4581
  return State.TEXT;
4545
4582
  case ContentModel.SCRIPT:
4546
- if (tagCloseToken && tagCloseToken.data[0][0] !== "/") {
4583
+ if (tagCloseToken && !tagCloseToken.data[0].startsWith("/")) {
4547
4584
  return State.SCRIPT;
4548
4585
  }
4549
4586
  else {
4550
4587
  return State.TEXT; /* <script/> (not legal but handle it anyway so the lexer doesn't choke on it) */
4551
4588
  }
4552
4589
  case ContentModel.STYLE:
4553
- if (tagCloseToken && tagCloseToken.data[0][0] !== "/") {
4590
+ if (tagCloseToken && !tagCloseToken.data[0].startsWith("/")) {
4554
4591
  return State.STYLE;
4555
4592
  }
4556
4593
  else {
@@ -4627,7 +4664,7 @@ class AttrDelimiter extends Rule {
4627
4664
  }
4628
4665
 
4629
4666
  const DEFAULT_PATTERN = "[a-z0-9-:]+";
4630
- const defaults$s = {
4667
+ const defaults$r = {
4631
4668
  pattern: DEFAULT_PATTERN,
4632
4669
  ignoreForeign: true,
4633
4670
  };
@@ -4664,7 +4701,7 @@ function generateDescription(name, pattern) {
4664
4701
  }
4665
4702
  class AttrPattern extends Rule {
4666
4703
  constructor(options) {
4667
- super({ ...defaults$s, ...options });
4704
+ super({ ...defaults$r, ...options });
4668
4705
  this.pattern = generateRegexp(this.options.pattern);
4669
4706
  }
4670
4707
  static schema() {
@@ -4725,7 +4762,7 @@ var QuoteStyle;
4725
4762
  QuoteStyle["AUTO_QUOTE"] = "auto";
4726
4763
  QuoteStyle["ANY_QUOTE"] = "any";
4727
4764
  })(QuoteStyle || (QuoteStyle = {}));
4728
- const defaults$r = {
4765
+ const defaults$q = {
4729
4766
  style: "auto",
4730
4767
  unquoted: false,
4731
4768
  };
@@ -4792,7 +4829,7 @@ class AttrQuotes extends Rule {
4792
4829
  };
4793
4830
  }
4794
4831
  constructor(options) {
4795
- super({ ...defaults$r, ...options });
4832
+ super({ ...defaults$q, ...options });
4796
4833
  this.style = parseStyle$3(this.options.style);
4797
4834
  }
4798
4835
  setup() {
@@ -4802,7 +4839,7 @@ class AttrQuotes extends Rule {
4802
4839
  return;
4803
4840
  }
4804
4841
  if (!event.quote) {
4805
- if (this.options.unquoted === false) {
4842
+ if (!this.options.unquoted) {
4806
4843
  const message = `Attribute "${event.key}" using unquoted value`;
4807
4844
  const context = {
4808
4845
  error: "unquoted",
@@ -4923,7 +4960,7 @@ class AttributeAllowedValues extends Rule {
4923
4960
  const meta = node.meta;
4924
4961
  /* ignore rule if element has no meta or meta does not specify attribute
4925
4962
  * allowed values */
4926
- if (!meta || !meta.attributes)
4963
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
4927
4964
  return;
4928
4965
  for (const attr of node.attributes) {
4929
4966
  if (Validator.validateAttribute(attr, meta.attributes)) {
@@ -4962,12 +4999,12 @@ class AttributeAllowedValues extends Rule {
4962
4999
  }
4963
5000
  }
4964
5001
 
4965
- const defaults$q = {
5002
+ const defaults$p = {
4966
5003
  style: "omit",
4967
5004
  };
4968
5005
  class AttributeBooleanStyle extends Rule {
4969
5006
  constructor(options) {
4970
- super({ ...defaults$q, ...options });
5007
+ super({ ...defaults$p, ...options });
4971
5008
  this.hasInvalidStyle = parseStyle$2(this.options.style);
4972
5009
  }
4973
5010
  static schema() {
@@ -4991,7 +5028,7 @@ class AttributeBooleanStyle extends Rule {
4991
5028
  const meta = node.meta;
4992
5029
  /* ignore rule if element has no meta or meta does not specify attribute
4993
5030
  * allowed values */
4994
- if (!meta || !meta.attributes)
5031
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
4995
5032
  return;
4996
5033
  /* check all boolean attributes */
4997
5034
  for (const attr of node.attributes) {
@@ -5043,12 +5080,12 @@ function reportMessage$1(attr, style) {
5043
5080
  return "";
5044
5081
  }
5045
5082
 
5046
- const defaults$p = {
5083
+ const defaults$o = {
5047
5084
  style: "omit",
5048
5085
  };
5049
5086
  class AttributeEmptyStyle extends Rule {
5050
5087
  constructor(options) {
5051
- super({ ...defaults$p, ...options });
5088
+ super({ ...defaults$o, ...options });
5052
5089
  this.hasInvalidStyle = parseStyle$1(this.options.style);
5053
5090
  }
5054
5091
  static schema() {
@@ -5072,7 +5109,7 @@ class AttributeEmptyStyle extends Rule {
5072
5109
  const meta = node.meta;
5073
5110
  /* ignore rule if element has no meta or meta does not specify attribute
5074
5111
  * allowed values */
5075
- if (!meta || !meta.attributes)
5112
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
5076
5113
  return;
5077
5114
  /* check all boolean attributes */
5078
5115
  for (const attr of node.attributes) {
@@ -5160,10 +5197,10 @@ class AttributeMisuse extends Rule {
5160
5197
  });
5161
5198
  }
5162
5199
  validateAttr(node, attr, meta) {
5163
- if (!meta || !meta.allowed) {
5200
+ if (!(meta === null || meta === void 0 ? void 0 : meta.allowed)) {
5164
5201
  return;
5165
5202
  }
5166
- const details = meta.allowed(node, attr);
5203
+ const details = meta.allowed(node._adapter, attr.value);
5167
5204
  if (details) {
5168
5205
  this.report({
5169
5206
  node,
@@ -5204,12 +5241,12 @@ function describePattern(pattern) {
5204
5241
  }
5205
5242
  }
5206
5243
 
5207
- const defaults$o = {
5244
+ const defaults$n = {
5208
5245
  pattern: "kebabcase",
5209
5246
  };
5210
5247
  class ClassPattern extends Rule {
5211
5248
  constructor(options) {
5212
- super({ ...defaults$o, ...options });
5249
+ super({ ...defaults$n, ...options });
5213
5250
  this.pattern = parsePattern(this.options.pattern);
5214
5251
  }
5215
5252
  static schema() {
@@ -5318,13 +5355,13 @@ class CloseOrder extends Rule {
5318
5355
  }
5319
5356
  }
5320
5357
 
5321
- const defaults$n = {
5358
+ const defaults$m = {
5322
5359
  include: null,
5323
5360
  exclude: null,
5324
5361
  };
5325
5362
  class Deprecated extends Rule {
5326
5363
  constructor(options) {
5327
- super({ ...defaults$n, ...options });
5364
+ super({ ...defaults$m, ...options });
5328
5365
  }
5329
5366
  static schema() {
5330
5367
  return {
@@ -5487,12 +5524,12 @@ let NoStyleTag$1 = class NoStyleTag extends Rule {
5487
5524
  }
5488
5525
  };
5489
5526
 
5490
- const defaults$m = {
5527
+ const defaults$l = {
5491
5528
  style: "uppercase",
5492
5529
  };
5493
5530
  class DoctypeStyle extends Rule {
5494
5531
  constructor(options) {
5495
- super({ ...defaults$m, ...options });
5532
+ super({ ...defaults$l, ...options });
5496
5533
  }
5497
5534
  static schema() {
5498
5535
  return {
@@ -5524,12 +5561,12 @@ class DoctypeStyle extends Rule {
5524
5561
  }
5525
5562
  }
5526
5563
 
5527
- const defaults$l = {
5564
+ const defaults$k = {
5528
5565
  style: "lowercase",
5529
5566
  };
5530
5567
  class ElementCase extends Rule {
5531
5568
  constructor(options) {
5532
- super({ ...defaults$l, ...options });
5569
+ super({ ...defaults$k, ...options });
5533
5570
  this.style = new CaseStyle(this.options.style, "element-case");
5534
5571
  }
5535
5572
  static schema() {
@@ -5595,14 +5632,14 @@ class ElementCase extends Rule {
5595
5632
  }
5596
5633
  }
5597
5634
 
5598
- const defaults$k = {
5635
+ const defaults$j = {
5599
5636
  pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
5600
5637
  whitelist: [],
5601
5638
  blacklist: [],
5602
5639
  };
5603
5640
  class ElementName extends Rule {
5604
5641
  constructor(options) {
5605
- super({ ...defaults$k, ...options });
5642
+ super({ ...defaults$j, ...options });
5606
5643
  /* eslint-disable-next-line security/detect-non-literal-regexp -- expected to be a regexp */
5607
5644
  this.pattern = new RegExp(this.options.pattern);
5608
5645
  }
@@ -5643,7 +5680,7 @@ class ElementName extends Rule {
5643
5680
  ...context.blacklist.map((cur) => `- ${cur}`),
5644
5681
  ];
5645
5682
  }
5646
- if (context.pattern !== defaults$k.pattern) {
5683
+ if (context.pattern !== defaults$j.pattern) {
5647
5684
  return [
5648
5685
  `<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
5649
5686
  "",
@@ -5834,7 +5871,7 @@ class ElementPermittedOccurrences extends Rule {
5834
5871
  this.on("dom:ready", (event) => {
5835
5872
  const doc = event.document;
5836
5873
  doc.visitDepthFirst((node) => {
5837
- if (!node || !node.meta) {
5874
+ if (!(node === null || node === void 0 ? void 0 : node.meta)) {
5838
5875
  return;
5839
5876
  }
5840
5877
  const rules = node.meta.permittedContent;
@@ -5879,7 +5916,7 @@ function isCategoryOrTag(value) {
5879
5916
  return typeof value === "string";
5880
5917
  }
5881
5918
  function isCategory$1(value) {
5882
- return value[0] === "@";
5919
+ return value.startsWith("@");
5883
5920
  }
5884
5921
  function formatCategoryOrTag(value) {
5885
5922
  return isCategory$1(value) ? value.slice(1) : `<${value}>`;
@@ -6039,7 +6076,7 @@ class ElementRequiredAttributes extends Rule {
6039
6076
  const node = event.previous;
6040
6077
  const meta = node.meta;
6041
6078
  /* handle missing metadata and missing attributes */
6042
- if (!meta || !meta.attributes) {
6079
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes)) {
6043
6080
  return;
6044
6081
  }
6045
6082
  for (const [key, attr] of Object.entries(meta.attributes)) {
@@ -6059,7 +6096,7 @@ class ElementRequiredAttributes extends Rule {
6059
6096
  }
6060
6097
 
6061
6098
  function isCategory(value) {
6062
- return value[0] === "@";
6099
+ return value.startsWith("@");
6063
6100
  }
6064
6101
  class ElementRequiredContent extends Rule {
6065
6102
  documentation(context) {
@@ -6187,7 +6224,7 @@ class EmptyTitle extends Rule {
6187
6224
  }
6188
6225
  }
6189
6226
 
6190
- const defaults$j = {
6227
+ const defaults$i = {
6191
6228
  allowArrayBrackets: true,
6192
6229
  shared: ["radio", "button", "reset", "submit"],
6193
6230
  };
@@ -6220,7 +6257,7 @@ function getDocumentation(context) {
6220
6257
  }
6221
6258
  class FormDupName extends Rule {
6222
6259
  constructor(options) {
6223
- super({ ...defaults$j, ...options });
6260
+ super({ ...defaults$i, ...options });
6224
6261
  }
6225
6262
  static schema() {
6226
6263
  return {
@@ -6351,7 +6388,7 @@ class FormDupName extends Rule {
6351
6388
  const meta = this.getMetaFor(tagName);
6352
6389
  /* istanbul ignore if: the earlier check for getTagsWithProperty ensures
6353
6390
  * these will actually be set so this is just an untestable fallback */
6354
- if (!meta || !meta.formAssociated) {
6391
+ if (!(meta === null || meta === void 0 ? void 0 : meta.formAssociated)) {
6355
6392
  return false;
6356
6393
  }
6357
6394
  return meta.formAssociated.listed;
@@ -6380,7 +6417,7 @@ class FormDupName extends Rule {
6380
6417
  }
6381
6418
  }
6382
6419
 
6383
- const defaults$i = {
6420
+ const defaults$h = {
6384
6421
  allowMultipleH1: false,
6385
6422
  minInitialRank: "h1",
6386
6423
  sectioningRoots: ["dialog", '[role="dialog"]', '[role="alertdialog"]'],
@@ -6411,7 +6448,7 @@ function parseMaxInitial(value) {
6411
6448
  }
6412
6449
  class HeadingLevel extends Rule {
6413
6450
  constructor(options) {
6414
- super({ ...defaults$i, ...options });
6451
+ super({ ...defaults$h, ...options });
6415
6452
  this.stack = [];
6416
6453
  this.minInitialRank = parseMaxInitial(this.options.minInitialRank);
6417
6454
  this.sectionRoots = this.options.sectioningRoots.map((it) => new Pattern(it));
@@ -6453,9 +6490,15 @@ class HeadingLevel extends Rule {
6453
6490
  };
6454
6491
  }
6455
6492
  setup() {
6456
- this.on("tag:start", isRelevant$3, (event) => this.onTagStart(event));
6457
- this.on("tag:ready", (event) => this.onTagReady(event));
6458
- this.on("tag:close", (event) => this.onTagClose(event));
6493
+ this.on("tag:start", isRelevant$3, (event) => {
6494
+ this.onTagStart(event);
6495
+ });
6496
+ this.on("tag:ready", (event) => {
6497
+ this.onTagReady(event);
6498
+ });
6499
+ this.on("tag:close", (event) => {
6500
+ this.onTagClose(event);
6501
+ });
6459
6502
  }
6460
6503
  onTagStart(event) {
6461
6504
  /* extract heading level from tagName (e.g "h1" -> 1)*/
@@ -6569,12 +6612,12 @@ class HeadingLevel extends Rule {
6569
6612
  }
6570
6613
  }
6571
6614
 
6572
- const defaults$h = {
6615
+ const defaults$g = {
6573
6616
  pattern: "kebabcase",
6574
6617
  };
6575
6618
  class IdPattern extends Rule {
6576
6619
  constructor(options) {
6577
- super({ ...defaults$h, ...options });
6620
+ super({ ...defaults$g, ...options });
6578
6621
  this.pattern = parsePattern(this.options.pattern);
6579
6622
  }
6580
6623
  static schema() {
@@ -6593,7 +6636,7 @@ class IdPattern extends Rule {
6593
6636
  }
6594
6637
  setup() {
6595
6638
  this.on("attr", (event) => {
6596
- var _a;
6639
+ var _a, _b;
6597
6640
  if (event.key.toLowerCase() !== "id") {
6598
6641
  return;
6599
6642
  }
@@ -6601,8 +6644,8 @@ class IdPattern extends Rule {
6601
6644
  if (event.value instanceof DynamicValue) {
6602
6645
  return;
6603
6646
  }
6604
- if (!event.value || !event.value.match(this.pattern)) {
6605
- const value = (_a = event.value) !== null && _a !== void 0 ? _a : "";
6647
+ if (!((_a = event.value) === null || _a === void 0 ? void 0 : _a.match(this.pattern))) {
6648
+ const value = (_b = event.value) !== null && _b !== void 0 ? _b : "";
6606
6649
  const pattern = this.pattern.toString();
6607
6650
  const message = `ID "${value}" does not match required pattern "${pattern}"`;
6608
6651
  this.report(event.target, message, event.valueLocation);
@@ -6976,12 +7019,12 @@ function findLabelByParent(el) {
6976
7019
  return [];
6977
7020
  }
6978
7021
 
6979
- const defaults$g = {
7022
+ const defaults$f = {
6980
7023
  maxlength: 70,
6981
7024
  };
6982
7025
  class LongTitle extends Rule {
6983
7026
  constructor(options) {
6984
- super({ ...defaults$g, ...options });
7027
+ super({ ...defaults$f, ...options });
6985
7028
  this.maxlength = this.options.maxlength;
6986
7029
  }
6987
7030
  static schema() {
@@ -7030,7 +7073,7 @@ class MetaRefresh extends Rule {
7030
7073
  }
7031
7074
  /* ensure content attribute is set */
7032
7075
  const content = target.getAttribute("content");
7033
- if (!content || !content.value || content.isDynamic) {
7076
+ if (!(content === null || content === void 0 ? void 0 : content.value) || content.isDynamic) {
7034
7077
  return;
7035
7078
  }
7036
7079
  /* ensure content attribute is valid */
@@ -7207,13 +7250,13 @@ class MultipleLabeledControls extends Rule {
7207
7250
  }
7208
7251
  }
7209
7252
 
7210
- const defaults$f = {
7253
+ const defaults$e = {
7211
7254
  include: null,
7212
7255
  exclude: null,
7213
7256
  };
7214
7257
  class NoAutoplay extends Rule {
7215
7258
  constructor(options) {
7216
- super({ ...defaults$f, ...options });
7259
+ super({ ...defaults$e, ...options });
7217
7260
  }
7218
7261
  documentation(context) {
7219
7262
  const tagName = context ? ` on <${context.tagName}>` : "";
@@ -7309,7 +7352,7 @@ class NoDeprecatedAttr extends Rule {
7309
7352
  if (meta === null) {
7310
7353
  return;
7311
7354
  }
7312
- const metaAttribute = meta.attributes && meta.attributes[attr];
7355
+ const metaAttribute = meta.attributes[attr];
7313
7356
  if (!metaAttribute) {
7314
7357
  return;
7315
7358
  }
@@ -7389,7 +7432,7 @@ class NoDupID extends Rule {
7389
7432
  for (const el of relevant) {
7390
7433
  const attr = el.getAttribute("id");
7391
7434
  /* istanbul ignore next: this has already been tested in isRelevant once but for type-safety it is checked again */
7392
- if (!attr || !attr.value) {
7435
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value)) {
7393
7436
  continue;
7394
7437
  }
7395
7438
  const id = attr.value.toString();
@@ -7454,14 +7497,14 @@ Omitted end tags can be ambigious for humans to read and many editors have troub
7454
7497
  }
7455
7498
  }
7456
7499
 
7457
- const defaults$e = {
7500
+ const defaults$d = {
7458
7501
  include: null,
7459
7502
  exclude: null,
7460
7503
  allowedProperties: ["display"],
7461
7504
  };
7462
7505
  class NoInlineStyle extends Rule {
7463
7506
  constructor(options) {
7464
- super({ ...defaults$e, ...options });
7507
+ super({ ...defaults$d, ...options });
7465
7508
  }
7466
7509
  static schema() {
7467
7510
  return {
@@ -7523,11 +7566,12 @@ class NoInlineStyle extends Rule {
7523
7566
  });
7524
7567
  }
7525
7568
  isRelevant(event) {
7569
+ var _a;
7526
7570
  if (event.key !== "style") {
7527
7571
  return false;
7528
7572
  }
7529
7573
  const { include, exclude } = this.options;
7530
- const key = event.originalAttribute || event.key;
7574
+ const key = (_a = event.originalAttribute) !== null && _a !== void 0 ? _a : event.key;
7531
7575
  /* ignore attributes not present in "include" */
7532
7576
  if (include && !include.includes(key)) {
7533
7577
  return false;
@@ -7663,7 +7707,7 @@ class NoMultipleMain extends Rule {
7663
7707
  }
7664
7708
  }
7665
7709
 
7666
- const defaults$d = {
7710
+ const defaults$c = {
7667
7711
  relaxed: false,
7668
7712
  };
7669
7713
  const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
@@ -7680,7 +7724,7 @@ const replacementTable = {
7680
7724
  };
7681
7725
  class NoRawCharacters extends Rule {
7682
7726
  constructor(options) {
7683
- super({ ...defaults$d, ...options });
7727
+ super({ ...defaults$c, ...options });
7684
7728
  this.relaxed = this.options.relaxed;
7685
7729
  }
7686
7730
  static schema() {
@@ -7721,7 +7765,8 @@ class NoRawCharacters extends Rule {
7721
7765
  if (event.quote) {
7722
7766
  return;
7723
7767
  }
7724
- this.findRawChars(event.target, event.value.toString(), event.valueLocation, unquotedAttrRegexp);
7768
+ 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
7769
+ unquotedAttrRegexp);
7725
7770
  });
7726
7771
  }
7727
7772
  /**
@@ -7754,6 +7799,39 @@ class NoRawCharacters extends Rule {
7754
7799
  }
7755
7800
  }
7756
7801
 
7802
+ const selectors = ["input[aria-label]", "textarea[aria-label]", "select[aria-label]"];
7803
+ class NoRedundantAriaLabel extends Rule {
7804
+ documentation() {
7805
+ return {
7806
+ description: "`aria-label` is redundant when an associated `<label>` element containing the same text exists.",
7807
+ url: "https://html-validate.org/rules/no-redundant-aria-label.html",
7808
+ };
7809
+ }
7810
+ setup() {
7811
+ this.on("dom:ready", (event) => {
7812
+ const { document } = event;
7813
+ const elements = document.querySelectorAll(selectors.join(","));
7814
+ for (const element of elements) {
7815
+ const ariaLabel = element.getAttribute("aria-label");
7816
+ const id = element.id;
7817
+ if (!id) {
7818
+ continue;
7819
+ }
7820
+ const label = document.querySelector(`label[for="${id}"]`);
7821
+ if (!ariaLabel || !label || label.textContent.trim() !== ariaLabel.value) {
7822
+ continue;
7823
+ }
7824
+ const message = "aria-label is redundant when label containing same text exists";
7825
+ this.report({
7826
+ message,
7827
+ node: element,
7828
+ location: ariaLabel.keyLocation,
7829
+ });
7830
+ }
7831
+ });
7832
+ }
7833
+ }
7834
+
7757
7835
  class NoRedundantFor extends Rule {
7758
7836
  documentation() {
7759
7837
  return {
@@ -7858,13 +7936,13 @@ class NoRedundantRole extends Rule {
7858
7936
  }
7859
7937
 
7860
7938
  const xmlns = /^(.+):.+$/;
7861
- const defaults$c = {
7939
+ const defaults$b = {
7862
7940
  ignoreForeign: true,
7863
7941
  ignoreXML: true,
7864
7942
  };
7865
7943
  class NoSelfClosing extends Rule {
7866
7944
  constructor(options) {
7867
- super({ ...defaults$c, ...options });
7945
+ super({ ...defaults$b, ...options });
7868
7946
  }
7869
7947
  static schema() {
7870
7948
  return {
@@ -7902,7 +7980,7 @@ class NoSelfClosing extends Rule {
7902
7980
  function isRelevant(node, options) {
7903
7981
  /* tags in XML namespaces are relevant only if ignoreXml is false, in which
7904
7982
  * case assume all xml elements must not be self-closed */
7905
- if (node.tagName && node.tagName.match(xmlns)) {
7983
+ if (node.tagName.match(xmlns)) {
7906
7984
  return !options.ignoreXML;
7907
7985
  }
7908
7986
  /* nodes with missing metadata is assumed relevant */
@@ -7953,13 +8031,13 @@ class NoTrailingWhitespace extends Rule {
7953
8031
  }
7954
8032
  }
7955
8033
 
7956
- const defaults$b = {
8034
+ const defaults$a = {
7957
8035
  include: null,
7958
8036
  exclude: null,
7959
8037
  };
7960
8038
  class NoUnknownElements extends Rule {
7961
8039
  constructor(options) {
7962
- super({ ...defaults$b, ...options });
8040
+ super({ ...defaults$a, ...options });
7963
8041
  }
7964
8042
  static schema() {
7965
8043
  return {
@@ -8015,9 +8093,7 @@ class NoUnknownElements extends Rule {
8015
8093
  class NoUnusedDisable extends Rule {
8016
8094
  documentation(context) {
8017
8095
  return {
8018
- description: context
8019
- ? `\`${context.ruleId}\` rule is disabled but no error was reported.`
8020
- : "Rule is disabled but no error was reported.",
8096
+ description: `\`${context.ruleId}\` rule is disabled but no error was reported.`,
8021
8097
  url: "https://html-validate.org/rules/no-unused-disable.html",
8022
8098
  };
8023
8099
  }
@@ -8071,13 +8147,13 @@ const replacement = {
8071
8147
  reset: '<button type="reset">',
8072
8148
  image: '<button type="button">',
8073
8149
  };
8074
- const defaults$a = {
8150
+ const defaults$9 = {
8075
8151
  include: null,
8076
8152
  exclude: null,
8077
8153
  };
8078
8154
  class PreferButton extends Rule {
8079
8155
  constructor(options) {
8080
- super({ ...defaults$a, ...options });
8156
+ super({ ...defaults$9, ...options });
8081
8157
  }
8082
8158
  static schema() {
8083
8159
  return {
@@ -8110,16 +8186,12 @@ class PreferButton extends Rule {
8110
8186
  };
8111
8187
  }
8112
8188
  documentation(context) {
8113
- const doc = {
8114
- description: `Prefer to use the generic \`<button>\` element instead of \`<input>\`.`,
8189
+ const src = `<input type="${context.type}">`;
8190
+ const dst = replacement[context.type] || `<button>`;
8191
+ return {
8192
+ description: `Prefer to use \`${dst}\` instead of \`"${src}\`.`,
8115
8193
  url: "https://html-validate.org/rules/prefer-button.html",
8116
8194
  };
8117
- if (context) {
8118
- const src = `<input type="${context.type}">`;
8119
- const dst = replacement[context.type] || `<button>`;
8120
- doc.description = `Prefer to use \`${dst}\` instead of \`"${src}\`.`;
8121
- }
8122
- return doc;
8123
8195
  }
8124
8196
  setup() {
8125
8197
  this.on("attr", (event) => {
@@ -8152,7 +8224,7 @@ class PreferButton extends Rule {
8152
8224
  }
8153
8225
  }
8154
8226
 
8155
- const defaults$9 = {
8227
+ const defaults$8 = {
8156
8228
  mapping: {
8157
8229
  article: "article",
8158
8230
  banner: "header",
@@ -8182,7 +8254,7 @@ const defaults$9 = {
8182
8254
  };
8183
8255
  class PreferNativeElement extends Rule {
8184
8256
  constructor(options) {
8185
- super({ ...defaults$9, ...options });
8257
+ super({ ...defaults$8, ...options });
8186
8258
  }
8187
8259
  static schema() {
8188
8260
  return {
@@ -8218,14 +8290,10 @@ class PreferNativeElement extends Rule {
8218
8290
  };
8219
8291
  }
8220
8292
  documentation(context) {
8221
- const doc = {
8222
- description: `Instead of using WAI-ARIA roles prefer to use the native HTML elements.`,
8293
+ return {
8294
+ description: `Instead of using the WAI-ARIA role "${context.role}" prefer to use the native <${context.replacement}> element.`,
8223
8295
  url: "https://html-validate.org/rules/prefer-native-element.html",
8224
8296
  };
8225
- if (context) {
8226
- doc.description = `Instead of using the WAI-ARIA role "${context.role}" prefer to use the native <${context.replacement}> element.`;
8227
- }
8228
- return doc;
8229
8297
  }
8230
8298
  setup() {
8231
8299
  const { mapping } = this.options;
@@ -8266,7 +8334,7 @@ class PreferNativeElement extends Rule {
8266
8334
  }
8267
8335
  getLocation(event) {
8268
8336
  const begin = event.location;
8269
- const end = event.valueLocation;
8337
+ 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
8270
8338
  const quote = event.quote ? 1 : 0;
8271
8339
  const size = end.offset + end.size - begin.offset + quote;
8272
8340
  return {
@@ -8302,12 +8370,12 @@ class PreferTbody extends Rule {
8302
8370
  }
8303
8371
  }
8304
8372
 
8305
- const defaults$8 = {
8373
+ const defaults$7 = {
8306
8374
  tags: ["script", "style"],
8307
8375
  };
8308
8376
  class RequireCSPNonce extends Rule {
8309
8377
  constructor(options) {
8310
- super({ ...defaults$8, ...options });
8378
+ super({ ...defaults$7, ...options });
8311
8379
  }
8312
8380
  static schema() {
8313
8381
  return {
@@ -8340,7 +8408,7 @@ class RequireCSPNonce extends Rule {
8340
8408
  const { tags } = this.options;
8341
8409
  const node = event.previous;
8342
8410
  /* ignore other tags */
8343
- if (!node || !tags.includes(node.tagName)) {
8411
+ if (!tags.includes(node.tagName)) {
8344
8412
  return;
8345
8413
  }
8346
8414
  /* ignore if nonce is set to non-empty value (or dynamic) */
@@ -8358,7 +8426,7 @@ class RequireCSPNonce extends Rule {
8358
8426
  }
8359
8427
  }
8360
8428
 
8361
- const defaults$7 = {
8429
+ const defaults$6 = {
8362
8430
  target: "all",
8363
8431
  include: null,
8364
8432
  exclude: null,
@@ -8370,7 +8438,7 @@ const supportSri = {
8370
8438
  };
8371
8439
  class RequireSri extends Rule {
8372
8440
  constructor(options) {
8373
- super({ ...defaults$7, ...options });
8441
+ super({ ...defaults$6, ...options });
8374
8442
  this.target = this.options.target;
8375
8443
  }
8376
8444
  static schema() {
@@ -8432,7 +8500,10 @@ class RequireSri extends Rule {
8432
8500
  }
8433
8501
  needSri(node) {
8434
8502
  const attr = this.elementSourceAttr(node);
8435
- if (!attr || attr.value === null || attr.value === "" || attr.isDynamic) {
8503
+ if (!attr) {
8504
+ return false;
8505
+ }
8506
+ if (attr.value === null || attr.value === "" || attr.isDynamic) {
8436
8507
  return false;
8437
8508
  }
8438
8509
  const url = attr.value.toString();
@@ -8489,7 +8560,7 @@ class ScriptType extends Rule {
8489
8560
  setup() {
8490
8561
  this.on("tag:end", (event) => {
8491
8562
  const node = event.previous;
8492
- if (!node || node.tagName !== "script") {
8563
+ if (node.tagName !== "script") {
8493
8564
  return;
8494
8565
  }
8495
8566
  const attr = node.getAttribute("type");
@@ -8532,7 +8603,7 @@ class SvgFocusable extends Rule {
8532
8603
  }
8533
8604
  }
8534
8605
 
8535
- const defaults$6 = {
8606
+ const defaults$5 = {
8536
8607
  characters: [
8537
8608
  { pattern: " ", replacement: "&nbsp;", description: "non-breaking space" },
8538
8609
  { pattern: "-", replacement: "&#8209;", description: "non-breaking hyphen" },
@@ -8571,7 +8642,7 @@ function matchAll(text, regexp) {
8571
8642
  }
8572
8643
  class TelNonBreaking extends Rule {
8573
8644
  constructor(options) {
8574
- super({ ...defaults$6, ...options });
8645
+ super({ ...defaults$5, ...options });
8575
8646
  this.regex = constructRegex(this.options.characters);
8576
8647
  }
8577
8648
  static schema() {
@@ -8612,9 +8683,7 @@ class TelNonBreaking extends Rule {
8612
8683
  });
8613
8684
  return {
8614
8685
  description: [
8615
- context
8616
- ? `The \`${context.pattern}\` character should be replaced with \`${context.replacement}\` character (${context.description}) when used in a telephone number.`
8617
- : `Replace this character with a non-breaking version.`,
8686
+ `The \`${context.pattern}\` character should be replaced with \`${context.replacement}\` character (${context.description}) when used in a telephone number.`,
8618
8687
  "",
8619
8688
  "Unless non-breaking characters is used there could be a line break inserted at that character.",
8620
8689
  "Line breaks make is harder to read and understand the telephone number.",
@@ -8772,18 +8841,16 @@ class TextContent extends Rule {
8772
8841
  description: `The textual content for this element is not valid.`,
8773
8842
  url: "https://html-validate.org/rules/text-content.html",
8774
8843
  };
8775
- if (context === null || context === void 0 ? void 0 : context.textContent) {
8776
- switch (context.textContent) {
8777
- case exports.TextContent.NONE:
8778
- doc.description = `The \`<${context.tagName}>\` element must not have textual content.`;
8779
- break;
8780
- case exports.TextContent.REQUIRED:
8781
- doc.description = `The \`<${context.tagName}>\` element must have textual content.`;
8782
- break;
8783
- case exports.TextContent.ACCESSIBLE:
8784
- doc.description = `The \`<${context.tagName}>\` element must have accessible text.`;
8785
- break;
8786
- }
8844
+ switch (context.textContent) {
8845
+ case exports.TextContent.NONE:
8846
+ doc.description = `The \`<${context.tagName}>\` element must not have textual content.`;
8847
+ break;
8848
+ case exports.TextContent.REQUIRED:
8849
+ doc.description = `The \`<${context.tagName}>\` element must have textual content.`;
8850
+ break;
8851
+ case exports.TextContent.ACCESSIBLE:
8852
+ doc.description = `The \`<${context.tagName}>\` element must have accessible text.`;
8853
+ break;
8787
8854
  }
8788
8855
  return doc;
8789
8856
  }
@@ -8859,7 +8926,7 @@ class TextContent extends Rule {
8859
8926
  }
8860
8927
  }
8861
8928
 
8862
- const defaults$5 = {
8929
+ const defaults$4 = {
8863
8930
  ignoreCase: false,
8864
8931
  requireSemicolon: true,
8865
8932
  };
@@ -8877,16 +8944,11 @@ function getLocation(location, entity, match) {
8877
8944
  function getDescription(context, options) {
8878
8945
  const url = "https://html.spec.whatwg.org/multipage/named-characters.html";
8879
8946
  let message;
8880
- if (context) {
8881
- if (context.terminated) {
8882
- message = `Unrecognized character reference \`${context.entity}\`.`;
8883
- }
8884
- else {
8885
- message = `Character reference \`${context.entity}\` must be terminated by a semicolon.`;
8886
- }
8947
+ if (context.terminated) {
8948
+ message = `Unrecognized character reference \`${context.entity}\`.`;
8887
8949
  }
8888
8950
  else {
8889
- message = `Unrecognized character reference.`;
8951
+ message = `Character reference \`${context.entity}\` must be terminated by a semicolon.`;
8890
8952
  }
8891
8953
  return [
8892
8954
  message,
@@ -8901,7 +8963,7 @@ function getDescription(context, options) {
8901
8963
  }
8902
8964
  class UnknownCharReference extends Rule {
8903
8965
  constructor(options) {
8904
- super({ ...defaults$5, ...options });
8966
+ super({ ...defaults$4, ...options });
8905
8967
  }
8906
8968
  static schema() {
8907
8969
  return {
@@ -9018,12 +9080,12 @@ var RuleContext;
9018
9080
  RuleContext[RuleContext["LEADING_CHARACTER"] = 3] = "LEADING_CHARACTER";
9019
9081
  RuleContext[RuleContext["DISALLOWED_CHARACTER"] = 4] = "DISALLOWED_CHARACTER";
9020
9082
  })(RuleContext || (RuleContext = {}));
9021
- const defaults$4 = {
9083
+ const defaults$3 = {
9022
9084
  relaxed: false,
9023
9085
  };
9024
9086
  class ValidID extends Rule {
9025
9087
  constructor(options) {
9026
- super({ ...defaults$4, ...options });
9088
+ super({ ...defaults$3, ...options });
9027
9089
  }
9028
9090
  static schema() {
9029
9091
  return {
@@ -9034,9 +9096,9 @@ class ValidID extends Rule {
9034
9096
  }
9035
9097
  documentation(context) {
9036
9098
  const { relaxed } = this.options;
9037
- const message = context
9038
- ? this.messages[context].replace("id", "ID").replace(/^(.)/, (m) => m.toUpperCase())
9039
- : "Element ID is not valid";
9099
+ const message = this.messages[context]
9100
+ .replace("id", "ID")
9101
+ .replace(/^(.)/, (m) => m.toUpperCase());
9040
9102
  const relaxedDescription = relaxed
9041
9103
  ? []
9042
9104
  : [
@@ -9132,12 +9194,12 @@ var Style;
9132
9194
  Style[Style["AlwaysOmit"] = 1] = "AlwaysOmit";
9133
9195
  Style[Style["AlwaysSelfclose"] = 2] = "AlwaysSelfclose";
9134
9196
  })(Style || (Style = {}));
9135
- const defaults$3 = {
9197
+ const defaults$2 = {
9136
9198
  style: "omit",
9137
9199
  };
9138
9200
  class VoidStyle extends Rule {
9139
9201
  constructor(options) {
9140
- super({ ...defaults$3, ...options });
9202
+ super({ ...defaults$2, ...options });
9141
9203
  this.style = parseStyle(this.options.style);
9142
9204
  }
9143
9205
  static schema() {
@@ -9149,20 +9211,16 @@ class VoidStyle extends Rule {
9149
9211
  };
9150
9212
  }
9151
9213
  documentation(context) {
9152
- const doc = {
9153
- description: "The current configuration requires a specific style for ending void elements.",
9214
+ const [desc, end] = styleDescription(context.style);
9215
+ return {
9216
+ description: `The current configuration requires void elements to ${desc}, use <${context.tagName}${end}> instead.`,
9154
9217
  url: "https://html-validate.org/rules/void-style.html",
9155
9218
  };
9156
- if (context) {
9157
- const [desc, end] = styleDescription(context.style);
9158
- doc.description = `The current configuration requires void elements to ${desc}, use <${context.tagName}${end}> instead.`;
9159
- }
9160
- return doc;
9161
9219
  }
9162
9220
  setup() {
9163
9221
  this.on("tag:end", (event) => {
9164
9222
  const active = event.previous; // The current active element (that is, the current element on the stack)
9165
- if (active && active.meta) {
9223
+ if (active.meta) {
9166
9224
  this.validateActive(active);
9167
9225
  }
9168
9226
  });
@@ -9334,7 +9392,7 @@ class H36 extends Rule {
9334
9392
  }
9335
9393
  }
9336
9394
 
9337
- const defaults$2 = {
9395
+ const defaults$1 = {
9338
9396
  allowEmpty: true,
9339
9397
  alias: [],
9340
9398
  };
@@ -9355,7 +9413,7 @@ function getTag(node) {
9355
9413
  }
9356
9414
  class H37 extends Rule {
9357
9415
  constructor(options) {
9358
- super({ ...defaults$2, ...options });
9416
+ super({ ...defaults$1, ...options });
9359
9417
  /* ensure alias is array */
9360
9418
  if (!Array.isArray(this.options.alias)) {
9361
9419
  this.options.alias = [this.options.alias];
@@ -9399,7 +9457,8 @@ class H37 extends Rule {
9399
9457
  return;
9400
9458
  }
9401
9459
  /* validate plain alt-attribute */
9402
- if (node.getAttributeValue("alt") || (node.hasAttribute("alt") && this.options.allowEmpty)) {
9460
+ if (Boolean(node.getAttributeValue("alt")) ||
9461
+ Boolean(node.hasAttribute("alt") && this.options.allowEmpty)) {
9403
9462
  return;
9404
9463
  }
9405
9464
  /* validate if any non-empty alias is present */
@@ -9581,6 +9640,7 @@ const bundledRules = {
9581
9640
  "no-missing-references": NoMissingReferences,
9582
9641
  "no-multiple-main": NoMultipleMain,
9583
9642
  "no-raw-characters": NoRawCharacters,
9643
+ "no-redundant-aria-label": NoRedundantAriaLabel,
9584
9644
  "no-redundant-for": NoRedundantFor,
9585
9645
  "no-redundant-role": NoRedundantRole,
9586
9646
  "no-self-closing": NoSelfClosing,
@@ -9621,6 +9681,7 @@ const config$4 = {
9621
9681
  "multiple-labeled-controls": "error",
9622
9682
  "no-autoplay": ["error", { include: ["audio", "video"] }],
9623
9683
  "no-dup-id": "error",
9684
+ "no-redundant-aria-label": "error",
9624
9685
  "no-redundant-for": "error",
9625
9686
  "no-redundant-role": "error",
9626
9687
  "prefer-native-element": "error",
@@ -9703,6 +9764,7 @@ const config$1 = {
9703
9764
  "no-inline-style": "error",
9704
9765
  "no-multiple-main": "error",
9705
9766
  "no-raw-characters": "error",
9767
+ "no-redundant-aria-label": "error",
9706
9768
  "no-redundant-for": "error",
9707
9769
  "no-redundant-role": "error",
9708
9770
  "no-self-closing": "error",
@@ -9829,7 +9891,7 @@ class ResolvedConfig {
9829
9891
  * @returns A list of transformed sources ready for validation.
9830
9892
  */
9831
9893
  transformSource(source, filename) {
9832
- const transformer = this.findTransformer(filename || source.filename);
9894
+ const transformer = this.findTransformer(filename !== null && filename !== void 0 ? filename : source.filename);
9833
9895
  const context = {
9834
9896
  hasChain: (filename) => {
9835
9897
  return !!this.findTransformer(filename);
@@ -9841,9 +9903,10 @@ class ResolvedConfig {
9841
9903
  if (transformer) {
9842
9904
  try {
9843
9905
  return Array.from(transformer.fn.call(context, source), (cur) => {
9906
+ var _a;
9844
9907
  /* keep track of which transformers that has been run on this source
9845
9908
  * by appending this entry to the transformedBy array */
9846
- cur.transformedBy = cur.transformedBy || [];
9909
+ (_a = cur.transformedBy) !== null && _a !== void 0 ? _a : (cur.transformedBy = []);
9847
9910
  cur.transformedBy.push(transformer.name);
9848
9911
  return cur;
9849
9912
  });
@@ -10015,7 +10078,7 @@ function mergeInternal(base, rhs) {
10015
10078
  }
10016
10079
  /* root property is merged with boolean "or" since it should always be truthy
10017
10080
  * if any config has it set. */
10018
- const root = base.root || rhs.root;
10081
+ const root = Boolean(base.root) || Boolean(rhs.root);
10019
10082
  if (root) {
10020
10083
  dst.root = root;
10021
10084
  }
@@ -10102,7 +10165,7 @@ class Config {
10102
10165
  * @internal
10103
10166
  */
10104
10167
  constructor(resolvers, options) {
10105
- var _a;
10168
+ var _a, _b;
10106
10169
  this.transformers = [];
10107
10170
  const initial = {
10108
10171
  extends: [],
@@ -10115,18 +10178,18 @@ class Config {
10115
10178
  this.initialized = false;
10116
10179
  this.resolvers = toArray(resolvers);
10117
10180
  /* load plugins */
10118
- this.plugins = this.loadPlugins(this.config.plugins || []);
10181
+ this.plugins = this.loadPlugins((_a = this.config.plugins) !== null && _a !== void 0 ? _a : []);
10119
10182
  this.configurations = this.loadConfigurations(this.plugins);
10120
10183
  this.extendMeta(this.plugins);
10121
10184
  /* process extended configs */
10122
- this.config = this.extendConfig((_a = this.config.extends) !== null && _a !== void 0 ? _a : []);
10185
+ this.config = this.extendConfig((_b = this.config.extends) !== null && _b !== void 0 ? _b : []);
10123
10186
  /* reset extends as we already processed them, this prevents the next config
10124
10187
  * from reapplying config from extended config as well as duplicate entries
10125
10188
  * when merging arrays */
10126
10189
  this.config.extends = [];
10127
10190
  /* rules explicitly set by passed options should have precedence over any
10128
10191
  * extended rules, not the other way around. */
10129
- if (options && options.rules) {
10192
+ if (options === null || options === void 0 ? void 0 : options.rules) {
10130
10193
  this.config = mergeInternal(this.config, { rules: options.rules });
10131
10194
  }
10132
10195
  }
@@ -10139,11 +10202,12 @@ class Config {
10139
10202
  * @public
10140
10203
  */
10141
10204
  init() {
10205
+ var _a;
10142
10206
  if (this.initialized) {
10143
10207
  return;
10144
10208
  }
10145
10209
  /* precompile transform patterns */
10146
- this.transformers = this.precompileTransformers(this.config.transform || {});
10210
+ this.transformers = this.precompileTransformers((_a = this.config.transform) !== null && _a !== void 0 ? _a : {});
10147
10211
  this.initialized = true;
10148
10212
  }
10149
10213
  /**
@@ -10167,11 +10231,10 @@ class Config {
10167
10231
  return this.config;
10168
10232
  }
10169
10233
  let base = {};
10170
- for (let i = 0; i < entries.length; i++) {
10171
- const entry = entries[i];
10234
+ for (const entry of entries) {
10172
10235
  let extended;
10173
10236
  if (this.configurations.has(entry)) {
10174
- extended = this.configurations.get(entry);
10237
+ extended = this.configurations.get(entry); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- map has/get combo
10175
10238
  }
10176
10239
  else {
10177
10240
  extended = Config.fromFile(this.resolvers, entry).config;
@@ -10186,12 +10249,13 @@ class Config {
10186
10249
  * @internal
10187
10250
  */
10188
10251
  getMetaTable() {
10252
+ var _a;
10189
10253
  /* use cached table if it exists */
10190
10254
  if (this.metaTable) {
10191
10255
  return this.metaTable;
10192
10256
  }
10193
10257
  const metaTable = new MetaTable();
10194
- const source = this.config.elements || ["html5"];
10258
+ const source = (_a = this.config.elements) !== null && _a !== void 0 ? _a : ["html5"];
10195
10259
  /* extend validation schema from plugins */
10196
10260
  for (const plugin of this.getPlugins()) {
10197
10261
  if (plugin.elementSchema) {
@@ -10289,6 +10353,7 @@ class Config {
10289
10353
  });
10290
10354
  }
10291
10355
  loadConfigurations(plugins) {
10356
+ var _a;
10292
10357
  const configs = new Map();
10293
10358
  /* builtin presets */
10294
10359
  for (const [name, config] of Object.entries(Presets)) {
@@ -10297,7 +10362,7 @@ class Config {
10297
10362
  }
10298
10363
  /* presets from plugins */
10299
10364
  for (const plugin of plugins) {
10300
- for (const [name, config] of Object.entries(plugin.configs || {})) {
10365
+ for (const [name, config] of Object.entries((_a = plugin.configs) !== null && _a !== void 0 ? _a : {})) {
10301
10366
  if (!config)
10302
10367
  continue;
10303
10368
  Config.validate(config, name);
@@ -10662,10 +10727,11 @@ class Parser {
10662
10727
  * stack when is allowed to omit.
10663
10728
  */
10664
10729
  closeOptional(token) {
10730
+ var _a;
10665
10731
  /* if the element doesn't have metadata it cannot have optional end
10666
10732
  * tags. Period. */
10667
10733
  const active = this.dom.getActive();
10668
- if (!(active.meta && active.meta.implicitClosed)) {
10734
+ if (!((_a = active.meta) === null || _a === void 0 ? void 0 : _a.implicitClosed)) {
10669
10735
  return false;
10670
10736
  }
10671
10737
  const tagName = token.data[2];
@@ -10817,9 +10883,10 @@ class Parser {
10817
10883
  }
10818
10884
  }
10819
10885
  processElement(node, source) {
10886
+ var _a;
10820
10887
  /* enable cache on node now that it is fully constructed */
10821
10888
  node.cacheEnable();
10822
- if (source.hooks && source.hooks.processElement) {
10889
+ if ((_a = source.hooks) === null || _a === void 0 ? void 0 : _a.processElement) {
10823
10890
  const processElement = source.hooks.processElement;
10824
10891
  const metaTable = this.metaTable;
10825
10892
  const context = {
@@ -10886,6 +10953,7 @@ class Parser {
10886
10953
  * @internal
10887
10954
  */
10888
10955
  consumeAttribute(source, node, token, next) {
10956
+ var _a;
10889
10957
  const keyLocation = this.getAttributeKeyLocation(token);
10890
10958
  const valueLocation = this.getAttributeValueLocation(next);
10891
10959
  const location = this.getAttributeLocation(token, next);
@@ -10904,7 +10972,7 @@ class Parser {
10904
10972
  * data right away but a transformer may override it to allow aliasing
10905
10973
  * attributes, e.g ng-attr-foo or v-bind:foo */
10906
10974
  let processAttribute = (attr) => [attr];
10907
- if (source.hooks && source.hooks.processAttribute) {
10975
+ if ((_a = source.hooks) === null || _a === void 0 ? void 0 : _a.processAttribute) {
10908
10976
  processAttribute = source.hooks.processAttribute;
10909
10977
  }
10910
10978
  /* handle deprecated callbacks */
@@ -11254,14 +11322,15 @@ class Reporter {
11254
11322
  const report = {
11255
11323
  valid: this.isValid(),
11256
11324
  results: Object.keys(this.result).map((filePath) => {
11325
+ var _a;
11257
11326
  const messages = Array.from(this.result[filePath], freeze).sort(messageSort);
11258
- const source = (sources || []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11327
+ const source = (sources !== null && sources !== void 0 ? sources : []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11259
11328
  return {
11260
11329
  filePath,
11261
11330
  messages,
11262
11331
  errorCount: countErrors(messages),
11263
11332
  warningCount: countWarnings(messages),
11264
- source: source ? source.originalData || source.data : null,
11333
+ source: source ? (_a = source.originalData) !== null && _a !== void 0 ? _a : source.data : null,
11265
11334
  };
11266
11335
  }),
11267
11336
  errorCount: 0,
@@ -11279,10 +11348,10 @@ class Reporter {
11279
11348
  }
11280
11349
  }
11281
11350
  function countErrors(messages) {
11282
- return messages.filter((m) => m.severity === exports.Severity.ERROR).length;
11351
+ return messages.filter((m) => m.severity === Number(exports.Severity.ERROR)).length;
11283
11352
  }
11284
11353
  function countWarnings(messages) {
11285
- return messages.filter((m) => m.severity === exports.Severity.WARN).length;
11354
+ return messages.filter((m) => m.severity === Number(exports.Severity.WARN)).length;
11286
11355
  }
11287
11356
  function sumErrors(results) {
11288
11357
  return results.reduce((sum, result) => {
@@ -11460,7 +11529,9 @@ class Engine {
11460
11529
  else {
11461
11530
  lines.push("(root)");
11462
11531
  }
11463
- node.childElements.forEach((child, index) => writeNode(child, level + 1, index));
11532
+ node.childElements.forEach((child, index) => {
11533
+ writeNode(child, level + 1, index);
11534
+ });
11464
11535
  }
11465
11536
  writeNode(document, 0, 0);
11466
11537
  return lines;
@@ -11625,9 +11696,10 @@ class Engine {
11625
11696
  * between rule name and its constructor.
11626
11697
  */
11627
11698
  initRules(config) {
11699
+ var _a;
11628
11700
  const availableRules = {};
11629
11701
  for (const plugin of config.getPlugins()) {
11630
- for (const [name, rule] of Object.entries(plugin.rules || {})) {
11702
+ for (const [name, rule] of Object.entries((_a = plugin.rules) !== null && _a !== void 0 ? _a : {})) {
11631
11703
  if (!rule)
11632
11704
  continue;
11633
11705
  availableRules[name] = rule;
@@ -11730,7 +11802,7 @@ class StaticConfigLoader extends ConfigLoader {
11730
11802
  }
11731
11803
  }
11732
11804
  getConfigFor(_handle, configOverride) {
11733
- const override = this.loadFromObject(configOverride || {});
11805
+ const override = this.loadFromObject(configOverride !== null && configOverride !== void 0 ? configOverride : {});
11734
11806
  if (override.isRootFound()) {
11735
11807
  override.init();
11736
11808
  return override.resolve();
@@ -11774,6 +11846,7 @@ class HtmlValidate {
11774
11846
  const [loader, config] = arg instanceof ConfigLoader ? [arg, undefined] : [undefined, arg];
11775
11847
  this.configLoader = loader !== null && loader !== void 0 ? loader : new StaticConfigLoader(config);
11776
11848
  }
11849
+ /* eslint-enable @typescript-eslint/unified-signatures */
11777
11850
  validateString(str, arg1, arg2, arg3) {
11778
11851
  const filename = typeof arg1 === "string" ? arg1 : "inline";
11779
11852
  const options = isConfigData(arg1) ? arg1 : isConfigData(arg2) ? arg2 : undefined;
@@ -11788,6 +11861,7 @@ class HtmlValidate {
11788
11861
  };
11789
11862
  return this.validateSource(source, options);
11790
11863
  }
11864
+ /* eslint-enable @typescript-eslint/unified-signatures */
11791
11865
  validateStringSync(str, arg1, arg2, arg3) {
11792
11866
  const filename = typeof arg1 === "string" ? arg1 : "inline";
11793
11867
  const options = isConfigData(arg1) ? arg1 : isConfigData(arg2) ? arg2 : undefined;
@@ -12059,7 +12133,7 @@ class HtmlValidate {
12059
12133
  * contextual details and suggestions.
12060
12134
  */
12061
12135
  async getRuleDocumentation(ruleId, config = null, context = null) {
12062
- const c = config || this.getConfigFor("inline");
12136
+ const c = config !== null && config !== void 0 ? config : this.getConfigFor("inline");
12063
12137
  const engine = new Engine(await c, Parser);
12064
12138
  return engine.getRuleDocumentation({ ruleId, context });
12065
12139
  }
@@ -12088,7 +12162,7 @@ class HtmlValidate {
12088
12162
  * contextual details and suggestions.
12089
12163
  */
12090
12164
  getRuleDocumentationSync(ruleId, config = null, context = null) {
12091
- const c = config || this.getConfigForSync("inline");
12165
+ const c = config !== null && config !== void 0 ? config : this.getConfigForSync("inline");
12092
12166
  const engine = new Engine(c, Parser);
12093
12167
  return engine.getRuleDocumentation({ ruleId, context });
12094
12168
  }
@@ -12144,7 +12218,7 @@ class HtmlValidate {
12144
12218
  /** @public */
12145
12219
  const name = "html-validate";
12146
12220
  /** @public */
12147
- const version = "8.0.5";
12221
+ const version = "8.2.0";
12148
12222
  /** @public */
12149
12223
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
12150
12224
 
@@ -12157,61 +12231,6 @@ function definePlugin(plugin) {
12157
12231
  return plugin;
12158
12232
  }
12159
12233
 
12160
- const defaults$1 = {
12161
- silent: false,
12162
- version,
12163
- logger(text) {
12164
- /* eslint-disable-next-line no-console -- expected to log */
12165
- console.error(kleur__default.default.red(text));
12166
- },
12167
- };
12168
- /**
12169
- * Tests if plugin is compatible with html-validate library. Unless the `silent`
12170
- * option is used a warning is displayed on the console.
12171
- *
12172
- * @public
12173
- * @since v5.0.0
12174
- * @param name - Name of plugin
12175
- * @param declared - What library versions the plugin support (e.g. declared peerDependencies)
12176
- * @returns - `true` if version is compatible
12177
- */
12178
- function compatibilityCheck(name, declared, options) {
12179
- const { silent, version: current, logger } = { ...defaults$1, ...options };
12180
- const valid = semver__default.default.satisfies(current, declared);
12181
- if (valid || silent) {
12182
- return valid;
12183
- }
12184
- const text = [
12185
- "-----------------------------------------------------------------------------------------------------",
12186
- `${name} requires html-validate version "${declared}" but current installed version is ${current}`,
12187
- "This is not a supported configuration. Please install a supported version before reporting bugs.",
12188
- "-----------------------------------------------------------------------------------------------------",
12189
- ].join("\n");
12190
- logger(text);
12191
- return false;
12192
- }
12193
-
12194
- /**
12195
- * Similar to `require(..)` but removes the cached copy first.
12196
- */
12197
- function requireUncached(require, moduleId) {
12198
- const filename = require.resolve(moduleId);
12199
- /* remove references from the parent module to prevent memory leak */
12200
- const m = require.cache[filename];
12201
- if (m && m.parent) {
12202
- const { parent } = m;
12203
- for (let i = parent.children.length - 1; i >= 0; i--) {
12204
- if (parent.children[i].id === filename) {
12205
- parent.children.splice(i, 1);
12206
- }
12207
- }
12208
- }
12209
- /* remove old module from cache */
12210
- delete require.cache[filename];
12211
- /* eslint-disable-next-line import/no-dynamic-require, security/detect-non-literal-require -- as expected but should be moved to upcoming resolver class */
12212
- return require(filename);
12213
- }
12214
-
12215
12234
  const ruleIds = new Set(Object.keys(rules));
12216
12235
  /**
12217
12236
  * Returns true if given ruleId is an existing builtin rule. It does not handle
@@ -12478,6 +12497,25 @@ function getFormatter(name) {
12478
12497
  return (_a = availableFormatters[name]) !== null && _a !== void 0 ? _a : null;
12479
12498
  }
12480
12499
 
12500
+ /**
12501
+ * @internal
12502
+ */
12503
+ function compatibilityCheckImpl(name, declared, options) {
12504
+ const { silent, version: current, logger } = options;
12505
+ const valid = semver__default.default.satisfies(current, declared);
12506
+ if (valid || silent) {
12507
+ return valid;
12508
+ }
12509
+ const text = [
12510
+ "-----------------------------------------------------------------------------------------------------",
12511
+ `${name} requires html-validate version "${declared}" but current installed version is ${current}`,
12512
+ "This is not a supported configuration. Please install a supported version before reporting bugs.",
12513
+ "-----------------------------------------------------------------------------------------------------",
12514
+ ].join("\n");
12515
+ logger(text);
12516
+ return false;
12517
+ }
12518
+
12481
12519
  exports.Attribute = Attribute;
12482
12520
  exports.Config = Config;
12483
12521
  exports.ConfigError = ConfigError;
@@ -12506,13 +12544,12 @@ exports.WrappedError = WrappedError;
12506
12544
  exports.bugs = bugs;
12507
12545
  exports.classifyNodeText = classifyNodeText;
12508
12546
  exports.codeframe = codeframe;
12509
- exports.compatibilityCheck = compatibilityCheck;
12547
+ exports.compatibilityCheckImpl = compatibilityCheckImpl;
12510
12548
  exports.definePlugin = definePlugin;
12511
12549
  exports.ensureError = ensureError;
12512
12550
  exports.getFormatter = getFormatter;
12513
12551
  exports.keywordPatternMatcher = keywordPatternMatcher;
12514
12552
  exports.name = name;
12515
- exports.requireUncached = requireUncached;
12516
12553
  exports.ruleExists = ruleExists;
12517
12554
  exports.sliceLocation = sliceLocation;
12518
12555
  exports.staticResolver = staticResolver;