Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
| [no-duplicate-class](rules/no-duplicate-class) | Disallow duplicate class names | 🔧 |
| [no-duplicate-id](rules/no-duplicate-id) | Disallow duplicate id attributes ||
| [no-duplicate-in-head](rules/no-duplicate-in-head) | Disallow duplicate tags in `<head>` | |
| [no-ineffective-attrs](rules/no-ineffective-attrs) | Disallow HTML attributes that have no effect in their context | |
| [no-inline-styles](rules/no-inline-styles) | Disallow using inline style | |
| [no-invalid-entity](rules/no-invalid-entity) | Disallows the use of invalid HTML entities | |
| [no-nested-interactive](rules/no-nested-interactive) | Disallows nested interactive elements | |
Expand Down
87 changes: 66 additions & 21 deletions docs/rules/require-attrs.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module.exports = {

### Options

This rule takes an array of objects which has tag name with attribute name.
This rule takes an array of option objects:

```js
module.exports = {
Expand All @@ -31,38 +31,83 @@ module.exports = {
"error",
{
tag: "img",
attr: "alt", // Enforce to use img with alt attribute.
attr: "alt",
},
{
tag: "svg",
attr: "viewBox" // Enforce to use svg and viewBox attributes with "0 0 100 100" value.
value: "0 0 100 100"
attr: "viewBox",
value: "0 0 100 100",
},
],
},
};
```

Examples of **incorrect** code for this rule with the option below:

```json
{
"tag": "img",
"attr": "alt"
},
{
"tag": "svg",
"attr": "viewBox",
"value": "0 0 100 100"
}
#### tag

- Type: `string`
- **Required**

The HTML tag name to check for the specified attribute.

#### attr

- Type: `string`
- **Required**

The attribute name that must be present on the specified tag.

#### value

- Type: `string`
- _Optional_

The expected value for the attribute. If specified, the attribute must have this exact value.

#### message

- Type: `string`
- _Optional_

Custom error message to display when the rule is violated. If not provided, a default message will be used.

```js
module.exports = {
rules: {
"@html-eslint/require-attrs": [
"error",
{
tag: "img",
attr: "alt",
message: "Images must have alternative text for accessibility",
},
],
},
};
```

```html,incorrect
<img /> <svg></svg>
Examples of **incorrect** code for this rule:

```html
<!-- Missing alt attribute -->
<img />

<!-- Missing viewBox attribute -->
<svg></svg>

<!-- Wrong viewBox value -->
<svg viewBox="wrong"></svg>
```

Examples of **correct** code for this rule with the option above:
Examples of **correct** code for this rule:

```html
<!-- Has required alt attribute -->
<img alt="" />

<!-- Has required viewBox attribute -->
<svg viewBox="0 0 100 100"></svg>

```html,correct
<img alt="" /><svg viewBox="0 0 100 100"></svg>
<!-- Correct viewBox value -->
<svg viewBox="0 0 100 100"></svg>
```
12 changes: 9 additions & 3 deletions packages/eslint-plugin/lib/rules/require-attrs.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* @property {string} tag
* @property {string} attr
* @property {string} [value]
* @property {string} [message]
*
*/

Expand Down Expand Up @@ -41,6 +42,7 @@ module.exports = {
tag: { type: "string" },
attr: { type: "string" },
value: { type: "string" },
message: { type: "string" },
},
required: ["tag", "attr"],
additionalProperties: false,
Expand All @@ -59,7 +61,7 @@ module.exports = {
*/
const options = context.options || [];
/**
* @type {Map<string, { tag: string, attr: string, value?: string}[]>}
* @type {Map<string, { tag: string, attr: string, value?: string, message?: string}[]>}
*/
const tagOptionsMap = new Map();

Expand Down Expand Up @@ -90,7 +92,9 @@ module.exports = {
);
if (!attr) {
context.report({
messageId: MESSAGE_IDS.MISSING,
...(option.message
? { message: option.message }
: { messageId: MESSAGE_IDS.MISSING }),
node,
data: {
attr: attrName,
Expand All @@ -111,7 +115,9 @@ module.exports = {
(!attr.value || attr.value.value !== option.value)
) {
context.report({
messageId: MESSAGE_IDS.UNEXPECTED,
...(option.message
? { message: option.message }
: { messageId: MESSAGE_IDS.UNEXPECTED }),
node: attr,
data: {
attr: attrName,
Expand Down
56 changes: 56 additions & 0 deletions packages/eslint-plugin/tests/rules/require-attrs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,44 @@ ruleTester.run("require-attrs", rule, {
},
],
},
// Test custom message option
{
code: `<img/>`,
options: [
{
tag: "img",
attr: "alt",
message: "Image must have alt text for accessibility",
},
],
errors: [
{
line: 1,
column: 1,
message: "Image must have alt text for accessibility",
},
],
},
{
code: `<svg viewBox="wrong"></svg>`,
options: [
{
tag: "svg",
attr: "viewBox",
value: "0 0 100 100",
message: "SVG viewBox must be '0 0 100 100'",
},
],
output: `<svg viewBox="0 0 100 100"></svg>`,
errors: [
{
line: 1,
column: 6,
endColumn: 21,
message: "SVG viewBox must be '0 0 100 100'",
},
],
},
],
});

Expand Down Expand Up @@ -354,5 +392,23 @@ templateRuleTester.run("[template] require-attrs", rule, {
},
],
},
// Test custom message option in template
{
code: "html`<div></div>`",
options: [
{
tag: "div",
attr: "role",
message: "Div elements should have a role attribute",
},
],
errors: [
{
line: 1,
column: 6,
message: "Div elements should have a role attribute",
},
],
},
],
});