Skip to content

feat: add svelte/no-trailing-spaces rule #240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 24, 2022
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
5 changes: 5 additions & 0 deletions .changeset/curly-tigers-destroy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-svelte": minor
---

feat: add `svelte/no-trailing-spaces` rule
1 change: 1 addition & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ These rules extend the rules provided by ESLint itself to work well in Svelte:
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/no-inner-declarations](./rules/no-inner-declarations.md) | disallow variable or `function` declarations in nested blocks | :star: |
| [svelte/no-trailing-spaces](./rules/no-trailing-spaces.md) | disallow trailing whitespace at the end of lines | :wrench: |

## System

Expand Down
83 changes: 83 additions & 0 deletions docs/rules/no-trailing-spaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
pageClass: "rule-details"
sidebarDepth: 0
title: "svelte/no-trailing-spaces"
description: "disallow trailing whitespace at the end of lines"
---

# svelte/no-trailing-spaces

> disallow trailing whitespace at the end of lines

- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>
- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.

## :book: Rule Details

This rule extends the base ESLint's [no-trailing-spaces] rule. The [no-trailing-spaces] rule does not understand HTML comments and will report trailing whitespace in HTML comments when using `ignoreComments` option.
This rule supports HTML comments generated by [svelte-eslint-parser].

[svelte-eslint-parser]: https://github.com/ota-meshi/svelte-eslint-parser

<ESLintCodeBlock fix>

<!-- prettier-ignore-start -->
<!--eslint-skip-->

```svelte
<script>
/* eslint svelte/no-trailing-spaces: "error" */

/* ✓ GOOD */
var foo = 0;
/* ✗ BAD */
var foo = 0;
</script>

<!-- ✓ GOOD -->
<div>
Text
</div>

<!-- ✗ BAD -->
<div>
Text
</div>
```

<!-- prettier-ignore-end -->

</ESLintCodeBlock>

## :wrench: Options

```jsonc
{
"no-trailing-spaces": "off", // Don't need ESLint's no-trailing-spaces rule, so turn it off.
"svelte/no-trailing-spaces": [
"error",
{
"skipBlankLines": false,
"ignoreComments": false
}
]
}
```

- `skipBlankLines` ... If `true`, allows trailing whitespace on empty lines.
- `ignoreComments` ... If `true`, allows trailing whitespace in comments.

Same as [no-trailing-spaces] rule option. See [here](https://eslint.org/docs/rules/no-trailing-spaces#options) for details.

## :couple: Related rules

- [no-trailing-spaces]

[no-trailing-spaces]: https://eslint.org/docs/rules/no-trailing-spaces

## :mag: Implementation

- [Rule source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/src/rules/no-trailing-spaces.ts)
- [Test source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/tests/src/rules/no-trailing-spaces.ts)

<sup>Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-trailing-spaces)</sup>
1 change: 1 addition & 0 deletions src/configs/prettier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export = {
"svelte/max-attributes-per-line": "off",
"svelte/mustache-spacing": "off",
"svelte/no-spaces-around-equal-signs-in-attribute": "off",
"svelte/no-trailing-spaces": "off",
"svelte/shorthand-attribute": "off",
"svelte/shorthand-directive": "off",
},
Expand Down
104 changes: 104 additions & 0 deletions src/rules/no-trailing-spaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type { AST } from "svelte-eslint-parser"
import { createRule } from "../utils"

