-
-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathhtml-closing-bracket-spacing.ts
109 lines (99 loc) · 2.73 KB
/
html-closing-bracket-spacing.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { createRule } from "../utils"
import type { AST } from "svelte-eslint-parser"
export default createRule("html-closing-bracket-spacing", {
meta: {
docs: {
description: "require or disallow a space before tag's closing brackets",
category: "Stylistic Issues",
conflictWithPrettier: true,
recommended: false,
},
schema: [
{
type: "object",
properties: {
startTag: {
enum: ["always", "never", "ignore"],
},
endTag: {
enum: ["always", "never", "ignore"],
},
selfClosingTag: {
enum: ["always", "never", "ignore"],
},
},
additionalProperties: false,
},
],
messages: {
expectedSpace: "Expected space before '>', but not found.",
unexpectedSpace: "Expected no space before '>', but found.",
},
fixable: "whitespace",
type: "layout",
},
create(ctx) {
const options = {
startTag: "never",
endTag: "never",
selfClosingTag: "always",
...ctx.options[0],
}
const src = ctx.getSourceCode()
/**
* Returns true if string contains newline characters
*/
function containsNewline(string: string): boolean {
return string.includes("\n")
}
/**
* Report
*/
function report(
node: AST.SvelteStartTag | AST.SvelteEndTag,
shouldHave: boolean,
) {
const tagSrc = src.getText(node)
const match = /(\s*)\/?>$/.exec(tagSrc)
const end = node.range[1]
const start = node.range[1] - match![0].length
const loc = {
start: src.getLocFromIndex(start),
end: src.getLocFromIndex(end),
}
ctx.report({
loc,
messageId: shouldHave ? "expectedSpace" : "unexpectedSpace",
*fix(fixer) {
if (shouldHave) {
yield fixer.insertTextBeforeRange([start, end], " ")
} else {
const spaces = match![1]
yield fixer.removeRange([start, start + spaces.length])
}
},
})
}
return {
"SvelteStartTag, SvelteEndTag"(
node: AST.SvelteStartTag | AST.SvelteEndTag,
) {
const tagType =
node.type === "SvelteEndTag"
? "endTag"
: node.selfClosing
? "selfClosingTag"
: "startTag"
if (options[tagType] === "ignore") return
const tagSrc = src.getText(node)
const match = /(\s*)\/?>$/.exec(tagSrc)
if (containsNewline(match![1])) return
if (options[tagType] === "always" && !match![1]) {
report(node, true)
} else if (options[tagType] === "never" && match![1]) {
report(node, false)
}
},
}
},
})