Skip to content

Commit e84397d

Browse files
authored
feat: Add prefer option to prefer-class-directive (#690)
1 parent 0e9ba36 commit e84397d

File tree

10 files changed

+103
-3
lines changed

10 files changed

+103
-3
lines changed

.changeset/popular-hotels-invent.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-svelte": minor
3+
---
4+
5+
Added prefer option to prefer-class-directive rule ('always' or 'empty'). The default is now 'empty' which is a slight relaxation of the rule.

docs/rules/prefer-class-directive.md

+18-2
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@ This rule aims to replace a class with ternary operator with the class directive
2222

2323
```svelte
2424
<script>
25-
/* eslint svelte/prefer-class-directive: "error" */
25+
/* eslint svelte/prefer-class-directive: ["error", {"prefer": "empty"}] */
26+
const selected = true;
2627
</script>
2728
2829
<!-- ✓ GOOD -->
30+
<button class:selected>foo</button>
2931
<button class:selected={current === 'foo'}>foo</button>
3032
3133
<!-- ✗ BAD -->
34+
<button class={selected ? 'selected' : ''}>foo</button>
3235
<button class={current === 'foo' ? 'selected' : ''}>foo</button>
3336
```
3437

@@ -40,7 +43,20 @@ You cannot enforce this style by using [prettier-plugin-svelte]. That is, this r
4043

4144
## :wrench: Options
4245

43-
Nothing.
46+
```json
47+
{
48+
"svelte/html-quotes": [
49+
"error",
50+
{
51+
"prefer": "empty" // or "always"
52+
}
53+
]
54+
}
55+
```
56+
57+
- `prefer` ... Whether to apply this rule always or just when there's an empty string. Default is `"empty"`.
58+
- `"empty"` ... Requires class directives only if one of the strings is empty.
59+
- `"always"` ... Requires class directives always rather than interpolation.
4460

4561
## :couple: Related Rules
4662

src/rules/prefer-class-directive.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,23 @@ export default createRule('prefer-class-directive', {
1414
conflictWithPrettier: false
1515
},
1616
fixable: 'code',
17-
schema: [],
17+
schema: [
18+
{
19+
type: 'object',
20+
properties: {
21+
prefer: { enum: ['always', 'empty'] }
22+
},
23+
additionalProperties: false
24+
}
25+
],
1826
messages: {
1927
unexpected: 'Unexpected class using the ternary operator.'
2028
},
2129
type: 'suggestion'
2230
},
2331
create(context) {
2432
const sourceCode = getSourceCode(context);
33+
const preferEmpty = context.options[0]?.prefer !== 'always';
2534

2635
type Expr = {
2736
not?: true;
@@ -298,6 +307,11 @@ export default createRule('prefer-class-directive', {
298307
// It's too complicated.
299308
return;
300309
}
310+
if (preferEmpty && [...map.values()].every((x) => x.trim())) {
311+
// We prefer directives when there's an empty string, but they're all not empty
312+
return;
313+
}
314+
301315
const prevIsWord = !startsWithNonWord(attr, index + 1);
302316
const nextIsWord = !endsWithNonWord(attr, index - 1);
303317
let canTransform = true;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"options": [{ "prefer": "always" }]
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
- message: Unexpected class using the ternary operator.
2+
line: 6
3+
column: 15
4+
suggestions: null
5+
- message: Unexpected class using the ternary operator.
6+
line: 7
7+
column: 18
8+
suggestions: null
9+
- message: Unexpected class using the ternary operator.
10+
line: 8
11+
column: 17
12+
suggestions: null
13+
- message: Unexpected class using the ternary operator.
14+
line: 10
15+
column: 20
16+
suggestions: null
17+
- message: Unexpected class using the ternary operator.
18+
line: 11
19+
column: 20
20+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
let selected = 'foo';
3+
let children = 1;
4+
</script>
5+
6+
<button class={selected ? 'selected' : ''}>foo</button>
7+
<button class="a {selected ? 'selected' : ''} b">foo</button>
8+
<button class="a{selected ? ' selected ' : ' '}b">foo</button>
9+
10+
<div class="d-flex {children > 1 ? 'gap-3' : ''}">foo</div>
11+
<div class="d-flex {children === 1 ? '' : 'gap-3'}">foo</div>
12+
13+
<!-- test01-input.svelte -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
let selected = 'foo';
3+
let children = 1;
4+
</script>
5+
6+
<button class:selected={selected}>foo</button>
7+
<button class="a b" class:selected={selected}>foo</button>
8+
<button class="a b" class:selected={selected}>foo</button>
9+
10+
<div class="d-flex" class:gap-3={children > 1}>foo</div>
11+
<div class="d-flex" class:gap-3={children !== 1}>foo</div>
12+
13+
<!-- test01-input.svelte -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"options": [{ "prefer": "always" }]
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"options": [{ "prefer": "empty" }]
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
let a = true;
3+
let a7 = 7;
4+
let danger = false;
5+
</script>
6+
7+
<button class={a ? 'a' : 'b'}>foo</button>
8+
<button class={!a ? 'b' : 'a'}>foo</button>
9+
<button class={a7 === 7 ? 'a' : 'b'}>foo</button>
10+
<button class="btn {danger ? 'btn-danger' : 'btn-primary'}">foo</button>

0 commit comments

Comments
 (0)