export default createRule("no-trailing-spaces", {
meta: {
type: "layout",
docs: {
description: "disallow trailing whitespace at the end of lines",
category: "Extension Rules",
recommended: false,
extensionRule: "no-trailing-spaces",
conflictWithPrettier: true,
},
fixable: "whitespace",
schema: [
{
type: "object",
properties: {
skipBlankLines: { type: "boolean" },
ignoreComments: { type: "boolean" },
},
additionalProperties: false,
},
],
messages: {
trailingSpace: "Trailing spaces not allowed.",
},
},
create(context) {
const options:
| { skipBlankLines?: boolean; ignoreComments?: boolean }
| undefined = context.options[0]
const skipBlankLines = options?.skipBlankLines || false
const ignoreComments = options?.ignoreComments || false

const sourceCode = context.getSourceCode()

const ignoreLineNumbers = new Set<number>()
if (ignoreComments) {
for (const { type, loc } of sourceCode.getAllComments()) {
const endLine = type === "Block" ? loc.end.line - 1 : loc.end.line
for (let i = loc.start.line; i <= endLine; i++) {
ignoreLineNumbers.add(i)
}
}
}

/**
* Reports a given location.
*/
function report(loc: AST.SourceLocation) {
context.report({
loc,
messageId: "trailingSpace",
fix(fixer) {
return fixer.removeRange([
sourceCode.getIndexFromLoc(loc.start),
sourceCode.getIndexFromLoc(loc.end),
])
},
})
}

/**
* Collects the location of the given node as the ignore line numbers.
*/
function collectIgnoreLineNumbers({ loc }: { loc: AST.SourceLocation }) {
const endLine = loc.end.line - 1
for (let i = loc.start.line; i <= endLine; i++) {
ignoreLineNumbers.add(i)
}
}

return {
TemplateElement: collectIgnoreLineNumbers,
...(ignoreComments
? {
SvelteHTMLComment: collectIgnoreLineNumbers,
}
: {}),
"Program:exit"() {
const lines = sourceCode.lines
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
const line = lines[lineIndex]
if (skipBlankLines && !line.trim()) {
continue
}
const lineNumber = lineIndex + 1
if (ignoreLineNumbers.has(lineNumber)) {
continue
}
const trimmed = line.trimEnd()
if (trimmed === line) {
continue
}
report({
start: { line: lineNumber, column: trimmed.length },
end: { line: lineNumber, column: line.length },
})
}
},
}
},
})
2 changes: 2 additions & 0 deletions src/utils/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import noShorthandStylePropertyOverrides from "../rules/no-shorthand-style-prope
import noSpacesAroundEqualSignsInAttribute from "../rules/no-spaces-around-equal-signs-in-attribute"
import noStoreAsync from "../rules/no-store-async"
import noTargetBlank from "../rules/no-target-blank"
import noTrailingSpaces from "../rules/no-trailing-spaces"
import noUnknownStyleDirectiveProperty from "../rules/no-unknown-style-directive-property"
import noUnusedSvelteIgnore from "../rules/no-unused-svelte-ignore"
import noUselessMustaches from "../rules/no-useless-mustaches"
Expand Down Expand Up @@ -62,6 +63,7 @@ export const rules = [
noSpacesAroundEqualSignsInAttribute,
noStoreAsync,
noTargetBlank,
noTrailingSpaces,
noUnknownStyleDirectiveProperty,
noUnusedSvelteIgnore,
noUselessMustaches,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"options": [
{
"ignoreComments": true
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
- message: Trailing spaces not allowed.
line: 5
column: 2
suggestions: null
- message: Trailing spaces not allowed.
line: 9
column: 6
suggestions: null
- message: Trailing spaces not allowed.
line: 14
column: 1
suggestions: null
- message: Trailing spaces not allowed.
line: 23
column: 12
suggestions: null
- message: Trailing spaces not allowed.
line: 26
column: 7
suggestions: null
- message: Trailing spaces not allowed.
line: 27
column: 7
suggestions: null
- message: Trailing spaces not allowed.
line: 30
column: 7
suggestions: null
- message: Trailing spaces not allowed.
line: 33
column: 7
suggestions: null
- message: Trailing spaces not allowed.
line: 34
column: 23
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!-- prettier-ignore -->
<script>
const str = `

`
// line comment
/**
* block comment
*/
/**
* block comment2
*/ const a = 42
// empty line

// empty line
</script>

<!--
HTML comment
-->

<!-- prettier-ignore -->
<span> Text
</span>
<!-- prettier-ignore -->
<span>
Text
</span>
<!-- prettier-ignore -->
<span>
Text </span>
<!-- prettier-ignore -->
<span>
<span>Text </span>
</span>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!-- prettier-ignore -->
<script>
const str = `

`
// line comment
/**
* block comment
*/
/**
* block comment2
*/ const a = 42
// empty line

// empty line
</script>

<!--
HTML comment
-->

<!-- prettier-ignore -->
<span> Text
</span>
<!-- prettier-ignore -->
<span>
Text
</span>
<!-- prettier-ignore -->
<span>
Text </span>
<!-- prettier-ignore -->
<span>
<span>Text </span>
</span>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"options": [
{
"skipBlankLines": true
}
]
}
Loading