html-validate 8.1.0 → 8.3.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 (40) hide show
  1. package/dist/cjs/cli.js +36 -10
  2. package/dist/cjs/cli.js.map +1 -1
  3. package/dist/cjs/core-nodejs.js +3 -2
  4. package/dist/cjs/core-nodejs.js.map +1 -1
  5. package/dist/cjs/core.js +198 -114
  6. package/dist/cjs/core.js.map +1 -1
  7. package/dist/cjs/elements.js +29 -5
  8. package/dist/cjs/elements.js.map +1 -1
  9. package/dist/cjs/html-validate.js +2 -2
  10. package/dist/cjs/html-validate.js.map +1 -1
  11. package/dist/cjs/jest-lib.js +3 -3
  12. package/dist/cjs/jest-lib.js.map +1 -1
  13. package/dist/cjs/meta-helper.js +16 -2
  14. package/dist/cjs/meta-helper.js.map +1 -1
  15. package/dist/cjs/test-utils.js +1 -1
  16. package/dist/cjs/test-utils.js.map +1 -1
  17. package/dist/cjs/tsdoc-metadata.json +1 -1
  18. package/dist/es/browser.js +1 -1
  19. package/dist/es/cli.js +36 -10
  20. package/dist/es/cli.js.map +1 -1
  21. package/dist/es/core-nodejs.js +3 -2
  22. package/dist/es/core-nodejs.js.map +1 -1
  23. package/dist/es/core.js +199 -115
  24. package/dist/es/core.js.map +1 -1
  25. package/dist/es/elements.js +29 -5
  26. package/dist/es/elements.js.map +1 -1
  27. package/dist/es/html-validate.js +3 -3
  28. package/dist/es/html-validate.js.map +1 -1
  29. package/dist/es/index.js +1 -1
  30. package/dist/es/jest-lib.js +3 -3
  31. package/dist/es/jest-lib.js.map +1 -1
  32. package/dist/es/meta-helper.js +16 -2
  33. package/dist/es/meta-helper.js.map +1 -1
  34. package/dist/es/test-utils.js +1 -1
  35. package/dist/es/test-utils.js.map +1 -1
  36. package/dist/tsdoc-metadata.json +1 -1
  37. package/dist/types/browser.d.ts +33 -56
  38. package/dist/types/index.d.ts +33 -56
  39. package/dist/types/jest.d.ts +4 -8
  40. package/package.json +19 -19
package/dist/cjs/core.js CHANGED
@@ -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;
@@ -2727,6 +2756,7 @@ const allowedKeys = ["exclude"];
2727
2756
  *
2728
2757
  * @public
2729
2758
  */
