html-validate 8.18.2 → 8.19.1

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.
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.43.1"
8
+ "packageVersion": "7.43.7"
9
9
  }
10
10
  ]
11
11
  }
package/dist/es/core.js CHANGED
@@ -5,7 +5,7 @@ import { n as naturalJoin } from './utils/natural-join.js';
5
5
  import fs from 'fs';
6
6
  import { codeFrameColumns } from '@babel/code-frame';
7
7
  import kleur from 'kleur';
8
- import { stylish as stylish$2 } from '@html-validate/stylish';
8
+ import { stylish as stylish$1 } from '@html-validate/stylish';
9
9
  import semver from 'semver';
10
10
 
11
11
  const $schema$2 = "http://json-schema.org/draft-06/schema#";
@@ -6214,6 +6214,7 @@ class EmptyTitle extends Rule {
6214
6214
 
6215
6215
  const defaults$k = {
6216
6216
  allowArrayBrackets: true,
6217
+ allowCheckboxDefault: true,
6217
6218
  shared: ["radio", "button", "reset", "submit"]
6218
6219
  };
6219
6220
  const UNIQUE_CACHE_KEY = Symbol("form-elements-unique");
@@ -6225,6 +6226,25 @@ function allowSharedName(node, shared) {
6225
6226
  const type = node.getAttribute("type");
6226
6227
  return Boolean(type == null ? void 0 : type.valueMatches(shared, false));
6227
6228
  }
6229
+ function isInputHidden(element) {
6230
+ return element.is("input") && element.getAttributeValue("type") === "hidden";
6231
+ }
6232
+ function isInputCheckbox(element) {
6233
+ return element.is("input") && element.getAttributeValue("type") === "checkbox";
6234
+ }
6235
+ function isCheckboxWithDefault(control, previous, options) {
6236
+ const { allowCheckboxDefault } = options;
6237
+ if (!allowCheckboxDefault) {
6238
+ return false;
6239
+ }
6240
+ if (!previous.potentialHiddenDefault) {
6241
+ return false;
6242
+ }
6243
+ if (!isInputCheckbox(control)) {
6244
+ return false;
6245
+ }
6246
+ return true;
6247
+ }
6228
6248
  function getDocumentation(context) {
6229
6249
  const trailer = "Each form control must have a unique name.";
6230
6250
  const { name } = context;
@@ -6247,6 +6267,9 @@ class FormDupName extends Rule {
6247
6267
  allowArrayBrackets: {
6248
6268
  type: "boolean"
6249
6269
  },
6270
+ allowCheckboxDefault: {
6271
+ type: "boolean"
6272
+ },
6250
6273
  shared: {
6251
6274
  type: "array",
6252
6275
  items: {
@@ -6312,14 +6335,20 @@ class FormDupName extends Rule {
6312
6335
  }
6313
6336
  if (!details && isarray) {
6314
6337
  elements.set(basename, {
6315
- array: true
6338
+ array: true,
6339
+ potentialHiddenDefault: false
6316
6340
  });
6317
6341
  }
6318
6342
  if (isarray) {
6319
6343
  return;
6320
6344
  }
6321
6345
  }
6322
- if (elements.has(name)) {
6346
+ const previous = elements.get(name);
6347
+ if (previous) {
6348
+ if (isCheckboxWithDefault(control, previous, this.options)) {
6349
+ previous.potentialHiddenDefault = false;
6350
+ return;
6351
+ }
6323
6352
  const context = {
6324
6353
  name,
6325
6354
  kind: "duplicate"
@@ -6332,7 +6361,8 @@ class FormDupName extends Rule {
6332
6361
  });
6333
6362
  } else {
6334
6363
  elements.set(name, {
6335
- array: false
6364
+ array: false,
6365
+ potentialHiddenDefault: isInputHidden(control)
6336
6366
  });
6337
6367
  }
6338
6368
  }
@@ -7186,20 +7216,23 @@ class MultipleLabeledControls extends Rule {
7186
7216
  }
7187
7217
  setup() {
7188
7218
  this.labelable = this.getTagsWithProperty("labelable").join(",");
7189
- this.on("element:ready", (event) => {
7190
- const { target } = event;
7191
- if (target.tagName !== "label") {
7192
- return;
7193
- }
7194
- const numControls = this.getNumLabledControls(target);
7195
- if (numControls <= 1) {
7196
- return;
7219
+ this.on("dom:ready", (event) => {
7220
+ const { document } = event;
7221
+ const labels = document.querySelectorAll("label");
7222
+ for (const label of labels) {
7223
+ const numControls = this.getNumLabledControls(label);
7224
+ if (numControls <= 1) {
7225
+ continue;
7226
+ }
7227
+ this.report(label, "<label> is associated with multiple controls", label.location);
7197
7228
  }
7198
- this.report(target, "<label> is associated with multiple controls", target.location);
7199
7229
  });
7200
7230
  }
7201
7231
  getNumLabledControls(src) {
7202
- const controls = src.querySelectorAll(this.labelable).map((node) => node.id);
7232
+ const controls = src.querySelectorAll(this.labelable).filter((node) => {
7233
+ var _a;
7234
+ return (_a = node.meta) == null ? void 0 : _a.labelable;
7235
+ }).map((node) => node.id);
7203
7236
  const attr = src.getAttribute("for");
7204
7237
  if (!attr || attr.isDynamic || !attr.value) {
7205
7238
  return controls.length;
@@ -9743,7 +9776,7 @@ class ValidID extends Rule {
9743
9776
  const message = this.messages[context].replace("id", "ID").replace(/^(.)/, (m) => m.toUpperCase());
9744
9777
  const relaxedDescription = relaxed ? [] : [
9745
9778
  " - ID must begin with a letter",
9746
- " - ID must only contain alphanumerical characters, `-` and `_`"
9779
+ " - ID must only contain letters, digits, `-` and `_`"
9747
9780
  ];
9748
9781
  return {
9749
9782
  description: [
@@ -9778,12 +9811,12 @@ class ValidID extends Rule {
9778
9811
  if (relaxed) {
9779
9812
  return;
9780
9813
  }
9781
- if (value.match(/^[^a-zA-Z]/)) {
9814
+ if (value.match(/^[^\p{L}]/u)) {
9782
9815
  const context = 3 /* LEADING_CHARACTER */;
9783
9816
  this.report(event.target, this.messages[context], event.valueLocation, context);
9784
9817
  return;
9785
9818
  }
9786
- if (value.match(/[^a-zA-Z0-9-_]/)) {
9819
+ if (value.match(/[^\p{L}\p{N}_-]/u)) {
9787
9820
  const context = 4 /* DISALLOWED_CHARACTER */;
9788
9821
  this.report(event.target, this.messages[context], event.valueLocation, context);
9789
9822
  }
@@ -9794,7 +9827,7 @@ class ValidID extends Rule {
9794
9827
  [1 /* EMPTY */]: "element id must not be empty",
9795
9828
  [2 /* WHITESPACE */]: "element id must not contain whitespace",
9796
9829
  [3 /* LEADING_CHARACTER */]: "element id must begin with a letter",
9797
- [4 /* DISALLOWED_CHARACTER */]: "element id must only contain alphanumerical, dash and underscore characters"
9830
+ [4 /* DISALLOWED_CHARACTER */]: "element id must only contain letters, digits, dash and underscore characters"
9798
9831
  };
9799
9832
  }
9800
9833
  isRelevant(event) {
@@ -9921,7 +9954,7 @@ function styleDescription(style) {
9921
9954
  class H30 extends Rule {
9922
9955
  documentation() {
9923
9956
  return {
9924
- description: "WCAG 2.1 requires each `<a>` anchor link to have a text describing the purpose of the link using either plain text or an `<img>` with the `alt` attribute set.",
9957
+ description: "WCAG 2.1 requires each `<a href>` anchor link to have a text describing the purpose of the link using either plain text or an `<img>` with the `alt` attribute set.",
9925
9958
  url: "https://html-validate.org/rules/wcag/h30.html"
9926
9959
  };
9927
9960
  }
@@ -9929,6 +9962,9 @@ class H30 extends Rule {
9929
9962
  this.on("dom:ready", (event) => {
9930
9963
  const links = event.document.getElementsByTagName("a");
9931
9964
  for (const link of links) {
9965
+ if (!link.hasAttribute("href")) {
9966
+ continue;
9967
+ }
9932
9968
  if (!inAccessibilityTree(link)) {
9933
9969
  continue;
9934
9970
  }
@@ -9999,7 +10035,10 @@ function hasAssociatedSubmit(document, form) {
9999
10035
  class H36 extends Rule {
10000
10036
  documentation() {
10001
10037
  return {
10002
- description: 'WCAG 2.1 requires all images used as submit buttons to have a textual description using the alt attribute. The alt text cannot be empty (`alt=""`).',
10038
+ description: [
10039
+ "WCAG 2.1 requires all images used as submit buttons to have a non-empty textual description using the `alt` attribute.",
10040
+ 'The alt text cannot be empty (`alt=""`).'
10041
+ ].join("\n"),
10003
10042
  url: "https://html-validate.org/rules/wcag/h36.html"
10004
10043
  };
10005
10044
  }
@@ -10011,8 +10050,17 @@ class H36 extends Rule {
10011
10050
  if (node.getAttributeValue("type") !== "image") {
10012
10051
  return;
10013
10052
  }
10053
+ if (!inAccessibilityTree(node)) {
10054
+ return;
10055
+ }
10014
10056
  if (!hasAltText(node)) {
10015
- this.report(node, "image used as submit button must have alt text");
10057
+ const message = "image used as submit button must have non-empty alt text";
10058
+ const alt = node.getAttribute("alt");
10059
+ this.report({
10060
+ node,
10061
+ message,
10062
+ location: alt ? alt.keyLocation : node.location
10063
+ });
10016
10064
  }
10017
10065
  });
10018
10066
  }
@@ -10022,19 +10070,6 @@ const defaults$1 = {
10022
10070
  allowEmpty: true,
10023
10071
  alias: []
10024
10072
  };
10025
- function needsAlt(node) {
10026
- if (node.is("img")) {
10027
- return true;
10028
- }
10029
- if (node.is("input") && node.getAttributeValue("type") === "image") {
10030
- return true;
10031
- }
10032
- return false;
10033
- }
10034
- function getTag(node) {
10035
- return node.is("input") ? `<input type="${/* istanbul ignore next */
10036
- node.getAttributeValue("type") ?? ""}">` : `<${node.tagName}>`;
10037
- }
10038
10073
  class H37 extends Rule {
10039
10074
  constructor(options) {
10040
10075
  super({ ...defaults$1, ...options });
@@ -10071,16 +10106,13 @@ class H37 extends Rule {
10071
10106
  setup() {
10072
10107
  this.on("dom:ready", (event) => {
10073
10108
  const { document } = event;
10074
- const nodes = document.querySelectorAll("img, input");
10109
+ const nodes = document.querySelectorAll("img");
10075
10110
  for (const node of nodes) {
10076
10111
  this.validateNode(node);
10077
10112
  }
10078
10113
  });
10079
10114
  }
10080
10115
  validateNode(node) {
10081
- if (!needsAlt(node)) {
10082
- return;
10083
- }
10084
10116
  if (!inAccessibilityTree(node)) {
10085
10117
  return;
10086
10118
  }
@@ -10092,11 +10124,12 @@ class H37 extends Rule {
10092
10124
  return;
10093
10125
  }
10094
10126
  }
10127
+ const tag = node.annotatedName;
10095
10128
  if (node.hasAttribute("alt")) {
10096
10129
  const attr = node.getAttribute("alt");
10097
- this.report(node, `${getTag(node)} cannot have empty "alt" attribute`, attr == null ? void 0 : attr.keyLocation);
10130
+ this.report(node, `${tag} cannot have empty "alt" attribute`, attr.keyLocation);
10098
10131
  } else {
10099
- this.report(node, `${getTag(node)} is missing required "alt" attribute`, node.location);
10132
+ this.report(node, `${tag} is missing required "alt" attribute`, node.location);
10100
10133
  }
10101
10134
  }
10102
10135
  }
@@ -10197,7 +10230,6 @@ const bundledRules$1 = {
10197
10230
  "wcag/h67": H67,
10198
10231
  "wcag/h71": H71
10199
10232
  };
10200
- var WCAG = bundledRules$1;
10201
10233
 
10202
10234
  const bundledRules = {
10203
10235
  "allowed-links": AllowedLinks,
@@ -10283,7 +10315,7 @@ const bundledRules = {
10283
10315
  "valid-id": ValidID,
10284
10316
  "void-content": VoidContent,
10285
10317
  "void-style": VoidStyle,
10286
- ...WCAG
10318
+ ...bundledRules$1
10287
10319
  };
10288
10320
 
10289
10321
  var defaultConfig = {};
@@ -10320,7 +10352,6 @@ const config$4 = {
10320
10352
  "wcag/h71": "error"
10321
10353
  }
10322
10354
  };
10323
- var a11y = config$4;
10324
10355
 
10325
10356
  const config$3 = {
10326
10357
  rules: {
@@ -10331,7 +10362,6 @@ const config$3 = {
10331
10362
  "require-sri": "error"
10332
10363
  }
10333
10364
  };
10334
- var document = config$3;
10335
10365
 
10336
10366
  const config$2 = {
10337
10367
  rules: {
@@ -10340,7 +10370,6 @@ const config$2 = {
10340
10370
  "void-style": "off"
10341
10371
  }
10342
10372
  };
10343
- var prettier = config$2;
10344
10373
 
10345
10374
  const config$1 = {
10346
10375
  rules: {
@@ -10424,7 +10453,6 @@ const config$1 = {
10424
10453
  "wcag/h71": "error"
10425
10454
  }
10426
10455
  };
10427
- var recommended = config$1;
10428
10456
 
10429
10457
  const config = {
10430
10458
  rules: {
@@ -10463,18 +10491,17 @@ const config = {
10463
10491
  "void-content": "error"
10464
10492
  }
10465
10493
  };
10466
- var standard = config;
10467
10494
 
10468
10495
  const presets = {
10469
- "html-validate:a11y": a11y,
10470
- "html-validate:document": document,
10471
- "html-validate:prettier": prettier,
10472
- "html-validate:recommended": recommended,
10473
- "html-validate:standard": standard,
10496
+ "html-validate:a11y": config$4,
10497
+ "html-validate:document": config$3,
10498
+ "html-validate:prettier": config$2,
10499
+ "html-validate:recommended": config$1,
10500
+ "html-validate:standard": config,
10474
10501
  /* @deprecated aliases */
10475
- "htmlvalidate:recommended": recommended,
10476
- "htmlvalidate:document": document,
10477
- "html-validate:a17y": a11y
10502
+ "htmlvalidate:recommended": config$1,
10503
+ "htmlvalidate:document": config$3,
10504
+ "html-validate:a17y": config$4
10478
10505
  };
10479
10506
  var Presets = presets;
10480
10507
 
@@ -12689,7 +12716,7 @@ class HtmlValidate {
12689
12716
  }
12690
12717
 
12691
12718
  const name = "html-validate";
12692
- const version = "8.18.2";
12719
+ const version = "8.19.1";
12693
12720
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
12694
12721
 
12695
12722
  function definePlugin(plugin) {
@@ -13375,7 +13402,6 @@ function checkstyleFormatter(results) {
13375
13402
  return output;
13376
13403
  }
13377
13404
  const formatter$3 = checkstyleFormatter;
13378
- var checkstyle = formatter$3;
13379
13405
 
13380
13406
  const defaults = {
13381
13407
  showLink: true,
@@ -13481,7 +13507,6 @@ function jsonFormatter(results) {
13481
13507
  return JSON.stringify(results);
13482
13508
  }
13483
13509
  const formatter$2 = jsonFormatter;
13484
- var json = formatter$2;
13485
13510
 
13486
13511
  function linkSummary(results) {
13487
13512
  const urls = results.reduce((result, it) => {
@@ -13500,7 +13525,7 @@ ${lines.join("")}
13500
13525
  `;
13501
13526
  }
13502
13527
  function stylish(results) {
13503
- const errors = stylish$2(
13528
+ const errors = stylish$1(
13504
13529
  results.map((it) => ({
13505
13530
  ...it,
13506
13531
  fixableErrorCount: 0,
@@ -13511,7 +13536,6 @@ function stylish(results) {
13511
13536
  return `${errors}${links}`;
13512
13537
  }
13513
13538
  const formatter$1 = stylish;
13514
- var stylish$1 = formatter$1;
13515
13539
 
13516
13540
  function textFormatter(results) {
13517
13541
  let output = "";
@@ -13539,14 +13563,13 @@ function textFormatter(results) {
13539
13563
  return total > 0 ? output : "";
13540
13564
  }
13541
13565
  const formatter = textFormatter;
13542
- var text = formatter;
13543
13566
 
13544
13567
  const availableFormatters = {
13545
- checkstyle,
13568
+ checkstyle: formatter$3,
13546
13569
  codeframe,
13547
- json,
13548
- stylish: stylish$1,
13549
- text
13570
+ json: formatter$2,
13571
+ stylish: formatter$1,
13572
+ text: formatter
13550
13573
  };
13551
13574
  function getFormatter(name) {
13552
13575
  return availableFormatters[name] ?? null;