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.
- package/dist/cjs/core.js +88 -65
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/tsdoc-metadata.json +1 -1
- package/dist/es/core.js +88 -65
- package/dist/es/core.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/package.json +15 -15
package/dist/cjs/core.js
CHANGED
|
@@ -7,7 +7,7 @@ var utils_naturalJoin = require('./utils/natural-join.js');
|
|
|
7
7
|
var fs = require('fs');
|
|
8
8
|
var codeFrame = require('@babel/code-frame');
|
|
9
9
|
var kleur = require('kleur');
|
|
10
|
-
var stylish$
|
|
10
|
+
var stylish$1 = require('@html-validate/stylish');
|
|
11
11
|
var semver = require('semver');
|
|
12
12
|
|
|
13
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -6224,6 +6224,7 @@ class EmptyTitle extends Rule {
|
|
|
6224
6224
|
|
|
6225
6225
|
const defaults$k = {
|
|
6226
6226
|
allowArrayBrackets: true,
|
|
6227
|
+
allowCheckboxDefault: true,
|
|
6227
6228
|
shared: ["radio", "button", "reset", "submit"]
|
|
6228
6229
|
};
|
|
6229
6230
|
const UNIQUE_CACHE_KEY = Symbol("form-elements-unique");
|
|
@@ -6235,6 +6236,25 @@ function allowSharedName(node, shared) {
|
|
|
6235
6236
|
const type = node.getAttribute("type");
|
|
6236
6237
|
return Boolean(type == null ? void 0 : type.valueMatches(shared, false));
|
|
6237
6238
|
}
|
|
6239
|
+
function isInputHidden(element) {
|
|
6240
|
+
return element.is("input") && element.getAttributeValue("type") === "hidden";
|
|
6241
|
+
}
|
|
6242
|
+
function isInputCheckbox(element) {
|
|
6243
|
+
return element.is("input") && element.getAttributeValue("type") === "checkbox";
|
|
6244
|
+
}
|
|
6245
|
+
function isCheckboxWithDefault(control, previous, options) {
|
|
6246
|
+
const { allowCheckboxDefault } = options;
|
|
6247
|
+
if (!allowCheckboxDefault) {
|
|
6248
|
+
return false;
|
|
6249
|
+
}
|
|
6250
|
+
if (!previous.potentialHiddenDefault) {
|
|
6251
|
+
return false;
|
|
6252
|
+
}
|
|
6253
|
+
if (!isInputCheckbox(control)) {
|
|
6254
|
+
return false;
|
|
6255
|
+
}
|
|
6256
|
+
return true;
|
|
6257
|
+
}
|
|
6238
6258
|
function getDocumentation(context) {
|
|
6239
6259
|
const trailer = "Each form control must have a unique name.";
|
|
6240
6260
|
const { name } = context;
|
|
@@ -6257,6 +6277,9 @@ class FormDupName extends Rule {
|
|
|
6257
6277
|
allowArrayBrackets: {
|
|
6258
6278
|
type: "boolean"
|
|
6259
6279
|
},
|
|
6280
|
+
allowCheckboxDefault: {
|
|
6281
|
+
type: "boolean"
|
|
6282
|
+
},
|
|
6260
6283
|
shared: {
|
|
6261
6284
|
type: "array",
|
|
6262
6285
|
items: {
|
|
@@ -6322,14 +6345,20 @@ class FormDupName extends Rule {
|
|
|
6322
6345
|
}
|
|
6323
6346
|
if (!details && isarray) {
|
|
6324
6347
|
elements.set(basename, {
|
|
6325
|
-
array: true
|
|
6348
|
+
array: true,
|
|
6349
|
+
potentialHiddenDefault: false
|
|
6326
6350
|
});
|
|
6327
6351
|
}
|
|
6328
6352
|
if (isarray) {
|
|
6329
6353
|
return;
|
|
6330
6354
|
}
|
|
6331
6355
|
}
|
|
6332
|
-
|
|
6356
|
+
const previous = elements.get(name);
|
|
6357
|
+
if (previous) {
|
|
6358
|
+
if (isCheckboxWithDefault(control, previous, this.options)) {
|
|
6359
|
+
previous.potentialHiddenDefault = false;
|
|
6360
|
+
return;
|
|
6361
|
+
}
|
|
6333
6362
|
const context = {
|
|
6334
6363
|
name,
|
|
6335
6364
|
kind: "duplicate"
|
|
@@ -6342,7 +6371,8 @@ class FormDupName extends Rule {
|
|
|
6342
6371
|
});
|
|
6343
6372
|
} else {
|
|
6344
6373
|
elements.set(name, {
|
|
6345
|
-
array: false
|
|
6374
|
+
array: false,
|
|
6375
|
+
potentialHiddenDefault: isInputHidden(control)
|
|
6346
6376
|
});
|
|
6347
6377
|
}
|
|
6348
6378
|
}
|
|
@@ -7196,20 +7226,23 @@ class MultipleLabeledControls extends Rule {
|
|
|
7196
7226
|
}
|
|
7197
7227
|
setup() {
|
|
7198
7228
|
this.labelable = this.getTagsWithProperty("labelable").join(",");
|
|
7199
|
-
this.on("
|
|
7200
|
-
const {
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7229
|
+
this.on("dom:ready", (event) => {
|
|
7230
|
+
const { document } = event;
|
|
7231
|
+
const labels = document.querySelectorAll("label");
|
|
7232
|
+
for (const label of labels) {
|
|
7233
|
+
const numControls = this.getNumLabledControls(label);
|
|
7234
|
+
if (numControls <= 1) {
|
|
7235
|
+
continue;
|
|
7236
|
+
}
|
|
7237
|
+
this.report(label, "<label> is associated with multiple controls", label.location);
|
|
7207
7238
|
}
|
|
7208
|
-
this.report(target, "<label> is associated with multiple controls", target.location);
|
|
7209
7239
|
});
|
|
7210
7240
|
}
|
|
7211
7241
|
getNumLabledControls(src) {
|
|
7212
|
-
const controls = src.querySelectorAll(this.labelable).
|
|
7242
|
+
const controls = src.querySelectorAll(this.labelable).filter((node) => {
|
|
7243
|
+
var _a;
|
|
7244
|
+
return (_a = node.meta) == null ? void 0 : _a.labelable;
|
|
7245
|
+
}).map((node) => node.id);
|
|
7213
7246
|
const attr = src.getAttribute("for");
|
|
7214
7247
|
if (!attr || attr.isDynamic || !attr.value) {
|
|
7215
7248
|
return controls.length;
|
|
@@ -9753,7 +9786,7 @@ class ValidID extends Rule {
|
|
|
9753
9786
|
const message = this.messages[context].replace("id", "ID").replace(/^(.)/, (m) => m.toUpperCase());
|
|
9754
9787
|
const relaxedDescription = relaxed ? [] : [
|
|
9755
9788
|
" - ID must begin with a letter",
|
|
9756
|
-
" - ID must only contain
|
|
9789
|
+
" - ID must only contain letters, digits, `-` and `_`"
|
|
9757
9790
|
];
|
|
9758
9791
|
return {
|
|
9759
9792
|
description: [
|
|
@@ -9788,12 +9821,12 @@ class ValidID extends Rule {
|
|
|
9788
9821
|
if (relaxed) {
|
|
9789
9822
|
return;
|
|
9790
9823
|
}
|
|
9791
|
-
if (value.match(/^[
|
|
9824
|
+
if (value.match(/^[^\p{L}]/u)) {
|
|
9792
9825
|
const context = 3 /* LEADING_CHARACTER */;
|
|
9793
9826
|
this.report(event.target, this.messages[context], event.valueLocation, context);
|
|
9794
9827
|
return;
|
|
9795
9828
|
}
|
|
9796
|
-
if (value.match(/[
|
|
9829
|
+
if (value.match(/[^\p{L}\p{N}_-]/u)) {
|
|
9797
9830
|
const context = 4 /* DISALLOWED_CHARACTER */;
|
|
9798
9831
|
this.report(event.target, this.messages[context], event.valueLocation, context);
|
|
9799
9832
|
}
|
|
@@ -9804,7 +9837,7 @@ class ValidID extends Rule {
|
|
|
9804
9837
|
[1 /* EMPTY */]: "element id must not be empty",
|
|
9805
9838
|
[2 /* WHITESPACE */]: "element id must not contain whitespace",
|
|
9806
9839
|
[3 /* LEADING_CHARACTER */]: "element id must begin with a letter",
|
|
9807
|
-
[4 /* DISALLOWED_CHARACTER */]: "element id must only contain
|
|
9840
|
+
[4 /* DISALLOWED_CHARACTER */]: "element id must only contain letters, digits, dash and underscore characters"
|
|
9808
9841
|
};
|
|
9809
9842
|
}
|
|
9810
9843
|
isRelevant(event) {
|
|
@@ -9931,7 +9964,7 @@ function styleDescription(style) {
|
|
|
9931
9964
|
class H30 extends Rule {
|
|
9932
9965
|
documentation() {
|
|
9933
9966
|
return {
|
|
9934
|
-
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.",
|
|
9967
|
+
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.",
|
|
9935
9968
|
url: "https://html-validate.org/rules/wcag/h30.html"
|
|
9936
9969
|
};
|
|
9937
9970
|
}
|
|
@@ -9939,6 +9972,9 @@ class H30 extends Rule {
|
|
|
9939
9972
|
this.on("dom:ready", (event) => {
|
|
9940
9973
|
const links = event.document.getElementsByTagName("a");
|
|
9941
9974
|
for (const link of links) {
|
|
9975
|
+
if (!link.hasAttribute("href")) {
|
|
9976
|
+
continue;
|
|
9977
|
+
}
|
|
9942
9978
|
if (!inAccessibilityTree(link)) {
|
|
9943
9979
|
continue;
|
|
9944
9980
|
}
|
|
@@ -10009,7 +10045,10 @@ function hasAssociatedSubmit(document, form) {
|
|
|
10009
10045
|
class H36 extends Rule {
|
|
10010
10046
|
documentation() {
|
|
10011
10047
|
return {
|
|
10012
|
-
description:
|
|
10048
|
+
description: [
|
|
10049
|
+
"WCAG 2.1 requires all images used as submit buttons to have a non-empty textual description using the `alt` attribute.",
|
|
10050
|
+
'The alt text cannot be empty (`alt=""`).'
|
|
10051
|
+
].join("\n"),
|
|
10013
10052
|
url: "https://html-validate.org/rules/wcag/h36.html"
|
|
10014
10053
|
};
|
|
10015
10054
|
}
|
|
@@ -10021,8 +10060,17 @@ class H36 extends Rule {
|
|
|
10021
10060
|
if (node.getAttributeValue("type") !== "image") {
|
|
10022
10061
|
return;
|
|
10023
10062
|
}
|
|
10063
|
+
if (!inAccessibilityTree(node)) {
|
|
10064
|
+
return;
|
|
10065
|
+
}
|
|
10024
10066
|
if (!hasAltText(node)) {
|
|
10025
|
-
|
|
10067
|
+
const message = "image used as submit button must have non-empty alt text";
|
|
10068
|
+
const alt = node.getAttribute("alt");
|
|
10069
|
+
this.report({
|
|
10070
|
+
node,
|
|
10071
|
+
message,
|
|
10072
|
+
location: alt ? alt.keyLocation : node.location
|
|
10073
|
+
});
|
|
10026
10074
|
}
|
|
10027
10075
|
});
|
|
10028
10076
|
}
|
|
@@ -10032,19 +10080,6 @@ const defaults$1 = {
|
|
|
10032
10080
|
allowEmpty: true,
|
|
10033
10081
|
alias: []
|
|
10034
10082
|
};
|
|
10035
|
-
function needsAlt(node) {
|
|
10036
|
-
if (node.is("img")) {
|
|
10037
|
-
return true;
|
|
10038
|
-
}
|
|
10039
|
-
if (node.is("input") && node.getAttributeValue("type") === "image") {
|
|
10040
|
-
return true;
|
|
10041
|
-
}
|
|
10042
|
-
return false;
|
|
10043
|
-
}
|
|
10044
|
-
function getTag(node) {
|
|
10045
|
-
return node.is("input") ? `<input type="${/* istanbul ignore next */
|
|
10046
|
-
node.getAttributeValue("type") ?? ""}">` : `<${node.tagName}>`;
|
|
10047
|
-
}
|
|
10048
10083
|
class H37 extends Rule {
|
|
10049
10084
|
constructor(options) {
|
|
10050
10085
|
super({ ...defaults$1, ...options });
|
|
@@ -10081,16 +10116,13 @@ class H37 extends Rule {
|
|
|
10081
10116
|
setup() {
|
|
10082
10117
|
this.on("dom:ready", (event) => {
|
|
10083
10118
|
const { document } = event;
|
|
10084
|
-
const nodes = document.querySelectorAll("img
|
|
10119
|
+
const nodes = document.querySelectorAll("img");
|
|
10085
10120
|
for (const node of nodes) {
|
|
10086
10121
|
this.validateNode(node);
|
|
10087
10122
|
}
|
|
10088
10123
|
});
|
|
10089
10124
|
}
|
|
10090
10125
|
validateNode(node) {
|
|
10091
|
-
if (!needsAlt(node)) {
|
|
10092
|
-
return;
|
|
10093
|
-
}
|
|
10094
10126
|
if (!inAccessibilityTree(node)) {
|
|
10095
10127
|
return;
|
|
10096
10128
|
}
|
|
@@ -10102,11 +10134,12 @@ class H37 extends Rule {
|
|
|
10102
10134
|
return;
|
|
10103
10135
|
}
|
|
10104
10136
|
}
|
|
10137
|
+
const tag = node.annotatedName;
|
|
10105
10138
|
if (node.hasAttribute("alt")) {
|
|
10106
10139
|
const attr = node.getAttribute("alt");
|
|
10107
|
-
this.report(node, `${
|
|
10140
|
+
this.report(node, `${tag} cannot have empty "alt" attribute`, attr.keyLocation);
|
|
10108
10141
|
} else {
|
|
10109
|
-
this.report(node, `${
|
|
10142
|
+
this.report(node, `${tag} is missing required "alt" attribute`, node.location);
|
|
10110
10143
|
}
|
|
10111
10144
|
}
|
|
10112
10145
|
}
|
|
@@ -10207,7 +10240,6 @@ const bundledRules$1 = {
|
|
|
10207
10240
|
"wcag/h67": H67,
|
|
10208
10241
|
"wcag/h71": H71
|
|
10209
10242
|
};
|
|
10210
|
-
var WCAG = bundledRules$1;
|
|
10211
10243
|
|
|
10212
10244
|
const bundledRules = {
|
|
10213
10245
|
"allowed-links": AllowedLinks,
|
|
@@ -10293,7 +10325,7 @@ const bundledRules = {
|
|
|
10293
10325
|
"valid-id": ValidID,
|
|
10294
10326
|
"void-content": VoidContent,
|
|
10295
10327
|
"void-style": VoidStyle,
|
|
10296
|
-
...
|
|
10328
|
+
...bundledRules$1
|
|
10297
10329
|
};
|
|
10298
10330
|
|
|
10299
10331
|
var defaultConfig = {};
|
|
@@ -10330,7 +10362,6 @@ const config$4 = {
|
|
|
10330
10362
|
"wcag/h71": "error"
|
|
10331
10363
|
}
|
|
10332
10364
|
};
|
|
10333
|
-
var a11y = config$4;
|
|
10334
10365
|
|
|
10335
10366
|
const config$3 = {
|
|
10336
10367
|
rules: {
|
|
@@ -10341,7 +10372,6 @@ const config$3 = {
|
|
|
10341
10372
|
"require-sri": "error"
|
|
10342
10373
|
}
|
|
10343
10374
|
};
|
|
10344
|
-
var document = config$3;
|
|
10345
10375
|
|
|
10346
10376
|
const config$2 = {
|
|
10347
10377
|
rules: {
|
|
@@ -10350,7 +10380,6 @@ const config$2 = {
|
|
|
10350
10380
|
"void-style": "off"
|
|
10351
10381
|
}
|
|
10352
10382
|
};
|
|
10353
|
-
var prettier = config$2;
|
|
10354
10383
|
|
|
10355
10384
|
const config$1 = {
|
|
10356
10385
|
rules: {
|
|
@@ -10434,7 +10463,6 @@ const config$1 = {
|
|
|
10434
10463
|
"wcag/h71": "error"
|
|
10435
10464
|
}
|
|
10436
10465
|
};
|
|
10437
|
-
var recommended = config$1;
|
|
10438
10466
|
|
|
10439
10467
|
const config = {
|
|
10440
10468
|
rules: {
|
|
@@ -10473,18 +10501,17 @@ const config = {
|
|
|
10473
10501
|
"void-content": "error"
|
|
10474
10502
|
}
|
|
10475
10503
|
};
|
|
10476
|
-
var standard = config;
|
|
10477
10504
|
|
|
10478
10505
|
const presets = {
|
|
10479
|
-
"html-validate:a11y":
|
|
10480
|
-
"html-validate:document":
|
|
10481
|
-
"html-validate:prettier":
|
|
10482
|
-
"html-validate:recommended":
|
|
10483
|
-
"html-validate:standard":
|
|
10506
|
+
"html-validate:a11y": config$4,
|
|
10507
|
+
"html-validate:document": config$3,
|
|
10508
|
+
"html-validate:prettier": config$2,
|
|
10509
|
+
"html-validate:recommended": config$1,
|
|
10510
|
+
"html-validate:standard": config,
|
|
10484
10511
|
/* @deprecated aliases */
|
|
10485
|
-
"htmlvalidate:recommended":
|
|
10486
|
-
"htmlvalidate:document":
|
|
10487
|
-
"html-validate:a17y":
|
|
10512
|
+
"htmlvalidate:recommended": config$1,
|
|
10513
|
+
"htmlvalidate:document": config$3,
|
|
10514
|
+
"html-validate:a17y": config$4
|
|
10488
10515
|
};
|
|
10489
10516
|
var Presets = presets;
|
|
10490
10517
|
|
|
@@ -12699,7 +12726,7 @@ class HtmlValidate {
|
|
|
12699
12726
|
}
|
|
12700
12727
|
|
|
12701
12728
|
const name = "html-validate";
|
|
12702
|
-
const version = "8.
|
|
12729
|
+
const version = "8.19.1";
|
|
12703
12730
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12704
12731
|
|
|
12705
12732
|
function definePlugin(plugin) {
|
|
@@ -13385,7 +13412,6 @@ function checkstyleFormatter(results) {
|
|
|
13385
13412
|
return output;
|
|
13386
13413
|
}
|
|
13387
13414
|
const formatter$3 = checkstyleFormatter;
|
|
13388
|
-
var checkstyle = formatter$3;
|
|
13389
13415
|
|
|
13390
13416
|
const defaults = {
|
|
13391
13417
|
showLink: true,
|
|
@@ -13491,7 +13517,6 @@ function jsonFormatter(results) {
|
|
|
13491
13517
|
return JSON.stringify(results);
|
|
13492
13518
|
}
|
|
13493
13519
|
const formatter$2 = jsonFormatter;
|
|
13494
|
-
var json = formatter$2;
|
|
13495
13520
|
|
|
13496
13521
|
function linkSummary(results) {
|
|
13497
13522
|
const urls = results.reduce((result, it) => {
|
|
@@ -13510,7 +13535,7 @@ ${lines.join("")}
|
|
|
13510
13535
|
`;
|
|
13511
13536
|
}
|
|
13512
13537
|
function stylish(results) {
|
|
13513
|
-
const errors = stylish$
|
|
13538
|
+
const errors = stylish$1.stylish(
|
|
13514
13539
|
results.map((it) => ({
|
|
13515
13540
|
...it,
|
|
13516
13541
|
fixableErrorCount: 0,
|
|
@@ -13521,7 +13546,6 @@ function stylish(results) {
|
|
|
13521
13546
|
return `${errors}${links}`;
|
|
13522
13547
|
}
|
|
13523
13548
|
const formatter$1 = stylish;
|
|
13524
|
-
var stylish$1 = formatter$1;
|
|
13525
13549
|
|
|
13526
13550
|
function textFormatter(results) {
|
|
13527
13551
|
let output = "";
|
|
@@ -13549,14 +13573,13 @@ function textFormatter(results) {
|
|
|
13549
13573
|
return total > 0 ? output : "";
|
|
13550
13574
|
}
|
|
13551
13575
|
const formatter = textFormatter;
|
|
13552
|
-
var text = formatter;
|
|
13553
13576
|
|
|
13554
13577
|
const availableFormatters = {
|
|
13555
|
-
checkstyle,
|
|
13578
|
+
checkstyle: formatter$3,
|
|
13556
13579
|
codeframe,
|
|
13557
|
-
json,
|
|
13558
|
-
stylish:
|
|
13559
|
-
text
|
|
13580
|
+
json: formatter$2,
|
|
13581
|
+
stylish: formatter$1,
|
|
13582
|
+
text: formatter
|
|
13560
13583
|
};
|
|
13561
13584
|
function getFormatter(name) {
|
|
13562
13585
|
return availableFormatters[name] ?? null;
|