Skip to content

Commit

Permalink
feat: Add prefer option to prefer-class-directive (#690)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdarnell authored Feb 29, 2024
1 parent 0e9ba36 commit e84397d
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/popular-hotels-invent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-svelte": minor
---

Added prefer option to prefer-class-directive rule ('always' or 'empty'). The default is now 'empty' which is a slight relaxation of the rule.
20 changes: 18 additions & 2 deletions docs/rules/prefer-class-directive.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ This rule aims to replace a class with ternary operator with the class directive

```svelte
<script>
/* eslint svelte/prefer-class-directive: "error" */
/* eslint svelte/prefer-class-directive: ["error", {"prefer": "empty"}] */
const selected = true;
</script>
<!-- ✓ GOOD -->
<button class:selected>foo</button>
<button class:selected={current === 'foo'}>foo</button>
<!-- ✗ BAD -->
<button class={selected ? 'selected' : ''}>foo</button>
<button class={current === 'foo' ? 'selected' : ''}>foo</button>
```

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

## :wrench: Options

Nothing.
```json
{
"svelte/html-quotes": [
"error",
{
"prefer": "empty" // or "always"
}
]
}
```

- `prefer` ... Whether to apply this rule always or just when there's an empty string. Default is `"empty"`.
- `"empty"` ... Requires class directives only if one of the strings is empty.
- `"always"` ... Requires class directives always rather than interpolation.

## :couple: Related Rules

Expand Down
16 changes: 15 additions & 1 deletion src/rules/prefer-class-directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,23 @@ export default createRule('prefer-class-directive', {
conflictWithPrettier: false
},
fixable: 'code',
schema: [],
schema: [
{
type: 'object',
properties: {
prefer: { enum: ['always', 'empty'] }
},
additionalProperties: false
}
],
messages: {
unexpected: 'Unexpected class using the ternary operator.'
},
type: 'suggestion'
},
create(context) {
const sourceCode = getSourceCode(context);
const preferEmpty = context.options[0]?.prefer !== 'always';

type Expr = {
not?: true;
Expand Down Expand Up @@ -298,6 +307,11 @@ export default createRule('prefer-class-directive', {
// It's too complicated.
return;
}
if (preferEmpty && [...map.values()].every((x) => x.trim())) {
// We prefer directives when there's an empty string, but they're all not empty
return;
}

const prevIsWord = !startsWithNonWord(attr, index + 1);
const nextIsWord = !endsWithNonWord(attr, index - 1);
let canTransform = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"options": [{ "prefer": "always" }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
- message: Unexpected class using the ternary operator.
line: 6
column: 15
suggestions: null
- message: Unexpected class using the ternary operator.
line: 7
column: 18
suggestions: null
- message: Unexpected class using the ternary operator.
line: 8
column: 17
suggestions: null
- message: Unexpected class using the ternary operator.
line: 10
column: 20
suggestions: null
- message: Unexpected class using the ternary operator.
line: 11
column: 20
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script>
let selected = 'foo';
let children = 1;
</script>

<button class={selected ? 'selected' : ''}>foo</button>
<button class="a {selected ? 'selected' : ''} b">foo</button>
<button class="a{selected ? ' selected ' : ' '}b">foo</button>

<div class="d-flex {children > 1 ? 'gap-3' : ''}">foo</div>
<div class="d-flex {children === 1 ? '' : 'gap-3'}">foo</div>

<!-- test01-input.svelte -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script>
let selected = 'foo';
let children = 1;
</script>

<button class:selected={selected}>foo</button>
<button class="a b" class:selected={selected}>foo</button>
<button class="a b" class:selected={selected}>foo</button>

<div class="d-flex" class:gap-3={children > 1}>foo</div>
<div class="d-flex" class:gap-3={children !== 1}>foo</div>

<!-- test01-input.svelte -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"options": [{ "prefer": "always" }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"options": [{ "prefer": "empty" }]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script>
let a = true;
let a7 = 7;
let danger = false;
</script>

<button class={a ? 'a' : 'b'}>foo</button>
<button class={!a ? 'b' : 'a'}>foo</button>
<button class={a7 === 7 ? 'a' : 'b'}>foo</button>
<button class="btn {danger ? 'btn-danger' : 'btn-primary'}">foo</button>

0 comments on commit e84397d

Please sign in to comment.