Commits (14)
# html-validate changelog
# [3.2.0](https://gitlab.com/html-validate/html-validate/compare/v3.1.0...v3.2.0) (2020-08-26)
### Features
- **rules:** new rule allowed-links ([d876206](https://gitlab.com/html-validate/html-validate/commit/d8762060c6a8b5b2f6a67cbbffd229b8232a7dfa))
# [3.1.0](https://gitlab.com/html-validate/html-validate/compare/v3.0.0...v3.1.0) (2020-08-20)
### Bug Fixes
......@@ -227,7 +233,7 @@
### Features
- **rules:** make options typesafe ([c85342a](https://gitlab.com/html-validate/html-validate/commit/c85342a5426ddba081fed8becaf3d4d499f0b66e))
- **rules:** make options type-safe ([c85342a](https://gitlab.com/html-validate/html-validate/commit/c85342a5426ddba081fed8becaf3d4d499f0b66e))
- **rules:** new rule `prefer-native-element` ([06c44ce](https://gitlab.com/html-validate/html-validate/commit/06c44cec1c66b518c030a31517d8cfd454c0c2d2))
# [2.9.0](https://gitlab.com/html-validate/html-validate/compare/v2.8.2...v2.9.0) (2020-01-17)
......@@ -644,7 +650,7 @@
- new rule `empty-title`.
- add `UserError` exception which is to be used for any error which is not
caused by an internal error, e.g. configuration errors or a plugin. The error
supresses the notice about internal error which should be reported as a bug.
suppresses the notice about internal error which should be reported as a bug.
- reworked and extendable validation of elements metadata. Plugins may now add
support for custom metadata.
......@@ -1041,7 +1047,7 @@
- easier API usage: `require('html-validate')` now returns class without using
`require(html-validate/build/htmlvalidate').default`.
- support `transform` in configuration to extract source html from other files.
- attach `depth` and `unique` readonly properties to `DOMNode` corresponding to
- attach `depth` and `unique` read-only properties to `DOMNode` corresponding to
the nodes depth in the DOM tree and a sequential id (unique for the session).
- new rule `no-conditional-comments` to disallow usage of conditional comments.
- handle conditional comments.
......
---
docType: content
title: Writing custom element metadata - Resticting element attributes
title: Writing custom element metadata - Restricting element attributes
---
# Writing custom element metadata: Restricting element attributes
......
---
docType: content
title: Writing custom element metadata - Resticting element content
title: Writing custom element metadata - Restricting element content
---
# Writing custom element metadata: Restricting element content
......
......@@ -41,9 +41,7 @@ for mobile browsers).
### HTML5 content model
Each element is matched against metadata for deeper logic and analyzation such
as whenever an element is allowed in the current context or if a required
element is missing.
Each element is matched against metadata for deeper logic and analysis such as whenever an element is allowed in the current context or if a required element is missing.
- permitted ancestors and descendants
- permitted order and occurrences
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/allowed-links.md inline validation: absolute-invalid 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 10,
"context": "absolute",
"line": 1,
"message": "Link destination must not be absolute url",
"offset": 9,
"ruleId": "allowed-links",
"selector": "a",
"severity": 2,
"size": 4,
},
],
"source": "<a href=\\"/foo\\">",
"warningCount": 0,
},
]
`;
exports[`docs/rules/allowed-links.md inline validation: absolute-valid 1`] = `Array []`;
exports[`docs/rules/allowed-links.md inline validation: base-invalid 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 10,
"context": "relative-base",
"line": 1,
"message": "Relative links must be relative to current folder",
"offset": 9,
"ruleId": "allowed-links",
"selector": "a",
"severity": 2,
"size": 3,
},
],
"source": "<a href=\\"foo\\">",
"warningCount": 0,
},
]
`;
exports[`docs/rules/allowed-links.md inline validation: base-valid 1`] = `Array []`;
exports[`docs/rules/allowed-links.md inline validation: external-invalid 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 10,
"context": "external",
"line": 1,
"message": "Link destination must not be external url",
"offset": 9,
"ruleId": "allowed-links",
"selector": "a",
"severity": 2,
"size": 22,
},
],
"source": "<a href=\\"http://example.net/foo\\">",
"warningCount": 0,
},
]
`;
exports[`docs/rules/allowed-links.md inline validation: external-valid 1`] = `Array []`;
exports[`docs/rules/allowed-links.md inline validation: relative-invalid 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 10,
"context": "relative-path",
"line": 1,
"message": "Link destination must not be relative url",
"offset": 9,
"ruleId": "allowed-links",
"selector": "a",
"severity": 2,
"size": 6,
},
],
"source": "<a href=\\"../foo\\">",
"warningCount": 0,
},
]
`;
exports[`docs/rules/allowed-links.md inline validation: relative-valid 1`] = `Array []`;
import HtmlValidate from "../../../src/htmlvalidate";
const markup: { [key: string]: string } = {};
markup["external-invalid"] = `<a href="http://example.net/foo">`;
markup["external-valid"] = `<a href="./foo">`;
markup["relative-invalid"] = `<a href="../foo">`;
markup["relative-valid"] = `<a href="/foo">`;
markup["absolute-invalid"] = `<a href="/foo">`;
markup["absolute-valid"] = `<a href="../foo">`;
markup["base-invalid"] = `<a href="foo">`;
markup["base-valid"] = `<a href="./foo">`;
describe("docs/rules/allowed-links.md", () => {
it("inline validation: external-invalid", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"allowed-links":["error",{"allowExternal":false}]}});
const report = htmlvalidate.validateString(markup["external-invalid"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: external-valid", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"allowed-links":["error",{"allowExternal":false}]}});
const report = htmlvalidate.validateString(markup["external-valid"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: relative-invalid", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"allowed-links":["error",{"allowRelative":false}]}});
const report = htmlvalidate.validateString(markup["relative-invalid"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: relative-valid", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"allowed-links":["error",{"allowRelative":false}]}});
const report = htmlvalidate.validateString(markup["relative-valid"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: absolute-invalid", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"allowed-links":["error",{"allowAbsolute":false}]}});
const report = htmlvalidate.validateString(markup["absolute-invalid"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: absolute-valid", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"allowed-links":["error",{"allowAbsolute":false}]}});
const report = htmlvalidate.validateString(markup["absolute-valid"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: base-invalid", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"allowed-links":["error",{"allowBase":false}]}});
const report = htmlvalidate.validateString(markup["base-invalid"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: base-valid", () => {
expect.assertions(1);
const htmlvalidate = new HtmlValidate({"rules":{"allowed-links":["error",{"allowBase":false}]}});
const report = htmlvalidate.validateString(markup["base-valid"]);
expect(report.results).toMatchSnapshot();
});
});
---
docType: rule
name: allowed-links
category: document
summary: Disallow link types
---
# Disallows link types (`allowed-links`)
This rules checks the link destination and disallows certain categories of links:
- External links
- Relative paths
- Relative to document base url
The rule checks links from:
- `<a href=""></a>`
- `<img src="..">`
- `<link src="..">`
- `<script src=".."></script>`
Anchor links are ignored by this rule.
## Rule details
This rules requires additional configuration to yield errors.
By default all links are allowed even when this rule is enabled.
## Options
This rule takes an optional object:
```json
{
"allowExternal": true,
"allowRelative": true,
"allowAbsolute": true,
"allowBase": true
}
```
### `allowExternal`
By setting `allowExternal` to `false` any link to a external resource will be disallowed.
<validate name="external-invalid" rules="allowed-links" allowed-links='{"allowExternal": false}'>
<a href="http://example.net/foo">
</validate>
<validate name="external-valid" rules="allowed-links" allowed-links='{"allowExternal": false}'>
<a href="./foo">
</validate>
### `allowRelative`
By setting `allowRelative` to `false` any link with a relative url will be disallowed.
<validate name="relative-invalid" rules="allowed-links" allowed-links='{"allowRelative": false}'>
<a href="../foo">
</validate>
<validate name="relative-valid" rules="allowed-links" allowed-links='{"allowRelative": false}'>
<a href="/foo">
</validate>
### `allowAbsolute`
By setting `allowAbsolute` to `false` any link with a absolute url will be disallowed.
<validate name="absolute-invalid" rules="allowed-links" allowed-links='{"allowAbsolute": false}'>
<a href="/foo">
</validate>
<validate name="absolute-valid" rules="allowed-links" allowed-links='{"allowAbsolute": false}'>
<a href="../foo">
</validate>
### `allowBase`
By setting `allowBase` to `false` relative urls can be used only if using an explicit path but not when relative to document base url.
This is useful when wanting to use relative urls but not rely on `<base href="..">` being set correctly.
Effectively this also means that links to files in the same folder must use `./target` even if `target` is valid.
<validate name="base-invalid" rules="allowed-links" allowed-links='{"allowBase": false}'>
<a href="foo">
</validate>
<validate name="base-valid" rules="allowed-links" allowed-links='{"allowBase": false}'>
<a href="./foo">
</validate>
......@@ -47,4 +47,4 @@ Examples include missing doctype and invalid references.
Use this preset together with other presets for full coverage.
This preset is enabled by plugins such as {@link usage/cypress cypress-html-validate} and {@link usage/protractor protractor-html-validate}.
## Comparision
## Comparison
......@@ -199,8 +199,7 @@ i.e a previously disabled warning will remain a warning after enabling it again.
<!-- [html-validate-disable deprecated] -->
Disable a rule for the rest of the file or until reenabled using `enable`
directive.
Disable a rule for the rest of the file or until re-enabled using `enable` directive.
### `disable-block`
......
This diff is collapsed.
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`rule allowed-links should contain contextual documentation absolute 1`] = `
Object {
"description": "Absolute links are not allowed by current configuration.",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
exports[`rule allowed-links should contain contextual documentation external 1`] = `
Object {
"description": "External links are not allowed by current configuration.",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
exports[`rule allowed-links should contain contextual documentation relative to base 1`] = `
Object {
"description": "Links relative to <base> are not allowed by current configuration.",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
exports[`rule allowed-links should contain contextual documentation relative to path 1`] = `
Object {
"description": "Relative links are not allowed by current configuration.",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
exports[`rule allowed-links should contain documentation 1`] = `
Object {
"description": "This link type is not allowed by current configuration",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
import HtmlValidate from "../htmlvalidate";
import "../matchers";
import { processAttribute } from "../transform/mocks/attribute";
import { Style } from "./allowed-links";
describe("rule allowed-links", () => {
let htmlvalidate: HtmlValidate;
describe("should report error for", () => {
it.each`
description | markup
${"<a href>"} | ${'<a href="/foo"></a>'}
${"<img src>"} | ${'<img src="/foo">'}
${"<link href>"} | ${'<link href="/foo">'}
${"<script src>"} | ${'<script src="/foo"></script>'}
`("$description", ({ markup }) => {
expect.assertions(1);
htmlvalidate = new HtmlValidate({
rules: { "allowed-links": ["error", { allowAbsolute: false }] },
});
const report = htmlvalidate.validateString(markup);
expect(report).toBeInvalid();
});
});
it("should not report error for anchor links", () => {
expect.assertions(1);
htmlvalidate = new HtmlValidate({
rules: { "allowed-links": ["error", { allowAbsolute: false }] },
});
const report = htmlvalidate.validateString('<a href="#foo"></a>');
expect(report).toBeValid();
});
it("should not report error for link is dynamic", () => {
expect.assertions(1);
htmlvalidate = new HtmlValidate({
rules: {
"allowed-links": ["error", { allowRelative: false }],
},
});
const report = htmlvalidate.validateString(
'<a dynamic-src="{{ expr }}"></a>',
null,
{
processAttribute,
}
);
expect(report).toBeValid();
});
describe("allowExternal: false", () => {
beforeAll(() => {
htmlvalidate = new HtmlValidate({
rules: { "allowed-links": ["error", { allowExternal: false }] },
});
});
it("should report error when link is external using //", () => {
expect.assertions(2);
const report = htmlvalidate.validateString(
'<a href="//example.net/foo"></a>'
);
expect(report).toBeInvalid();
expect(report).toHaveError(
"allowed-links",
"Link destination must not be external url"
);
});
it("should report error when link is external using protocol://", () => {
expect.assertions(2);
const report = htmlvalidate.validateString(
'<a href="http://example.net/foo"></a>'
);
expect(report).toBeInvalid();
expect(report).toHaveError(
"allowed-links",
"Link destination must not be external url"
);
});
it("should not report error link is absolute", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<a href="/foo"></a>');
expect(report).toBeValid();
});
it("should not report error link is relative to path", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<a href="./foo"></a>');
expect(report).toBeValid();
});
it("should not report error link is relative to base", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<a href="foo"></a>');
expect(report).toBeValid();
});
});
describe("allowRelative: false", () => {
beforeAll(() => {
htmlvalidate = new HtmlValidate({
rules: { "allowed-links": ["error", { allowRelative: false }] },
});
});
it("should not report error when link is external using //", () => {
expect.assertions(1);
const report = htmlvalidate.validateString(
'<a href="//example.net/foo"></a>'
);
expect(report).toBeValid();
});
it("should not report error when link is external using protocol://", () => {
expect.assertions(1);
const report = htmlvalidate.validateString(
'<a href="http://example.net/foo"></a>'
);
expect(report).toBeValid();
});
it("should not report error link is absolute", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<a href="/foo"></a>');
expect(report).toBeValid();
});
it("should report error link is relative to path", () => {
expect.assertions(2);
const report = htmlvalidate.validateString('<a href="./foo"></a>');
expect(report).toBeInvalid();
expect(report).toHaveError(
"allowed-links",
"Link destination must not be relative url"
);
});
it("should report error link is relative to base", () => {
expect.assertions(2);
const report = htmlvalidate.validateString('<a href="foo"></a>');
expect(report).toBeInvalid();
expect(report).toHaveError(
"allowed-links",
"Link destination must not be relative url"
);
});
});
describe("allowBase: false", () => {
beforeAll(() => {
htmlvalidate = new HtmlValidate({
rules: { "allowed-links": ["error", { allowBase: false }] },
});
});
it("should not report error when link is external using //", () => {
expect.assertions(1);
const report = htmlvalidate.validateString(
'<a href="//example.net/foo"></a>'
);
expect(report).toBeValid();
});
it("should not report error when link is external using protocol://", () => {
expect.assertions(1);
const report = htmlvalidate.validateString(
'<a href="http://example.net/foo"></a>'
);
expect(report).toBeValid();
});
it("should not report error link is absolute", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<a href="/foo"></a>');
expect(report).toBeValid();
});
it("should not report error link is relative to path", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<a href="./foo"></a>');
expect(report).toBeValid();
});
it("should report error link is relative to base", () => {
expect.assertions(2);
const report = htmlvalidate.validateString('<a href="foo"></a>');
expect(report).toBeInvalid();
expect(report).toHaveError(
"allowed-links",
"Relative links must be relative to current folder"
);
});
});
describe("allowAbsolute: false", () => {
beforeAll(() => {
htmlvalidate = new HtmlValidate({
rules: { "allowed-links": ["error", { allowAbsolute: false }] },
});
});
it("should not report error when link is external using //", () => {
expect.assertions(1);
const report = htmlvalidate.validateString(
'<a href="//example.net/foo"></a>'
);
expect(report).toBeValid();
});
it("should not report error when link is external using protocol://", () => {
expect.assertions(1);
const report = htmlvalidate.validateString(
'<a href="http://example.net/foo"></a>'
);
expect(report).toBeValid();
});
it("should report error link is absolute", () => {
expect.assertions(2);
const report = htmlvalidate.validateString('<a href="/foo"></a>');
expect(report).toBeInvalid();
expect(report).toHaveError(
"allowed-links",
"Link destination must not be absolute url"
);
});
it("should not report error link is relative to path", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<a href="./foo"></a>');
expect(report).toBeValid();
});
it("should report error link is relative to base", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<a href="foo"></a>');
expect(report).toBeValid();
});
});
it("should contain documentation", () => {
expect.assertions(1);
htmlvalidate = new HtmlValidate({
rules: { "allowed-links": "error" },
});
expect(
htmlvalidate.getRuleDocumentation("allowed-links")
).toMatchSnapshot();
});
describe("should contain contextual documentation", () => {
it.each`
style | value
${"external"} | ${Style.EXTERNAL}
${"relative to base"} | ${Style.RELATIVE_BASE}
${"relative to path"} | ${Style.RELATIVE_PATH}
${"absolute"} | ${Style.ABSOLUTE}
`("$style", ({ value }) => {
expect.assertions(1);
htmlvalidate = new HtmlValidate({
rules: { "allowed-links": "error" },
});
expect(
htmlvalidate.getRuleDocumentation("allowed-links", null, value)
).toMatchSnapshot();
});
});
});
import { DynamicValue } from "../dom";
import { AttributeEvent } from "../event";
import { Rule, RuleDocumentation, ruleDocumentationUrl } from "../rule";
export const enum Style {
EXTERNAL = "external",
RELATIVE_BASE = "relative-base",
RELATIVE_PATH = "relative-path",
ABSOLUTE = "absolute",
ANCHOR = "anchor",
}
interface RuleOptions {
allowExternal: boolean;
allowRelative: boolean;
allowAbsolute: boolean;
allowBase: boolean;
}
const defaults: RuleOptions = {
allowExternal: true,
allowRelative: true,
allowAbsolute: true,
allowBase: true,
};
const mapping: Record<string, string> = {
a: "href",
img: "src",
link: "href",
script: "src",
};
const description: Record<Style, string> = {
[Style.EXTERNAL]: "External links are not allowed by current configuration.",
[Style.RELATIVE_BASE]:
"Links relative to <base> are not allowed by current configuration.",
[Style.RELATIVE_PATH]:
"Relative links are not allowed by current configuration.",
[Style.ABSOLUTE]: "Absolute links are not allowed by current configuration.",
[Style.ANCHOR]: undefined,
};
export default class AllowedLinks extends Rule<Style, RuleOptions> {
public constructor(options: RuleOptions) {
super(Object.assign({}, defaults, options));
}
public documentation(context: Style): RuleDocumentation {
const message =
description[context] ||
"This link type is not allowed by current configuration";
return {
description: message,
url: ruleDocumentationUrl(__filename),
};
}
public setup(): void {
this.on("attr", (event: AttributeEvent) => {
if (!this.isRelevant(event)) {
return;
}
const link = event.value.toString();
const style = this.getStyle(link);
switch (style) {
case Style.ANCHOR:
/* anchor links are always allowed by this rule */
break;
case Style.ABSOLUTE:
this.handleAbsolute(event, style);
break;
case Style.EXTERNAL:
this.handleExternal(event, style);
break;
case Style.RELATIVE_BASE:
this.handleRelativeBase(event, style);
break;
case Style.RELATIVE_PATH:
this.handleRelativePath(event, style);
break;
}
});
}
protected isRelevant(event: AttributeEvent): boolean {
const { target, key, value } = event;
/* don't check links with dynamic values */
if (value instanceof DynamicValue) {
return false;
}
const attr = mapping[target.tagName];
return attr && attr === key;
}
protected getStyle(value: string): Style {
/* http://example.net or //example.net */
if (value.match(/^([a-z]+:)?\/\//g)) {
return Style.EXTERNAL;
}
switch (value[0]) {
/* /foo/bar */
case "/":
return Style.ABSOLUTE;
/* ../foo/bar */
case ".":
return Style.RELATIVE_PATH;
/* #foo */
case "#":
return Style.ANCHOR;
/* foo/bar */
default:
return Style.RELATIVE_BASE;
}
}
protected handleAbsolute(event: AttributeEvent, style: Style): void {
const { allowAbsolute } = this.options;
if (!allowAbsolute) {
this.report(
event.target,
"Link destination must not be absolute url",
event.valueLocation,
style
);
}
}
private handleExternal(event: AttributeEvent, style: Style): void {
const { allowExternal } = this.options;
if (!allowExternal) {
this.report(
event.target,
"Link destination must not be external url",
event.valueLocation,
style
);
}
}
private handleRelativePath(event: AttributeEvent, style: Style): void {
const { allowRelative } = this.options;
if (!allowRelative) {
this.report(
event.target,
"Link destination must not be relative url",
event.valueLocation,
style
);
}
}
private handleRelativeBase(event: AttributeEvent, style: Style): void {
const { allowRelative, allowBase } = this.options;
if (!allowRelative) {
this.report(
event.target,
"Link destination must not be relative url",
event.valueLocation,
style
);
} else if (!allowBase) {
this.report(
event.target,
"Relative links must be relative to current folder",
event.valueLocation,
style
);
}
}
}
import { RuleConstructor } from "../rule";
import AllowedLinks from "./allowed-links";
import AttrCase from "./attr-case";
import AttrQuotes from "./attr-quotes";
import AttributeAllowedValues from "./attribute-allowed-values";
import AttributeBooleanStyle from "./attribute-boolean-style";
import AttributeEmptyStyle from "./attribute-empty-style";
import AttrQuotes from "./attr-quotes";
import ClassPattern from "./class-pattern";
import CloseAttr from "./close-attr";
import CloseOrder from "./close-order";
import DeprecatedRule from "./deprecated-rule";
import Deprecated from "./deprecated";
import DeprecatedRule from "./deprecated-rule";
import DoctypeHtml from "./doctype-html";
import ElementCase from "./element-case";
import ElementName from "./element-name";
......@@ -50,22 +51,23 @@ import ScriptElement from "./script-element";
import ScriptType from "./script-type";
import SvgFocusable from "./svg-focusable";
import UnrecognizedCharRef from "./unrecognized-char-ref";
import Void from "./void";
import VoidContent from "./void-content";
import VoidStyle from "./void-style";
import Void from "./void";
import WCAG from "./wcag";
const bundledRules: Record<string, RuleConstructor<any, any>> = {
"allowed-links": AllowedLinks,
"attr-case": AttrCase,
"attr-quotes": AttrQuotes,
"attribute-allowed-values": AttributeAllowedValues,
"attribute-boolean-style": AttributeBooleanStyle,
"attribute-empty-style": AttributeEmptyStyle,
"attr-quotes": AttrQuotes,
"class-pattern": ClassPattern,
"close-attr": CloseAttr,
"close-order": CloseOrder,
"deprecated-rule": DeprecatedRule,
deprecated: Deprecated,
"deprecated-rule": DeprecatedRule,
"doctype-html": DoctypeHtml,
"element-case": ElementCase,
"element-name": ElementName,
......@@ -107,9 +109,9 @@ const bundledRules: Record<string, RuleConstructor<any, any>> = {
"script-type": ScriptType,
"svg-focusable": SvgFocusable,
"unrecognized-char-ref": UnrecognizedCharRef,
void: Void,
"void-content": VoidContent,
"void-style": VoidStyle,
void: Void,
...WCAG,
};
......