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/es/core.js CHANGED
@@ -284,7 +284,7 @@ class NestedError extends Error {
284
284
  super(message);
285
285
  Error.captureStackTrace(this, NestedError);
286
286
  this.name = NestedError.name;
287
- if (nested && nested.stack) {
287
+ if (nested === null || nested === void 0 ? void 0 : nested.stack) {
288
288
  this.stack += `\nCaused by: ${nested.stack}`;
289
289
  }
290
290
  }
@@ -1019,7 +1019,8 @@ function hasAttribute(node, attr) {
1019
1019
  * Matches attribute against value.
1020
1020
  */
1021
1021
  function matchAttribute(node, key, op, value) {
1022
- const nodeValue = (node.getAttributeValue(key) || "").toLowerCase();
1022
+ var _a;
1023
+ const nodeValue = ((_a = node.getAttributeValue(key)) !== null && _a !== void 0 ? _a : "").toLowerCase();
1023
1024
  switch (op) {
1024
1025
  case "!=":
1025
1026
  return nodeValue !== value;
@@ -1381,6 +1382,16 @@ class Attribute {
1381
1382
  get isDynamic() {
1382
1383
  return this.value instanceof DynamicValue;
1383
1384
  }
1385
+ /**
1386
+ * Test attribute value.
1387
+ *
1388
+ * @param pattern - Pattern to match value against. Can be a RegExp, literal
1389
+ * string or an array of strings (returns true if any value matches the
1390
+ * array).
1391
+ * @param dynamicMatches - If true `DynamicValue` will always match, if false
1392
+ * it never matches.
1393
+ * @returns `true` if attribute value matches pattern.
1394
+ */
1384
1395
  valueMatches(pattern, dynamicMatches = true) {
1385
1396
  if (this.value === null) {
1386
1397
  return false;
@@ -1766,7 +1777,7 @@ class DOMTokenList extends Array {
1766
1777
  this.value = value.expr;
1767
1778
  }
1768
1779
  else {
1769
- this.value = value || "";
1780
+ this.value = value !== null && value !== void 0 ? value : "";
1770
1781
  }
1771
1782
  }
1772
1783
  item(n) {
@@ -1991,7 +2002,7 @@ class IdMatcher extends Matcher {
1991
2002
  class AttrMatcher extends Matcher {
1992
2003
  constructor(attr) {
1993
2004
  super();
1994
- const [, key, op, value] = attr.match(/^(.+?)(?:([~^$*|]?=)"([^"]+?)")?$/);
2005
+ const [, key, op, value] = attr.match(/^(.+?)(?:([~^$*|]?=)"([^"]+?)")?$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
1995
2006
  this.key = key;
1996
2007
  this.op = op;
1997
2008
  this.value = value;
@@ -2028,11 +2039,11 @@ class PseudoClassMatcher extends Matcher {
2028
2039
  }
2029
2040
  class Pattern {
2030
2041
  constructor(pattern) {
2031
- const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)(.*)$/);
2042
+ const match = pattern.match(/^([~+\->]?)((?:[*]|[^.#[:]+)?)(.*)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2032
2043
  match.shift(); /* remove full matched string */
2033
2044
  this.selector = pattern;
2034
2045
  this.combinator = parseCombinator(match.shift(), pattern);
2035
- this.tagName = match.shift() || "*";
2046
+ this.tagName = match.shift() || "*"; // eslint-disable-line @typescript-eslint/prefer-nullish-coalescing -- empty string */
2036
2047
  this.pattern = Array.from(splitPattern(match[0]), (it) => this.createMatcher(it));
2037
2048
  }
2038
2049
  match(node, context) {
@@ -2206,6 +2217,21 @@ function isElementNode(node) {
2206
2217
  function isValidTagName(tagName) {
2207
2218
  return Boolean(tagName !== "" && tagName !== "*");
2208
2219
  }
2220
+ function createAdapter(node) {
2221
+ return {
2222
+ closest(selectors) {
2223
+ var _a;
2224
+ return (_a = node.closest(selectors)) === null || _a === void 0 ? void 0 : _a._adapter;
2225
+ },
2226
+ getAttribute(name) {
2227
+ var _a;
2228
+ return (_a = node.getAttribute(name)) === null || _a === void 0 ? void 0 : _a.value;
2229
+ },
2230
+ hasAttribute(name) {
2231
+ return node.hasAttribute(name);
2232
+ },
2233
+ };
2234
+ }
2209
2235
  /**
2210
2236
  * @public
2211
2237
  */
@@ -2214,9 +2240,9 @@ class HtmlElement extends DOMNode {
2214
2240
  const nodeType = tagName ? NodeType.ELEMENT_NODE : NodeType.DOCUMENT_NODE;
2215
2241
  super(nodeType, tagName, location);
2216
2242
  if (!isValidTagName(tagName)) {
2217
- throw new Error(`The tag name provided ('${tagName || ""}') is not a valid name`);
2243
+ throw new Error(`The tag name provided ('${tagName !== null && tagName !== void 0 ? tagName : ""}') is not a valid name`);
2218
2244
  }
2219
- this.tagName = tagName || "#document";
2245
+ this.tagName = tagName !== null && tagName !== void 0 ? tagName : "#document";
2220
2246
  this.parent = parent !== null && parent !== void 0 ? parent : null;
2221
2247
  this.attr = {};
2222
2248
  this.metaElement = meta !== null && meta !== void 0 ? meta : null;
@@ -2224,6 +2250,7 @@ class HtmlElement extends DOMNode {
2224
2250
  this.voidElement = meta ? Boolean(meta.void) : false;
2225
2251
  this.depth = 0;
2226
2252
  this.annotation = null;
2253
+ this._adapter = createAdapter(this);
2227
2254
  if (parent) {
2228
2255
  parent.childNodes.push(this);
2229
2256
  /* calculate depth in domtree */
@@ -2283,7 +2310,7 @@ class HtmlElement extends DOMNode {
2283
2310
  */
2284
2311
  get ariaLabelledby() {
2285
2312
  const attr = this.getAttribute("aria-labelledby");
2286
- if (!attr || !attr.value) {
2313
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value)) {
2287
2314
  return null;
2288
2315
  }
2289
2316
  if (attr.value instanceof DynamicValue) {
@@ -2401,6 +2428,7 @@ class HtmlElement extends DOMNode {
2401
2428
  setMetaProperty(this.metaElement, key, value);
2402
2429
  }
2403
2430
  else {
2431
+ /* eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- technical debt */
2404
2432
  delete this.metaElement[key];
2405
2433
  }
2406
2434
  }
@@ -2676,11 +2704,12 @@ class DOMTree {
2676
2704
  this.active = node;
2677
2705
  }
2678
2706
  popActive() {
2707
+ var _a;
2679
2708
  if (this.active.isRootElement()) {
2680
2709
  /* root element should never be popped, continue as if nothing happened */
2681
2710
  return;
2682
2711
  }
2683
- this.active = this.active.parent || this.root;
2712
+ this.active = (_a = this.active.parent) !== null && _a !== void 0 ? _a : this.root;
2684
2713
  }
2685
2714
  getActive() {
2686
2715
  return this.active;
@@ -2716,6 +2745,7 @@ const allowedKeys = ["exclude"];
2716
2745
  *
2717
2746
  * @public
2718
2747
  */
2748
+ /* eslint-disable-next-line @typescript-eslint/no-extraneous-class -- technical debt, should probably be plain functions maybe in an object */
2719
2749
  class Validator {
2720
2750
  /**
2721
2751
  * Test if element is used in a proper context.
@@ -2757,7 +2787,7 @@ class Validator {
2757
2787
  return false;
2758
2788
  }
2759
2789
  // Check if the rule has a quantifier
2760
- const [, category, quantifier] = rule.match(/^(@?.*?)([?*]?)$/);
2790
+ const [, category, quantifier] = rule.match(/^(@?.*?)([?*]?)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2761
2791
  const limit = category && quantifier && parseQuantifier(quantifier);
2762
2792
  if (limit) {
2763
2793
  const siblings = children.filter((cur) => Validator.validatePermittedCategory(cur, rule, true));
@@ -2803,6 +2833,7 @@ class Validator {
2803
2833
  * In both of these cases no error should be reported. */
2804
2834
  const orderSpecified = rules.find((cur) => Validator.validatePermittedCategory(node, cur, true));
2805
2835
  if (orderSpecified) {
2836
+ /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt, should never happen */
2806
2837
  cb(node, prev);
2807
2838
  return false;
2808
2839
  }
@@ -2943,7 +2974,7 @@ class Validator {
2943
2974
  */
2944
2975
  /* eslint-disable-next-line complexity -- rule does not like switch */
2945
2976
  static validatePermittedCategory(node, category, defaultMatch) {
2946
- const [, rawCategory] = category.match(/^(@?.*?)([?*]?)$/);
2977
+ const [, rawCategory] = category.match(/^(@?.*?)([?*]?)$/); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- will always match
2947
2978
  /* match tagName when an explicit name is given */
2948
2979
  if (!rawCategory.startsWith("@")) {
2949
2980
  return node.tagName === rawCategory;
@@ -2968,9 +2999,9 @@ class Validator {
2968
2999
  case "@interactive":
2969
3000
  return node.meta.interactive;
2970
3001
  case "@script":
2971
- return node.meta.scriptSupporting;
3002
+ return Boolean(node.meta.scriptSupporting);
2972
3003
  case "@form":
2973
- return node.meta.form;
3004
+ return Boolean(node.meta.form);
2974
3005
  default:
2975
3006
  throw new Error(`Invalid content category "${category}"`);
2976
3007
  }
@@ -3155,10 +3186,12 @@ var configurationSchema = {
3155
3186
  properties: properties
3156
3187
  };
3157
3188
 
3158
- var TRANSFORMER_API;
3159
- (function (TRANSFORMER_API) {
3160
- TRANSFORMER_API[TRANSFORMER_API["VERSION"] = 1] = "VERSION";
3161
- })(TRANSFORMER_API || (TRANSFORMER_API = {}));
3189
+ /**
3190
+ * @internal
3191
+ */
3192
+ const TRANSFORMER_API = {
3193
+ VERSION: 1,
3194
+ };
3162
3195
 
3163
3196
  /**
3164
3197
  * @public
@@ -3405,7 +3438,7 @@ function classifyNodeText(node, options = {}) {
3405
3438
  const { accessible = false, ignoreHiddenRoot = false } = options;
3406
3439
  const cacheKey = getCachekey(options);
3407
3440
  if (node.cacheExists(cacheKey)) {
3408
- return node.cacheGet(cacheKey);
3441
+ return node.cacheGet(cacheKey); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- has/get combo
3409
3442
  }
3410
3443
  if (!ignoreHiddenRoot && isHTMLHidden(node)) {
3411
3444
  return node.cacheSet(cacheKey, TextClassification.EMPTY_TEXT);
@@ -3453,8 +3486,12 @@ function findTextNodes(node, options) {
3453
3486
 
3454
3487
  function hasAltText(image) {
3455
3488
  const alt = image.getAttribute("alt");
3456
- /* missing or boolean */
3457
- if (alt === null || alt.value === null) {
3489
+ /* missing attribute */
3490
+ if (!alt) {
3491
+ return false;
3492
+ }
3493
+ /* (incorrectly) set as boolean value */
3494
+ if (alt.value === null) {
3458
3495
  return false;
3459
3496
  }
3460
3497
  return alt.isDynamic || alt.value.toString() !== "";
@@ -3462,8 +3499,12 @@ function hasAltText(image) {
3462
3499
 
3463
3500
  function hasAriaLabel(node) {
3464
3501
  const label = node.getAttribute("aria-label");
3465
- /* missing or boolean */
3466
- if (label === null || label.value === null) {
3502
+ /* missing attribute */
3503
+ if (!label) {
3504
+ return false;
3505
+ }
3506
+ /* (incorrectly) set as boolean value */
3507
+ if (label.value === null) {
3467
3508
  return false;
3468
3509
  }
3469
3510
  return label.isDynamic || label.value.toString() !== "";
@@ -3544,7 +3585,7 @@ class Rule {
3544
3585
  this.options = options;
3545
3586
  this.enabled = true;
3546
3587
  this.blockers = [];
3547
- this.severity = 0;
3588
+ this.severity = Severity.DISABLED;
3548
3589
  this.name = "";
3549
3590
  }
3550
3591
  getSeverity() {
@@ -3697,13 +3738,14 @@ class Rule {
3697
3738
  }
3698
3739
  }
3699
3740
  findLocation(src) {
3741
+ var _a, _b;
3700
3742
  if (src.location) {
3701
3743
  return src.location;
3702
3744
  }
3703
- if (src.event && src.event.location) {
3745
+ if ((_a = src.event) === null || _a === void 0 ? void 0 : _a.location) {
3704
3746
  return src.event.location;
3705
3747
  }
3706
- if (src.node && src.node.location) {
3748
+ if ((_b = src.node) === null || _b === void 0 ? void 0 : _b.location) {
3707
3749
  return src.node.location;
3708
3750
  }
3709
3751
  return {};
@@ -3876,7 +3918,8 @@ class AllowedLinks extends Rule {
3876
3918
  };
3877
3919
  }
3878
3920
  documentation(context) {
3879
- const message = description[context] || "This link type is not allowed by current configuration";
3921
+ var _a;
3922
+ const message = (_a = description[context]) !== null && _a !== void 0 ? _a : "This link type is not allowed by current configuration";
3880
3923
  return {
3881
3924
  description: message,
3882
3925
  url: "https://html-validate.org/rules/allowed-links.html",
@@ -4140,7 +4183,7 @@ function isValidUsage(target, meta) {
4140
4183
  return true;
4141
4184
  }
4142
4185
  /* interactive and labelable elements are valid */
4143
- if (meta.interactive || meta.labelable) {
4186
+ if (Boolean(meta.interactive) || Boolean(meta.labelable)) {
4144
4187
  return true;
4145
4188
  }
4146
4189
  return false;
@@ -4175,7 +4218,7 @@ class AriaLabelMisuse extends Rule {
4175
4218
  }
4176
4219
  validateElement(target) {
4177
4220
  const attr = target.getAttribute("aria-label");
4178
- if (!attr || !attr.value || attr.valueMatches("", false)) {
4221
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value) || attr.valueMatches("", false)) {
4179
4222
  return;
4180
4223
  }
4181
4224
  /* ignore elements without meta */
@@ -4906,7 +4949,7 @@ class AttributeAllowedValues extends Rule {
4906
4949
  const meta = node.meta;
4907
4950
  /* ignore rule if element has no meta or meta does not specify attribute
4908
4951
  * allowed values */
4909
- if (!meta || !meta.attributes)
4952
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
4910
4953
  return;
4911
4954
  for (const attr of node.attributes) {
4912
4955
  if (Validator.validateAttribute(attr, meta.attributes)) {
@@ -4974,7 +5017,7 @@ class AttributeBooleanStyle extends Rule {
4974
5017
  const meta = node.meta;
4975
5018
  /* ignore rule if element has no meta or meta does not specify attribute
4976
5019
  * allowed values */
4977
- if (!meta || !meta.attributes)
5020
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
4978
5021
  return;
4979
5022
  /* check all boolean attributes */
4980
5023
  for (const attr of node.attributes) {
@@ -5055,7 +5098,7 @@ class AttributeEmptyStyle extends Rule {
5055
5098
  const meta = node.meta;
5056
5099
  /* ignore rule if element has no meta or meta does not specify attribute
5057
5100
  * allowed values */
5058
- if (!meta || !meta.attributes)
5101
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes))
5059
5102
  return;
5060
5103
  /* check all boolean attributes */
5061
5104
  for (const attr of node.attributes) {
@@ -5143,10 +5186,10 @@ class AttributeMisuse extends Rule {
5143
5186
  });
5144
5187
  }
5145
5188
  validateAttr(node, attr, meta) {
5146
- if (!meta || !meta.allowed) {
5189
+ if (!(meta === null || meta === void 0 ? void 0 : meta.allowed)) {
5147
5190
  return;
5148
5191
  }
5149
- const details = meta.allowed(node, attr);
5192
+ const details = meta.allowed(node._adapter, attr.value);
5150
5193
  if (details) {
5151
5194
  this.report({
5152
5195
  node,
@@ -5817,7 +5860,7 @@ class ElementPermittedOccurrences extends Rule {
5817
5860
  this.on("dom:ready", (event) => {
5818
5861
  const doc = event.document;
5819
5862
  doc.visitDepthFirst((node) => {
5820
- if (!node || !node.meta) {
5863
+ if (!(node === null || node === void 0 ? void 0 : node.meta)) {
5821
5864
  return;
5822
5865
  }
5823
5866
  const rules = node.meta.permittedContent;
@@ -6022,7 +6065,7 @@ class ElementRequiredAttributes extends Rule {
6022
6065
  const node = event.previous;
6023
6066
  const meta = node.meta;
6024
6067
  /* handle missing metadata and missing attributes */
6025
- if (!meta || !meta.attributes) {
6068
+ if (!(meta === null || meta === void 0 ? void 0 : meta.attributes)) {
6026
6069
  return;
6027
6070
  }
6028
6071
  for (const [key, attr] of Object.entries(meta.attributes)) {
@@ -6334,7 +6377,7 @@ class FormDupName extends Rule {
6334
6377
  const meta = this.getMetaFor(tagName);
6335
6378
  /* istanbul ignore if: the earlier check for getTagsWithProperty ensures
6336
6379
  * these will actually be set so this is just an untestable fallback */
6337
- if (!meta || !meta.formAssociated) {
6380
+ if (!(meta === null || meta === void 0 ? void 0 : meta.formAssociated)) {
6338
6381
  return false;
6339
6382
  }
6340
6383
  return meta.formAssociated.listed;
@@ -6368,7 +6411,7 @@ const defaults$h = {
6368
6411
  minInitialRank: "h1",
6369
6412
  sectioningRoots: ["dialog", '[role="dialog"]', '[role="alertdialog"]'],
6370
6413
  };
6371
- function isRelevant$3(event) {
6414
+ function isRelevant$4(event) {
6372
6415
  const node = event.target;
6373
6416
  return Boolean(node.meta && node.meta.heading);
6374
6417
  }
@@ -6436,7 +6479,7 @@ class HeadingLevel extends Rule {
6436
6479
  };
6437
6480
  }
6438
6481
  setup() {
6439
- this.on("tag:start", isRelevant$3, (event) => {
6482
+ this.on("tag:start", isRelevant$4, (event) => {
6440
6483
  this.onTagStart(event);
6441
6484
  });
6442
6485
  this.on("tag:ready", (event) => {
@@ -6582,7 +6625,7 @@ class IdPattern extends Rule {
6582
6625
  }
6583
6626
  setup() {
6584
6627
  this.on("attr", (event) => {
6585
- var _a;
6628
+ var _a, _b;
6586
6629
  if (event.key.toLowerCase() !== "id") {
6587
6630
  return;
6588
6631
  }
@@ -6590,8 +6633,8 @@ class IdPattern extends Rule {
6590
6633
  if (event.value instanceof DynamicValue) {
6591
6634
  return;
6592
6635
  }
6593
- if (!event.value || !event.value.match(this.pattern)) {
6594
- const value = (_a = event.value) !== null && _a !== void 0 ? _a : "";
6636
+ if (!((_a = event.value) === null || _a === void 0 ? void 0 : _a.match(this.pattern))) {
6637
+ const value = (_b = event.value) !== null && _b !== void 0 ? _b : "";
6595
6638
  const pattern = this.pattern.toString();
6596
6639
  const message = `ID "${value}" does not match required pattern "${pattern}"`;
6597
6640
  this.report(event.target, message, event.valueLocation);
@@ -7019,7 +7062,7 @@ class MetaRefresh extends Rule {
7019
7062
  }
7020
7063
  /* ensure content attribute is set */
7021
7064
  const content = target.getAttribute("content");
7022
- if (!content || !content.value || content.isDynamic) {
7065
+ if (!(content === null || content === void 0 ? void 0 : content.value) || content.isDynamic) {
7023
7066
  return;
7024
7067
  }
7025
7068
  /* ensure content attribute is valid */
@@ -7096,7 +7139,7 @@ class MapDupName extends Rule {
7096
7139
  }
7097
7140
  }
7098
7141
 
7099
- function isRelevant$2(event) {
7142
+ function isRelevant$3(event) {
7100
7143
  return event.target.is("map");
7101
7144
  }
7102
7145
  function hasStaticValue(attr) {
@@ -7110,7 +7153,7 @@ class MapIdName extends Rule {
7110
7153
  };
7111
7154
  }
7112
7155
  setup() {
7113
- this.on("tag:ready", isRelevant$2, (event) => {
7156
+ this.on("tag:ready", isRelevant$3, (event) => {
7114
7157
  var _a;
7115
7158
  const { target } = event;
7116
7159
  const id = target.getAttribute("id");
@@ -7298,7 +7341,7 @@ class NoDeprecatedAttr extends Rule {
7298
7341
  if (meta === null) {
7299
7342
  return;
7300
7343
  }
7301
- const metaAttribute = meta.attributes && meta.attributes[attr];
7344
+ const metaAttribute = meta.attributes[attr];
7302
7345
  if (!metaAttribute) {
7303
7346
  return;
7304
7347
  }
@@ -7374,11 +7417,11 @@ class NoDupID extends Rule {
7374
7417
  const { document } = event;
7375
7418
  const existing = new Set();
7376
7419
  const elements = document.querySelectorAll("[id]");
7377
- const relevant = elements.filter(isRelevant$1);
7420
+ const relevant = elements.filter(isRelevant$2);
7378
7421
  for (const el of relevant) {
7379
7422
  const attr = el.getAttribute("id");
7380
7423
  /* istanbul ignore next: this has already been tested in isRelevant once but for type-safety it is checked again */
7381
- if (!attr || !attr.value) {
7424
+ if (!(attr === null || attr === void 0 ? void 0 : attr.value)) {
7382
7425
  continue;
7383
7426
  }
7384
7427
  const id = attr.value.toString();
@@ -7390,7 +7433,7 @@ class NoDupID extends Rule {
7390
7433
  });
7391
7434
  }
7392
7435
  }
7393
- function isRelevant$1(element) {
7436
+ function isRelevant$2(element) {
7394
7437
  const attr = element.getAttribute("id");
7395
7438
  /* istanbul ignore next: can not really happen as querySelector will only return elements with id present */
7396
7439
  if (!attr) {
@@ -7407,6 +7450,41 @@ function isRelevant$1(element) {
7407
7450
  return true;
7408
7451
  }
7409
7452
 
7453
+ function isRelevant$1(event) {
7454
+ return event.target.is("button");
7455
+ }
7456
+ class NoImplicitButtonType extends Rule {
7457
+ documentation() {
7458
+ return {
7459
+ description: [
7460
+ "`<button>` is missing required `type` attribute",
7461
+ "",
7462
+ "When the `type` attribute is omitted it defaults to `submit`.",
7463
+ "Submit buttons are triggered when a keyboard user presses <kbd>Enter</kbd>.",
7464
+ "",
7465
+ "As this may or may not be inteded this rule enforces that the `type` attribute be explicitly set to one of the valid types:",
7466
+ "",
7467
+ "- `button` - a generic button.",
7468
+ "- `submit` - a submit button.",
7469
+ "- `reset`- a button to reset form fields.",
7470
+ ].join("\n"),
7471
+ url: "https://html-validate.org/rules/no-implicit-button-type.html",
7472
+ };
7473
+ }
7474
+ setup() {
7475
+ this.on("element:ready", isRelevant$1, (event) => {
7476
+ const { target } = event;
7477
+ const attr = target.getAttribute("type");
7478
+ if (!attr) {
7479
+ this.report({
7480
+ node: event.target,
7481
+ message: `<button> is missing required "type" attribute`,
7482
+ });
7483
+ }
7484
+ });
7485
+ }
7486
+ }
7487
+
7410
7488
  class NoImplicitClose extends Rule {
7411
7489
  documentation() {
7412
7490
  return {
@@ -7512,11 +7590,12 @@ class NoInlineStyle extends Rule {
7512
7590
  });
7513
7591
  }
7514
7592
  isRelevant(event) {
7593
+ var _a;
7515
7594
  if (event.key !== "style") {
7516
7595
  return false;
7517
7596
  }
7518
7597
  const { include, exclude } = this.options;
7519
- const key = event.originalAttribute || event.key;
7598
+ const key = (_a = event.originalAttribute) !== null && _a !== void 0 ? _a : event.key;
7520
7599
  /* ignore attributes not present in "include" */
7521
7600
  if (include && !include.includes(key)) {
7522
7601
  return false;
@@ -7710,7 +7789,8 @@ class NoRawCharacters extends Rule {
7710
7789
  if (event.quote) {
7711
7790
  return;
7712
7791
  }
7713
- this.findRawChars(event.target, event.value.toString(), event.valueLocation, unquotedAttrRegexp);
7792
+ 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
7793
+ unquotedAttrRegexp);
7714
7794
  });
7715
7795
  }
7716
7796
  /**
@@ -7924,7 +8004,7 @@ class NoSelfClosing extends Rule {
7924
8004
  function isRelevant(node, options) {
7925
8005
  /* tags in XML namespaces are relevant only if ignoreXml is false, in which
7926
8006
  * case assume all xml elements must not be self-closed */
7927
- if (node.tagName && node.tagName.match(xmlns)) {
8007
+ if (node.tagName.match(xmlns)) {
7928
8008
  return !options.ignoreXML;
7929
8009
  }
7930
8010
  /* nodes with missing metadata is assumed relevant */
@@ -8130,16 +8210,12 @@ class PreferButton extends Rule {
8130
8210
  };
8131
8211
  }
8132
8212
  documentation(context) {
8133
- const doc = {
8134
- description: `Prefer to use the generic \`<button>\` element instead of \`<input>\`.`,
8213
+ const src = `<input type="${context.type}">`;
8214
+ const dst = replacement[context.type] || `<button>`;
8215
+ return {
8216
+ description: `Prefer to use \`${dst}\` instead of \`"${src}\`.`,
8135
8217
  url: "https://html-validate.org/rules/prefer-button.html",
8136
8218
  };
8137
- if (context) {
8138
- const src = `<input type="${context.type}">`;
8139
- const dst = replacement[context.type] || `<button>`;
8140
- doc.description = `Prefer to use \`${dst}\` instead of \`"${src}\`.`;
8141
- }
8142
- return doc;
8143
8219
  }
8144
8220
  setup() {
8145
8221
  this.on("attr", (event) => {
@@ -8238,14 +8314,10 @@ class PreferNativeElement extends Rule {
8238
8314
  };
8239
8315
  }
8240
8316
  documentation(context) {
8241
- const doc = {
8242
- description: `Instead of using WAI-ARIA roles prefer to use the native HTML elements.`,
8317
+ return {
8318
+ description: `Instead of using the WAI-ARIA role "${context.role}" prefer to use the native <${context.replacement}> element.`,
8243
8319
  url: "https://html-validate.org/rules/prefer-native-element.html",
8244
8320
  };
8245
- if (context) {
8246
- doc.description = `Instead of using the WAI-ARIA role "${context.role}" prefer to use the native <${context.replacement}> element.`;
8247
- }
8248
- return doc;
8249
8321
  }
8250
8322
  setup() {
8251
8323
  const { mapping } = this.options;
@@ -8286,7 +8358,7 @@ class PreferNativeElement extends Rule {
8286
8358
  }
8287
8359
  getLocation(event) {
8288
8360
  const begin = event.location;
8289
- const end = event.valueLocation;
8361
+ 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
8290
8362
  const quote = event.quote ? 1 : 0;
8291
8363
  const size = end.offset + end.size - begin.offset + quote;
8292
8364
  return {
@@ -8360,7 +8432,7 @@ class RequireCSPNonce extends Rule {
8360
8432
  const { tags } = this.options;
8361
8433
  const node = event.previous;
8362
8434
  /* ignore other tags */
8363
- if (!node || !tags.includes(node.tagName)) {
8435
+ if (!tags.includes(node.tagName)) {
8364
8436
  return;
8365
8437
  }
8366
8438
  /* ignore if nonce is set to non-empty value (or dynamic) */
@@ -8452,7 +8524,10 @@ class RequireSri extends Rule {
8452
8524
  }
8453
8525
  needSri(node) {
8454
8526
  const attr = this.elementSourceAttr(node);
8455
- if (!attr || attr.value === null || attr.value === "" || attr.isDynamic) {
8527
+ if (!attr) {
8528
+ return false;
8529
+ }
8530
+ if (attr.value === null || attr.value === "" || attr.isDynamic) {
8456
8531
  return false;
8457
8532
  }
8458
8533
  const url = attr.value.toString();
@@ -8509,7 +8584,7 @@ class ScriptType extends Rule {
8509
8584
  setup() {
8510
8585
  this.on("tag:end", (event) => {
8511
8586
  const node = event.previous;
8512
- if (!node || node.tagName !== "script") {
8587
+ if (node.tagName !== "script") {
8513
8588
  return;
8514
8589
  }
8515
8590
  const attr = node.getAttribute("type");
@@ -8790,18 +8865,16 @@ class TextContent extends Rule {
8790
8865
  description: `The textual content for this element is not valid.`,
8791
8866
  url: "https://html-validate.org/rules/text-content.html",
8792
8867
  };
8793
- if (context === null || context === void 0 ? void 0 : context.textContent) {
8794
- switch (context.textContent) {
8795
- case TextContent$1.NONE:
8796
- doc.description = `The \`<${context.tagName}>\` element must not have textual content.`;
8797
- break;
8798
- case TextContent$1.REQUIRED:
8799
- doc.description = `The \`<${context.tagName}>\` element must have textual content.`;
8800
- break;
8801
- case TextContent$1.ACCESSIBLE:
8802
- doc.description = `The \`<${context.tagName}>\` element must have accessible text.`;
8803
- break;
8804
- }
8868
+ switch (context.textContent) {
8869
+ case TextContent$1.NONE:
8870
+ doc.description = `The \`<${context.tagName}>\` element must not have textual content.`;
8871
+ break;
8872
+ case TextContent$1.REQUIRED:
8873
+ doc.description = `The \`<${context.tagName}>\` element must have textual content.`;
8874
+ break;
8875
+ case TextContent$1.ACCESSIBLE:
8876
+ doc.description = `The \`<${context.tagName}>\` element must have accessible text.`;
8877
+ break;
8805
8878
  }
8806
8879
  return doc;
8807
8880
  }
@@ -9162,20 +9235,16 @@ class VoidStyle extends Rule {
9162
9235
  };
9163
9236
  }
9164
9237
  documentation(context) {
9165
- const doc = {
9166
- description: "The current configuration requires a specific style for ending void elements.",
9238
+ const [desc, end] = styleDescription(context.style);
9239
+ return {
9240
+ description: `The current configuration requires void elements to ${desc}, use <${context.tagName}${end}> instead.`,
9167
9241
  url: "https://html-validate.org/rules/void-style.html",
9168
9242
  };
9169
- if (context) {
9170
- const [desc, end] = styleDescription(context.style);
9171
- doc.description = `The current configuration requires void elements to ${desc}, use <${context.tagName}${end}> instead.`;
9172
- }
9173
- return doc;
9174
9243
  }
9175
9244
  setup() {
9176
9245
  this.on("tag:end", (event) => {
9177
9246
  const active = event.previous; // The current active element (that is, the current element on the stack)
9178
- if (active && active.meta) {
9247
+ if (active.meta) {
9179
9248
  this.validateActive(active);
9180
9249
  }
9181
9250
  });
@@ -9412,7 +9481,8 @@ class H37 extends Rule {
9412
9481
  return;
9413
9482
  }
9414
9483
  /* validate plain alt-attribute */
9415
- if (node.getAttributeValue("alt") || (node.hasAttribute("alt") && this.options.allowEmpty)) {
9484
+ if (Boolean(node.getAttributeValue("alt")) ||
9485
+ Boolean(node.hasAttribute("alt") && this.options.allowEmpty)) {
9416
9486
  return;
9417
9487
  }
9418
9488
  /* validate if any non-empty alias is present */
@@ -9589,6 +9659,7 @@ const bundledRules = {
9589
9659
  "no-dup-attr": NoDupAttr,
9590
9660
  "no-dup-class": NoDupClass,
9591
9661
  "no-dup-id": NoDupID,
9662
+ "no-implicit-button-type": NoImplicitButtonType,
9592
9663
  "no-implicit-close": NoImplicitClose,
9593
9664
  "no-inline-style": NoInlineStyle,
9594
9665
  "no-missing-references": NoMissingReferences,
@@ -9635,6 +9706,7 @@ const config$4 = {
9635
9706
  "multiple-labeled-controls": "error",
9636
9707
  "no-autoplay": ["error", { include: ["audio", "video"] }],
9637
9708
  "no-dup-id": "error",
9709
+ "no-implicit-button-type": "error",
9638
9710
  "no-redundant-aria-label": "error",
9639
9711
  "no-redundant-for": "error",
9640
9712
  "no-redundant-role": "error",
@@ -9714,6 +9786,7 @@ const config$1 = {
9714
9786
  "no-dup-attr": "error",
9715
9787
  "no-dup-class": "error",
9716
9788
  "no-dup-id": "error",
9789
+ "no-implicit-button-type": "error",
9717
9790
  "no-implicit-close": "error",
9718
9791
  "no-inline-style": "error",
9719
9792
  "no-multiple-main": "error",
@@ -9845,7 +9918,7 @@ class ResolvedConfig {
9845
9918
  * @returns A list of transformed sources ready for validation.
9846
9919
  */
9847
9920
  transformSource(source, filename) {
9848
- const transformer = this.findTransformer(filename || source.filename);
9921
+ const transformer = this.findTransformer(filename !== null && filename !== void 0 ? filename : source.filename);
9849
9922
  const context = {
9850
9923
  hasChain: (filename) => {
9851
9924
  return !!this.findTransformer(filename);
@@ -9857,9 +9930,10 @@ class ResolvedConfig {
9857
9930
  if (transformer) {
9858
9931
  try {
9859
9932
  return Array.from(transformer.fn.call(context, source), (cur) => {
9933
+ var _a;
9860
9934
  /* keep track of which transformers that has been run on this source
9861
9935
  * by appending this entry to the transformedBy array */
9862
- cur.transformedBy = cur.transformedBy || [];
9936
+ (_a = cur.transformedBy) !== null && _a !== void 0 ? _a : (cur.transformedBy = []);
9863
9937
  cur.transformedBy.push(transformer.name);
9864
9938
  return cur;
9865
9939
  });
@@ -10031,7 +10105,7 @@ function mergeInternal(base, rhs) {
10031
10105
  }
10032
10106
  /* root property is merged with boolean "or" since it should always be truthy
10033
10107
  * if any config has it set. */
10034
- const root = base.root || rhs.root;
10108
+ const root = Boolean(base.root) || Boolean(rhs.root);
10035
10109
  if (root) {
10036
10110
  dst.root = root;
10037
10111
  }
@@ -10118,7 +10192,7 @@ class Config {
10118
10192
  * @internal
10119
10193
  */
10120
10194
  constructor(resolvers, options) {
10121
- var _a;
10195
+ var _a, _b;
10122
10196
  this.transformers = [];
10123
10197
  const initial = {
10124
10198
  extends: [],
@@ -10131,18 +10205,18 @@ class Config {
10131
10205
  this.initialized = false;
10132
10206
  this.resolvers = toArray(resolvers);
10133
10207
  /* load plugins */
10134
- this.plugins = this.loadPlugins(this.config.plugins || []);
10208
+ this.plugins = this.loadPlugins((_a = this.config.plugins) !== null && _a !== void 0 ? _a : []);
10135
10209
  this.configurations = this.loadConfigurations(this.plugins);
10136
10210
  this.extendMeta(this.plugins);
10137
10211
  /* process extended configs */
10138
- this.config = this.extendConfig((_a = this.config.extends) !== null && _a !== void 0 ? _a : []);
10212
+ this.config = this.extendConfig((_b = this.config.extends) !== null && _b !== void 0 ? _b : []);
10139
10213
  /* reset extends as we already processed them, this prevents the next config
10140
10214
  * from reapplying config from extended config as well as duplicate entries
10141
10215
  * when merging arrays */
10142
10216
  this.config.extends = [];
10143
10217
  /* rules explicitly set by passed options should have precedence over any
10144
10218
  * extended rules, not the other way around. */
10145
- if (options && options.rules) {
10219
+ if (options === null || options === void 0 ? void 0 : options.rules) {
10146
10220
  this.config = mergeInternal(this.config, { rules: options.rules });
10147
10221
  }
10148
10222
  }
@@ -10155,11 +10229,12 @@ class Config {
10155
10229
  * @public
10156
10230
  */
10157
10231
  init() {
10232
+ var _a;
10158
10233
  if (this.initialized) {
10159
10234
  return;
10160
10235
  }
10161
10236
  /* precompile transform patterns */
10162
- this.transformers = this.precompileTransformers(this.config.transform || {});
10237
+ this.transformers = this.precompileTransformers((_a = this.config.transform) !== null && _a !== void 0 ? _a : {});
10163
10238
  this.initialized = true;
10164
10239
  }
10165
10240
  /**
@@ -10186,7 +10261,7 @@ class Config {
10186
10261
  for (const entry of entries) {
10187
10262
  let extended;
10188
10263
  if (this.configurations.has(entry)) {
10189
- extended = this.configurations.get(entry);
10264
+ extended = this.configurations.get(entry); // eslint-disable-line @typescript-eslint/no-non-null-assertion -- map has/get combo
10190
10265
  }
10191
10266
  else {
10192
10267
  extended = Config.fromFile(this.resolvers, entry).config;
@@ -10201,12 +10276,13 @@ class Config {
10201
10276
  * @internal
10202
10277
  */
10203
10278
  getMetaTable() {
10279
+ var _a;
10204
10280
  /* use cached table if it exists */
10205
10281
  if (this.metaTable) {
10206
10282
  return this.metaTable;
10207
10283
  }
10208
10284
  const metaTable = new MetaTable();
10209
- const source = this.config.elements || ["html5"];
10285
+ const source = (_a = this.config.elements) !== null && _a !== void 0 ? _a : ["html5"];
10210
10286
  /* extend validation schema from plugins */
10211
10287
  for (const plugin of this.getPlugins()) {
10212
10288
  if (plugin.elementSchema) {
@@ -10304,6 +10380,7 @@ class Config {
10304
10380
  });
10305
10381
  }
10306
10382
  loadConfigurations(plugins) {
10383
+ var _a;
10307
10384
  const configs = new Map();
10308
10385
  /* builtin presets */
10309
10386
  for (const [name, config] of Object.entries(Presets)) {
@@ -10312,7 +10389,7 @@ class Config {
10312
10389
  }
10313
10390
  /* presets from plugins */
10314
10391
  for (const plugin of plugins) {
10315
- for (const [name, config] of Object.entries(plugin.configs || {})) {
10392
+ for (const [name, config] of Object.entries((_a = plugin.configs) !== null && _a !== void 0 ? _a : {})) {
10316
10393
  if (!config)
10317
10394
  continue;
10318
10395
  Config.validate(config, name);
@@ -10677,10 +10754,11 @@ class Parser {
10677
10754
  * stack when is allowed to omit.
10678
10755
  */
10679
10756
  closeOptional(token) {
10757
+ var _a;
10680
10758
  /* if the element doesn't have metadata it cannot have optional end
10681
10759
  * tags. Period. */
10682
10760
  const active = this.dom.getActive();
10683
- if (!(active.meta && active.meta.implicitClosed)) {
10761
+ if (!((_a = active.meta) === null || _a === void 0 ? void 0 : _a.implicitClosed)) {
10684
10762
  return false;
10685
10763
  }
10686
10764
  const tagName = token.data[2];
@@ -10832,9 +10910,10 @@ class Parser {
10832
10910
  }
10833
10911
  }
10834
10912
  processElement(node, source) {
10913
+ var _a;
10835
10914
  /* enable cache on node now that it is fully constructed */
10836
10915
  node.cacheEnable();
10837
- if (source.hooks && source.hooks.processElement) {
10916
+ if ((_a = source.hooks) === null || _a === void 0 ? void 0 : _a.processElement) {
10838
10917
  const processElement = source.hooks.processElement;
10839
10918
  const metaTable = this.metaTable;
10840
10919
  const context = {
@@ -10901,6 +10980,7 @@ class Parser {
10901
10980
  * @internal
10902
10981
  */
10903
10982
  consumeAttribute(source, node, token, next) {
10983
+ var _a;
10904
10984
  const keyLocation = this.getAttributeKeyLocation(token);
10905
10985
  const valueLocation = this.getAttributeValueLocation(next);
10906
10986
  const location = this.getAttributeLocation(token, next);
@@ -10919,7 +10999,7 @@ class Parser {
10919
10999
  * data right away but a transformer may override it to allow aliasing
10920
11000
  * attributes, e.g ng-attr-foo or v-bind:foo */
10921
11001
  let processAttribute = (attr) => [attr];
10922
- if (source.hooks && source.hooks.processAttribute) {
11002
+ if ((_a = source.hooks) === null || _a === void 0 ? void 0 : _a.processAttribute) {
10923
11003
  processAttribute = source.hooks.processAttribute;
10924
11004
  }
10925
11005
  /* handle deprecated callbacks */
@@ -11269,14 +11349,15 @@ class Reporter {
11269
11349
  const report = {
11270
11350
  valid: this.isValid(),
11271
11351
  results: Object.keys(this.result).map((filePath) => {
11352
+ var _a;
11272
11353
  const messages = Array.from(this.result[filePath], freeze).sort(messageSort);
11273
- const source = (sources || []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11354
+ const source = (sources !== null && sources !== void 0 ? sources : []).find((source) => { var _a; return filePath === ((_a = source.filename) !== null && _a !== void 0 ? _a : ""); });
11274
11355
  return {
11275
11356
  filePath,
11276
11357
  messages,
11277
11358
  errorCount: countErrors(messages),
11278
11359
  warningCount: countWarnings(messages),
11279
- source: source ? source.originalData || source.data : null,
11360
+ source: source ? (_a = source.originalData) !== null && _a !== void 0 ? _a : source.data : null,
11280
11361
  };
11281
11362
  }),
11282
11363
  errorCount: 0,
@@ -11294,10 +11375,10 @@ class Reporter {
11294
11375
  }
11295
11376
  }
11296
11377
  function countErrors(messages) {
11297
- return messages.filter((m) => m.severity === Severity.ERROR).length;
11378
+ return messages.filter((m) => m.severity === Number(Severity.ERROR)).length;
11298
11379
  }
11299
11380
  function countWarnings(messages) {
11300
- return messages.filter((m) => m.severity === Severity.WARN).length;
11381
+ return messages.filter((m) => m.severity === Number(Severity.WARN)).length;
11301
11382
  }
11302
11383
  function sumErrors(results) {
11303
11384
  return results.reduce((sum, result) => {
@@ -11642,9 +11723,10 @@ class Engine {
11642
11723
  * between rule name and its constructor.
11643
11724
  */
11644
11725
  initRules(config) {
11726
+ var _a;
11645
11727
  const availableRules = {};
11646
11728
  for (const plugin of config.getPlugins()) {
11647
- for (const [name, rule] of Object.entries(plugin.rules || {})) {
11729
+ for (const [name, rule] of Object.entries((_a = plugin.rules) !== null && _a !== void 0 ? _a : {})) {
11648
11730
  if (!rule)
11649
11731
  continue;
11650
11732
  availableRules[name] = rule;
@@ -11747,7 +11829,7 @@ class StaticConfigLoader extends ConfigLoader {
11747
11829
  }
11748
11830
  }
11749
11831
  getConfigFor(_handle, configOverride) {
11750
- const override = this.loadFromObject(configOverride || {});
11832
+ const override = this.loadFromObject(configOverride !== null && configOverride !== void 0 ? configOverride : {});
11751
11833
  if (override.isRootFound()) {
11752
11834
  override.init();
11753
11835
  return override.resolve();
@@ -11791,6 +11873,7 @@ class HtmlValidate {
11791
11873
  const [loader, config] = arg instanceof ConfigLoader ? [arg, undefined] : [undefined, arg];
11792
11874
  this.configLoader = loader !== null && loader !== void 0 ? loader : new StaticConfigLoader(config);
11793
11875
  }
11876
+ /* eslint-enable @typescript-eslint/unified-signatures */
11794
11877
  validateString(str, arg1, arg2, arg3) {
11795
11878
  const filename = typeof arg1 === "string" ? arg1 : "inline";
11796
11879
  const options = isConfigData(arg1) ? arg1 : isConfigData(arg2) ? arg2 : undefined;
@@ -11805,6 +11888,7 @@ class HtmlValidate {
11805
11888
  };
11806
11889
  return this.validateSource(source, options);
11807
11890
  }
11891
+ /* eslint-enable @typescript-eslint/unified-signatures */
11808
11892
  validateStringSync(str, arg1, arg2, arg3) {
11809
11893
  const filename = typeof arg1 === "string" ? arg1 : "inline";
11810
11894
  const options = isConfigData(arg1) ? arg1 : isConfigData(arg2) ? arg2 : undefined;
@@ -12076,7 +12160,7 @@ class HtmlValidate {
12076
12160
  * contextual details and suggestions.
12077
12161
  */
12078
12162
  async getRuleDocumentation(ruleId, config = null, context = null) {
12079
- const c = config || this.getConfigFor("inline");
12163
+ const c = config !== null && config !== void 0 ? config : this.getConfigFor("inline");
12080
12164
  const engine = new Engine(await c, Parser);
12081
12165
  return engine.getRuleDocumentation({ ruleId, context });
12082
12166
  }
@@ -12105,7 +12189,7 @@ class HtmlValidate {
12105
12189
  * contextual details and suggestions.
12106
12190
  */
12107
12191
  getRuleDocumentationSync(ruleId, config = null, context = null) {
12108
- const c = config || this.getConfigForSync("inline");
12192
+ const c = config !== null && config !== void 0 ? config : this.getConfigForSync("inline");
12109
12193
  const engine = new Engine(c, Parser);
12110
12194
  return engine.getRuleDocumentation({ ruleId, context });
12111
12195
  }
@@ -12161,7 +12245,7 @@ class HtmlValidate {
12161
12245
  /** @public */
12162
12246
  const name = "html-validate";
12163
12247
  /** @public */
12164
- const version = "8.1.0";
12248
+ const version = "8.3.0";
12165
12249
  /** @public */
12166
12250
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
12167
12251
 
@@ -12459,5 +12543,5 @@ function compatibilityCheckImpl(name, declared, options) {
12459
12543
  return false;
12460
12544
  }
12461
12545
 
12462
- export { Attribute as A, codeframe as B, Config as C, DynamicValue as D, EventHandler as E, name as F, bugs as G, HtmlValidate as H, MetaTable as M, NodeClosed as N, Presets as P, ResolvedConfig as R, Severity as S, TextNode as T, UserError as U, Validator as V, WrappedError as W, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, DOMTokenList as d, ensureError as e, HtmlElement as f, getFormatter as g, DOMNode as h, DOMTree as i, NodeType as j, SchemaValidationError as k, NestedError as l, TextContent$1 as m, MetaCopyableProperty as n, Rule as o, TextClassification as p, classifyNodeText as q, keywordPatternMatcher as r, staticResolver as s, sliceLocation as t, Reporter as u, version as v, definePlugin as w, Parser as x, ruleExists as y, compatibilityCheckImpl as z };
12546
+ export { Attribute as A, codeframe as B, Config as C, DOMNode as D, EventHandler as E, name as F, bugs as G, HtmlValidate as H, MetaCopyableProperty as M, NodeClosed as N, Presets as P, ResolvedConfig as R, Severity as S, TextNode as T, UserError as U, Validator as V, WrappedError as W, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, DOMTokenList as d, ensureError as e, DOMTree as f, getFormatter as g, DynamicValue as h, HtmlElement as i, NodeType as j, NestedError as k, SchemaValidationError as l, MetaTable as m, TextContent$1 as n, Rule as o, TextClassification as p, classifyNodeText as q, keywordPatternMatcher as r, staticResolver as s, sliceLocation as t, Reporter as u, version as v, definePlugin as w, Parser as x, ruleExists as y, compatibilityCheckImpl as z };
12463
12547
  //# sourceMappingURL=core.js.map