Skip to content

Commit 2bbd049

Browse files
Winterbaseballyama
andauthored
feat: Add fixes for block-lang rule (#844)
Co-authored-by: baseballyama <[email protected]>
1 parent cb83f9e commit 2bbd049

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+353
-58
lines changed

.changeset/fifty-parents-itch.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-svelte': minor
3+
---
4+
5+
feat: Added suggestion to the `block-lang` rule.

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ These rules relate to better ways of doing things to help you avoid problems:
354354

355355
| Rule ID | Description | |
356356
|:--------|:------------|:---|
357-
| [svelte/block-lang](https://sveltejs.github.io/eslint-plugin-svelte/rules/block-lang/) | disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks. | |
357+
| [svelte/block-lang](https://sveltejs.github.io/eslint-plugin-svelte/rules/block-lang/) | disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks. | :bulb: |
358358
| [svelte/button-has-type](https://sveltejs.github.io/eslint-plugin-svelte/rules/button-has-type/) | disallow usage of button without an explicit type attribute | |
359359
| [svelte/no-at-debug-tags](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-debug-tags/) | disallow the use of `{@debug}` | :star: |
360360
| [svelte/no-ignored-unsubscribe](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-ignored-unsubscribe/) | disallow ignoring the unsubscribe method returned by the `subscribe()` on Svelte stores. | |

docs/rules.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ These rules relate to better ways of doing things to help you avoid problems:
5151

5252
| Rule ID | Description | |
5353
| :--------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------- | :------- |
54-
| [svelte/block-lang](./rules/block-lang.md) | disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks. | |
54+
| [svelte/block-lang](./rules/block-lang.md) | disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks. | :bulb: |
5555
| [svelte/button-has-type](./rules/button-has-type.md) | disallow usage of button without an explicit type attribute | |
5656
| [svelte/no-at-debug-tags](./rules/no-at-debug-tags.md) | disallow the use of `{@debug}` | :star: |
5757
| [svelte/no-ignored-unsubscribe](./rules/no-ignored-unsubscribe.md) | disallow ignoring the unsubscribe method returned by the `subscribe()` on Svelte stores. | |

docs/rules/block-lang.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ since: 'v2.18.0'
1010

1111
> disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks.
1212
13+
- :bulb: Some problems reported by this rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
14+
1315
## :book: Rule Details
1416

1517
This rule enforces all svelte components to use the same set of languages for their scripts and styles.

packages/eslint-plugin-svelte/src/rules/block-lang.ts

+85-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { createRule } from '../utils/index.js';
2-
import { getLangValue } from '../utils/ast-utils.js';
2+
import { findAttribute, getLangValue } from '../utils/ast-utils.js';
33
import type { SvelteScriptElement, SvelteStyleElement } from 'svelte-eslint-parser/lib/ast';
44
import { getSourceCode } from '../utils/compat.js';
5+
import type { SuggestionReportDescriptor, SourceCode } from '../types.js';
56

67
export default createRule('block-lang', {
78
meta: {
@@ -54,7 +55,8 @@ export default createRule('block-lang', {
5455
}
5556
],
5657
messages: {},
57-
type: 'suggestion'
58+
type: 'suggestion',
59+
hasSuggestions: true
5860
},
5961
create(context) {
6062
if (!getSourceCode(context).parserServices.isSvelte) {
@@ -88,7 +90,8 @@ export default createRule('block-lang', {
8890
loc: { line: 1, column: 1 },
8991
message: `The <script> block should be present and its lang attribute should be ${prettyPrintLangs(
9092
allowedScriptLangs
91-
)}.`
93+
)}.`,
94+
suggest: buildAddLangSuggestions(allowedScriptLangs, 'script', getSourceCode(context))
9295
});
9396
}
9497
for (const scriptNode of scriptNodes) {
@@ -97,16 +100,19 @@ export default createRule('block-lang', {
97100
node: scriptNode,
98101
message: `The lang attribute of the <script> block should be ${prettyPrintLangs(
99102
allowedScriptLangs
100-
)}.`
103+
)}.`,
104+
suggest: buildReplaceLangSuggestions(allowedScriptLangs, scriptNode)
101105
});
102106
}
103107
}
104108
if (styleNodes.length === 0 && enforceStylePresent) {
109+
const sourceCode = getSourceCode(context);
105110
context.report({
106111
loc: { line: 1, column: 1 },
107112
message: `The <style> block should be present and its lang attribute should be ${prettyPrintLangs(
108113
allowedStyleLangs
109-
)}.`
114+
)}.`,
115+
suggest: buildAddLangSuggestions(allowedStyleLangs, 'style', sourceCode)
110116
});
111117
}
112118
for (const styleNode of styleNodes) {
@@ -115,7 +121,8 @@ export default createRule('block-lang', {
115121
node: styleNode,
116122
message: `The lang attribute of the <style> block should be ${prettyPrintLangs(
117123
allowedStyleLangs
118-
)}.`
124+
)}.`,
125+
suggest: buildReplaceLangSuggestions(allowedStyleLangs, styleNode)
119126
});
120127
}
121128
}
@@ -124,18 +131,89 @@ export default createRule('block-lang', {
124131
}
125132
});
126133

