Skip to content

Commit bdfef79

Browse files
authored
feat: add enforceTemplatedAttrValue option on quotes (#387)
* feat: add enforceTemplatedAttrValue on quotes * Update quotes.md * Update quotes.test.js
1 parent e458a3b commit bdfef79

File tree

3 files changed

+109
-7
lines changed

3 files changed

+109
-7
lines changed

docs/rules/quotes.md

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# quotes
22

3-
This rule enforces enforces consistent use of quotes for attribute values (`'` or `"`).
3+
This rule enforces consistent use of quotes for attribute values (`'` or `"`).
44

55
## How to use
66

@@ -16,10 +16,14 @@ module.exports = {
1616

1717
### Options
1818

19-
This rule has two options
19+
This rule accepts the following options
2020

21-
- `"double"` (default): Requires the use of double quotes(`"`).
22-
- `"single"`: Requires the use of single quotes(`'`)
21+
1. Quote style (string):
22+
- "double" (default): Enforces the use of double quotes (`"`).
23+
- "single": Enforces the use of single quotes (`'`).
24+
2. `enforceTemplatedAttrValue` (boolean):
25+
- false (default): Does not enforce quote style inside template expressions.
26+
- true: Enforces quote style inside templated attribute values.
2327

2428
#### "double"
2529

@@ -30,13 +34,34 @@ Examples of **incorrect** code for this rule with the default `"double"` option:
3034
<div id='foo'></div>
3135
```
3236

37+
<!-- prettier-ignore-end -->
38+
3339
Examples of **correct** code for this rule with the default `"double"` option:
3440

3541
```html,correct
3642
<div id="foo"></div>
3743
<div id='containing "double" quotes'></div>
3844
```
3945

46+
Examples of **incorrect** code for this rule with the `"double"` and `enforceTemplatedAttrValue: true`:
47+
48+
<!-- prettier-ignore -->
49+
```js,incorrect
50+
html`<div id=${value}></div>`;
51+
html`<div id='${value}'></div>`;
52+
```
53+
54+
<!-- prettier-ignore-end -->
55+
56+
Examples of **correct** code for this rule with the `"double"` and `enforceTemplatedAttrValue: true`:
57+
58+
<!-- prettier-ignore -->
59+
```js,correct
60+
html`<div id="${value}"></div>`;
61+
```
62+
63+
<!-- prettier-ignore-end -->
64+
4065
#### "single"
4166

4267
Examples of **incorrect** code for this rule with the `"single"` option:
@@ -53,6 +78,27 @@ Examples of **correct** code for this rule with the default `"single"` option:
5378
<div id="containing 'single' quotes"></div>
5479
```
5580

81+
<!-- prettier-ignore-end -->
82+
83+
Examples of **incorrect** code for this rule with the `"single"` and `enforceTemplatedAttrValue: true`:
84+
85+
<!-- prettier-ignore -->
86+
```js,incorrect
87+
html`<div id=${value}></div>`;
88+
html`<div id="${value}"></div>`;
89+
```
90+
91+
<!-- prettier-ignore-end -->
92+
93+
Examples of **correct** code for this rule with the `"single"` and `enforceTemplatedAttrValue: true`:
94+
95+
<!-- prettier-ignore -->
96+
```js,correct
97+
html`<div id='${value}'></div>`;
98+
```
99+
100+
<!-- prettier-ignore-end -->
101+
56102
## Further Reading
57103

58104
- [MDN - Quoting attributes](https://developer.mozilla.org/en-US/docs/MDN/Guidelines/Code_guidelines/HTML#Quoting_attributes)

packages/eslint-plugin/lib/rules/quotes.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
* @import {Attribute, Tag, ScriptTag, StyleTag} from "@html-eslint/types";
44
* @import {RuleModule} from "../types";
55
*
6-
* @typedef {"single" | "double"} Option
6+
* @typedef {"single" | "double"} SingleOrQuoteOption
7+
* @typedef {{enforceTemplatedAttrValue: boolean}} ObjectOption
78
*/
89

910
const { NODE_TYPES } = require("@html-eslint/parser");
@@ -25,7 +26,7 @@ const QUOTES_STYLES = {
2526
const QUOTES_CODES = [`"`, `'`];
2627

2728
/**
28-
* @type {RuleModule<[Option]>}
29+
* @type {RuleModule<[SingleOrQuoteOption, ObjectOption]>}
2930
*/
3031
module.exports = {
3132
meta: {
@@ -43,6 +44,16 @@ module.exports = {
4344
{
4445
enum: [QUOTES_STYLES.SINGLE, QUOTES_STYLES.DOUBLE],
4546
},
47+
{
48+
type: "object",
49+
properties: {
50+
enforceTemplatedAttrValue: {
51+
type: "boolean",
52+
default: false,
53+
},
54+
},
55+
additionalProperties: false,
56+
},
4657
],
4758
messages: {
4859
[MESSAGE_IDS.UNEXPECTED]:
@@ -58,6 +69,10 @@ module.exports = {
5869
? context.options[0]
5970
: QUOTES_STYLES.DOUBLE;
6071
const expectedQuote = SELECTED_STYLE === QUOTES_STYLES.DOUBLE ? `"` : `'`;
72+
const enforceTemplatedAttrValue =
73+
context.options &&
74+
context.options[1] &&
75+
context.options[1].enforceTemplatedAttrValue;
6176

6277
const sourceCode = getSourceCode(context);
6378

@@ -91,7 +106,10 @@ module.exports = {
91106
* Allow template expression.
92107
* ex: html`<div foo=${foo}></div>`
93108
*/
94-
if (attr.value.parts.some((part) => part.type === NODE_TYPES.Template)) {
109+
if (
110+
!enforceTemplatedAttrValue &&
111+
attr.value.parts.some((part) => part.type === NODE_TYPES.Template)
112+
) {
95113
return;
96114
}
97115

packages/eslint-plugin/tests/rules/quotes.test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ templateRuleTester.run("[template] quotes", rule, {
173173
const handler = () => {};
174174
html\`<div onclick=\${handler}></div>\``,
175175
},
176+
{
177+
code: `html\`<div id = "\${foo}">\``,
178+
options: ["double", { enforceTemplatedAttrValue: true }],
179+
},
180+
{
181+
code: `html\`<div id = '\${foo}'>\``,
182+
options: ["single", { enforceTemplatedAttrValue: true }],
183+
},
176184
],
177185
invalid: [
178186
{
@@ -184,5 +192,35 @@ html\`<div onclick=\${handler}></div>\``,
184192
},
185193
],
186194
},
195+
{
196+
code: `html\`<div id = \${foo}>\``,
197+
output: `html\`<div id = "\${foo}">\``,
198+
options: ["double", { enforceTemplatedAttrValue: true }],
199+
errors: [
200+
{
201+
messageId: "missing",
202+
},
203+
],
204+
},
205+
{
206+
code: `html\`<div id = '\${foo}'>\``,
207+
output: `html\`<div id = "\${foo}">\``,
208+
options: ["double", { enforceTemplatedAttrValue: true }],
209+
errors: [
210+
{
211+
messageId: "unexpected",
212+
},
213+
],
214+
},
215+
{
216+
code: `html\`<div id = prefix_\${foo}>\``,
217+
output: `html\`<div id = 'prefix_\${foo}'>\``,
218+
options: ["single", { enforceTemplatedAttrValue: true }],
219+
errors: [
220+
{
221+
messageId: "missing",
222+
},
223+
],
224+
},
187225
],
188226
});

0 commit comments

Comments
 (0)