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

feat(rules): `deprecated` takes `include` and `exclude` options

parent fa8e9b12
Pipeline #295706592 passed with stages
in 10 minutes and 24 seconds
......@@ -40,3 +40,27 @@ The message will be shown alongside the regular message:
<validate name="custom-message" rules="deprecated" elements="deprecated.json">
<my-element>...</my-element>
</validate>
## Options
This rule takes an optional object:
```javascript
{
"include": [],
"exclude": [],
}
```
### `include`
If set only elements listed in this array generates errors.
### `exclude`
If set elements listed in this array is ignored.
## Version history
- v%version% - `include` and `exclude` options added.
- v1.13.0 - Rule added.
......@@ -7,7 +7,7 @@ describe("rule deprecated", () => {
beforeAll(() => {
htmlvalidate = new HtmlValidate({
root: true,
rules: { deprecated: "error" },
rules: { deprecated: ["error", { exclude: ["applet"] }] },
elements: [
"html5",
{
......@@ -32,9 +32,17 @@ describe("rule deprecated", () => {
expect(report).toBeValid();
});
it("should not report error for ignored deprecated elements", () => {
expect.assertions(1);
const markup = "<applet></applet>";
const report = htmlvalidate.validateString(markup);
expect(report).toBeValid();
});
it("should report error when deprecated element is used", () => {
expect.assertions(2);
const report = htmlvalidate.validateString("<marquee>foobar</marquee>");
const markup = "<marquee>foobar</marquee>";
const report = htmlvalidate.validateString(markup);
expect(report).toBeInvalid();
expect(report).toHaveError("deprecated", "<marquee> is deprecated");
});
......
......@@ -2,14 +2,59 @@ import { sliceLocation, Location } from "../context";
import { HtmlElement } from "../dom";
import { TagStartEvent } from "../event";
import { DeprecatedElement } from "../meta/element";
import { Rule, RuleDocumentation, ruleDocumentationUrl } from "../rule";
import { Rule, RuleDocumentation, ruleDocumentationUrl, SchemaObject } from "../rule";
interface Context extends DeprecatedElement {
interface RuleContext extends DeprecatedElement {
tagName: string;
}
export default class Deprecated extends Rule<Context> {
public documentation(context?: Context): RuleDocumentation {
interface RuleOptions {
include: string[] | null;
exclude: string[] | null;
}
const defaults: RuleOptions = {
include: null,
exclude: null,
};
export default class Deprecated extends Rule<RuleContext, RuleOptions> {
public constructor(options: Partial<RuleOptions>) {
super({ ...defaults, ...options });
}
public static schema(): SchemaObject {
return {
exclude: {
anyOf: [
{
items: {
type: "string",
},
type: "array",
},
{
type: "null",
},
],
},
include: {
anyOf: [
{
items: {
type: "string",
},
type: "array",
},
{
type: "null",
},
],
},
};
}
public documentation(context?: RuleContext): RuleDocumentation {
const doc: RuleDocumentation = {
description: "This element is deprecated and should not be used in new code.",
url: ruleDocumentationUrl(__filename),
......@@ -41,35 +86,43 @@ export default class Deprecated extends Rule<Context> {
return;
}
/* ignore if element is not deprecated */
const deprecated = node.meta.deprecated;
if (deprecated) {
const location = sliceLocation(event.location, 1);
if (typeof deprecated === "string") {
this.reportString(deprecated, node, location);
} else if (typeof deprecated === "boolean") {
this.reportBoolean(node, location);
} else {
this.reportObject(deprecated, node, location);
}
if (!deprecated) {
return;
}
/* ignore if element is ignored by used configuration */
if (this.isKeywordIgnored(node.tagName)) {
return;
}
const location = sliceLocation(event.location, 1);
if (typeof deprecated === "string") {
this.reportString(deprecated, node, location);
} else if (typeof deprecated === "boolean") {
this.reportBoolean(node, location);
} else {
this.reportObject(deprecated, node, location);
}
});
}
private reportString(deprecated: string, node: HtmlElement, location: Location): void {
const context: Context = { tagName: node.tagName };
const context: RuleContext = { tagName: node.tagName };
const message = `<${node.tagName}> is deprecated: ${deprecated}`;
this.report(node, message, location, context);
}
private reportBoolean(node: HtmlElement, location: Location): void {
const context: Context = { tagName: node.tagName };
const context: RuleContext = { tagName: node.tagName };
const message = `<${node.tagName}> is deprecated`;
this.report(node, message, location, context);
}
private reportObject(deprecated: DeprecatedElement, node: HtmlElement, location: Location): void {
const context: Context = { ...deprecated, tagName: node.tagName };
const context: RuleContext = { ...deprecated, tagName: node.tagName };
const message = `<${node.tagName}> is deprecated${
deprecated.message ? `: ${deprecated.message}` : ""
}`;
......
Supports Markdown
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