Commit 01187381 authored by David Sveningsson's avatar David Sveningsson
Browse files

feat(rules): new method `getTagsDerivedFrom` to get tag and tags inheriting from it

parent f3a59b91
Pipeline #115694425 passed with stages
in 11 minutes and 17 seconds
......@@ -175,3 +175,11 @@ Report a new error.
location)
- _`context`_ - If set it will be passed to `documentation()` later to allow
retrieving contextual documentation.
### `getTagsWithProperty(propName: MetaLookupableProperty): string[]`
Find all tags which has enabled given property.
### `getTagsDerivedFrom(tagName: string): string[]`
Find tag matching tagName or inheriting from it.
......@@ -392,6 +392,27 @@ describe("MetaTable", () => {
expect(table.getTagsWithProperty("phrasing")).toEqual([]);
});
});
describe("getTagsDerivedFrom()", () => {
it("should return list of all tags derived from given tagname", () => {
expect.assertions(2);
const table = new MetaTable();
table.loadFromObject({
foo: mockEntry({}),
bar: mockEntry({
inherit: "foo",
}),
});
expect(table.getTagsDerivedFrom("foo")).toEqual(["foo", "bar"]);
expect(table.getTagsDerivedFrom("bar")).toEqual(["bar"]);
});
it("should return empty list if nothing matches", () => {
expect.assertions(1);
const table = new MetaTable();
expect(table.getTagsDerivedFrom("missing")).toEqual([]);
});
});
});
function mockEntry(stub = {}): MetaData {
......
......@@ -134,6 +134,15 @@ export class MetaTable {
.map(([tagName]) => tagName);
}
/**
* Find tag matching tagName or inheriting from it.
*/
public getTagsDerivedFrom(tagName: string): string[] {
return Object.entries(this.elements)
.filter(([key, entry]) => key === tagName || entry.inherit === tagName)
.map(([tagName]) => tagName);
}
private addEntry(tagName: string, entry: MetaData): void {
const defaultEntry = {
void: false,
......@@ -149,7 +158,6 @@ export class MetaTable {
`Element <${tagName}> cannot inherit from <${name}>: no such element`
);
}
delete entry.inherit;
}
/* merge all sources together */
......
......@@ -206,6 +206,12 @@ describe("rule base class", () => {
expect(rule.getTagsWithProperty("form")).toEqual(["form"]);
expect(spy).toHaveBeenCalledWith("form");
});
it("getTagsDerivedFrom() should lookup properties from metadata", () => {
const spy = jest.spyOn(meta, "getTagsDerivedFrom");
expect(rule.getTagsDerivedFrom("form")).toEqual(["form"]);
expect(spy).toHaveBeenCalledWith("form");
});
});
it("ruleDocumentationUrl() should return URL to rule documentation", () => {
......
......@@ -82,10 +82,20 @@ export abstract class Rule<ContextType = void, OptionsType = void> {
return this.enabled && this.severity >= Severity.WARN;
}
/**
* Find all tags which has enabled given property.
*/
public getTagsWithProperty(propName: MetaLookupableProperty): string[] {
return this.meta.getTagsWithProperty(propName);
}
/**
* Find tag matching tagName or inheriting from it.
*/
public getTagsDerivedFrom(tagName: string): string[] {
return this.meta.getTagsDerivedFrom(tagName);
}
/**
* Report a new error.
*
......
......@@ -6,6 +6,14 @@ describe("wcag/h71", () => {
beforeAll(() => {
htmlvalidate = new HtmlValidate({
elements: [
"html5",
{
custom: {
inherit: "fieldset",
},
},
],
rules: { "wcag/h71": "error" },
});
});
......@@ -19,6 +27,15 @@ describe("wcag/h71", () => {
);
});
it("should report error when custom element inherits from <fieldset>", () => {
const report = htmlvalidate.validateString("<custom></custom>");
expect(report).toBeInvalid();
expect(report).toHaveError(
"WCAG/H71",
"<custom> must have a <legend> as the first child"
);
});
it("should not report when <fieldset> have <legend>", () => {
const report = htmlvalidate.validateString(
"<fieldset><legend>foo</legend></fieldset>"
......
......@@ -19,7 +19,7 @@ class H71 extends Rule {
public setup(): void {
this.on("dom:ready", (event: DOMReadyEvent) => {
const { document } = event;
const fieldsets = document.querySelectorAll("fieldset");
const fieldsets = document.querySelectorAll(this.selector);
for (const fieldset of fieldsets) {
this.validate(fieldset);
}
......@@ -39,6 +39,10 @@ class H71 extends Rule {
`${node.annotatedName} must have a <legend> as the first child`
);
}
private get selector(): string {
return this.getTagsDerivedFrom("fieldset").join(",");
}
}
module.exports = H71;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment