Skip to content

Commit 6aa4790

Browse files
authored
Add ignoreWarnings option (#15)
1 parent 9878994 commit 6aa4790

File tree

12 files changed

+343
-29
lines changed

12 files changed

+343
-29
lines changed

README.md

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,30 @@ If you are using [eslint-plugin-svelte3] you need to remove it.
9999

100100
:::
101101

102+
#### settings["@ota-meshi/svelte"]
103+
104+
You can change the behavior of this plugin with some settings.
105+
106+
- `ignoreWarnings` (optional) ... Specifies an array of rules that ignore reports in the template.
107+
For example, set rules on the template that cannot avoid false positives.
108+
109+
e.g.
110+
111+
```js
112+
module.exports = {
113+
// ...
114+
settings: {
115+
"@ota-meshi/svelte": {
116+
ignoreWarnings: [
117+
"@typescript-eslint/no-unsafe-assignment",
118+
"@typescript-eslint/no-unsafe-member-access",
119+
],
120+
},
121+
},
122+
// ...
123+
}
124+
```
125+
102126
### Running ESLint from the command line
103127

104128
If you want to run `eslint` from the command line, make sure you include the `.svelte` extension using [the `--ext` option](https://eslint.org/docs/user-guide/configuring#specifying-file-extensions-to-lint) or a glob pattern, because ESLint targets only `.js` files by default.
@@ -138,18 +162,19 @@ The rules with the following star :star: are included in the configs.
138162

139163
<!--RULES_TABLE_START-->
140164

141-
| Rule ID | Description | |
142-
|:--------|:------------|:---|
143-
| [@ota-meshi/svelte/button-has-type](https://ota-meshi.github.io/eslint-plugin-svelte/rules/button-has-type.html) | disallow usage of button without an explicit type attribute | |
144-
| [@ota-meshi/svelte/comment-directive](https://ota-meshi.github.io/eslint-plugin-svelte/rules/comment-directive.html) | support comment-directives in HTML template | :star: |
145-
| [@ota-meshi/svelte/no-at-debug-tags](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-at-debug-tags.html) | disallow the use of `{@debug}` | :star: |
146-
| [@ota-meshi/svelte/no-at-html-tags](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-at-html-tags.html) | disallow use of `{@html}` to prevent XSS attack | :star: |
147-
| [@ota-meshi/svelte/no-dupe-else-if-blocks](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-else-if-blocks.html) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
148-
| [@ota-meshi/svelte/no-inner-declarations](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-inner-declarations.html) | disallow variable or `function` declarations in nested blocks | :star: |
149-
| [@ota-meshi/svelte/no-target-blank](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-target-blank.html) | disallow target="_blank" attribute without rel="noopener noreferrer" | |
150-
| [@ota-meshi/svelte/no-useless-mustaches](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-useless-mustaches.html) | disallow unnecessary mustache interpolations | :wrench: |
151-
| [@ota-meshi/svelte/prefer-class-directive](https://ota-meshi.github.io/eslint-plugin-svelte/rules/prefer-class-directive.html) | require class directives instead of ternary expressions | :wrench: |
152-
| [@ota-meshi/svelte/spaced-html-comment](https://ota-meshi.github.io/eslint-plugin-svelte/rules/spaced-html-comment.html) | enforce consistent spacing after the `<!--` and before the `-->` in a HTML comment | :wrench: |
165+
| Rule ID | Description | |
166+
| :----------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | :------- |
167+
| [@ota-meshi/svelte/button-has-type](https://ota-meshi.github.io/eslint-plugin-svelte/rules/button-has-type.html) | disallow usage of button without an explicit type attribute | |
168+
| [@ota-meshi/svelte/comment-directive](https://ota-meshi.github.io/eslint-plugin-svelte/rules/comment-directive.html) | support comment-directives in HTML template | :star: |
169+
| [@ota-meshi/svelte/no-at-debug-tags](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-at-debug-tags.html) | disallow the use of `{@debug}` | :star: |
170+
| [@ota-meshi/svelte/no-at-html-tags](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-at-html-tags.html) | disallow use of `{@html}` to prevent XSS attack | :star: |
171+
| [@ota-meshi/svelte/no-dupe-else-if-blocks](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-else-if-blocks.html) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
172+
| [@ota-meshi/svelte/no-inner-declarations](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-inner-declarations.html) | disallow variable or `function` declarations in nested blocks | :star: |
173+
| [@ota-meshi/svelte/no-target-blank](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-target-blank.html) | disallow target="\_blank" attribute without rel="noopener noreferrer" | |
174+
| [@ota-meshi/svelte/no-useless-mustaches](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-useless-mustaches.html) | disallow unnecessary mustache interpolations | :wrench: |
175+
| [@ota-meshi/svelte/prefer-class-directive](https://ota-meshi.github.io/eslint-plugin-svelte/rules/prefer-class-directive.html) | require class directives instead of ternary expressions | :wrench: |
176+
| [@ota-meshi/svelte/spaced-html-comment](https://ota-meshi.github.io/eslint-plugin-svelte/rules/spaced-html-comment.html) | enforce consistent spacing after the `<!--` and before the `-->` in a HTML comment | :wrench: |
177+
| [@ota-meshi/svelte/system](https://ota-meshi.github.io/eslint-plugin-svelte/rules/system.html) | system rule for working this plugin | :star: |
153178

154179
<!--RULES_TABLE_END-->
155180
<!--RULES_SECTION_END-->

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ The rules with the following star :star: are included in the `plugin:@ota-meshi/
2121
| [@ota-meshi/svelte/no-useless-mustaches](./no-useless-mustaches.md) | disallow unnecessary mustache interpolations | :wrench: |
2222
| [@ota-meshi/svelte/prefer-class-directive](./prefer-class-directive.md) | require class directives instead of ternary expressions | :wrench: |
2323
| [@ota-meshi/svelte/spaced-html-comment](./spaced-html-comment.md) | enforce consistent spacing after the `<!--` and before the `-->` in a HTML comment | :wrench: |
24+
| [@ota-meshi/svelte/system](./system.md) | system rule for working this plugin | :star: |

docs/rules/system.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
pageClass: "rule-details"
3+
sidebarDepth: 0
4+
title: "@ota-meshi/svelte/system"
5+
description: "system rule for working this plugin"
6+
---
7+
8+
# @ota-meshi/svelte/system
9+
10+
> system rule for working this plugin
11+
12+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>
13+
- :gear: This rule is included in `"plugin:@ota-meshi/svelte/base"` and `"plugin:@ota-meshi/svelte/recommended"`.
14+
15+
## :book: Rule Details
16+
17+
This rule is a system rule for working the this plugin. This rule does not report any errors, but make sure the rule is enabled for the this plugin to work properly.
18+
19+
## :wrench: Options
20+
21+
Nothing.
22+
23+
## :mag: Implementation
24+
25+
- [Rule source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/src/rules/system.ts)
26+
- [Test source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/tests/src/rules/system.ts)

docs/user-guide/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,30 @@ If you are using [eslint-plugin-svelte3] you need to remove it.
5757

5858
:::
5959

60+
#### settings["@ota-meshi/svelte"]
61+
62+
You can change the behavior of this plugin with some settings.
63+
64+
- `ignoreWarnings` (optional) ... Specifies an array of rules that ignore reports in the template.
65+
For example, set rules on the template that cannot avoid false positives.
66+
67+
e.g.
68+
69+
```js
70+
module.exports = {
71+
// ...
72+
settings: {
73+
"@ota-meshi/svelte": {
74+
ignoreWarnings: [
75+
"@typescript-eslint/no-unsafe-assignment",
76+
"@typescript-eslint/no-unsafe-member-access",
77+
],
78+
},
79+
},
80+
// ...
81+
}
82+
```
83+
6084
### Running ESLint from the command line
6185

6286
If you want to run `eslint` from the command line, make sure you include the `.svelte` extension using [the `--ext` option](https://eslint.org/docs/user-guide/configuring#specifying-file-extensions-to-lint) or a glob pattern, because ESLint targets only `.js` files by default.

src/configs/recommended.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ export = {
1111
"@ota-meshi/svelte/no-at-html-tags": "error",
1212
"@ota-meshi/svelte/no-dupe-else-if-blocks": "error",
1313
"@ota-meshi/svelte/no-inner-declarations": "error",
14+
"@ota-meshi/svelte/system": "error",
1415
},
1516
}

src/rules/comment-directive.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,7 @@ export default createRule("comment-directive", {
121121
})
122122
}
123123
directives.disableBlock(comment.loc.start, rule.ruleId, {
124-
kind: parsed.type,
125-
loc: rule.loc,
124+
loc: rule.loc.start,
126125
})
127126
}
128127
} else {
@@ -134,8 +133,7 @@ export default createRule("comment-directive", {
134133
})
135134
}
136135
directives.disableBlock(comment.loc.start, ALL_RULES, {
137-
kind: parsed.type,
138-
loc: comment.loc,
136+
loc: comment.loc.start,
139137
})
140138
}
141139
} else {
@@ -149,8 +147,7 @@ export default createRule("comment-directive", {
149147
})
150148
}
151149
directives.enableBlock(comment.loc.start, rule.ruleId, {
152-
kind: parsed.type,
153-
loc: rule.loc,
150+
loc: rule.loc.start,
154151
})
155152
}
156153
} else {
@@ -162,8 +159,7 @@ export default createRule("comment-directive", {
162159
})
163160
}
164161
directives.enableBlock(comment.loc.start, ALL_RULES, {
165-
kind: parsed.type,
166-
loc: comment.loc,
162+
loc: comment.loc.start,
167163
})
168164
}
169165
}
@@ -193,8 +189,7 @@ export default createRule("comment-directive", {
193189
})
194190
}
195191
directives.disableLine(line, rule.ruleId, {
196-
kind: parsed.type,
197-
loc: rule.loc,
192+
loc: rule.loc.start,
198193
})
199194
}
200195
} else {
@@ -206,8 +201,7 @@ export default createRule("comment-directive", {
206201
})
207202
}
208203
directives.disableLine(line, ALL_RULES, {
209-
kind: parsed.type,
210-
loc: comment.loc,
204+
loc: comment.loc.start,
211205
})
212206
}
213207
}
@@ -220,8 +214,7 @@ export default createRule("comment-directive", {
220214
},
221215
SvelteScriptElement(node) {
222216
directives.enableBlock(node.startTag.loc.end, ALL_RULES, {
223-
kind: "system",
224-
loc: node.loc,
217+
loc: node.loc.start,
225218
})
226219
},
227220
}

src/rules/system.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { getShared } from "../shared"
2+
import { createRule } from "../utils"
3+
import { isRegExp, toRegExp } from "../utils/regexp"
4+
5+
export default createRule("system", {
6+
meta: {
7+
docs: {
8+
description: "system rule for working this plugin",
9+
recommended: "base",
10+
},
11+
schema: [],
12+
messages: {},
13+
type: "problem",
14+
},
15+
create(context) {
16+
const shared = getShared(context.getFilename())
17+
if (!shared) return {}
18+
19+
const directives = shared.newCommentDirectives({
20+
ruleId: "@ota-meshi/svelte/system",
21+
})
22+
23+
const ignoreWarnings =
24+
context.settings?.["@ota-meshi/svelte"]?.ignoreWarnings
25+
if (!Array.isArray(ignoreWarnings)) {
26+
context.report({
27+
loc: { line: 1, column: 0 },
28+
message:
29+
'The settings["@ota-meshi/svelte"].ignoreWarnings must be an array.',
30+
})
31+
return {}
32+
}
33+
const ignoreTests: ((ruleId: string) => boolean)[] = []
34+
for (const ignoreWarning of ignoreWarnings) {
35+
if (typeof ignoreWarning !== "string") {
36+
context.report({
37+
loc: { line: 1, column: 0 },
38+
message:
39+
'The array element in the settings["@ota-meshi/svelte"].ignoreWarnings must be a string.',
40+
})
41+
return {}
42+
}
43+
if (isRegExp(ignoreWarning)) {
44+
const regexp = toRegExp(ignoreWarning)
45+
ignoreTests.push((ruleId) => regexp.test(ruleId))
46+
} else {
47+
ignoreTests.push((ruleId) => ruleId === ignoreWarning)
48+
}
49+
}
50+
51+
/** Checks wether given rule is ignore rule or not */
52+
function isIgnoreRule(ruleId: string): boolean {
53+
return ignoreTests.some((test) => test(ruleId))
54+
}
55+
56+
directives.disableBlock({ line: 1, column: 0 }, isIgnoreRule, {
57+
loc: { line: 1, column: 0 },
58+
})
59+
return {
60+
SvelteScriptElement(node) {
61+
directives.enableBlock(node.startTag.loc.end, isIgnoreRule, {
62+
loc: node.startTag.loc.end,
63+
})
64+
if (node.endTag) {
65+
directives.enableBlock(node.endTag.loc.start, isIgnoreRule, {
66+
loc: node.endTag.loc.start,
67+
})
68+
}
69+
},
70+
}
71+
},
72+
})

src/shared/comment-directives.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ const COMPUTED = Symbol()
44
const ALL = Symbol()
55

66
type Define = {
7-
kind: string
8-
loc: AST.SourceLocation
7+
loc: AST.Position
98
}
109
type Block = {
1110
loc: AST.Position
@@ -89,7 +88,7 @@ export class CommentDirectives {
8988

9089
if (reportUnusedDisableDirectives) {
9190
const usedDirectiveKeys = new Set(
92-
[...usedDirectives].map((d) => locToKey(d.define.loc.start)),
91+
[...usedDirectives].map((d) => locToKey(d.define.loc)),
9392
)
9493
filteredMessages = filteredMessages.filter((m) => {
9594
if (m.ruleId !== this.ruleId) {

src/utils/regexp.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const RE_REGEXP_CHAR = /[$()*+.?[\\\]^{|}]/gu
2+
const RE_HAS_REGEXP_CHAR = new RegExp(RE_REGEXP_CHAR.source)
3+
4+
const RE_REGEXP_STR = /^\/(.+)\/(.*)$/u
5+
6+
/**
7+
* Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
8+
* "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
9+
*
10+
* @param {string} string The string to escape.
11+
* @returns {string} Returns the escaped string.
12+
*/
13+
function escape(string: string) {
14+
return string && RE_HAS_REGEXP_CHAR.test(string)
15+
? string.replace(RE_REGEXP_CHAR, "\\$&")
16+
: string
17+
}
18+
19+
/**
20+
* Convert a string to the `RegExp`.
21+
* Normal strings (e.g. `"foo"`) is converted to `/^foo$/` of `RegExp`.
22+
* Strings like `"/^foo/i"` are converted to `/^foo/i` of `RegExp`.
23+
*
24+
* @param {string} string The string to convert.
25+
* @returns {RegExp} Returns the `RegExp`.
26+
*/
27+
export function toRegExp(string: string): RegExp {
28+
const parts = RE_REGEXP_STR.exec(string)
29+
if (parts) {
30+
return new RegExp(parts[1], parts[2])
31+
}
32+
return new RegExp(`^${escape(string)}$`)
33+
}
34+
35+
/**
36+
* Checks whether given string is regexp string
37+
* @param {string} string
38+
* @returns {boolean}
39+
*/
40+
export function isRegExp(string: string): boolean {
41+
return Boolean(RE_REGEXP_STR.test(string))
42+
}

src/utils/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import noTargetBlank from "../rules/no-target-blank"
99
import noUselessMustaches from "../rules/no-useless-mustaches"
1010
import preferClassDirective from "../rules/prefer-class-directive"
1111
import spacedHtmlComment from "../rules/spaced-html-comment"
12+
import system from "../rules/system"
1213

1314
export const rules = [
1415
buttonHasType,
@@ -21,4 +22,5 @@ export const rules = [
2122
noUselessMustaches,
2223
preferClassDirective,
2324
spacedHtmlComment,
25+
system,
2426
] as RuleModule[]

0 commit comments

Comments
 (0)