html-validate 7.12.0 → 7.12.2
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/README.md +1 -1
- package/dist/cjs/core.js +161 -48
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/rules-helper.js +25 -0
- package/dist/cjs/rules-helper.js.map +1 -1
- package/dist/es/core.js +162 -49
- package/dist/es/core.js.map +1 -1
- package/dist/es/rules-helper.js +25 -1
- package/dist/es/rules-helper.js.map +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
package/dist/cjs/core.js
CHANGED
|
@@ -3653,7 +3653,7 @@ class Rule {
|
|
|
3653
3653
|
}
|
|
3654
3654
|
}
|
|
3655
3655
|
|
|
3656
|
-
const defaults$
|
|
3656
|
+
const defaults$w = {
|
|
3657
3657
|
allowExternal: true,
|
|
3658
3658
|
allowRelative: true,
|
|
3659
3659
|
allowAbsolute: true,
|
|
@@ -3697,7 +3697,7 @@ function matchList(value, list) {
|
|
|
3697
3697
|
}
|
|
3698
3698
|
class AllowedLinks extends Rule {
|
|
3699
3699
|
constructor(options) {
|
|
3700
|
-
super({ ...defaults$
|
|
3700
|
+
super({ ...defaults$w, ...options });
|
|
3701
3701
|
this.allowExternal = parseAllow(this.options.allowExternal);
|
|
3702
3702
|
this.allowRelative = parseAllow(this.options.allowRelative);
|
|
3703
3703
|
this.allowAbsolute = parseAllow(this.options.allowAbsolute);
|
|
@@ -3845,7 +3845,7 @@ var RuleContext$1;
|
|
|
3845
3845
|
RuleContext["MISSING_ALT"] = "missing-alt";
|
|
3846
3846
|
RuleContext["MISSING_HREF"] = "missing-href";
|
|
3847
3847
|
})(RuleContext$1 || (RuleContext$1 = {}));
|
|
3848
|
-
const defaults$
|
|
3848
|
+
const defaults$v = {
|
|
3849
3849
|
accessible: true,
|
|
3850
3850
|
};
|
|
3851
3851
|
function findByTarget(target, siblings) {
|
|
@@ -3883,7 +3883,7 @@ function getDescription$1(context) {
|
|
|
3883
3883
|
}
|
|
3884
3884
|
class AreaAlt extends Rule {
|
|
3885
3885
|
constructor(options) {
|
|
3886
|
-
super({ ...defaults$
|
|
3886
|
+
super({ ...defaults$v, ...options });
|
|
3887
3887
|
}
|
|
3888
3888
|
static schema() {
|
|
3889
3889
|
return {
|
|
@@ -4052,13 +4052,13 @@ class ConfigError extends UserError {
|
|
|
4052
4052
|
}
|
|
4053
4053
|
}
|
|
4054
4054
|
|
|
4055
|
-
const defaults$
|
|
4055
|
+
const defaults$u = {
|
|
4056
4056
|
style: "lowercase",
|
|
4057
4057
|
ignoreForeign: true,
|
|
4058
4058
|
};
|
|
4059
4059
|
class AttrCase extends Rule {
|
|
4060
4060
|
constructor(options) {
|
|
4061
|
-
super({ ...defaults$
|
|
4061
|
+
super({ ...defaults$u, ...options });
|
|
4062
4062
|
this.style = new rulesHelper.CaseStyle(this.options.style, "attr-case");
|
|
4063
4063
|
}
|
|
4064
4064
|
static schema() {
|
|
@@ -4403,7 +4403,7 @@ class AttrDelimiter extends Rule {
|
|
|
4403
4403
|
}
|
|
4404
4404
|
|
|
4405
4405
|
const DEFAULT_PATTERN = "[a-z0-9-:]+";
|
|
4406
|
-
const defaults$
|
|
4406
|
+
const defaults$t = {
|
|
4407
4407
|
pattern: DEFAULT_PATTERN,
|
|
4408
4408
|
ignoreForeign: true,
|
|
4409
4409
|
};
|
|
@@ -4440,7 +4440,7 @@ function generateDescription(name, pattern) {
|
|
|
4440
4440
|
}
|
|
4441
4441
|
class AttrPattern extends Rule {
|
|
4442
4442
|
constructor(options) {
|
|
4443
|
-
super({ ...defaults$
|
|
4443
|
+
super({ ...defaults$t, ...options });
|
|
4444
4444
|
this.pattern = generateRegexp(this.options.pattern);
|
|
4445
4445
|
}
|
|
4446
4446
|
static schema() {
|
|
@@ -4501,7 +4501,7 @@ var QuoteStyle;
|
|
|
4501
4501
|
QuoteStyle["AUTO_QUOTE"] = "auto";
|
|
4502
4502
|
QuoteStyle["ANY_QUOTE"] = "any";
|
|
4503
4503
|
})(QuoteStyle || (QuoteStyle = {}));
|
|
4504
|
-
const defaults$
|
|
4504
|
+
const defaults$s = {
|
|
4505
4505
|
style: "auto",
|
|
4506
4506
|
unquoted: false,
|
|
4507
4507
|
};
|
|
@@ -4568,7 +4568,7 @@ class AttrQuotes extends Rule {
|
|
|
4568
4568
|
};
|
|
4569
4569
|
}
|
|
4570
4570
|
constructor(options) {
|
|
4571
|
-
super({ ...defaults$
|
|
4571
|
+
super({ ...defaults$s, ...options });
|
|
4572
4572
|
this.style = parseStyle$4(this.options.style);
|
|
4573
4573
|
}
|
|
4574
4574
|
setup() {
|
|
@@ -4738,12 +4738,12 @@ class AttributeAllowedValues extends Rule {
|
|
|
4738
4738
|
}
|
|
4739
4739
|
}
|
|
4740
4740
|
|
|
4741
|
-
const defaults$
|
|
4741
|
+
const defaults$r = {
|
|
4742
4742
|
style: "omit",
|
|
4743
4743
|
};
|
|
4744
4744
|
class AttributeBooleanStyle extends Rule {
|
|
4745
4745
|
constructor(options) {
|
|
4746
|
-
super({ ...defaults$
|
|
4746
|
+
super({ ...defaults$r, ...options });
|
|
4747
4747
|
this.hasInvalidStyle = parseStyle$3(this.options.style);
|
|
4748
4748
|
}
|
|
4749
4749
|
static schema() {
|
|
@@ -4819,12 +4819,12 @@ function reportMessage$1(attr, style) {
|
|
|
4819
4819
|
return "";
|
|
4820
4820
|
}
|
|
4821
4821
|
|
|
4822
|
-
const defaults$
|
|
4822
|
+
const defaults$q = {
|
|
4823
4823
|
style: "omit",
|
|
4824
4824
|
};
|
|
4825
4825
|
class AttributeEmptyStyle extends Rule {
|
|
4826
4826
|
constructor(options) {
|
|
4827
|
-
super({ ...defaults$
|
|
4827
|
+
super({ ...defaults$q, ...options });
|
|
4828
4828
|
this.hasInvalidStyle = parseStyle$2(this.options.style);
|
|
4829
4829
|
}
|
|
4830
4830
|
static schema() {
|
|
@@ -4980,12 +4980,12 @@ function describePattern(pattern) {
|
|
|
4980
4980
|
}
|
|
4981
4981
|
}
|
|
4982
4982
|
|
|
4983
|
-
const defaults$
|
|
4983
|
+
const defaults$p = {
|
|
4984
4984
|
pattern: "kebabcase",
|
|
4985
4985
|
};
|
|
4986
4986
|
class ClassPattern extends Rule {
|
|
4987
4987
|
constructor(options) {
|
|
4988
|
-
super({ ...defaults$
|
|
4988
|
+
super({ ...defaults$p, ...options });
|
|
4989
4989
|
this.pattern = parsePattern(this.options.pattern);
|
|
4990
4990
|
}
|
|
4991
4991
|
static schema() {
|
|
@@ -5094,13 +5094,13 @@ class CloseOrder extends Rule {
|
|
|
5094
5094
|
}
|
|
5095
5095
|
}
|
|
5096
5096
|
|
|
5097
|
-
const defaults$
|
|
5097
|
+
const defaults$o = {
|
|
5098
5098
|
include: null,
|
|
5099
5099
|
exclude: null,
|
|
5100
5100
|
};
|
|
5101
5101
|
class Deprecated extends Rule {
|
|
5102
5102
|
constructor(options) {
|
|
5103
|
-
super({ ...defaults$
|
|
5103
|
+
super({ ...defaults$o, ...options });
|
|
5104
5104
|
}
|
|
5105
5105
|
static schema() {
|
|
5106
5106
|
return {
|
|
@@ -5263,12 +5263,12 @@ let NoStyleTag$1 = class NoStyleTag extends Rule {
|
|
|
5263
5263
|
}
|
|
5264
5264
|
};
|
|
5265
5265
|
|
|
5266
|
-
const defaults$
|
|
5266
|
+
const defaults$n = {
|
|
5267
5267
|
style: "uppercase",
|
|
5268
5268
|
};
|
|
5269
5269
|
class DoctypeStyle extends Rule {
|
|
5270
5270
|
constructor(options) {
|
|
5271
|
-
super({ ...defaults$
|
|
5271
|
+
super({ ...defaults$n, ...options });
|
|
5272
5272
|
}
|
|
5273
5273
|
static schema() {
|
|
5274
5274
|
return {
|
|
@@ -5300,12 +5300,12 @@ class DoctypeStyle extends Rule {
|
|
|
5300
5300
|
}
|
|
5301
5301
|
}
|
|
5302
5302
|
|
|
5303
|
-
const defaults$
|
|
5303
|
+
const defaults$m = {
|
|
5304
5304
|
style: "lowercase",
|
|
5305
5305
|
};
|
|
5306
5306
|
class ElementCase extends Rule {
|
|
5307
5307
|
constructor(options) {
|
|
5308
|
-
super({ ...defaults$
|
|
5308
|
+
super({ ...defaults$m, ...options });
|
|
5309
5309
|
this.style = new rulesHelper.CaseStyle(this.options.style, "element-case");
|
|
5310
5310
|
}
|
|
5311
5311
|
static schema() {
|
|
@@ -5371,14 +5371,14 @@ class ElementCase extends Rule {
|
|
|
5371
5371
|
}
|
|
5372
5372
|
}
|
|
5373
5373
|
|
|
5374
|
-
const defaults$
|
|
5374
|
+
const defaults$l = {
|
|
5375
5375
|
pattern: "^[a-z][a-z0-9\\-._]*-[a-z0-9\\-._]*$",
|
|
5376
5376
|
whitelist: [],
|
|
5377
5377
|
blacklist: [],
|
|
5378
5378
|
};
|
|
5379
5379
|
class ElementName extends Rule {
|
|
5380
5380
|
constructor(options) {
|
|
5381
|
-
super({ ...defaults$
|
|
5381
|
+
super({ ...defaults$l, ...options });
|
|
5382
5382
|
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
5383
5383
|
this.pattern = new RegExp(this.options.pattern);
|
|
5384
5384
|
}
|
|
@@ -5419,7 +5419,7 @@ class ElementName extends Rule {
|
|
|
5419
5419
|
...context.blacklist.map((cur) => `- ${cur}`),
|
|
5420
5420
|
];
|
|
5421
5421
|
}
|
|
5422
|
-
if (context.pattern !== defaults$
|
|
5422
|
+
if (context.pattern !== defaults$l.pattern) {
|
|
5423
5423
|
return [
|
|
5424
5424
|
`<${context.tagName}> is not a valid element name. This project is configured to only allow names matching the following regular expression:`,
|
|
5425
5425
|
"",
|
|
@@ -5963,46 +5963,125 @@ class EmptyTitle extends Rule {
|
|
|
5963
5963
|
}
|
|
5964
5964
|
}
|
|
5965
5965
|
|
|
5966
|
-
const
|
|
5966
|
+
const defaults$k = {
|
|
5967
|
+
allowArrayBrackets: true,
|
|
5968
|
+
shared: ["radio"],
|
|
5969
|
+
};
|
|
5970
|
+
const UNIQUE_CACHE_KEY = Symbol("form-elements-unique");
|
|
5971
|
+
const SHARED_CACHE_KEY = Symbol("form-elements-shared");
|
|
5967
5972
|
function haveName(name) {
|
|
5968
5973
|
return typeof name === "string" && name !== "";
|
|
5969
5974
|
}
|
|
5970
|
-
function
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
+
function allowSharedName(node, shared) {
|
|
5976
|
+
const type = node.getAttribute("type");
|
|
5977
|
+
return Boolean(type && type.valueMatches(shared, false));
|
|
5978
|
+
}
|
|
5979
|
+
function getDocumentation(context) {
|
|
5980
|
+
const trailer = "Each form control must have a unique name.";
|
|
5981
|
+
if (!context) {
|
|
5982
|
+
return trailer;
|
|
5983
|
+
}
|
|
5984
|
+
else {
|
|
5985
|
+
const { name } = context;
|
|
5986
|
+
switch (context.kind) {
|
|
5987
|
+
case "duplicate":
|
|
5988
|
+
return [`Duplicate form control name "${name}"`, trailer].join("\n");
|
|
5989
|
+
case "mix":
|
|
5990
|
+
return [
|
|
5991
|
+
`Form control name cannot mix regular name "{{ name }}" with array brackets "{{ name }}[]"`,
|
|
5992
|
+
trailer,
|
|
5993
|
+
].join("\n");
|
|
5994
|
+
}
|
|
5975
5995
|
}
|
|
5976
|
-
return true;
|
|
5977
5996
|
}
|
|
5978
5997
|
class FormDupName extends Rule {
|
|
5979
|
-
|
|
5998
|
+
constructor(options) {
|
|
5999
|
+
super({ ...defaults$k, ...options });
|
|
6000
|
+
}
|
|
6001
|
+
static schema() {
|
|
6002
|
+
return {
|
|
6003
|
+
allowArrayBrackets: {
|
|
6004
|
+
type: "boolean",
|
|
6005
|
+
},
|
|
6006
|
+
shared: {
|
|
6007
|
+
type: "array",
|
|
6008
|
+
items: {
|
|
6009
|
+
enum: ["radio", "checkbox", "submit"],
|
|
6010
|
+
},
|
|
6011
|
+
},
|
|
6012
|
+
};
|
|
6013
|
+
}
|
|
6014
|
+
documentation(context) {
|
|
5980
6015
|
return {
|
|
5981
|
-
description:
|
|
6016
|
+
description: getDocumentation(context),
|
|
5982
6017
|
url: "https://html-validate.org/rules/form-dup-name.html",
|
|
5983
6018
|
};
|
|
5984
6019
|
}
|
|
5985
6020
|
setup() {
|
|
5986
6021
|
const selector = this.getSelector();
|
|
6022
|
+
const { shared } = this.options;
|
|
5987
6023
|
this.on("dom:ready", (event) => {
|
|
5988
|
-
var _a;
|
|
6024
|
+
var _a, _b;
|
|
5989
6025
|
const { document } = event;
|
|
5990
|
-
const controls = document.querySelectorAll(selector)
|
|
5991
|
-
|
|
6026
|
+
const controls = document.querySelectorAll(selector);
|
|
6027
|
+
const [sharedControls, uniqueControls] = rulesHelper.partition(controls, (it) => {
|
|
6028
|
+
return allowSharedName(it, shared);
|
|
6029
|
+
});
|
|
6030
|
+
/* validate all form controls which require unique elements first so each
|
|
6031
|
+
* form has a populated list of unique names */
|
|
6032
|
+
for (const control of uniqueControls) {
|
|
6033
|
+
const attr = control.getAttribute("name");
|
|
6034
|
+
const name = attr === null || attr === void 0 ? void 0 : attr.value;
|
|
6035
|
+
if (!attr || !haveName(name)) {
|
|
6036
|
+
continue;
|
|
6037
|
+
}
|
|
6038
|
+
const form = (_a = control.closest("form")) !== null && _a !== void 0 ? _a : document.root;
|
|
6039
|
+
this.validateUniqueName(control, form, attr, name);
|
|
6040
|
+
}
|
|
6041
|
+
/* validate all form controls which allows shared names to ensure there is
|
|
6042
|
+
* no collision with other form controls */
|
|
6043
|
+
for (const control of sharedControls) {
|
|
5992
6044
|
const attr = control.getAttribute("name");
|
|
5993
6045
|
const name = attr === null || attr === void 0 ? void 0 : attr.value;
|
|
5994
|
-
if (attr
|
|
5995
|
-
|
|
5996
|
-
this.validateName(control, form, attr, name);
|
|
6046
|
+
if (!attr || !haveName(name)) {
|
|
6047
|
+
continue;
|
|
5997
6048
|
}
|
|
6049
|
+
const form = (_b = control.closest("form")) !== null && _b !== void 0 ? _b : document.root;
|
|
6050
|
+
this.validateSharedName(control, form, attr, name);
|
|
5998
6051
|
}
|
|
5999
6052
|
});
|
|
6000
6053
|
}
|
|
6001
|
-
|
|
6002
|
-
const elements = this.
|
|
6054
|
+
validateUniqueName(control, form, attr, name) {
|
|
6055
|
+
const elements = this.getUniqueElements(form);
|
|
6056
|
+
const { allowArrayBrackets } = this.options;
|
|
6057
|
+
if (allowArrayBrackets) {
|
|
6058
|
+
const isarray = name.endsWith("[]");
|
|
6059
|
+
const basename = isarray ? name.slice(0, -2) : name;
|
|
6060
|
+
const details = elements.get(basename);
|
|
6061
|
+
if (details && details.array !== isarray) {
|
|
6062
|
+
const context = {
|
|
6063
|
+
name: basename,
|
|
6064
|
+
kind: "mix",
|
|
6065
|
+
};
|
|
6066
|
+
this.report({
|
|
6067
|
+
node: control,
|
|
6068
|
+
location: attr.valueLocation,
|
|
6069
|
+
message: 'Cannot mix "{{ name }}[]" and "{{ name }}"',
|
|
6070
|
+
context,
|
|
6071
|
+
});
|
|
6072
|
+
return;
|
|
6073
|
+
}
|
|
6074
|
+
else if (!details && isarray) {
|
|
6075
|
+
elements.set(basename, {
|
|
6076
|
+
array: true,
|
|
6077
|
+
});
|
|
6078
|
+
return;
|
|
6079
|
+
}
|
|
6080
|
+
}
|
|
6003
6081
|
if (elements.has(name)) {
|
|
6004
6082
|
const context = {
|
|
6005
6083
|
name,
|
|
6084
|
+
kind: "duplicate",
|
|
6006
6085
|
};
|
|
6007
6086
|
this.report({
|
|
6008
6087
|
node: control,
|
|
@@ -6012,9 +6091,32 @@ class FormDupName extends Rule {
|
|
|
6012
6091
|
});
|
|
6013
6092
|
}
|
|
6014
6093
|
else {
|
|
6015
|
-
elements.
|
|
6094
|
+
elements.set(name, {
|
|
6095
|
+
array: false,
|
|
6096
|
+
});
|
|
6016
6097
|
}
|
|
6017
6098
|
}
|
|
6099
|
+
validateSharedName(control, form, attr, name) {
|
|
6100
|
+
var _a;
|
|
6101
|
+
const uniqueElements = this.getUniqueElements(form);
|
|
6102
|
+
const sharedElements = this.getSharedElements(form);
|
|
6103
|
+
/* istanbul ignore next: type will always be set or shared name wouldn't be allowed */
|
|
6104
|
+
const type = (_a = control.getAttributeValue("type")) !== null && _a !== void 0 ? _a : "";
|
|
6105
|
+
if (uniqueElements.has(name) ||
|
|
6106
|
+
(sharedElements.has(name) && sharedElements.get(name) !== type)) {
|
|
6107
|
+
const context = {
|
|
6108
|
+
name,
|
|
6109
|
+
kind: "duplicate",
|
|
6110
|
+
};
|
|
6111
|
+
this.report({
|
|
6112
|
+
node: control,
|
|
6113
|
+
location: attr.valueLocation,
|
|
6114
|
+
message: 'Duplicate form control name "{{ name }}"',
|
|
6115
|
+
context,
|
|
6116
|
+
});
|
|
6117
|
+
}
|
|
6118
|
+
sharedElements.set(name, type);
|
|
6119
|
+
}
|
|
6018
6120
|
getSelector() {
|
|
6019
6121
|
const tags = this.getTagsWithProperty("formAssociated").filter((it) => {
|
|
6020
6122
|
return this.isListedElement(it);
|
|
@@ -6030,14 +6132,25 @@ class FormDupName extends Rule {
|
|
|
6030
6132
|
}
|
|
6031
6133
|
return meta.formAssociated.listed;
|
|
6032
6134
|
}
|
|
6033
|
-
|
|
6034
|
-
const existing = form.cacheGet(
|
|
6135
|
+
getUniqueElements(form) {
|
|
6136
|
+
const existing = form.cacheGet(UNIQUE_CACHE_KEY);
|
|
6137
|
+
if (existing) {
|
|
6138
|
+
return existing;
|
|
6139
|
+
}
|
|
6140
|
+
else {
|
|
6141
|
+
const elements = new Map();
|
|
6142
|
+
form.cacheSet(UNIQUE_CACHE_KEY, elements);
|
|
6143
|
+
return elements;
|
|
6144
|
+
}
|
|
6145
|
+
}
|
|
6146
|
+
getSharedElements(form) {
|
|
6147
|
+
const existing = form.cacheGet(SHARED_CACHE_KEY);
|
|
6035
6148
|
if (existing) {
|
|
6036
6149
|
return existing;
|
|
6037
6150
|
}
|
|
6038
6151
|
else {
|
|
6039
|
-
const elements = new
|
|
6040
|
-
form.cacheSet(
|
|
6152
|
+
const elements = new Map();
|
|
6153
|
+
form.cacheSet(SHARED_CACHE_KEY, elements);
|
|
6041
6154
|
return elements;
|
|
6042
6155
|
}
|
|
6043
6156
|
}
|
|
@@ -11424,7 +11537,7 @@ class HtmlValidate {
|
|
|
11424
11537
|
/** @public */
|
|
11425
11538
|
const name = "html-validate";
|
|
11426
11539
|
/** @public */
|
|
11427
|
-
const version = "7.12.
|
|
11540
|
+
const version = "7.12.2";
|
|
11428
11541
|
/** @public */
|
|
11429
11542
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
11430
11543
|
|