html-validate 10.7.0 → 10.8.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.
- package/dist/cjs/core.js +135 -19
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/tsdoc-metadata.json +1 -1
- package/dist/esm/browser.js +1 -1
- package/dist/esm/cli.js +2 -2
- package/dist/esm/core-browser.js +1 -1
- package/dist/esm/core-nodejs.js +1 -1
- package/dist/esm/core.js +136 -20
- package/dist/esm/core.js.map +1 -1
- package/dist/esm/html-validate.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/package.json +1 -1
package/dist/cjs/core.js
CHANGED
|
@@ -4008,7 +4008,7 @@ class Rule {
|
|
|
4008
4008
|
}
|
|
4009
4009
|
}
|
|
4010
4010
|
|
|
4011
|
-
const defaults$
|
|
4011
|
+
const defaults$A = {
|
|
4012
4012
|
allowExternal: true,
|
|
4013
4013
|
allowRelative: true,
|
|
4014
4014
|
allowAbsolute: true,
|
|
@@ -4052,7 +4052,7 @@ class AllowedLinks extends Rule {
|
|
|
4052
4052
|
allowRelative;
|
|
4053
4053
|
allowAbsolute;
|
|
4054
4054
|
constructor(options) {
|
|
4055
|
-
super({ ...defaults$
|
|
4055
|
+
super({ ...defaults$A, ...options });
|
|
4056
4056
|
this.allowExternal = parseAllow(this.options.allowExternal);
|
|
4057
4057
|
this.allowRelative = parseAllow(this.options.allowRelative);
|
|
4058
4058
|
this.allowAbsolute = parseAllow(this.options.allowAbsolute);
|
|
@@ -4220,7 +4220,7 @@ class AllowedLinks extends Rule {
|
|
|
4220
4220
|
}
|
|
4221
4221
|
}
|
|
4222
4222
|
|
|
4223
|
-
const defaults$
|
|
4223
|
+
const defaults$z = {
|
|
4224
4224
|
accessible: true
|
|
4225
4225
|
};
|
|
4226
4226
|
function findByTarget(target, siblings) {
|
|
@@ -4250,7 +4250,7 @@ function getDescription$1(context) {
|
|
|
4250
4250
|
}
|
|
4251
4251
|
class AreaAlt extends Rule {
|
|
4252
4252
|
constructor(options) {
|
|
4253
|
-
super({ ...defaults$
|
|
4253
|
+
super({ ...defaults$z, ...options });
|
|
4254
4254
|
}
|
|
4255
4255
|
static schema() {
|
|
4256
4256
|
return {
|
|
@@ -4329,7 +4329,7 @@ class AriaHiddenBody extends Rule {
|
|
|
4329
4329
|
}
|
|
4330
4330
|
}
|
|
4331
4331
|
|
|
4332
|
-
const defaults$
|
|
4332
|
+
const defaults$y = {
|
|
4333
4333
|
allowAnyNamable: false,
|
|
4334
4334
|
elements: {
|
|
4335
4335
|
include: null,
|
|
@@ -4377,7 +4377,7 @@ function isValidUsage(target, meta) {
|
|
|
4377
4377
|
}
|
|
4378
4378
|
class AriaLabelMisuse extends Rule {
|
|
4379
4379
|
constructor(options) {
|
|
4380
|
-
super({ ...defaults$
|
|
4380
|
+
super({ ...defaults$y, ...options });
|
|
4381
4381
|
}
|
|
4382
4382
|
static schema() {
|
|
4383
4383
|
return {
|
|
@@ -4546,14 +4546,14 @@ class CaseStyle {
|
|
|
4546
4546
|
}
|
|
4547
4547
|
}
|
|
4548
4548
|
|
|
4549
|
-
const defaults$
|
|
4549
|
+
const defaults$x = {
|
|
4550
4550
|
style: "lowercase",
|
|
4551
4551
|
ignoreForeign: true
|
|
4552
4552
|
};
|
|
4553
4553
|
class AttrCase extends Rule {
|
|
4554
4554
|
style;
|
|
4555
4555
|
constructor(options) {
|
|
4556
|
-
super({ ...defaults$
|
|
4556
|
+
super({ ...defaults$x, ...options });
|
|
4557
4557
|
this.style = new CaseStyle(this.options.style, "attr-case");
|
|
4558
4558
|
}
|
|
4559
4559
|
static schema() {
|
|
@@ -4958,7 +4958,7 @@ class AttrDelimiter extends Rule {
|
|
|
4958
4958
|
}
|
|
4959
4959
|
|
|
4960
4960
|
const DEFAULT_PATTERN = "[a-z0-9-:]+";
|
|
4961
|
-
const defaults$
|
|
4961
|
+
const defaults$w = {
|
|
4962
4962
|
pattern: DEFAULT_PATTERN,
|
|
4963
4963
|
ignoreForeign: true
|
|
4964
4964
|
};
|
|
@@ -4991,7 +4991,7 @@ function generateDescription(name, pattern) {
|
|
|
4991
4991
|
class AttrPattern extends Rule {
|
|
4992
4992
|
pattern;
|
|
4993
4993
|
constructor(options) {
|
|
4994
|
-
super({ ...defaults$
|
|
4994
|
+
super({ ...defaults$w, ...options });
|
|
4995
4995
|
this.pattern = generateRegexp(this.options.pattern);
|
|
4996
4996
|
}
|
|
4997
4997
|
static schema() {
|
|
@@ -5038,7 +5038,7 @@ class AttrPattern extends Rule {
|
|
|
5038
5038
|
}
|
|
5039
5039
|
}
|
|
5040
5040
|
|
|
5041
|
-
const defaults$
|
|
5041
|
+
const defaults$v = {
|
|
5042
5042
|
style: "auto",
|
|
5043
5043
|
unquoted: false
|
|
5044
5044
|
};
|
|
@@ -5104,7 +5104,7 @@ class AttrQuotes extends Rule {
|
|
|
5104
5104
|
};
|
|
5105
5105
|
}
|
|
5106
5106
|
constructor(options) {
|
|
5107
|
-
super({ ...defaults$
|
|
5107
|
+
super({ ...defaults$v, ...options });
|
|
5108
5108
|
this.style = parseStyle$3(this.options.style);
|
|
5109
5109
|
}
|
|
5110
5110
|
setup() {
|
|
@@ -5260,13 +5260,13 @@ class AttributeAllowedValues extends Rule {
|
|
|
5260
5260
|
}
|
|
5261
5261
|
}
|
|
5262
5262
|
|
|
5263
|
-
const defaults$
|
|
5263
|
+
const defaults$u = {
|
|
5264
5264
|
style: "omit"
|
|
5265
5265
|
};
|
|
5266
5266
|
class AttributeBooleanStyle extends Rule {
|
|
5267
5267
|
hasInvalidStyle;
|
|
5268
5268
|
constructor(options) {
|
|
5269
|
-
super({ ...defaults$
|
|
5269
|
+
super({ ...defaults$u, ...options });
|
|
5270
5270
|
this.hasInvalidStyle = parseStyle$2(this.options.style);
|
|
5271
5271
|
}
|
|
5272
5272
|
static schema() {
|
|
@@ -5336,13 +5336,13 @@ function reportMessage$1(attr, style) {
|
|
|
5336
5336
|
return "";
|
|
5337
5337
|
}
|
|
5338
5338
|
|
|
5339
|
-
const defaults$
|
|
5339
|
+
const defaults$t = {
|
|
5340
5340
|
style: "omit"
|
|
5341
5341
|
};
|
|
5342
5342
|
class AttributeEmptyStyle extends Rule {
|
|
5343
5343
|
hasInvalidStyle;
|
|
5344
5344
|
constructor(options) {
|
|
5345
|
-
super({ ...defaults$
|
|
5345
|
+
super({ ...defaults$t, ...options });
|
|
5346
5346
|
this.hasInvalidStyle = parseStyle$1(this.options.style);
|
|
5347
5347
|
}
|
|
5348
5348
|
static schema() {
|
|
@@ -5459,6 +5459,122 @@ class AttributeMisuse extends Rule {
|
|
|
5459
5459
|
}
|
|
5460
5460
|
}
|
|
5461
5461
|
|
|
5462
|
+
const defaults$s = {
|
|
5463
|
+
preferred: void 0
|
|
5464
|
+
};
|
|
5465
|
+
function isPasswordInput(event) {
|
|
5466
|
+
const { target } = event;
|
|
5467
|
+
if (!target.is("input")) {
|
|
5468
|
+
return false;
|
|
5469
|
+
}
|
|
5470
|
+
const type = target.getAttribute("type");
|
|
5471
|
+
return type?.value?.toString().toLowerCase() === "password";
|
|
5472
|
+
}
|
|
5473
|
+
function isGroupingToken(token) {
|
|
5474
|
+
return token.startsWith("section-") || token === "shipping" || token === "billing";
|
|
5475
|
+
}
|
|
5476
|
+
class AutocompletePassword extends Rule {
|
|
5477
|
+
preferred;
|
|
5478
|
+
constructor(options) {
|
|
5479
|
+
super({ ...defaults$s, ...options });
|
|
5480
|
+
this.preferred = options.preferred?.toLowerCase();
|
|
5481
|
+
}
|
|
5482
|
+
static schema() {
|
|
5483
|
+
return {
|
|
5484
|
+
preferred: {
|
|
5485
|
+
type: "string"
|
|
5486
|
+
}
|
|
5487
|
+
};
|
|
5488
|
+
}
|
|
5489
|
+
documentation(context) {
|
|
5490
|
+
const url = "https://html-validate.org/rules/autocomplete-password.html";
|
|
5491
|
+
switch (context.kind) {
|
|
5492
|
+
case "preferred-mismatch":
|
|
5493
|
+
return {
|
|
5494
|
+
description: [
|
|
5495
|
+
`\`<input type="password">\` should use \`autocomplete="${context.preferred}"\`.`,
|
|
5496
|
+
"",
|
|
5497
|
+
`The configured preferred autocomplete value is \`"${context.preferred}"\` but the element uses \`"${context.value}"\`.`
|
|
5498
|
+
].join("\n"),
|
|
5499
|
+
url
|
|
5500
|
+
};
|
|
5501
|
+
case "off":
|
|
5502
|
+
case "missing":
|
|
5503
|
+
default: {
|
|
5504
|
+
const error = context.kind === "off" ? '`<input type="password">` should not use `autocomplete="off"`.' : '`<input type="password">` must have the `autocomplete` attribute.';
|
|
5505
|
+
return {
|
|
5506
|
+
description: [
|
|
5507
|
+
error,
|
|
5508
|
+
"",
|
|
5509
|
+
"Browsers and password managers often ignore the absence of autocomplete and autofill password fields anyway, which can lead to unexpected behavior where users unknowingly submit autofilled passwords for unrelated fields.",
|
|
5510
|
+
"",
|
|
5511
|
+
"Use one of the following values:",
|
|
5512
|
+
"",
|
|
5513
|
+
'- `autocomplete="new-password"` for password creation forms',
|
|
5514
|
+
'- `autocomplete="current-password"` for login forms'
|
|
5515
|
+
].join("\n"),
|
|
5516
|
+
url
|
|
5517
|
+
};
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
}
|
|
5521
|
+
setup() {
|
|
5522
|
+
this.on("tag:ready", isPasswordInput, (event) => {
|
|
5523
|
+
const { preferred } = this;
|
|
5524
|
+
const { target } = event;
|
|
5525
|
+
const autocomplete = target.getAttribute("autocomplete");
|
|
5526
|
+
if (!autocomplete) {
|
|
5527
|
+
const context = { kind: "missing" };
|
|
5528
|
+
this.report({
|
|
5529
|
+
node: target,
|
|
5530
|
+
message: '<input type="password"> is missing required "autocomplete" attribute',
|
|
5531
|
+
location: target.location,
|
|
5532
|
+
context
|
|
5533
|
+
});
|
|
5534
|
+
return;
|
|
5535
|
+
}
|
|
5536
|
+
if (autocomplete.isDynamic || !autocomplete.value) {
|
|
5537
|
+
return;
|
|
5538
|
+
}
|
|
5539
|
+
const raw = autocomplete.value.toString().toLowerCase();
|
|
5540
|
+
const tokens = new DOMTokenList(raw, autocomplete.valueLocation);
|
|
5541
|
+
const index = tokens.findIndex((token) => !isGroupingToken(token));
|
|
5542
|
+
const value = tokens.item(index);
|
|
5543
|
+
const location = tokens.location(index);
|
|
5544
|
+
if (!value) {
|
|
5545
|
+
return;
|
|
5546
|
+
}
|
|
5547
|
+
if (value === "off") {
|
|
5548
|
+
const context = { kind: "off" };
|
|
5549
|
+
this.report({
|
|
5550
|
+
node: target,
|
|
5551
|
+
message: '<input type="password"> should not use autocomplete="off"',
|
|
5552
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- location must be present if value is */
|
|
5553
|
+
location,
|
|
5554
|
+
context
|
|
5555
|
+
});
|
|
5556
|
+
return;
|
|
5557
|
+
}
|
|
5558
|
+
if (preferred) {
|
|
5559
|
+
if (value !== preferred) {
|
|
5560
|
+
const context = {
|
|
5561
|
+
kind: "preferred-mismatch",
|
|
5562
|
+
value,
|
|
5563
|
+
preferred
|
|
5564
|
+
};
|
|
5565
|
+
this.report({
|
|
5566
|
+
node: target,
|
|
5567
|
+
message: `<input type="password"> should use autocomplete="${preferred}"`,
|
|
5568
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- location must be present if value is */
|
|
5569
|
+
location,
|
|
5570
|
+
context
|
|
5571
|
+
});
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5574
|
+
});
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
5577
|
+
|
|
5462
5578
|
const patternNamesValues = [
|
|
5463
5579
|
"kebabcase",
|
|
5464
5580
|
"camelcase",
|
|
@@ -9755,9 +9871,7 @@ const fieldNameGroup = {
|
|
|
9755
9871
|
nickname: "text",
|
|
9756
9872
|
username: "username",
|
|
9757
9873
|
"new-password": "password",
|
|
9758
|
-
// eslint-disable-line sonarjs/no-hardcoded-passwords -- false positive, it is not used as a password
|
|
9759
9874
|
"current-password": "password",
|
|
9760
|
-
// eslint-disable-line sonarjs/no-hardcoded-passwords -- false positive, it is not used as a password
|
|
9761
9875
|
"one-time-code": "password",
|
|
9762
9876
|
"organization-title": "text",
|
|
9763
9877
|
organization: "text",
|
|
@@ -10799,6 +10913,7 @@ const bundledRules = {
|
|
|
10799
10913
|
"attribute-boolean-style": AttributeBooleanStyle,
|
|
10800
10914
|
"attribute-empty-style": AttributeEmptyStyle,
|
|
10801
10915
|
"attribute-misuse": AttributeMisuse,
|
|
10916
|
+
"autocomplete-password": AutocompletePassword,
|
|
10802
10917
|
"class-pattern": ClassPattern,
|
|
10803
10918
|
"close-attr": CloseAttr,
|
|
10804
10919
|
"close-order": CloseOrder,
|
|
@@ -11164,6 +11279,7 @@ const config$1 = {
|
|
|
11164
11279
|
"attribute-boolean-style": "error",
|
|
11165
11280
|
"attribute-empty-style": "error",
|
|
11166
11281
|
"attribute-misuse": "error",
|
|
11282
|
+
"autocomplete-password": "error",
|
|
11167
11283
|
"close-attr": "error",
|
|
11168
11284
|
"close-order": "error",
|
|
11169
11285
|
deprecated: "error",
|
|
@@ -12178,7 +12294,7 @@ class EventHandler {
|
|
|
12178
12294
|
}
|
|
12179
12295
|
|
|
12180
12296
|
const name = "html-validate";
|
|
12181
|
-
const version = "10.
|
|
12297
|
+
const version = "10.8.0";
|
|
12182
12298
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12183
12299
|
|
|
12184
12300
|
function freeze(src) {
|