2759
+ /* eslint-disable-next-line @typescript-eslint/no-extraneous-class -- technical debt, should probably be plain functions maybe in an object */
2730
2760
  class Validator {
2731
2761
  /**
2732
2762
  * Test if element is used in a proper context.
@@ -2768,7 +2798,7 @@ class Validator {
2768
2798
  return false;
2769
2799
  }
2770
2800
  // Check if the rule has a quantifier
2771
- const [, category, quantifier] = rule.match(/^(@?.*?)([?*]?)$/);
2801
+ const [, category, quantifier] = rule.match(/^(@?.*?)([?*]?)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2772
2802
  const limit = category && quantifier && parseQuantifier(quantifier);
2773
2803
  if (limit) {
2774
2804
  const siblings = children.filter((cur) => Validator.validatePermittedCategory(cur, rule, true));
@@ -2814,6 +2844,7 @@ class Validator {
2814
2844
  * In both of these cases no error should be reported. */
2815
2845
  const orderSpecified = rules.find((cur) => Validator.validatePermittedCategory(node, cur, true));
2816
2846
  if (orderSpecified) {
2847
+ /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt, should never happen */
2817
2848
  cb(node, prev);
2818
2849
  return false;
2819
2850
  }
@@ -2954,7 +2985,7 @@ class Validator {
2954
2985
  */
2955
2986
  /* eslint-disable-next-line complexity -- rule does not like switch */
2956
2987
  static validatePermittedCategory(node, category, defaultMatch) {
2957
- const [, rawCategory] = category.match(/^(@?.*?)([?*]?)$/);
2988
+ const [, rawCategory] = category.match(/^(@?.*?)([?*]?)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2958
2989
  /* match tagName when an explicit name is given */
2959
2990
  if (!rawCategory.startsWith("@")) {
2960
2991
  return node.tagName === rawCategory;
@@ -2979,9 +3010,9 @@ class Validator {
2979
3010
  case "@interactive":
2980
3011
  return node.meta.interactive;
2981
3012
  case "@script":
2982
- return node.meta.scriptSupporting;
3013
+ return Boolean(node.meta.scriptSupporting);
2983
3014
  case "@form":
2984
- return node.meta.form;
3015
+ return Boolean(node.meta.form);
2985
3016
  default:
2986
3017
  throw new Error(`Invalid content category "${category}"`);
2987
3018
  }
@@ -3166,10 +3197,12 @@ var configurationSchema = {
3166
3197
  properties: properties
3167
3198
  };
3168
3199
 
3169
- var TRANSFORMER_API;
3170
- (function (TRANSFORMER_API) {
3171
- TRANSFORMER_API[TRANSFORMER_API["VERSION"] = 1] = "VERSION";
3172
- })(TRANSFORMER_API || (TRANSFORMER_API = {}));
3200
+ /**
3201
+ * @internal
3202
+ */
3203
+ const TRANSFORMER_API = {
3204
+ VERSION: 1,
3205
+ };
3173
3206
 
3174
3207
  /**
3175
3208
  * @public
@@ -3416,7 +3449,7 @@ function classifyNodeText(node, options = {}) {
3416
3449
  const { accessible = false, ignoreHiddenRoot = false } = options;
3417
3450
  const cacheKey = getCachekey(options);
3418
3451
  if (node.cacheExists(cacheKey)) {
3419
- return node.cacheGet(cacheKey);
3452
+ return node.cacheGet(cacheKey); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- has/get combo
3420
3453
  }
3421
3454
  if (!ignoreHiddenRoot && isHTMLHidden(node)) {
3422
3455
  return node.cacheSet(cacheKey, exports.TextClassification.EMPTY_TEXT);
@@ -3464,8 +3497,12 @@ function findTextNodes(node, options) {
3464
3497
 
3465
3498
  function hasAltText(image) {
3466
3499
  const alt = image.getAttribute("alt");
3467
- /* missing or boolean */
3468
- 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) {
3469
3506
  return false;
3470
3507
  }
3471
3508
  return alt.isDynamic || alt.value.toString() !== "";
@@ -3473,8 +3510,12 @@ function hasAltText(image) {
3473
3510
 
3474
3511
  function hasAriaLabel(node) {
3475
3512
  const label = node.getAttribute("aria-label");
3476
- /* missing or boolean */
3477
- 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) {
3478
3519
  return false;
3479
3520
  }
3480
3521
  return label.isDynamic || label.value.toString() !== "";
@@ -3555,7 +3596,7 @@ class Rule {
3555
3596
  this.options = options;
3556
3597
  this.enabled = true;
3557
3598
  this.blockers = [];
3558
- this.severity = 0;
3599
+ this.severity = exports.Severity.DISABLED;
3559
3600
  this.name = "";
3560
3601
  }
3561
3602
  getSeverity() {
@@ -3708,13 +3749,14 @@ class Rule {
3708
3749
  }
3709
3750
  }
3710
3751
  findLocation(src) {
3752
+ var _a, _b;
3711
3753
  if (src.location) {
3712
3754
  return src.location;
3713
3755
  }
3714
- if (src.event && src.event.location) {
3756
+ if ((_a = src.event) === null || _a === void 0 ? void 0 : _a.location) {
3715
3757
  return src.event.location;
3716
3758
  }
3717
- if (src.node && src.node.location) {
3759
+ if ((_b = src.node) === null || _b === void 0 ? void 0 : _b.location) {
3718
3760
  return src.node.location;
3719
3761
  }
3720
3762
  return {};
@@ -3887,7 +3929,8 @@ class AllowedLinks extends Rule {
3887
3929
  };
3888
3930
  }
3889
3931
  documentation(context) {
3890
- 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";
3891
3934
  return {
3892
3935
  description: message,
3893
3936
  url: "https://html-validate.org/rules/allowed-links.html",
@@ -4151,7 +4194,7 @@ function isValidUsage(target, meta) {
4151
4194
  return true;
4152
4195
  }
4153
4196
  /* interactive and labelable elements are valid */
4154
- if (meta.interactive || meta.labelable) {
4197
+ if (Boolean(meta.interactive) || Boolean(meta.labelable)) {
4155
4198
  return true;
4156
4199
  }
4157
4200
  return false;
@@ -4186,7 +4229,7 @@ class AriaLabelMisuse extends Rule {
4186
4229
  }
4187
4230
  validateElement(target) {
4188
4231
  const attr = target.getAttribute("aria-label");
4189
- if (!attr || !attr.value || attr.valueMatches("", false)) {
4232
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value) || attr.valueMatches("", false)) {
4190
4233
  return;
4191
4234
  }
4192
4235
  /* ignore elements without meta */
@@ -4917,7 +4960,7 @@ class AttributeAllowedValues extends Rule {
4917
4960
  const meta = node.meta;
4918
4961
  /* ignore rule if element has no meta or meta does not specify attribute
4919
4962
  * allowed values */
4920
- if (!meta || !meta.attributes)
4963
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
4921
4964
  return;
4922
4965
  for (const attr of node.attributes) {
4923
4966
  if (Validator.validateAttribute(attr, meta.attributes)) {
@@ -4985,7 +5028,7 @@ class AttributeBooleanStyle extends Rule {
4985
5028
  const meta = node.meta;
4986
5029
  /* ignore rule if element has no meta or meta does not specify attribute
4987
5030
  * allowed values */
4988
- if (!meta || !meta.attributes)
5031
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
4989
5032
  return;
4990
5033
  /* check all boolean attributes */
4991
5034
  for (const attr of node.attributes) {
@@ -5066,7 +5109,7 @@ class AttributeEmptyStyle extends Rule {
5066
5109
  const meta = node.meta;
5067
5110
  /* ignore rule if element has no meta or meta does not specify attribute
5068
5111
  * allowed values */
5069
- if (!meta || !meta.attributes)
5112
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
5070
5113
  return;
5071
5114
  /* check all boolean attributes */
5072
5115
  for (const attr of node.attributes) {
@@ -5154,10 +5197,10 @@ class AttributeMisuse extends Rule {
5154
5197
  });
5155
5198
  }
5156
5199
  validateAttr(node, attr, meta) {
5157
- if (!meta || !meta.allowed) {
5200
+ if (!(meta === null || meta === void 0 ? void 0 : meta.allowed)) {
5158
5201
  return;
5159
5202
  }
5160
- const details = meta.allowed(node, attr);
5203
+ const details = meta.allowed(node._adapter, attr.value);
5161
5204
  if (details) {
5162
5205
  this.report({
5163
5206
  node,
@@ -5828,7 +5871,7 @@ class ElementPermittedOccurrences extends Rule {
5828
5871
  this.on("dom:ready", (event) => {
5829
5872
  const doc = event.document;
5830
5873
  doc.visitDepthFirst((node) => {
5831
- if (!node || !node.meta) {
5874
+ if (!(node === null || node === void 0 ? void 0 : node.meta)) {
5832
5875
  return;
5833
5876
  }
5834
5877
  const rules = node.meta.permittedContent;
@@ -6033,7 +6076,7 @@ class ElementRequiredAttributes extends Rule {
6033
6076
  const node = event.previous;
6034
6077
  const meta = node.meta;
6035
6078
  /* handle missing metadata and missing attributes */
6036
- if (!meta || !meta.attributes) {
6079
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes)) {
6037
6080
  return;
6038
6081
  }
6039
6082
  for (const [key, attr] of Object.entries(meta.attributes)) {
@@ -6345,7 +6388,7 @@ class FormDupName extends Rule {
6345
6388
  const meta = this.getMetaFor(tagName);
6346
6389
  /* istanbul ignore if: the earlier check for getTagsWithProperty ensures
6347
6390
  * these will actually be set so this is just an untestable fallback */
6348
- if (!meta || !meta.formAssociated) {
6391
+ if (!(meta === null || meta === void 0 ? void 0 : meta.formAssociated)) {
6349
6392
  return false;
6350
6393
  }
6351
6394
  return meta.formAssociated.listed;
@@ -6379,7 +6422,7 @@ const defaults$h = {
6379
6422
  minInitialRank: "h1",
6380
6423
  sectioningRoots: ["dialog", '[role="dialog"]', '[role="alertdialog"]'],
6381
6424
  };
6382
- function isRelevant$3(event) {
6425
+ function isRelevant$4(event) {
6383
6426
  const node = event.target;
6384
6427
  return Boolean(node.meta && node.meta.heading);
6385
6428
  }
@@ -6447,7 +6490,7 @@ class HeadingLevel extends Rule {
6447
6490
  };
6448
6491
  }
6449
6492
  setup() {
6450
- this.on("tag:start", isRelevant$3, (event) => {
6493
+ this.on("tag:start", isRelevant$4, (event) => {
6451
6494
  this.onTagStart(event);
6452
6495
  });
6453
6496
  this.on("tag:ready", (event) => {
@@ -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);
@@ -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 */
@@ -7107,7 +7150,7 @@ class MapDupName extends Rule {
7107
7150
  }
7108
7151
  }
7109
7152
 
7110
- function isRelevant$2(event) {
7153
+ function isRelevant$3(event) {
7111
7154
  return event.target.is("map");
7112
7155
  }
7113
7156
  function hasStaticValue(attr) {
@@ -7121,7 +7164,7 @@ class MapIdName extends Rule {
7121
7164
  };
7122
7165
  }
7123
7166
  setup() {
7124
- this.on("tag:ready", isRelevant$2, (event) => {
7167
+ this.on("tag:ready", isRelevant$3, (event) => {
7125
7168
  var _a;
7126
7169
  const { target } = event;
7127
7170
  const id = target.getAttribute("id");
@@ -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
  }
@@ -7385,11 +7428,11 @@ class NoDupID extends Rule {
7385
7428
  const { document } = event;
7386
7429
  const existing = new Set();
7387
7430
  const elements = document.querySelectorAll("[id]");
7388
- const relevant = elements.filter(isRelevant$1);
7431
+ const relevant = elements.filter(isRelevant$2);
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();
@@ -7401,7 +7444,7 @@ class NoDupID extends Rule {
7401
7444
  });
7402
7445
  }
7403
7446
  }
7404
- function isRelevant$1(element) {
7447
+ function isRelevant$2(element) {
7405
7448
  const attr = element.getAttribute("id");
7406
7449
  /* istanbul ignore next: can not really happen as querySelector will only return elements with id present */
7407
7450
  if (!attr) {
@@ -7418,6 +7461,41 @@ function isRelevant$1(element) {
7418
7461
  return true;
7419
7462
  }
7420
7463
 
7464
+ function isRelevant$1(event) {
7465
+ return event.target.is("button");
7466
+ }
7467
+ class NoImplicitButtonType extends Rule {
7468
+ documentation() {
7469
+ return {
7470
+ description: [
7471
+ "`<button>` is missing required `type` attribute",
7472
+ "",
7473
+ "When the `type` attribute is omitted it defaults to `submit`.",
7474
+ "Submit buttons are triggered when a keyboard user presses <kbd>Enter</kbd>.",
7475
+ "",
7476
+ "As this may or may not be inteded this rule enforces that the `type` attribute be explicitly set to one of the valid types:",
7477
+ "",
7478
+ "- `button` - a generic button.",
7479
+ "- `submit` - a submit button.",
7480
+ "- `reset`- a button to reset form fields.",
7481
+ ].join("\n"),
7482
+ url: "https://html-validate.org/rules/no-implicit-button-type.html",
7483
+ };
7484
+ }
7485
+ setup() {
7486
+ this.on("element:ready", isRelevant$1, (event) => {
7487
+ const { target } = event;
7488
+ const attr = target.getAttribute("type");
7489
+ if (!attr) {
7490
+ this.report({
7491
+ node: event.target,
7492
+ message: `<button> is missing required "type" attribute`,
7493
+ });
7494
+ }
7495
+ });
7496
+ }
7497
+ }
7498
+
7421
7499
  class NoImplicitClose extends Rule {
7422
7500
  documentation() {
7423
7501
  return {
@@ -7523,11 +7601,12 @@ class NoInlineStyle extends Rule {
7523
7601
  });
7524
7602
  }
7525
7603
  isRelevant(event) {
7604
+ var _a;
7526
7605
  if (event.key !== "style") {
7527
7606
  return false;
7528
7607
  }
7529
7608
  const { include, exclude } = this.options;
7530
- const key = event.originalAttribute || event.key;
7609
+ const key = (_a = event.originalAttribute) !== null && _a !== void 0 ? _a : event.key;
7531
7610
  /* ignore attributes not present in "include" */
7532
7611
  if (include && !include.includes(key)) {
7533
7612
  return false;
@@ -7721,7 +7800,8 @@ class NoRawCharacters extends Rule {
7721
7800
  if (event.quote) {
7722
7801
  return;
7723
7802
  }
7724
- this.findRawChars(event.target, event.value.toString(), event.valueLocation, unquotedAttrRegexp);
7803
+ 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
7804
+ unquotedAttrRegexp);
7725
7805
  });
7726
7806
  }
7727
7807
  /**
@@ -7935,7 +8015,7 @@ class NoSelfClosing extends Rule {
7935
8015
  function isRelevant(node, options) {
7936
8016
  /* tags in XML namespaces are relevant only if ignoreXml is false, in which
7937
8017
  * case assume all xml elements must not be self-closed */
7938
- if (node.tagName && node.tagName.match(xmlns)) {
8018
+ if (node.tagName.match(xmlns)) {
7939
8019
  return !options.ignoreXML;
7940
8020
  }
7941
8021
  /* nodes with missing metadata is assumed relevant */
@@ -8141,16 +8221,12 @@ class PreferButton extends Rule {
8141
8221
  };
8142
8222
  }
8143
8223
  documentation(context) {
8144
- const doc = {
8145
- description: `Prefer to use the generic \`<button>\` element instead of \`<input>\`.`,
8224
+ const src = `<input type="${context.type}">`;
8225
+ const dst = replacement[context.type] || `<button>`;
8226
+ return {
8227
+ description: `Prefer to use \`${dst}\` instead of \`"${src}\`.`,
8146
8228
  url: "https://html-validate.org/rules/prefer-button.html",
8147
8229
  };
8148
- if (context) {
8149
- const src = `<input type="${context.type}">`;
8150
- const dst = replacement[context.type] || `<button>`;
8151
- doc.description = `Prefer to use \`${dst}\` instead of \`"${src}\`.`;
8152
- }
8153
- return doc;
8154
8230
  }
8155
8231
  setup() {
8156
8232
  this.on("attr", (event) => {
@@ -8249,14 +8325,10 @@ class PreferNativeElement extends Rule {
8249
8325
  };
8250
8326
  }
8251
8327
  documentation(context) {
8252
- const doc = {
8253
- description: `Instead of using WAI-ARIA roles prefer to use the native HTML elements.`,
8328
+ return {
8329
+ description: `Instead of using the WAI-ARIA role "${context.role}" prefer to use the native <${context.replacement}> element.`,
8254
8330
  url: "https://html-validate.org/rules/prefer-native-element.html",
8255
8331
  };
8256
- if (context) {
8257
- doc.description = `Instead of using the WAI-ARIA role "${context.role}" prefer to use the native <${context.replacement}> element.`;
8258
- }
8259
- return doc;
8260
8332
  }
8261
8333
  setup() {
8262
8334
  const { mapping } = this.options;
@@ -8297,7 +8369,7 @@ class PreferNativeElement extends Rule {
8297
8369
  }
8298
8370
  getLocation(event) {
8299
8371
  const begin = event.location;
8300
- const end = event.valueLocation;
8372
+ 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
8301
8373
  const quote = event.quote ? 1 : 0;
8302
8374
  const size = end.offset + end.size - begin.offset + quote;
8303
8375
  return {
@@ -8371,7 +8443,7 @@ class RequireCSPNonce extends Rule {
8371
8443
  const { tags } = this.options;
8372
8444
  const node = event.previous;
8373
8445
  /* ignore other tags */
8374
- if (!node || !tags.includes(node.tagName)) {
8446
+ if (!tags.includes(node.tagName)) {
8375
8447
  return;
8376
8448
  }
8377
8449
  /* ignore if nonce is set to non-empty value (or dynamic) */
@@ -8463,7 +8535,10 @@ class RequireSri extends Rule {
8463
8535
  }
8464
8536
  needSri(node) {
8465
8537
  const attr = this.elementSourceAttr(node);
8466
- if (!attr || attr.value === null || attr.value === "" || attr.isDynamic) {
8538
+ if (!attr) {
8539
+ return false;
8540
+ }
8541
+ if (attr.value === null || attr.value === "" || attr.isDynamic) {
8467
8542
  return false;
8468
8543
  }
8469
8544
  const url = attr.value.toString();
@@ -8520,7 +8595,7 @@ class ScriptType extends Rule {
8520
8595
  setup() {
8521
8596
  this.on("tag:end", (event) => {
8522
8597
  const node = event.previous;
8523
- if (!node || node.tagName !== "script") {
8598
+ if (node.tagName !== "script") {
8524
8599
  return;
8525
8600
  }
8526
8601
  const attr = node.getAttribute("type");
@@ -8801,18 +8876,16 @@ class TextContent extends Rule {
8801
8876
  description: `The textual content for this element is not valid.`,
8802
8877
  url: "https://html-validate.org/rules/text-content.html",
8803
8878
  };
8804
- if (context === null || context === void 0 ? void 0 : context.textContent) {
8805
- switch (context.textContent) {
8806
- case exports.TextContent.NONE:
8807
- doc.description = `The \`<${context.tagName}>\` element must not have textual content.`;
8808
- break;
8809
- case exports.TextContent.REQUIRED:
8810
- doc.description = `The \`<${context.tagName}>\` element must have textual content.`;
8811
- break;
8812
- case exports.TextContent.ACCESSIBLE:
8813
- doc.description = `The \`<${context.tagName}>\` element must have accessible text.`;
8814
- break;
8815
- }
8879
+ switch (context.textContent) {
8880
+ case exports.TextContent.NONE:
8881
+ doc.description = `The \`<${context.tagName}>\` element must not have textual content.`;
8882
+ break;
8883
+ case exports.TextContent.REQUIRED:
8884
+ doc.description = `The \`<${context.tagName}>\` element must have textual content.`;
8885
+ break;
8886
+ case exports.TextContent.ACCESSIBLE:
8887
+ doc.description = `The \`<${context.tagName}>\` element must have accessible text.`;
8888
+ break;
8816
8889
  }
8817
8890
  return doc;
8818
8891
  }
@@ -9173,20 +9246,16 @@ class VoidStyle extends Rule {
9173
9246
  };
9174
9247
  }
9175
9248
  documentation(context) {
9176
- const doc = {
9177
- description: "The current configuration requires a specific style for ending void elements.",
9249
+ const [desc, end] = styleDescription(context.style);
9250
+ return {
9251
+ description: `The current configuration requires void elements to ${desc}, use <${context.tagName}${end}> instead.`,
9178
9252
  url: "https://html-validate.org/rules/void-style.html",
9179
9253
  };
9180
- if (context) {
9181
- const [desc, end] = styleDescription(context.style);
9182
- doc.description = `The current configuration requires void elements to ${desc}, use <${context.tagName}${end}> instead.`;
9183
- }
9184
- return doc;
9185
9254
  }
9186
9255
  setup() {
9187
9256
  this.on("tag:end", (event) => {
9188
9257
  const active = event.previous; // The current active element (that is, the current element on the stack)
9189
- if (active && active.meta) {
9258
+ if (active.meta) {
9190
9259
  this.validateActive(active);
9191
9260
  }
9192
9261
  });
@@ -9423,7 +9492,8 @@ class H37 extends Rule {
9423
9492
  return;
9424
9493
  }
9425
9494
  /* validate plain alt-attribute */
9426
- if (node.getAttributeValue("alt") || (node.hasAttribute("alt") && this.options.allowEmpty)) {
9495
+ if (Boolean(node.getAttributeValue("alt")) ||
9496
+ Boolean(node.hasAttribute("alt") && this.options.allowEmpty)) {
9427
9497
  return;
9428
9498
  }
9429
9499
  /* validate if any non-empty alias is present */
@@ -9600,6 +9670,7 @@ const bundledRules = {
9600
9670
  "no-dup-attr": NoDupAttr,
9601
9671
  "no-dup-class": NoDupClass,
9602
9672
  "no-dup-id": NoDupID,
9673
+ "no-implicit-button-type": NoImplicitButtonType,
9603
9674
  "no-implicit-close": NoImplicitClose,
9604
9675
  "no-inline-style": NoInlineStyle,
9605
9676
  "no-missing-references": NoMissingReferences,
@@ -9646,6 +9717,7 @@ const config$4 = {
9646
9717
  "multiple-labeled-controls": "error",
9647
9718
  "no-autoplay": ["error", { include: ["audio", "video"] }],
9648
9719
  "no-dup-id": "error",
9720
+ "no-implicit-button-type": "error",
9649
9721
  "no-redundant-aria-label": "error",
9650
9722
  "no-redundant-for": "error",
9651
9723
  "no-redundant-role": "error",
@@ -9725,6 +9797,7 @@ const config$1 = {
9725
9797
  "no-dup-attr": "error",
9726
9798
  "no-dup-class": "error",
9727
9799
  "no-dup-id": "error",
9800
+ "no-implicit-button-type": "error",
9728
9801
  "no-implicit-close": "error",
9729
9802
  "no-inline-style": "error",
9730
9803
  "no-multiple-main": "error",
@@ -9856,7 +9929,7 @@ class ResolvedConfig {
9856
9929
  * @returns A list of transformed sources ready for validation.
9857
9930
  */
9858
9931
  transformSource(source, filename) {
9859
- const transformer = this.findTransformer(filename || source.filename);
9932
+ const transformer = this.findTransformer(filename !== null && filename !== void 0 ? filename : source.filename);
9860
9933
  const context = {
9861
9934
  hasChain: (filename) => {
9862
9935
  return !!this.findTransformer(filename);
@@ -9868,9 +9941,10 @@ class ResolvedConfig {
9868
9941
  if (transformer) {
9869
9942
  try {
9870
9943
  return Array.from(transformer.fn.call(context, source), (cur) => {
9944
+ var _a;
9871
9945
  /* keep track of which transformers that has been run on this source
9872
9946
  * by appending this entry to the transformedBy array */
9873
- cur.transformedBy = cur.transformedBy || [];
9947
+ (_a = cur.transformedBy) !== null && _a !== void 0 ? _a : (cur.transformedBy = []);
9874
9948
  cur.transformedBy.push(transformer.name);
9875
9949
  return cur;
9876
9950
  });
@@ -10042,7 +10116,7 @@ function mergeInternal(base, rhs) {
10042
10116
  }
10043
10117
  /* root property is merged with boolean "or" since it should always be truthy
10044
10118
  * if any config has it set. */
10045
- const root = base.root || rhs.root;
10119
+ const root = Boolean(base.root) || Boolean(rhs.root);
10046
10120
  if (root) {
10047
10121
  dst.root = root;
10048
10122
  }
@@ -10129,7 +10203,7 @@ class Config {
10129
10203
  * @internal
10130
10204
  */
10131
10205
  constructor(resolvers, options) {
10132
- var _a;
10206
+ var _a, _b;
10133
10207
  this.transformers = [];
10134
10208
  const initial = {
10135
10209
  extends: [],
@@ -10142,18 +10216,18 @@ class Config {
10142
10216
  this.initialized = false;
10143
10217
  this.resolvers = toArray(resolvers);
10144
10218
  /* load plugins */
10145
- this.plugins = this.loadPlugins(this.config.plugins || []);
10219
+ this.plugins = this.loadPlugins((_a = this.config.plugins) !== null && _a !== void 0 ? _a : []);
10146
10220
  this.configurations = this.loadConfigurations(this.plugins);
10147
10221
  this.extendMeta(this.plugins);
10148
10222
  /* process extended configs */
10149
- this.config = this.extendConfig((_a = this.config.extends) !== null && _a !== void 0 ? _a : []);
10223
+ this.config = this.extendConfig((_b = this.config.extends) !== null && _b !== void 0 ? _b : []);
10150
10224
  /* reset extends as we already processed them, this prevents the next config
10151
10225
  * from reapplying config from extended config as well as duplicate entries
10152
10226
  * when merging arrays */
10153
10227
  this.config.extends = [];
10154
10228
  /* rules explicitly set by passed options should have precedence over any
10155
10229
  * extended rules, not the other way around. */
10156
- if (options && options.rules) {
10230
+ if (options === null || options === void 0 ? void 0 : options.rules) {
10157
10231
  this.config = mergeInternal(this.config, { rules: options.rules });
10158
10232
  }
10159
10233
  }
@@ -10166,11 +10240,12 @@ class Config {
10166
10240
  * @public
10167
10241
  */
10168
10242
  init() {
10243
+ var _a;
10169
10244
  if (this.initialized) {
10170
10245
  return;
10171
10246
  }
10172
10247
  /* precompile transform patterns */
10173
- this.transformers = this.precompileTransformers(this.config.transform || {});
10248
+ this.transformers = this.precompileTransformers((_a = this.config.transform) !== null && _a !== void 0 ? _a : {});
10174
10249
  this.initialized = true;
10175
10250
  }
10176
10251
  /**
@@ -10197,7 +10272,7 @@ class Config {
10197
10272
  for (const entry of entries) {
10198
10273
  let extended;
10199
10274
  if (this.configurations.has(entry)) {
10200
- extended = this.configurations.get(entry);
10275
+ extended = this.configurations.get(entry); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- map has/get combo
10201
10276
  }
10202
10277
  else {
10203
10278
  extended = Config.fromFile(this.resolvers, entry).config;
@@ -10212,12 +10287,13 @@ class Config {
10212
10287
  * @internal
10213
10288
  */
10214
10289
  getMetaTable() {
10290
+ var _a;
10215
10291
  /* use cached table if it exists */
10216
10292
  if (this.metaTable) {
10217
10293
  return this.metaTable;
10218
10294
  }
10219
10295
  const metaTable = new MetaTable();
10220
- const source = this.config.elements || ["html5"];
10296
+ const source = (_a = this.config.elements) !== null && _a !== void 0 ? _a : ["html5"];
10221
10297
  /* extend validation schema from plugins */
10222
10298
  for (const plugin of this.getPlugins()) {
10223
10299
  if (plugin.elementSchema) {
@@ -10315,6 +10391,7 @@ class Config {
10315
10391
  });
10316
10392
  }
10317
10393
  loadConfigurations(plugins) {
10394
+ var _a;
10318
10395
  const configs = new Map();
10319
10396
  /* builtin presets */
10320
10397
  for (const [name, config] of Object.entries(Presets)) {
@@ -10323,7 +10400,7 @@ class Config {
10323
10400
  }
10324
10401
  /* presets from plugins */
10325
10402
  for (const plugin of plugins) {
10326
- for (const [name, config] of Object.entries(plugin.configs || {})) {
10403
+ for (const [name, config] of Object.entries((_a = plugin.configs) !== null && _a !== void 0 ? _a : {})) {
10327
10404
  if (!config)
10328
10405
  continue;
10329
10406
  Config.validate(config, name);
@@ -10688,10 +10765,11 @@ class Parser {
10688
10765
  * stack when is allowed to omit.
10689
10766
  */
10690
10767
  closeOptional(token) {
10768
+ var _a;
10691
10769
  /* if the element doesn't have metadata it cannot have optional end
10692
10770
  * tags. Period. */
10693
10771
  const active = this.dom.getActive();
10694
- if (!(active.meta && active.meta.implicitClosed)) {
10772
+ if (!((_a = active.meta) === null || _a === void 0 ? void 0 : _a.implicitClosed)) {
10695
10773
  return false;
10696
10774
  }
10697
10775
  const tagName = token.data[2];
@@ -10843,9 +10921,10 @@ class Parser {
10843
10921
  }
10844
10922
  }
10845
10923
  processElement(node, source) {
10924
+ var _a;
10846
10925
  /* enable cache on node now that it is fully constructed */
10847
10926
  node.cacheEnable();
10848
- if (source.hooks && source.hooks.processElement) {
10927
+ if ((_a = source.hooks) === null || _a === void 0 ? void 0 : _a.processElement) {
10849
10928
  const processElement = source.hooks.processElement;
10850
10929
  const metaTable = this.metaTable;
10851
10930
  const context = {
@@ -10912,6 +10991,7 @@ class Parser {
10912
10991
  * @internal
10913
10992
  */
10914
10993
  consumeAttribute(source, node, token, next) {
10994
+ var _a;
10915
10995
  const keyLocation = this.getAttributeKeyLocation(token);
10916
10996
  const valueLocation = this.getAttributeValueLocation(next);
10917
10997
  const location = this.getAttributeLocation(token, next);
@@ -10930,7 +11010,7 @@ class Parser {
10930
11010
  * data right away but a transformer may override it to allow aliasing
10931
11011
  * attributes, e.g ng-attr-foo or v-bind:foo */
10932
11012
  let processAttribute = (attr) => [attr];
10933
- if (source.hooks && source.hooks.processAttribute) {
11013
+ if ((_a = source.hooks) === null || _a === void 0 ? void 0 : _a.processAttribute) {
10934
11014
  processAttribute = source.hooks.processAttribute;
10935
11015
  }
10936
11016
  /* handle deprecated callbacks */
@@ -11280,14 +11360,15 @@ class Reporter {
11280
11360
  const report = {
11281
11361
  valid: this.isValid(),
11282
11362
  results: Object.keys(this.result).map((filePath) => {
11363
+ var _a;
11283
11364
  const messages = Array.from(this.result[filePath], freeze).sort(messageSort);
11284
- const source = (sources || []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11365
+ const source = (sources !== null && sources !== void 0 ? sources : []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11285
11366
  return {
11286
11367
  filePath,
11287
11368
  messages,
11288
11369
  errorCount: countErrors(messages),
11289
11370
  warningCount: countWarnings(messages),
11290
- source: source ? source.originalData || source.data : null,
11371
+ source: source ? (_a = source.originalData) !== null && _a !== void 0 ? _a : source.data : null,
11291
11372
  };
11292
11373
  }),
11293
11374
  errorCount: 0,
@@ -11305,10 +11386,10 @@ class Reporter {
11305
11386
  }
11306
11387
  }
11307
11388
  function countErrors(messages) {
11308
- return messages.filter((m) => m.severity === exports.Severity.ERROR).length;
11389
+ return messages.filter((m) => m.severity === Number(exports.Severity.ERROR)).length;
11309
11390
  }
11310
11391
  function countWarnings(messages) {
11311
- return messages.filter((m) => m.severity === exports.Severity.WARN).length;
11392
+ return messages.filter((m) => m.severity === Number(exports.Severity.WARN)).length;
11312
11393
  }
11313
11394
  function sumErrors(results) {
11314
11395
  return results.reduce((sum, result) => {
@@ -11653,9 +11734,10 @@ class Engine {
11653
11734
  * between rule name and its constructor.
11654
11735
  */
11655
11736
  initRules(config) {
11737
+ var _a;
11656
11738
  const availableRules = {};
11657
11739
  for (const plugin of config.getPlugins()) {
11658
- for (const [name, rule] of Object.entries(plugin.rules || {})) {
11740
+ for (const [name, rule] of Object.entries((_a = plugin.rules) !== null && _a !== void 0 ? _a : {})) {
11659
11741
  if (!rule)
11660
11742
  continue;
11661
11743
  availableRules[name] = rule;
@@ -11758,7 +11840,7 @@ class StaticConfigLoader extends ConfigLoader {
11758
11840
  }
11759
11841
  }
11760
11842
  getConfigFor(_handle, configOverride) {
11761
- const override = this.loadFromObject(configOverride || {});
11843
+ const override = this.loadFromObject(configOverride !== null && configOverride !== void 0 ? configOverride : {});
11762
11844
  if (override.isRootFound()) {
11763
11845
  override.init();
11764
11846
  return override.resolve();
@@ -11802,6 +11884,7 @@ class HtmlValidate {
11802
11884
  const [loader, config] = arg instanceof ConfigLoader ? [arg, undefined] : [undefined, arg];
11803
11885
  this.configLoader = loader !== null && loader !== void 0 ? loader : new StaticConfigLoader(config);
11804
11886
  }
11887
+ /* eslint-enable @typescript-eslint/unified-signatures */
11805
11888
  validateString(str, arg1, arg2, arg3) {
11806
11889
  const filename = typeof arg1 === "string" ? arg1 : "inline";
11807
11890
  const options = isConfigData(arg1) ? arg1 : isConfigData(arg2) ? arg2 : undefined;
@@ -11816,6 +11899,7 @@ class HtmlValidate {
11816
11899
  };
11817
11900
  return this.validateSource(source, options);
11818
11901
  }
11902
+ /* eslint-enable @typescript-eslint/unified-signatures */
11819
11903
  validateStringSync(str, arg1, arg2, arg3) {
11820
11904
  const filename = typeof arg1 === "string" ? arg1 : "inline";
11821
11905
  const options = isConfigData(arg1) ? arg1 : isConfigData(arg2) ? arg2 : undefined;
@@ -12087,7 +12171,7 @@ class HtmlValidate {
12087
12171
  * contextual details and suggestions.
12088
12172
  */
12089
12173
  async getRuleDocumentation(ruleId, config = null, context = null) {
12090
- const c = config || this.getConfigFor("inline");
12174
+ const c = config !== null && config !== void 0 ? config : this.getConfigFor("inline");
12091
12175
  const engine = new Engine(await c, Parser);
12092
12176
  return engine.getRuleDocumentation({ ruleId, context });
12093
12177
  }
@@ -12116,7 +12200,7 @@ class HtmlValidate {
12116
12200
  * contextual details and suggestions.
12117
12201
  */
12118
12202
  getRuleDocumentationSync(ruleId, config = null, context = null) {
12119
- const c = config || this.getConfigForSync("inline");
12203
+ const c = config !== null && config !== void 0 ? config : this.getConfigForSync("inline");
12120
12204
  const engine = new Engine(c, Parser);
12121
12205
  return engine.getRuleDocumentation({ ruleId, context });
12122
12206
  }
@@ -12172,7 +12256,7 @@ class HtmlValidate {
12172
12256
  /** @public */
12173
12257
  const name = "html-validate";
12174
12258
  /** @public */
12175
- const version = "8.1.0";
12259
+ const version = "8.3.0";
12176
12260
  /** @public */
12177
12261
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
12178
12262