Commit 6604e88e authored by David Sveningsson's avatar David Sveningsson

feat(rules): add `include` and `exclude` options to `no-inline-style`

fixes html-validate-angular#3
parent 4730ead8
Pipeline #139696331 passed with stages
in 9 minutes and 30 seconds
......@@ -5,7 +5,7 @@ category: style
summary: Disallow inline style
---
# disallow inline style (`no-inline-style`)
# Disallow inline style (`no-inline-style`)
Inline style is a sign of unstructured CSS. Use class or ID with a separate
stylesheet.
......@@ -23,3 +23,31 @@ Examples of **correct** code for this rule:
<validate name="correct" rules="no-inline-style">
<p class="error"></p>
</validate>
## Options
This rule takes an optional object:
```javascript
{
"include": []
"exclude": []
}
```
Both `include` and `exclude` are only useful when using a framework with dynamic attributes such as `ng-style` or `:style` to allow/disallow one or more specific variant of the attribute.
For instance:
```html
<p :style="style></p>
```
would normally trigger the rule when using {@link frameworks/vue html-validate-vue} but by adding `:style` to `exclude` it can be allowed.
### `include`
If set only attributes listed in this array generates errors.
### `exclude`
If set attributes listed in this array is ignored.
import HtmlValidate from "../htmlvalidate";
import "../matchers";
import { processAttribute } from "../transform/mocks/attribute";
describe("rule no-inline-style", () => {
let htmlvalidate: HtmlValidate;
beforeAll(() => {
htmlvalidate = new HtmlValidate({
rules: { "no-inline-style": "error" },
describe("default configuration", () => {
beforeAll(() => {
htmlvalidate = new HtmlValidate({
rules: { "no-inline-style": "error" },
});
});
it("should report when style attribute is used", () => {
expect.assertions(2);
const report = htmlvalidate.validateString('<p style=""></p>');
expect(report).toBeInvalid();
expect(report).toHaveError(
"no-inline-style",
"Inline style is not allowed"
);
});
it("should report when dynamic style attribute is used", () => {
expect.assertions(2);
const report = htmlvalidate.validateString(
'<p dynamic-style=""></p>',
null,
{ processAttribute }
);
expect(report).toBeInvalid();
expect(report).toHaveError(
"no-inline-style",
"Inline style is not allowed"
);
});
});
it("should report when style attribute is used", () => {
expect.assertions(2);
const report = htmlvalidate.validateString('<p style=""></p>');
expect(report).toBeInvalid();
expect(report).toHaveError(
"no-inline-style",
"Inline style is not allowed"
);
describe("configured with include", () => {
beforeAll(() => {
htmlvalidate = new HtmlValidate({
rules: { "no-inline-style": ["error", { include: ["style"] }] },
});
});
it("should report when style attribute is used", () => {
expect.assertions(2);
const report = htmlvalidate.validateString('<p style=""></p>');
expect(report).toBeInvalid();
expect(report).toHaveError(
"no-inline-style",
"Inline style is not allowed"
);
});
it("should not report when dynamic style attribute is used", () => {
expect.assertions(1);
const report = htmlvalidate.validateString(
'<p dynamic-style=""></p>',
null,
{ processAttribute }
);
expect(report).toBeValid();
});
});
describe("configured with exclude", () => {
beforeAll(() => {
htmlvalidate = new HtmlValidate({
rules: { "no-inline-style": ["error", { exclude: ["style"] }] },
});
});
it("should not report when style attribute is used", () => {
expect.assertions(1);
const report = htmlvalidate.validateString('<p style=""></p>');
expect(report).toBeValid();
});
it("should report when dynamic style attribute is used", () => {
expect.assertions(2);
const report = htmlvalidate.validateString(
'<p dynamic-style=""></p>',
null,
{ processAttribute }
);
expect(report).toBeInvalid();
expect(report).toHaveError(
"no-inline-style",
"Inline style is not allowed"
);
});
});
it("smoketest", () => {
expect.assertions(1);
htmlvalidate = new HtmlValidate({
rules: { "no-inline-style": "error" },
});
const report = htmlvalidate.validateFile(
"test-files/rules/no-inline-style.html"
);
......@@ -30,6 +106,9 @@ describe("rule no-inline-style", () => {
it("should contain documentation", () => {
expect.assertions(1);
htmlvalidate = new HtmlValidate({
rules: { "no-inline-style": "error" },
});
expect(
htmlvalidate.getRuleDocumentation("no-inline-style")
).toMatchSnapshot();
......
import { AttributeEvent } from "../event";
import { Rule, RuleDocumentation, ruleDocumentationUrl } from "../rule";
export default class NoInlineStyle extends Rule {
export interface RuleOptions {
include: string[] | null;
exclude: string[] | null;
}
const defaults: RuleOptions = {
include: null,
exclude: null,
};
export default class NoInlineStyle extends Rule<void, RuleOptions> {
public constructor(options: RuleOptions) {
super(Object.assign({}, defaults, options));
}
public documentation(): RuleDocumentation {
return {
description:
......@@ -12,9 +26,30 @@ export default class NoInlineStyle extends Rule {
public setup(): void {
this.on("attr", (event: AttributeEvent) => {
if (event.key === "style") {
if (this.isRelevant(event)) {
this.report(event.target, "Inline style is not allowed");
}
});
}
private isRelevant(event: AttributeEvent): boolean {
if (event.key !== "style") {
return false;
}
const { include, exclude } = this.options;
const key = event.originalAttribute || event.key;
/* ignore attributes not present in "include" */
if (include && !include.includes(key)) {
return false;
}
/* ignore attributes present in "exclude" */
if (exclude && exclude.includes(key)) {
return false;
}
return true;
}
}
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