html-validate 7.11.0 → 7.12.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/browser.d.ts +1 -1
- package/dist/cjs/browser.js +1 -0
- package/dist/cjs/browser.js.map +1 -1
- package/dist/cjs/cli.js +1 -0
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/core.d.ts +30 -4
- package/dist/cjs/core.js +229 -5
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/elements.js +25 -8
- package/dist/cjs/elements.js.map +1 -1
- package/dist/cjs/html-validate.js +8 -1
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/jest.d.ts +1 -1
- package/dist/cjs/meta-helper.d.ts +1 -1
- package/dist/cjs/rules-helper.d.ts +1 -1
- package/dist/cjs/test-utils.d.ts +1 -1
- package/dist/es/browser.d.ts +1 -1
- package/dist/es/browser.js +1 -1
- package/dist/es/cli.js +1 -0
- package/dist/es/cli.js.map +1 -1
- package/dist/es/core.d.ts +30 -4
- package/dist/es/core.js +229 -6
- package/dist/es/core.js.map +1 -1
- package/dist/es/elements.js +25 -8
- package/dist/es/elements.js.map +1 -1
- package/dist/es/html-validate.js +8 -1
- package/dist/es/html-validate.js.map +1 -1
- package/dist/es/index.d.ts +3 -3
- package/dist/es/index.js +1 -1
- package/dist/es/jest.d.ts +1 -1
- package/dist/es/meta-helper.d.ts +1 -1
- package/dist/es/rules-helper.d.ts +1 -1
- package/dist/es/test-utils.d.ts +1 -1
- package/dist/schema/elements.json +19 -0
- package/package.json +5 -5
package/dist/es/core.d.ts
CHANGED
|
@@ -343,6 +343,14 @@ declare abstract class Rule<ContextType = void, OptionsType = void> {
|
|
|
343
343
|
isKeywordIgnored<T extends IncludeExcludeOptions>(this: {
|
|
344
344
|
options: T;
|
|
345
345
|
}, keyword: string, matcher?: (list: string[], it: string) => boolean): boolean;
|
|
346
|
+
/**
|
|
347
|
+
* Get [[MetaElement]] for the given tag. If no specific metadata is present
|
|
348
|
+
* the global metadata is returned or null if no global is present.
|
|
349
|
+
*
|
|
350
|
+
* @public
|
|
351
|
+
* @returns A shallow copy of metadata.
|
|
352
|
+
*/
|
|
353
|
+
getMetaFor(tagName: string): MetaElement | null;
|
|
346
354
|
/**
|
|
347
355
|
* Find all tags which has enabled given property.
|
|
348
356
|
*/
|
|
@@ -1002,13 +1010,16 @@ declare class Attribute {
|
|
|
1002
1010
|
/**
|
|
1003
1011
|
* Test attribute value.
|
|
1004
1012
|
*
|
|
1005
|
-
* @param pattern - Pattern to match value against.
|
|
1013
|
+
* @param pattern - Pattern to match value against. Can be a RegExp, literal
|
|
1014
|
+
* string or an array of strings (returns true if any value matches the
|
|
1015
|
+
* array).
|
|
1006
1016
|
* @param dynamicMatches - If true `DynamicValue` will always match, if false
|
|
1007
1017
|
* it never matches.
|
|
1008
1018
|
* @returns `true` if attribute value matches pattern.
|
|
1009
1019
|
*/
|
|
1010
1020
|
valueMatches(pattern: RegExp, dynamicMatches?: boolean): boolean;
|
|
1011
1021
|
valueMatches(pattern: string, dynamicMatches?: boolean): boolean;
|
|
1022
|
+
valueMatches(pattern: string[], dynamicMatches?: boolean): boolean;
|
|
1012
1023
|
}
|
|
1013
1024
|
|
|
1014
1025
|
interface CSSStyleDeclaration {
|
|
@@ -1688,8 +1699,10 @@ declare enum TextContent {
|
|
|
1688
1699
|
* description if there is an error.
|
|
1689
1700
|
*
|
|
1690
1701
|
* @public
|
|
1702
|
+
* @param node - The node the attribute belongs to.
|
|
1703
|
+
* @param attr - The current attribute being validated.
|
|
1691
1704
|
*/
|
|
1692
|
-
type MetaAttributeAllowedCallback = (node: HtmlElement) => string | null | undefined;
|
|
1705
|
+
type MetaAttributeAllowedCallback = (node: HtmlElement, attr: Attribute) => string | null | undefined;
|
|
1693
1706
|
/**
|
|
1694
1707
|
* @public
|
|
1695
1708
|
*/
|
|
@@ -1708,6 +1721,10 @@ interface DeprecatedElement {
|
|
|
1708
1721
|
documentation?: string;
|
|
1709
1722
|
source?: string;
|
|
1710
1723
|
}
|
|
1724
|
+
interface FormAssociated {
|
|
1725
|
+
/** Listed elements have a name attribute and is listed in the form and fieldset elements property. */
|
|
1726
|
+
listed: boolean;
|
|
1727
|
+
}
|
|
1711
1728
|
/**
|
|
1712
1729
|
* @public
|
|
1713
1730
|
*/
|
|
@@ -1727,6 +1744,8 @@ interface MetaData {
|
|
|
1727
1744
|
implicitClosed?: string[];
|
|
1728
1745
|
scriptSupporting?: boolean;
|
|
1729
1746
|
form?: boolean;
|
|
1747
|
+
/** Mark element as a form-associated element */
|
|
1748
|
+
formAssociated?: Partial<FormAssociated>;
|
|
1730
1749
|
labelable?: boolean | PropertyExpression;
|
|
1731
1750
|
deprecatedAttributes?: string[];
|
|
1732
1751
|
requiredAttributes?: string[];
|
|
@@ -1743,7 +1762,7 @@ interface MetaData {
|
|
|
1743
1762
|
* Properties listed here can be used to reverse search elements with the given
|
|
1744
1763
|
* property enabled. See [[MetaTable.getTagsWithProperty]].
|
|
1745
1764
|
*/
|
|
1746
|
-
type MetaLookupableProperty = "metadata" | "flow" | "sectioning" | "heading" | "phrasing" | "embedded" | "interactive" | "deprecated" | "foreign" | "void" | "transparent" | "scriptSupporting" | "form" | "labelable";
|
|
1765
|
+
type MetaLookupableProperty = "metadata" | "flow" | "sectioning" | "heading" | "phrasing" | "embedded" | "interactive" | "deprecated" | "foreign" | "void" | "transparent" | "scriptSupporting" | "form" | "formAssociated" | "labelable";
|
|
1747
1766
|
/**
|
|
1748
1767
|
* Properties listed here can be copied (loaded) onto another element using
|
|
1749
1768
|
* [[HtmlElement.loadMeta]].
|
|
@@ -1756,6 +1775,7 @@ declare const MetaCopyableProperty: Array<keyof MetaElement>;
|
|
|
1756
1775
|
*/
|
|
1757
1776
|
interface MetaElement extends Omit<MetaData, "deprecatedAttributes" | "requiredAttributes"> {
|
|
1758
1777
|
tagName: string;
|
|
1778
|
+
formAssociated?: FormAssociated;
|
|
1759
1779
|
attributes: Record<string, MetaAttribute>;
|
|
1760
1780
|
textContent?: TextContent;
|
|
1761
1781
|
}
|
|
@@ -2041,6 +2061,11 @@ declare class NestedError extends Error {
|
|
|
2041
2061
|
* @public
|
|
2042
2062
|
*/
|
|
2043
2063
|
declare class UserError extends NestedError {
|
|
2064
|
+
constructor(message: string, nested?: Error);
|
|
2065
|
+
/**
|
|
2066
|
+
* @public
|
|
2067
|
+
*/
|
|
2068
|
+
prettyFormat(): string | undefined;
|
|
2044
2069
|
}
|
|
2045
2070
|
|
|
2046
2071
|
/**
|
|
@@ -2069,6 +2094,7 @@ declare class WrappedError<T> extends Error {
|
|
|
2069
2094
|
* @public
|
|
2070
2095
|
*/
|
|
2071
2096
|
declare class ConfigError extends UserError {
|
|
2097
|
+
constructor(message: string, nested?: Error);
|
|
2072
2098
|
}
|
|
2073
2099
|
|
|
2074
2100
|
/**
|
|
@@ -2393,4 +2419,4 @@ interface AvailableFormatters {
|
|
|
2393
2419
|
declare function getFormatter(name: keyof AvailableFormatters): Formatter;
|
|
2394
2420
|
declare function getFormatter(name: string): Formatter | null;
|
|
2395
2421
|
|
|
2396
|
-
export {
|
|
2422
|
+
export { EventCallback as $, AttributeData as A, Reporter as B, Config as C, DynamicValue as D, EventDump as E, Message as F, Result as G, HtmlValidate as H, DeferredMessage as I, TransformContext as J, Transformer as K, Location as L, MetaData as M, NodeClosed as N, TemplateExtractor as O, ProcessAttributeCallback as P, Plugin as Q, Rule as R, Severity as S, TextNode as T, UserError as U, SchemaValidationPatch as V, WrappedError as W, definePlugin as X, Parser as Y, ruleExists as Z, EventHandler as _, ConfigData as a, Event as a0, ConfigReadyEvent as a1, SourceReadyEvent as a2, TokenEvent as a3, TagStartEvent as a4, TagOpenEvent as a5, TagEndEvent as a6, TagCloseEvent as a7, TagReadyEvent as a8, ElementReadyEvent as a9, AttributeEvent as aa, WhitespaceEvent as ab, ConditionalEvent as ac, DirectiveEvent as ad, DoctypeEvent as ae, DOMLoadEvent as af, DOMReadyEvent as ag, TriggerEventMap as ah, ListenEventMap as ai, FileSystemConfigLoader as aj, Formatter as ak, getFormatter as al, compatibilityCheck as am, CompatibilityOptions as an, ConfigError as b, ConfigLoader as c, StaticConfigLoader as d, Attribute as e, HtmlElement as f, CSSStyleDeclaration as g, TokenDump as h, SchemaValidationError as i, NestedError as j, MetaDataTable as k, MetaElement as l, MetaAttribute as m, MetaAttributeAllowedCallback as n, MetaTable as o, presets as p, MetaCopyableProperty as q, RuleConstructor as r, RuleDocumentation as s, Source as t, SourceHooks as u, version as v, ProcessElementCallback as w, ProcessElementContext as x, sliceLocation as y, Report as z };
|
package/dist/es/core.js
CHANGED
|
@@ -303,6 +303,10 @@ class Attribute {
|
|
|
303
303
|
if (this.value instanceof DynamicValue) {
|
|
304
304
|
return dynamicMatches;
|
|
305
305
|
}
|
|
306
|
+
/* test against an array of keywords */
|
|
307
|
+
if (Array.isArray(pattern)) {
|
|
308
|
+
return pattern.includes(this.value);
|
|
309
|
+
}
|
|
306
310
|
/* test value against pattern */
|
|
307
311
|
if (pattern instanceof RegExp) {
|
|
308
312
|
return this.value.match(pattern) !== null;
|
|
@@ -466,6 +470,7 @@ const MetaCopyableProperty = [
|
|
|
466
470
|
"interactive",
|
|
467
471
|
"transparent",
|
|
468
472
|
"form",
|
|
473
|
+
"formAssociated",
|
|
469
474
|
"labelable",
|
|
470
475
|
"attributes",
|
|
471
476
|
"permittedContent",
|
|
@@ -1640,6 +1645,7 @@ class NestedError extends Error {
|
|
|
1640
1645
|
constructor(message, nested) {
|
|
1641
1646
|
super(message);
|
|
1642
1647
|
Error.captureStackTrace(this, NestedError);
|
|
1648
|
+
this.name = NestedError.name;
|
|
1643
1649
|
if (nested && nested.stack) {
|
|
1644
1650
|
this.stack += `\nCaused by: ${nested.stack}`;
|
|
1645
1651
|
}
|
|
@@ -1650,6 +1656,48 @@ class NestedError extends Error {
|
|
|
1650
1656
|
* @public
|
|
1651
1657
|
*/
|
|
1652
1658
|
class UserError extends NestedError {
|
|
1659
|
+
constructor(message, nested) {
|
|
1660
|
+
super(message, nested);
|
|
1661
|
+
Error.captureStackTrace(this, UserError);
|
|
1662
|
+
this.name = UserError.name;
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* @public
|
|
1666
|
+
*/
|
|
1667
|
+
/* istanbul ignore next: default implementation */
|
|
1668
|
+
prettyFormat() {
|
|
1669
|
+
return undefined;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
/**
|
|
1674
|
+
* @internal
|
|
1675
|
+
*/
|
|
1676
|
+
class InheritError extends UserError {
|
|
1677
|
+
constructor({ tagName, inherit }) {
|
|
1678
|
+
const message = `Element <${tagName}> cannot inherit from <${inherit}>: no such element`;
|
|
1679
|
+
super(message);
|
|
1680
|
+
Error.captureStackTrace(this, InheritError);
|
|
1681
|
+
this.name = InheritError.name;
|
|
1682
|
+
this.tagName = tagName;
|
|
1683
|
+
this.inherit = inherit;
|
|
1684
|
+
this.filename = null;
|
|
1685
|
+
}
|
|
1686
|
+
prettyFormat() {
|
|
1687
|
+
const { message, tagName, inherit } = this;
|
|
1688
|
+
const source = this.filename
|
|
1689
|
+
? ["", "This error occurred when loading element metadata from:", `"${this.filename}"`, ""]
|
|
1690
|
+
: [""];
|
|
1691
|
+
return [
|
|
1692
|
+
message,
|
|
1693
|
+
...source,
|
|
1694
|
+
"This usually occurs when the elements are defined in the wrong order, try one of the following:",
|
|
1695
|
+
"",
|
|
1696
|
+
` - Ensure the spelling of "${inherit}" is correct.`,
|
|
1697
|
+
` - Ensure the file containing "${inherit}" is loaded before the file containing "${tagName}".`,
|
|
1698
|
+
` - Move the definition of "${inherit}" above the definition for "${tagName}".`,
|
|
1699
|
+
].join("\n");
|
|
1700
|
+
}
|
|
1653
1701
|
}
|
|
1654
1702
|
|
|
1655
1703
|
function getSummary(schema, obj, errors) {
|
|
@@ -1839,6 +1887,10 @@ const patternProperties = {
|
|
|
1839
1887
|
title: "Mark element as a submittable form element",
|
|
1840
1888
|
type: "boolean"
|
|
1841
1889
|
},
|
|
1890
|
+
formAssociated: {
|
|
1891
|
+
title: "Mark element as a form-associated element",
|
|
1892
|
+
$ref: "#/definitions/FormAssociated"
|
|
1893
|
+
},
|
|
1842
1894
|
labelable: {
|
|
1843
1895
|
title: "Mark this element as labelable",
|
|
1844
1896
|
description: "This element may contain an associated label element.",
|
|
@@ -1984,6 +2036,16 @@ const definitions = {
|
|
|
1984
2036
|
}
|
|
1985
2037
|
}
|
|
1986
2038
|
},
|
|
2039
|
+
FormAssociated: {
|
|
2040
|
+
type: "object",
|
|
2041
|
+
additionalProperties: false,
|
|
2042
|
+
properties: {
|
|
2043
|
+
listed: {
|
|
2044
|
+
type: "boolean",
|
|
2045
|
+
title: "Listed elements have a name attribute and is listed in the form and fieldset elements property."
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
},
|
|
1987
2049
|
Permitted: {
|
|
1988
2050
|
type: "array",
|
|
1989
2051
|
items: {
|
|
@@ -2073,6 +2135,9 @@ const definitions = {
|
|
|
2073
2135
|
items: {
|
|
2074
2136
|
type: "string"
|
|
2075
2137
|
}
|
|
2138
|
+
},
|
|
2139
|
+
{
|
|
2140
|
+
type: "null"
|
|
2076
2141
|
}
|
|
2077
2142
|
]
|
|
2078
2143
|
}
|
|
@@ -2239,6 +2304,9 @@ function migrateAttributes(src) {
|
|
|
2239
2304
|
function migrateElement(src) {
|
|
2240
2305
|
const result = {
|
|
2241
2306
|
...src,
|
|
2307
|
+
...{
|
|
2308
|
+
formAssociated: undefined,
|
|
2309
|
+
},
|
|
2242
2310
|
attributes: migrateAttributes(src),
|
|
2243
2311
|
textContent: src.textContent,
|
|
2244
2312
|
};
|
|
@@ -2249,6 +2317,14 @@ function migrateElement(src) {
|
|
|
2249
2317
|
if (!result.textContent) {
|
|
2250
2318
|
delete result.textContent;
|
|
2251
2319
|
}
|
|
2320
|
+
if (src.formAssociated) {
|
|
2321
|
+
result.formAssociated = {
|
|
2322
|
+
listed: Boolean(src.formAssociated.listed),
|
|
2323
|
+
};
|
|
2324
|
+
}
|
|
2325
|
+
else {
|
|
2326
|
+
delete result.formAssociated;
|
|
2327
|
+
}
|
|
2252
2328
|
return result;
|
|
2253
2329
|
}
|
|
2254
2330
|
|
|
@@ -2383,6 +2459,10 @@ class MetaTable {
|
|
|
2383
2459
|
this.loadFromObject(data, filename);
|
|
2384
2460
|
}
|
|
2385
2461
|
catch (err) {
|
|
2462
|
+
if (err instanceof InheritError) {
|
|
2463
|
+
err.filename = filename;
|
|
2464
|
+
throw err;
|
|
2465
|
+
}
|
|
2386
2466
|
if (err instanceof SchemaValidationError) {
|
|
2387
2467
|
throw err;
|
|
2388
2468
|
}
|
|
@@ -2435,7 +2515,10 @@ class MetaTable {
|
|
|
2435
2515
|
const name = entry.inherit;
|
|
2436
2516
|
parent = this.elements[name];
|
|
2437
2517
|
if (!parent) {
|
|
2438
|
-
throw new
|
|
2518
|
+
throw new InheritError({
|
|
2519
|
+
tagName,
|
|
2520
|
+
inherit: name,
|
|
2521
|
+
});
|
|
2439
2522
|
}
|
|
2440
2523
|
}
|
|
2441
2524
|
/* merge all sources together */
|
|
@@ -3404,6 +3487,16 @@ class Rule {
|
|
|
3404
3487
|
isKeywordIgnored(keyword, matcher = (list, it) => list.includes(it)) {
|
|
3405
3488
|
return isKeywordIgnored(this.options, keyword, matcher);
|
|
3406
3489
|
}
|
|
3490
|
+
/**
|
|
3491
|
+
* Get [[MetaElement]] for the given tag. If no specific metadata is present
|
|
3492
|
+
* the global metadata is returned or null if no global is present.
|
|
3493
|
+
*
|
|
3494
|
+
* @public
|
|
3495
|
+
* @returns A shallow copy of metadata.
|
|
3496
|
+
*/
|
|
3497
|
+
getMetaFor(tagName) {
|
|
3498
|
+
return this.meta.getMetaFor(tagName);
|
|
3499
|
+
}
|
|
3407
3500
|
/**
|
|
3408
3501
|
* Find all tags which has enabled given property.
|
|
3409
3502
|
*/
|
|
@@ -3920,6 +4013,11 @@ class AriaLabelMisuse extends Rule {
|
|
|
3920
4013
|
* @public
|
|
3921
4014
|
*/
|
|
3922
4015
|
class ConfigError extends UserError {
|
|
4016
|
+
constructor(message, nested) {
|
|
4017
|
+
super(message, nested);
|
|
4018
|
+
Error.captureStackTrace(this, ConfigError);
|
|
4019
|
+
this.name = ConfigError.name;
|
|
4020
|
+
}
|
|
3923
4021
|
}
|
|
3924
4022
|
|
|
3925
4023
|
const defaults$t = {
|
|
@@ -4809,7 +4907,7 @@ class AttributeMisuse extends Rule {
|
|
|
4809
4907
|
if (!meta || !meta.allowed) {
|
|
4810
4908
|
return;
|
|
4811
4909
|
}
|
|
4812
|
-
const details = meta.allowed(node);
|
|
4910
|
+
const details = meta.allowed(node, attr);
|
|
4813
4911
|
if (details) {
|
|
4814
4912
|
this.report({
|
|
4815
4913
|
node,
|
|
@@ -5833,12 +5931,92 @@ class EmptyTitle extends Rule {
|
|
|
5833
5931
|
}
|
|
5834
5932
|
}
|
|
5835
5933
|
|
|
5934
|
+
const CACHE_KEY = Symbol("form-elements");
|
|
5935
|
+
function haveName(name) {
|
|
5936
|
+
return typeof name === "string" && name !== "";
|
|
5937
|
+
}
|
|
5938
|
+
function isRelevant$4(node) {
|
|
5939
|
+
if (node.is("input")) {
|
|
5940
|
+
/* ignore radiobuttons and checkboxes */
|
|
5941
|
+
const type = node.getAttribute("type");
|
|
5942
|
+
return !type || !type.valueMatches(["radio", "checkbox"], true);
|
|
5943
|
+
}
|
|
5944
|
+
return true;
|
|
5945
|
+
}
|
|
5946
|
+
class FormDupName extends Rule {
|
|
5947
|
+
documentation() {
|
|
5948
|
+
return {
|
|
5949
|
+
description: "Each form control must have a unique name.",
|
|
5950
|
+
url: "https://html-validate.org/rules/form-dup-name.html",
|
|
5951
|
+
};
|
|
5952
|
+
}
|
|
5953
|
+
setup() {
|
|
5954
|
+
const selector = this.getSelector();
|
|
5955
|
+
this.on("dom:ready", (event) => {
|
|
5956
|
+
var _a;
|
|
5957
|
+
const { document } = event;
|
|
5958
|
+
const controls = document.querySelectorAll(selector).filter(isRelevant$4);
|
|
5959
|
+
for (const control of controls) {
|
|
5960
|
+
const attr = control.getAttribute("name");
|
|
5961
|
+
const name = attr === null || attr === void 0 ? void 0 : attr.value;
|
|
5962
|
+
if (attr && haveName(name)) {
|
|
5963
|
+
const form = (_a = control.closest("form")) !== null && _a !== void 0 ? _a : document.root;
|
|
5964
|
+
this.validateName(control, form, attr, name);
|
|
5965
|
+
}
|
|
5966
|
+
}
|
|
5967
|
+
});
|
|
5968
|
+
}
|
|
5969
|
+
validateName(control, form, attr, name) {
|
|
5970
|
+
const elements = this.getElements(form);
|
|
5971
|
+
if (elements.has(name)) {
|
|
5972
|
+
const context = {
|
|
5973
|
+
name,
|
|
5974
|
+
};
|
|
5975
|
+
this.report({
|
|
5976
|
+
node: control,
|
|
5977
|
+
location: attr.valueLocation,
|
|
5978
|
+
message: 'Duplicate form control name "{{ name }}"',
|
|
5979
|
+
context,
|
|
5980
|
+
});
|
|
5981
|
+
}
|
|
5982
|
+
else {
|
|
5983
|
+
elements.add(name);
|
|
5984
|
+
}
|
|
5985
|
+
}
|
|
5986
|
+
getSelector() {
|
|
5987
|
+
const tags = this.getTagsWithProperty("formAssociated").filter((it) => {
|
|
5988
|
+
return this.isListedElement(it);
|
|
5989
|
+
});
|
|
5990
|
+
return tags.join(", ");
|
|
5991
|
+
}
|
|
5992
|
+
isListedElement(tagName) {
|
|
5993
|
+
const meta = this.getMetaFor(tagName);
|
|
5994
|
+
/* istanbul ignore if: the earlier check for getTagsWithProperty ensures
|
|
5995
|
+
* these will actually be set so this is just an untestable fallback */
|
|
5996
|
+
if (!meta || !meta.formAssociated) {
|
|
5997
|
+
return false;
|
|
5998
|
+
}
|
|
5999
|
+
return meta.formAssociated.listed;
|
|
6000
|
+
}
|
|
6001
|
+
getElements(form) {
|
|
6002
|
+
const existing = form.cacheGet(CACHE_KEY);
|
|
6003
|
+
if (existing) {
|
|
6004
|
+
return existing;
|
|
6005
|
+
}
|
|
6006
|
+
else {
|
|
6007
|
+
const elements = new Set();
|
|
6008
|
+
form.cacheSet(CACHE_KEY, elements);
|
|
6009
|
+
return elements;
|
|
6010
|
+
}
|
|
6011
|
+
}
|
|
6012
|
+
}
|
|
6013
|
+
|
|
5836
6014
|
const defaults$j = {
|
|
5837
6015
|
allowMultipleH1: false,
|
|
5838
6016
|
minInitialRank: "h1",
|
|
5839
6017
|
sectioningRoots: ["dialog", '[role="dialog"]'],
|
|
5840
6018
|
};
|
|
5841
|
-
function isRelevant$
|
|
6019
|
+
function isRelevant$3(event) {
|
|
5842
6020
|
const node = event.target;
|
|
5843
6021
|
return Boolean(node.meta && node.meta.heading);
|
|
5844
6022
|
}
|
|
@@ -5906,7 +6084,7 @@ class HeadingLevel extends Rule {
|
|
|
5906
6084
|
};
|
|
5907
6085
|
}
|
|
5908
6086
|
setup() {
|
|
5909
|
-
this.on("tag:start", isRelevant$
|
|
6087
|
+
this.on("tag:start", isRelevant$3, (event) => this.onTagStart(event));
|
|
5910
6088
|
this.on("tag:ready", (event) => this.onTagReady(event));
|
|
5911
6089
|
this.on("tag:close", (event) => this.onTagClose(event));
|
|
5912
6090
|
}
|
|
@@ -6440,6 +6618,42 @@ class MapDupName extends Rule {
|
|
|
6440
6618
|
}
|
|
6441
6619
|
}
|
|
6442
6620
|
|
|
6621
|
+
function isRelevant$2(event) {
|
|
6622
|
+
return event.target.is("map");
|
|
6623
|
+
}
|
|
6624
|
+
function hasStaticValue(attr) {
|
|
6625
|
+
return Boolean(attr && !(attr.value instanceof DynamicValue));
|
|
6626
|
+
}
|
|
6627
|
+
class MapIdName extends Rule {
|
|
6628
|
+
documentation() {
|
|
6629
|
+
return {
|
|
6630
|
+
description: "When the `id` attribute is present on a `<map>` element it must be equal to the `name` attribute.",
|
|
6631
|
+
url: "https://html-validate.org/rules/map-id-name.html",
|
|
6632
|
+
};
|
|
6633
|
+
}
|
|
6634
|
+
setup() {
|
|
6635
|
+
this.on("tag:ready", isRelevant$2, (event) => {
|
|
6636
|
+
var _a;
|
|
6637
|
+
const { target } = event;
|
|
6638
|
+
const id = target.getAttribute("id");
|
|
6639
|
+
const name = target.getAttribute("name");
|
|
6640
|
+
// /* ignore missing attributes or dynamic value */
|
|
6641
|
+
if (!hasStaticValue(id) || !hasStaticValue(name)) {
|
|
6642
|
+
return;
|
|
6643
|
+
}
|
|
6644
|
+
/* ignore when id and name is the same */
|
|
6645
|
+
if (id.value === name.value) {
|
|
6646
|
+
return;
|
|
6647
|
+
}
|
|
6648
|
+
this.report({
|
|
6649
|
+
node: event.target,
|
|
6650
|
+
message: `"id" and "name" attribute must be the same on <map> elements`,
|
|
6651
|
+
location: (_a = id.valueLocation) !== null && _a !== void 0 ? _a : name.valueLocation,
|
|
6652
|
+
});
|
|
6653
|
+
});
|
|
6654
|
+
}
|
|
6655
|
+
}
|
|
6656
|
+
|
|
6443
6657
|
class MissingDoctype extends Rule {
|
|
6444
6658
|
documentation() {
|
|
6445
6659
|
return {
|
|
@@ -8904,12 +9118,14 @@ const bundledRules = {
|
|
|
8904
9118
|
"element-required-content": ElementRequiredContent,
|
|
8905
9119
|
"empty-heading": EmptyHeading,
|
|
8906
9120
|
"empty-title": EmptyTitle,
|
|
9121
|
+
"form-dup-name": FormDupName,
|
|
8907
9122
|
"heading-level": HeadingLevel,
|
|
8908
9123
|
"id-pattern": IdPattern,
|
|
8909
9124
|
"input-attributes": InputAttributes,
|
|
8910
9125
|
"input-missing-label": InputMissingLabel,
|
|
8911
9126
|
"long-title": LongTitle,
|
|
8912
9127
|
"map-dup-name": MapDupName,
|
|
9128
|
+
"map-id-name": MapIdName,
|
|
8913
9129
|
"meta-refresh": MetaRefresh,
|
|
8914
9130
|
"missing-doctype": MissingDoctype,
|
|
8915
9131
|
"multiple-labeled-controls": MultipleLabeledControls,
|
|
@@ -9018,9 +9234,11 @@ const config$1 = {
|
|
|
9018
9234
|
"element-required-content": "error",
|
|
9019
9235
|
"empty-heading": "error",
|
|
9020
9236
|
"empty-title": "error",
|
|
9237
|
+
"form-dup-name": "error",
|
|
9021
9238
|
"input-attributes": "error",
|
|
9022
9239
|
"long-title": "error",
|
|
9023
9240
|
"map-dup-name": "error",
|
|
9241
|
+
"map-id-name": "error",
|
|
9024
9242
|
"meta-refresh": "error",
|
|
9025
9243
|
"multiple-labeled-controls": "error",
|
|
9026
9244
|
"no-autoplay": ["error", { include: ["audio", "video"] }],
|
|
@@ -9081,6 +9299,7 @@ const config = {
|
|
|
9081
9299
|
"element-required-attributes": "error",
|
|
9082
9300
|
"element-required-content": "error",
|
|
9083
9301
|
"map-dup-name": "error",
|
|
9302
|
+
"map-id-name": "error",
|
|
9084
9303
|
"multiple-labeled-controls": "error",
|
|
9085
9304
|
"no-deprecated-attr": "error",
|
|
9086
9305
|
"no-dup-attr": "error",
|
|
@@ -9910,6 +10129,8 @@ class Parser {
|
|
|
9910
10129
|
}
|
|
9911
10130
|
/* resolve any dynamic meta element properties */
|
|
9912
10131
|
this.dom.resolveMeta(this.metaTable);
|
|
10132
|
+
/* enable cache on root element, all children already have cached enabled */
|
|
10133
|
+
this.dom.root.cacheEnable();
|
|
9913
10134
|
/* trigger any rules waiting for DOM ready */
|
|
9914
10135
|
this.trigger("dom:ready", {
|
|
9915
10136
|
document: this.dom,
|
|
@@ -10741,6 +10962,8 @@ class Engine {
|
|
|
10741
10962
|
var _a, _b;
|
|
10742
10963
|
/* wait for a tag to open and find the current block by using its parent */
|
|
10743
10964
|
if (directiveBlock === null) {
|
|
10965
|
+
/* istanbul ignore next: there will always be a parent (root element if
|
|
10966
|
+
* nothing else) but typescript doesn't know that */
|
|
10744
10967
|
directiveBlock = (_b = (_a = data.target.parent) === null || _a === void 0 ? void 0 : _a.unique) !== null && _b !== void 0 ? _b : null;
|
|
10745
10968
|
}
|
|
10746
10969
|
/* disable rules directly on the node so it will be recorded for later,
|
|
@@ -11169,7 +11392,7 @@ class HtmlValidate {
|
|
|
11169
11392
|
/** @public */
|
|
11170
11393
|
const name = "html-validate";
|
|
11171
11394
|
/** @public */
|
|
11172
|
-
const version = "7.
|
|
11395
|
+
const version = "7.12.0";
|
|
11173
11396
|
/** @public */
|
|
11174
11397
|
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
11175
11398
|
|
|
@@ -11612,5 +11835,5 @@ function getFormatter(name) {
|
|
|
11612
11835
|
return (_a = availableFormatters[name]) !== null && _a !== void 0 ? _a : null;
|
|
11613
11836
|
}
|
|
11614
11837
|
|
|
11615
|
-
export { Config as C, DynamicValue as D, EventHandler as E, FileSystemConfigLoader as F, HtmlValidate as H, MetaTable as M, NodeClosed as N, Parser as P, Rule as R, Severity as S, TextNode as T, UserError as U, WrappedError as W, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, HtmlElement as d, SchemaValidationError as e, NestedError as f, MetaCopyableProperty as g, Reporter as h, TemplateExtractor as i, definePlugin as j, getFormatter as k, legacyRequire as l, ensureError as m, configDataFromFile as n, compatibilityCheck as o, presets as p, codeframe as q, ruleExists as r, sliceLocation as s, isTextNode as t, isElementNode as u, version as v, generateIdSelector as w, name as x, bugs as y };
|
|
11838
|
+
export { Attribute as A, Config as C, DynamicValue as D, EventHandler as E, FileSystemConfigLoader as F, HtmlValidate as H, MetaTable as M, NodeClosed as N, Parser as P, Rule as R, Severity as S, TextNode as T, UserError as U, WrappedError as W, ConfigError as a, ConfigLoader as b, StaticConfigLoader as c, HtmlElement as d, SchemaValidationError as e, NestedError as f, MetaCopyableProperty as g, Reporter as h, TemplateExtractor as i, definePlugin as j, getFormatter as k, legacyRequire as l, ensureError as m, configDataFromFile as n, compatibilityCheck as o, presets as p, codeframe as q, ruleExists as r, sliceLocation as s, isTextNode as t, isElementNode as u, version as v, generateIdSelector as w, name as x, bugs as y };
|
|
11616
11839
|
//# sourceMappingURL=core.js.map
|