134+
function buildAddLangSuggestions(
135+
langs: (string | null)[],
136+
tagName: 'script' | 'style',
137+
sourceCode: SourceCode
138+
): SuggestionReportDescriptor[] {
139+
return langs
140+
.filter((lang) => lang != null && lang !== '')
141+
.map((lang) => {
142+
return {
143+
desc: `Add a lang attribute to a <${tagName}> block with the value "${lang}".`,
144+
fix: (fixer) => {
145+
const langAttributeText = getLangAttributeText(lang ?? '', true);
146+
return fixer.insertTextAfterRange(
147+
tagName === 'script' ? [0, 0] : [sourceCode.text.length, sourceCode.text.length],
148+
`<${tagName}${langAttributeText}>\n</${tagName}>\n\n`
149+
);
150+
}
151+
};
152+
});
153+
}
154+
155+
function buildReplaceLangSuggestions(
156+
langs: (string | null)[],
157+
node: SvelteScriptElement | SvelteStyleElement
158+
): SuggestionReportDescriptor[] {
159+
const tagName = node.name.name;
160+
const langAttribute = findAttribute(node, 'lang');
161+
const filteredLangs = langs.filter((lang) => lang != null && lang !== '');
162+
163+
if (filteredLangs.length === 0 && langs.includes(null) && langAttribute !== null) {
164+
return [
165+
{
166+
desc: `Replace a <${tagName}> block with the lang attribute omitted.`,
167+
fix: (fixer) => {
168+
return fixer.remove({
169+
type: langAttribute.type,
170+
range: [langAttribute.range[0] - 1, langAttribute.range[1]]
171+
});
172+
}
173+
}
174+
];
175+
}
176+
return filteredLangs.map((lang) => {
177+
const langAttributeText = getLangAttributeText(lang ?? '', true);
178+
if (langAttribute) {
179+
return {
180+
desc: `Replace a <${tagName}> block with the lang attribute set to "${lang}".`,
181+
fix: (fixer) => {
182+
return fixer.replaceText(langAttribute, langAttributeText.trim());
183+
}
184+
};
185+
}
186+
return {
187+
desc: `Add lang attribute to a <${tagName}> block with the value "${lang}".`,
188+
fix: (fixer) => {
189+
return fixer.insertTextBeforeRange(
190+
[node.startTag.range[0] + tagName.length + 1, 0],
191+
langAttributeText
192+
);
193+
}
194+
};
195+
});
196+
}
197+
127198
/**
128199
* Prints the list of allowed languages, with special handling of the `null` option.
129200
*/
130201
function prettyPrintLangs(langs: (string | null)[]): string {
131202
const hasNull = langs.includes(null);
132203
const nonNullLangs = langs.filter((lang) => lang !== null).map((lang) => `"${lang}"`);
133204
if (nonNullLangs.length === 0) {
134-
// No special behaviour for `hasNull`, because that can never happen.
205+
// No special behavior for `hasNull`, because that can never happen.
135206
return 'omitted';
136207
}
137208
const hasNullText = hasNull ? 'either omitted or ' : '';
138209
const nonNullText =
139210
nonNullLangs.length === 1 ? nonNullLangs[0] : `one of ${nonNullLangs.join(', ')}`;
140211
return hasNullText + nonNullText;
141212
}
213+
214+
/**
215+
* Returns the lang attribute text, with special handling of the `null` lang option with respect to the `prependWhitespace` argument.
216+
*/
217+
function getLangAttributeText(lang: string, prependWhitespace: boolean): string {
218+
return `${prependWhitespace ? ' ' : ''}lang="${lang}"`;
219+
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
- message: The lang attribute of the <script> block should be "javascript".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Add lang attribute to a <script> block with the value "javascript".
6+
output: |
7+
<script lang="javascript"></script>
8+
9+
<style lang="javascript"></style>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
- message: The lang attribute of the <script> block should be "javascript".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Replace a <script> block with the lang attribute set to "javascript".
6+
output: |
7+
<script lang="javascript"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
- message: The lang attribute of the <script> block should be "javascript".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Add lang attribute to a <script> block with the value "javascript".
6+
output: |
7+
<script lang="javascript"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
- message: The lang attribute of the <script> block should be "javascript".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Replace a <script> block with the lang attribute set to "javascript".
6+
output: |
7+
<script lang="javascript"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
- message: The lang attribute of the <script> block should be "javascript".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Replace a <script> block with the lang attribute set to "javascript".
6+
output: |
7+
<script lang="javascript"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
- message: The lang attribute of the <script> block should be "js".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Replace a <script> block with the lang attribute set to "js".
6+
output: |
7+
<script lang="js"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
- message: The lang attribute of the <script> block should be "js".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Add lang attribute to a <script> block with the value "js".
6+
output: |
7+
<script lang="js"></script>
8+
9+
<style lang="js"></style>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
- message: The lang attribute of the <script> block should be "js".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Add lang attribute to a <script> block with the value "js".
6+
output: |
7+
<script lang="js"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
- message: The lang attribute of the <script> block should be "js".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Replace a <script> block with the lang attribute set to "js".
6+
output: |
7+
<script lang="js"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
- message: The lang attribute of the <script> block should be "js".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Replace a <script> block with the lang attribute set to "js".
6+
output: |
7+
<script lang="js"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
- message: The lang attribute of the <script> block should be "ts".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Replace a <script> block with the lang attribute set to "ts".
6+
output: |
7+
<script context="module" lang="ts"></script>
8+
9+
<script lang="ts"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
- message: The lang attribute of the <script> block should be "ts".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Replace a <script> block with the lang attribute set to "ts".
6+
output: |
7+
<script context="module" lang="ts"></script>
8+
9+
<script lang="ts"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
- message: The lang attribute of the <script> block should be "ts".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Add lang attribute to a <script> block with the value "ts".
6+
output: |
7+
<script lang="ts" context="module"></script>
8+
9+
<script lang="ts"></script>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
- message: The lang attribute of the <script> block should be "ts".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Add lang attribute to a <script> block with the value "ts".
6+
output: |
7+
<script lang="ts" context="module"></script>
8+
9+
<script lang="ts"></script>
10+
11+
<style lang="ts"></style>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
- message: The lang attribute of the <script> block should be "ts".
22
line: 1
33
column: 1
4-
suggestions: null
4+
suggestions:
5+
- desc: Replace a <script> block with the lang attribute set to "ts".
6+
output: |
7+
<script context="module" lang="ts"></script>
8+
9+
<script lang="ts"></script>

packages/eslint-plugin-svelte/tests/fixtures/rules/block-lang/invalid/script/multiple/javascript01-errors.yaml

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,10 @@
22
one of "ts", "typescript".
33
line: 1
44
column: 1
5-
suggestions: null
5+
suggestions:
6+
- desc: Replace a <script> block with the lang attribute set to "ts".
7+
output: |
8+
<script lang="ts"></script>
9+
- desc: Replace a <script> block with the lang attribute set to "typescript".
10+
output: |
11+
<script lang="typescript"></script>

packages/eslint-plugin-svelte/tests/fixtures/rules/block-lang/invalid/script/multiple/js01-errors.yaml

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,10 @@
22
one of "ts", "typescript".
33
line: 1
44
column: 1
5-
suggestions: null
5+
suggestions:
6+
- desc: Replace a <script> block with the lang attribute set to "ts".
7+
output: |
8+
<script lang="ts"></script>
9+
- desc: Replace a <script> block with the lang attribute set to "typescript".
10+
output: |
11+
<script lang="typescript"></script>

packages/eslint-plugin-svelte/tests/fixtures/rules/block-lang/invalid/script/multiple/null-as-style-lang01-errors.yaml

+11-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,14 @@
22
one of "ts", "typescript".
33
line: 1
44
column: 1
5-
suggestions: null
5+
suggestions:
6+
- desc: Replace a <script> block with the lang attribute set to "ts".
7+
output: |
8+
<script lang="ts"></script>
9+
10+
<style></style>
11+
- desc: Replace a <script> block with the lang attribute set to "typescript".
12+
output: |
13+
<script lang="typescript"></script>
14+
15+
<style></style>

packages/eslint-plugin-svelte/tests/fixtures/rules/block-lang/invalid/script/multiple/ts-as-style-lang01-errors.yaml

+11-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,14 @@
22
one of "ts", "typescript".
33
line: 1
44
column: 1
5-
suggestions: null
5+
suggestions:
6+
- desc: Replace a <script> block with the lang attribute set to "ts".
7+
output: |
8+
<script lang="ts"></script>
9+
10+
<style lang="ts"></style>
11+
- desc: Replace a <script> block with the lang attribute set to "typescript".
12+
output: |
13+
<script lang="typescript"></script>
14+
15+
<style lang="ts"></style>

0 commit comments

Comments
 (0)