html-validate 8.14.0 → 8.15.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 +522 -22
- package/dist/cjs/core.js.map +1 -1
- package/dist/es/core.js +522 -22
- package/dist/es/core.js.map +1 -1
- package/package.json +5 -5
package/dist/cjs/core.js
CHANGED
|
@@ -6556,26 +6556,6 @@ class IdPattern extends Rule {
|
|
|
6556
6556
|
const restricted = /* @__PURE__ */ new Map([
|
|
6557
6557
|
["accept", ["file"]],
|
|
6558
6558
|
["alt", ["image"]],
|
|
6559
|
-
[
|
|
6560
|
-
"autocomplete",
|
|
6561
|
-
[
|
|
6562
|
-
"hidden",
|
|
6563
|
-
"text",
|
|
6564
|
-
"search",
|
|
6565
|
-
"url",
|
|
6566
|
-
"tel",
|
|
6567
|
-
"email",
|
|
6568
|
-
"password",
|
|
6569
|
-
"date",
|
|
6570
|
-
"month",
|
|
6571
|
-
"week",
|
|
6572
|
-
"time",
|
|
6573
|
-
"datetime-local",
|
|
6574
|
-
"number",
|
|
6575
|
-
"range",
|
|
6576
|
-
"color"
|
|
6577
|
-
]
|
|
6578
|
-
],
|
|
6579
6559
|
["capture", ["file"]],
|
|
6580
6560
|
["checked", ["checkbox", "radio"]],
|
|
6581
6561
|
["dirname", ["text", "search"]],
|
|
@@ -6956,7 +6936,7 @@ class MetaRefresh extends Rule {
|
|
|
6956
6936
|
}
|
|
6957
6937
|
}
|
|
6958
6938
|
function parseContent(text) {
|
|
6959
|
-
const match = text.match(/^(\d+)(?:\s*;\s*url=(.*))?/);
|
|
6939
|
+
const match = text.match(/^(\d+)(?:\s*;\s*url=(.*))?/i);
|
|
6960
6940
|
if (match) {
|
|
6961
6941
|
return {
|
|
6962
6942
|
delay: parseInt(match[1], 10),
|
|
@@ -9043,6 +9023,522 @@ class UnknownCharReference extends Rule {
|
|
|
9043
9023
|
}
|
|
9044
9024
|
}
|
|
9045
9025
|
|
|
9026
|
+
const expectedOrder = ["section", "hint", "contact", "field1", "field2", "webauthn"];
|
|
9027
|
+
const fieldNames1 = [
|
|
9028
|
+
"name",
|
|
9029
|
+
"honorific-prefix",
|
|
9030
|
+
"given-name",
|
|
9031
|
+
"additional-name",
|
|
9032
|
+
"family-name",
|
|
9033
|
+
"honorific-suffix",
|
|
9034
|
+
"nickname",
|
|
9035
|
+
"username",
|
|
9036
|
+
"new-password",
|
|
9037
|
+
"current-password",
|
|
9038
|
+
"one-time-code",
|
|
9039
|
+
"organization-title",
|
|
9040
|
+
"organization",
|
|
9041
|
+
"street-address",
|
|
9042
|
+
"address-line1",
|
|
9043
|
+
"address-line2",
|
|
9044
|
+
"address-line3",
|
|
9045
|
+
"address-level4",
|
|
9046
|
+
"address-level3",
|
|
9047
|
+
"address-level2",
|
|
9048
|
+
"address-level1",
|
|
9049
|
+
"country",
|
|
9050
|
+
"country-name",
|
|
9051
|
+
"postal-code",
|
|
9052
|
+
"cc-name",
|
|
9053
|
+
"cc-given-name",
|
|
9054
|
+
"cc-additional-name",
|
|
9055
|
+
"cc-family-name",
|
|
9056
|
+
"cc-number",
|
|
9057
|
+
"cc-exp",
|
|
9058
|
+
"cc-exp-month",
|
|
9059
|
+
"cc-exp-year",
|
|
9060
|
+
"cc-csc",
|
|
9061
|
+
"cc-type",
|
|
9062
|
+
"transaction-currency",
|
|
9063
|
+
"transaction-amount",
|
|
9064
|
+
"language",
|
|
9065
|
+
"bday",
|
|
9066
|
+
"bday-day",
|
|
9067
|
+
"bday-month",
|
|
9068
|
+
"bday-year",
|
|
9069
|
+
"sex",
|
|
9070
|
+
"url",
|
|
9071
|
+
"photo"
|
|
9072
|
+
];
|
|
9073
|
+
const fieldNames2 = [
|
|
9074
|
+
"tel",
|
|
9075
|
+
"tel-country-code",
|
|
9076
|
+
"tel-national",
|
|
9077
|
+
"tel-area-code",
|
|
9078
|
+
"tel-local",
|
|
9079
|
+
"tel-local-prefix",
|
|
9080
|
+
"tel-local-suffix",
|
|
9081
|
+
"tel-extension",
|
|
9082
|
+
"email",
|
|
9083
|
+
"impp"
|
|
9084
|
+
];
|
|
9085
|
+
const fieldNameGroup = {
|
|
9086
|
+
name: "text",
|
|
9087
|
+
"honorific-prefix": "text",
|
|
9088
|
+
"given-name": "text",
|
|
9089
|
+
"additional-name": "text",
|
|
9090
|
+
"family-name": "text",
|
|
9091
|
+
"honorific-suffix": "text",
|
|
9092
|
+
nickname: "text",
|
|
9093
|
+
username: "username",
|
|
9094
|
+
"new-password": "password",
|
|
9095
|
+
"current-password": "password",
|
|
9096
|
+
"one-time-code": "password",
|
|
9097
|
+
"organization-title": "text",
|
|
9098
|
+
organization: "text",
|
|
9099
|
+
"street-address": "multiline",
|
|
9100
|
+
"address-line1": "text",
|
|
9101
|
+
"address-line2": "text",
|
|
9102
|
+
"address-line3": "text",
|
|
9103
|
+
"address-level4": "text",
|
|
9104
|
+
"address-level3": "text",
|
|
9105
|
+
"address-level2": "text",
|
|
9106
|
+
"address-level1": "text",
|
|
9107
|
+
country: "text",
|
|
9108
|
+
"country-name": "text",
|
|
9109
|
+
"postal-code": "text",
|
|
9110
|
+
"cc-name": "text",
|
|
9111
|
+
"cc-given-name": "text",
|
|
9112
|
+
"cc-additional-name": "text",
|
|
9113
|
+
"cc-family-name": "text",
|
|
9114
|
+
"cc-number": "text",
|
|
9115
|
+
"cc-exp": "month",
|
|
9116
|
+
"cc-exp-month": "numeric",
|
|
9117
|
+
"cc-exp-year": "numeric",
|
|
9118
|
+
"cc-csc": "text",
|
|
9119
|
+
"cc-type": "text",
|
|
9120
|
+
"transaction-currency": "text",
|
|
9121
|
+
"transaction-amount": "numeric",
|
|
9122
|
+
language: "text",
|
|
9123
|
+
bday: "date",
|
|
9124
|
+
"bday-day": "numeric",
|
|
9125
|
+
"bday-month": "numeric",
|
|
9126
|
+
"bday-year": "numeric",
|
|
9127
|
+
sex: "text",
|
|
9128
|
+
url: "url",
|
|
9129
|
+
photo: "url",
|
|
9130
|
+
tel: "tel",
|
|
9131
|
+
"tel-country-code": "text",
|
|
9132
|
+
"tel-national": "text",
|
|
9133
|
+
"tel-area-code": "text",
|
|
9134
|
+
"tel-local": "text",
|
|
9135
|
+
"tel-local-prefix": "text",
|
|
9136
|
+
"tel-local-suffix": "text",
|
|
9137
|
+
"tel-extension": "text",
|
|
9138
|
+
email: "username",
|
|
9139
|
+
impp: "url"
|
|
9140
|
+
};
|
|
9141
|
+
const disallowedInputTypes = ["checkbox", "radio", "file", "submit", "image", "reset", "button"];
|
|
9142
|
+
function matchSection(token) {
|
|
9143
|
+
return token.startsWith("section-");
|
|
9144
|
+
}
|
|
9145
|
+
function matchHint(token) {
|
|
9146
|
+
return token === "shipping" || token === "billing";
|
|
9147
|
+
}
|
|
9148
|
+
function matchFieldNames1(token) {
|
|
9149
|
+
return fieldNames1.includes(token);
|
|
9150
|
+
}
|
|
9151
|
+
function matchContact(token) {
|
|
9152
|
+
const haystack = ["home", "work", "mobile", "fax", "pager"];
|
|
9153
|
+
return haystack.includes(token);
|
|
9154
|
+
}
|
|
9155
|
+
function matchFieldNames2(token) {
|
|
9156
|
+
return fieldNames2.includes(token);
|
|
9157
|
+
}
|
|
9158
|
+
function matchWebauthn(token) {
|
|
9159
|
+
return token === "webauthn";
|
|
9160
|
+
}
|
|
9161
|
+
function matchToken(token) {
|
|
9162
|
+
if (matchSection(token)) {
|
|
9163
|
+
return "section";
|
|
9164
|
+
}
|
|
9165
|
+
if (matchHint(token)) {
|
|
9166
|
+
return "hint";
|
|
9167
|
+
}
|
|
9168
|
+
if (matchFieldNames1(token)) {
|
|
9169
|
+
return "field1";
|
|
9170
|
+
}
|
|
9171
|
+
if (matchFieldNames2(token)) {
|
|
9172
|
+
return "field2";
|
|
9173
|
+
}
|
|
9174
|
+
if (matchContact(token)) {
|
|
9175
|
+
return "contact";
|
|
9176
|
+
}
|
|
9177
|
+
if (matchWebauthn(token)) {
|
|
9178
|
+
return "webauthn";
|
|
9179
|
+
}
|
|
9180
|
+
return null;
|
|
9181
|
+
}
|
|
9182
|
+
function getControlGroups(type) {
|
|
9183
|
+
const allGroups = [
|
|
9184
|
+
"text",
|
|
9185
|
+
"multiline",
|
|
9186
|
+
"password",
|
|
9187
|
+
"url",
|
|
9188
|
+
"username",
|
|
9189
|
+
"tel",
|
|
9190
|
+
"numeric",
|
|
9191
|
+
"month",
|
|
9192
|
+
"date"
|
|
9193
|
+
];
|
|
9194
|
+
const mapping = {
|
|
9195
|
+
hidden: allGroups,
|
|
9196
|
+
text: allGroups.filter((it) => it !== "multiline"),
|
|
9197
|
+
search: allGroups.filter((it) => it !== "multiline"),
|
|
9198
|
+
password: ["password"],
|
|
9199
|
+
url: ["url"],
|
|
9200
|
+
email: ["username"],
|
|
9201
|
+
tel: ["tel"],
|
|
9202
|
+
number: ["numeric"],
|
|
9203
|
+
month: ["month"],
|
|
9204
|
+
date: ["date"]
|
|
9205
|
+
};
|
|
9206
|
+
const groups = mapping[type];
|
|
9207
|
+
if (groups) {
|
|
9208
|
+
return groups;
|
|
9209
|
+
}
|
|
9210
|
+
return [];
|
|
9211
|
+
}
|
|
9212
|
+
function isDisallowedType(node, type) {
|
|
9213
|
+
if (!node.is("input")) {
|
|
9214
|
+
return false;
|
|
9215
|
+
}
|
|
9216
|
+
return disallowedInputTypes.includes(type);
|
|
9217
|
+
}
|
|
9218
|
+
function getTerminalMessage(context) {
|
|
9219
|
+
switch (context.msg) {
|
|
9220
|
+
case 0 /* InvalidAttribute */:
|
|
9221
|
+
return "autocomplete attribute cannot be used on {{ what }}";
|
|
9222
|
+
case 1 /* InvalidValue */:
|
|
9223
|
+
return '"{{ value }}" cannot be used on {{ what }}';
|
|
9224
|
+
case 2 /* InvalidOrder */:
|
|
9225
|
+
return '"{{ second }}" must appear before "{{ first }}"';
|
|
9226
|
+
case 3 /* InvalidToken */:
|
|
9227
|
+
return '"{{ token }}" is not a valid autocomplete token or field name';
|
|
9228
|
+
case 4 /* InvalidCombination */:
|
|
9229
|
+
return '"{{ second }}" cannot be combined with "{{ first }}"';
|
|
9230
|
+
case 5 /* MissingField */:
|
|
9231
|
+
return "autocomplete attribute is missing field name";
|
|
9232
|
+
}
|
|
9233
|
+
}
|
|
9234
|
+
function getMarkdownMessage(context) {
|
|
9235
|
+
switch (context.msg) {
|
|
9236
|
+
case 0 /* InvalidAttribute */:
|
|
9237
|
+
return [
|
|
9238
|
+
`\`autocomplete\` attribute cannot be used on \`${context.what}\``,
|
|
9239
|
+
"",
|
|
9240
|
+
"The following input types cannot use the `autocomplete` attribute:",
|
|
9241
|
+
"",
|
|
9242
|
+
...disallowedInputTypes.map((it) => `- \`${it}\``)
|
|
9243
|
+
].join("\n");
|
|
9244
|
+
case 1 /* InvalidValue */: {
|
|
9245
|
+
const message = `\`"${context.value}"\` cannot be used on \`${context.what}\``;
|
|
9246
|
+
if (context.type === "form") {
|
|
9247
|
+
return [
|
|
9248
|
+
message,
|
|
9249
|
+
"",
|
|
9250
|
+
'The `<form>` element can only use the values `"on"` and `"off"`.'
|
|
9251
|
+
].join("\n");
|
|
9252
|
+
}
|
|
9253
|
+
if (context.type === "hidden") {
|
|
9254
|
+
return [
|
|
9255
|
+
message,
|
|
9256
|
+
"",
|
|
9257
|
+
'`<input type="hidden">` cannot use the values `"on"` and `"off"`.'
|
|
9258
|
+
].join("\n");
|
|
9259
|
+
}
|
|
9260
|
+
const controlGroups = getControlGroups(context.type);
|
|
9261
|
+
const currentGroup = fieldNameGroup[context.value];
|
|
9262
|
+
return [
|
|
9263
|
+
message,
|
|
9264
|
+
"",
|
|
9265
|
+
`\`${context.what}\` allows autocomplete fields from the following group${controlGroups.length > 1 ? "s" : ""}:`,
|
|
9266
|
+
"",
|
|
9267
|
+
...controlGroups.map((it) => `- ${it}`),
|
|
9268
|
+
"",
|
|
9269
|
+
`The field \`"${context.value}"\` belongs to the group /${currentGroup}/ which cannot be used with this input type.`
|
|
9270
|
+
].join("\n");
|
|
9271
|
+
}
|
|
9272
|
+
case 2 /* InvalidOrder */:
|
|
9273
|
+
return [
|
|
9274
|
+
`\`"${context.second}"\` must appear before \`"${context.first}"\``,
|
|
9275
|
+
"",
|
|
9276
|
+
"The autocomplete tokens must appear in the following order:",
|
|
9277
|
+
"",
|
|
9278
|
+
"- Optional section name (`section-` prefix).",
|
|
9279
|
+
"- Optional `shipping` or `billing` token.",
|
|
9280
|
+
"- Optional `home`, `work`, `mobile`, `fax` or `pager` token (for fields supporting it).",
|
|
9281
|
+
"- Field name",
|
|
9282
|
+
"- Optional `webauthn` token."
|
|
9283
|
+
].join("\n");
|
|
9284
|
+
case 3 /* InvalidToken */:
|
|
9285
|
+
return `\`"${context.token}"\` is not a valid autocomplete token or field name`;
|
|
9286
|
+
case 4 /* InvalidCombination */:
|
|
9287
|
+
return `\`"${context.second}"\` cannot be combined with \`"${context.first}"\``;
|
|
9288
|
+
case 5 /* MissingField */:
|
|
9289
|
+
return "Autocomplete attribute is missing field name";
|
|
9290
|
+
}
|
|
9291
|
+
}
|
|
9292
|
+
class ValidAutocomplete extends Rule {
|
|
9293
|
+
documentation(context) {
|
|
9294
|
+
return {
|
|
9295
|
+
description: getMarkdownMessage(context),
|
|
9296
|
+
url: "https://html-validate.org/rules/valid-autocomplete.html"
|
|
9297
|
+
};
|
|
9298
|
+
}
|
|
9299
|
+
setup() {
|
|
9300
|
+
this.on("dom:ready", (event) => {
|
|
9301
|
+
const { document } = event;
|
|
9302
|
+
const elements = document.querySelectorAll("[autocomplete]");
|
|
9303
|
+
for (const element of elements) {
|
|
9304
|
+
const autocomplete = element.getAttribute("autocomplete");
|
|
9305
|
+
if (autocomplete.value === null || autocomplete.value instanceof DynamicValue) {
|
|
9306
|
+
continue;
|
|
9307
|
+
}
|
|
9308
|
+
const location = autocomplete.valueLocation;
|
|
9309
|
+
const value = autocomplete.value.toLowerCase();
|
|
9310
|
+
const tokens = new DOMTokenList(value, location);
|
|
9311
|
+
if (tokens.length === 0) {
|
|
9312
|
+
continue;
|
|
9313
|
+
}
|
|
9314
|
+
this.validate(element, value, tokens, autocomplete.keyLocation, location);
|
|
9315
|
+
}
|
|
9316
|
+
});
|
|
9317
|
+
}
|
|
9318
|
+
validate(node, value, tokens, keyLocation, valueLocation) {
|
|
9319
|
+
switch (node.tagName) {
|
|
9320
|
+
case "form":
|
|
9321
|
+
this.validateFormAutocomplete(node, value, valueLocation);
|
|
9322
|
+
break;
|
|
9323
|
+
case "input":
|
|
9324
|
+
case "textarea":
|
|
9325
|
+
case "select":
|
|
9326
|
+
this.validateControlAutocomplete(node, tokens, keyLocation);
|
|
9327
|
+
break;
|
|
9328
|
+
}
|
|
9329
|
+
}
|
|
9330
|
+
validateControlAutocomplete(node, tokens, keyLocation) {
|
|
9331
|
+
const type = node.getAttributeValue("type") ?? "text";
|
|
9332
|
+
const mantle = type !== "hidden" ? "expectation" : "anchor";
|
|
9333
|
+
if (isDisallowedType(node, type)) {
|
|
9334
|
+
const context = {
|
|
9335
|
+
msg: 0 /* InvalidAttribute */,
|
|
9336
|
+
what: `<input type="${type}">`
|
|
9337
|
+
};
|
|
9338
|
+
this.report({
|
|
9339
|
+
node,
|
|
9340
|
+
message: getTerminalMessage(context),
|
|
9341
|
+
location: keyLocation,
|
|
9342
|
+
context
|
|
9343
|
+
});
|
|
9344
|
+
return;
|
|
9345
|
+
}
|
|
9346
|
+
if (tokens.includes("on") || tokens.includes("off")) {
|
|
9347
|
+
this.validateOnOff(node, mantle, tokens);
|
|
9348
|
+
return;
|
|
9349
|
+
}
|
|
9350
|
+
this.validateTokens(node, tokens, keyLocation);
|
|
9351
|
+
}
|
|
9352
|
+
validateFormAutocomplete(node, value, location) {
|
|
9353
|
+
const trimmed = value.trim();
|
|
9354
|
+
if (["on", "off"].includes(trimmed)) {
|
|
9355
|
+
return;
|
|
9356
|
+
}
|
|
9357
|
+
const context = {
|
|
9358
|
+
msg: 1 /* InvalidValue */,
|
|
9359
|
+
type: "form",
|
|
9360
|
+
value: trimmed,
|
|
9361
|
+
what: "<form>"
|
|
9362
|
+
};
|
|
9363
|
+
this.report({
|
|
9364
|
+
node,
|
|
9365
|
+
message: getTerminalMessage(context),
|
|
9366
|
+
location,
|
|
9367
|
+
context
|
|
9368
|
+
});
|
|
9369
|
+
}
|
|
9370
|
+
validateOnOff(node, mantle, tokens) {
|
|
9371
|
+
const index = tokens.findIndex((it) => it === "on" || it === "off");
|
|
9372
|
+
const value = tokens.item(index);
|
|
9373
|
+
const location = tokens.location(index);
|
|
9374
|
+
if (tokens.length > 1) {
|
|
9375
|
+
const context = {
|
|
9376
|
+
msg: 4 /* InvalidCombination */,
|
|
9377
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
9378
|
+
first: tokens.item(index > 0 ? 0 : 1),
|
|
9379
|
+
second: value
|
|
9380
|
+
};
|
|
9381
|
+
this.report({
|
|
9382
|
+
node,
|
|
9383
|
+
message: getTerminalMessage(context),
|
|
9384
|
+
location,
|
|
9385
|
+
context
|
|
9386
|
+
});
|
|
9387
|
+
}
|
|
9388
|
+
switch (mantle) {
|
|
9389
|
+
case "expectation":
|
|
9390
|
+
return;
|
|
9391
|
+
case "anchor": {
|
|
9392
|
+
const context = {
|
|
9393
|
+
msg: 1 /* InvalidValue */,
|
|
9394
|
+
type: "hidden",
|
|
9395
|
+
value,
|
|
9396
|
+
what: `<input type="hidden">`
|
|
9397
|
+
};
|
|
9398
|
+
this.report({
|
|
9399
|
+
node,
|
|
9400
|
+
message: getTerminalMessage(context),
|
|
9401
|
+
location: tokens.location(0),
|
|
9402
|
+
context
|
|
9403
|
+
});
|
|
9404
|
+
}
|
|
9405
|
+
}
|
|
9406
|
+
}
|
|
9407
|
+
validateTokens(node, tokens, keyLocation) {
|
|
9408
|
+
const order = [];
|
|
9409
|
+
for (const { item, location } of tokens.iterator()) {
|
|
9410
|
+
const tokenType = matchToken(item);
|
|
9411
|
+
if (tokenType) {
|
|
9412
|
+
order.push(tokenType);
|
|
9413
|
+
} else {
|
|
9414
|
+
const context = {
|
|
9415
|
+
msg: 3 /* InvalidToken */,
|
|
9416
|
+
token: item
|
|
9417
|
+
};
|
|
9418
|
+
this.report({
|
|
9419
|
+
node,
|
|
9420
|
+
message: getTerminalMessage(context),
|
|
9421
|
+
location,
|
|
9422
|
+
context
|
|
9423
|
+
});
|
|
9424
|
+
return;
|
|
9425
|
+
}
|
|
9426
|
+
}
|
|
9427
|
+
const fieldTokens = order.map((it) => it === "field1" || it === "field2");
|
|
9428
|
+
this.validateFieldPresence(node, tokens, fieldTokens, keyLocation);
|
|
9429
|
+
this.validateContact(node, tokens, order);
|
|
9430
|
+
this.validateOrder(node, tokens, order);
|
|
9431
|
+
this.validateControlGroup(node, tokens, fieldTokens);
|
|
9432
|
+
}
|
|
9433
|
+
/**
|
|
9434
|
+
* Ensure that exactly one field name is present from the two field lists.
|
|
9435
|
+
*/
|
|
9436
|
+
validateFieldPresence(node, tokens, fieldTokens, keyLocation) {
|
|
9437
|
+
const numFields = fieldTokens.filter(Boolean).length;
|
|
9438
|
+
if (numFields === 0) {
|
|
9439
|
+
const context = {
|
|
9440
|
+
msg: 5 /* MissingField */
|
|
9441
|
+
};
|
|
9442
|
+
this.report({
|
|
9443
|
+
node,
|
|
9444
|
+
message: getTerminalMessage(context),
|
|
9445
|
+
location: keyLocation,
|
|
9446
|
+
context
|
|
9447
|
+
});
|
|
9448
|
+
} else if (numFields > 1) {
|
|
9449
|
+
const a = fieldTokens.indexOf(true);
|
|
9450
|
+
const b = fieldTokens.lastIndexOf(true);
|
|
9451
|
+
const context = {
|
|
9452
|
+
msg: 4 /* InvalidCombination */,
|
|
9453
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
9454
|
+
first: tokens.item(a),
|
|
9455
|
+
second: tokens.item(b)
|
|
9456
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
9457
|
+
};
|
|
9458
|
+
this.report({
|
|
9459
|
+
node,
|
|
9460
|
+
message: getTerminalMessage(context),
|
|
9461
|
+
location: tokens.location(b),
|
|
9462
|
+
context
|
|
9463
|
+
});
|
|
9464
|
+
}
|
|
9465
|
+
}
|
|
9466
|
+
/**
|
|
9467
|
+
* Ensure contact token is only used with field names from the second list.
|
|
9468
|
+
*/
|
|
9469
|
+
validateContact(node, tokens, order) {
|
|
9470
|
+
if (order.includes("contact") && order.includes("field1")) {
|
|
9471
|
+
const a = order.indexOf("field1");
|
|
9472
|
+
const b = order.indexOf("contact");
|
|
9473
|
+
const context = {
|
|
9474
|
+
msg: 4 /* InvalidCombination */,
|
|
9475
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
9476
|
+
first: tokens.item(a),
|
|
9477
|
+
second: tokens.item(b)
|
|
9478
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
9479
|
+
};
|
|
9480
|
+
this.report({
|
|
9481
|
+
node,
|
|
9482
|
+
message: getTerminalMessage(context),
|
|
9483
|
+
location: tokens.location(b),
|
|
9484
|
+
context
|
|
9485
|
+
});
|
|
9486
|
+
}
|
|
9487
|
+
}
|
|
9488
|
+
validateOrder(node, tokens, order) {
|
|
9489
|
+
const indicies = order.map((it) => expectedOrder.indexOf(it));
|
|
9490
|
+
for (let i = 0; i < indicies.length - 1; i++) {
|
|
9491
|
+
if (indicies[0] > indicies[i + 1]) {
|
|
9492
|
+
const context = {
|
|
9493
|
+
msg: 2 /* InvalidOrder */,
|
|
9494
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion -- it must be present of it wouldn't be found */
|
|
9495
|
+
first: tokens.item(i),
|
|
9496
|
+
second: tokens.item(i + 1)
|
|
9497
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
9498
|
+
};
|
|
9499
|
+
this.report({
|
|
9500
|
+
node,
|
|
9501
|
+
message: getTerminalMessage(context),
|
|
9502
|
+
location: tokens.location(i + 1),
|
|
9503
|
+
context
|
|
9504
|
+
});
|
|
9505
|
+
}
|
|
9506
|
+
}
|
|
9507
|
+
}
|
|
9508
|
+
validateControlGroup(node, tokens, fieldTokens) {
|
|
9509
|
+
const numFields = fieldTokens.filter(Boolean).length;
|
|
9510
|
+
if (numFields === 0) {
|
|
9511
|
+
return;
|
|
9512
|
+
}
|
|
9513
|
+
if (!node.is("input")) {
|
|
9514
|
+
return;
|
|
9515
|
+
}
|
|
9516
|
+
const attr = node.getAttribute("type");
|
|
9517
|
+
const type = (attr == null ? void 0 : attr.value) ?? "text";
|
|
9518
|
+
if (type instanceof DynamicValue) {
|
|
9519
|
+
return;
|
|
9520
|
+
}
|
|
9521
|
+
const controlGroups = getControlGroups(type);
|
|
9522
|
+
const fieldIndex = fieldTokens.indexOf(true);
|
|
9523
|
+
const fieldToken = tokens.item(fieldIndex);
|
|
9524
|
+
const fieldGroup = fieldNameGroup[fieldToken];
|
|
9525
|
+
if (!controlGroups.includes(fieldGroup)) {
|
|
9526
|
+
const context = {
|
|
9527
|
+
msg: 1 /* InvalidValue */,
|
|
9528
|
+
type,
|
|
9529
|
+
value: fieldToken,
|
|
9530
|
+
what: `<input type="${type}">`
|
|
9531
|
+
};
|
|
9532
|
+
this.report({
|
|
9533
|
+
node,
|
|
9534
|
+
message: getTerminalMessage(context),
|
|
9535
|
+
location: tokens.location(fieldIndex),
|
|
9536
|
+
context
|
|
9537
|
+
});
|
|
9538
|
+
}
|
|
9539
|
+
}
|
|
9540
|
+
}
|
|
9541
|
+
|
|
9046
9542
|
const defaults$3 = {
|
|
9047
9543
|
relaxed: false
|
|
9048
9544
|
};
|
|
@@ -9597,6 +10093,7 @@ const bundledRules = {
|
|
|
9597
10093
|
"text-content": TextContent,
|
|
9598
10094
|
"unique-landmark": UniqueLandmark,
|
|
9599
10095
|
"unrecognized-char-ref": UnknownCharReference,
|
|
10096
|
+
"valid-autocomplete": ValidAutocomplete,
|
|
9600
10097
|
"valid-id": ValidID,
|
|
9601
10098
|
"void-content": VoidContent,
|
|
9602
10099
|
"void-style": VoidStyle,
|
|
@@ -9627,6 +10124,7 @@ const config$4 = {
|
|
|
9627
10124
|
"svg-focusable": "off",
|
|
9628
10125
|
"text-content": "error",
|
|
9629
10126
|
"unique-landmark": "error",
|
|
10127
|
+
"valid-autocomplete": "error",
|
|
9630
10128
|
"wcag/h30": "error",
|
|
9631
10129
|
"wcag/h32": "error",
|
|
9632
10130
|
"wcag/h36": "error",
|
|
@@ -9726,6 +10224,7 @@ const config$1 = {
|
|
|
9726
10224
|
"text-content": "error",
|
|
9727
10225
|
"unique-landmark": "error",
|
|
9728
10226
|
"unrecognized-char-ref": "error",
|
|
10227
|
+
"valid-autocomplete": "error",
|
|
9729
10228
|
"valid-id": ["error", { relaxed: false }],
|
|
9730
10229
|
void: "off",
|
|
9731
10230
|
"void-content": "error",
|
|
@@ -9773,6 +10272,7 @@ const config = {
|
|
|
9773
10272
|
"no-unused-disable": "error",
|
|
9774
10273
|
"script-element": "error",
|
|
9775
10274
|
"unrecognized-char-ref": "error",
|
|
10275
|
+
"valid-autocomplete": "error",
|
|
9776
10276
|
"valid-id": ["error", { relaxed: true }],
|
|
9777
10277
|
"void-content": "error"
|
|
9778
10278
|
}
|
|
@@ -11998,7 +12498,7 @@ class HtmlValidate {
|
|
|
11998
12498
|
}
|
|
11999
12499
|
|
|
12000
12500
|
const name = "html-validate";
|
|
12001
|
-
const version = "8.
|
|
12501
|
+
const version = "8.15.0";
|
|
12002
12502
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
12003
12503
|
|
|
12004
12504
|
function definePlugin(plugin) {
|