Skip to content

Commit 937acbc

Browse files
committed
feat: Add fixes for block-lang rule
1 parent d117d7f commit 937acbc

File tree

1 file changed

+61
-5
lines changed

1 file changed

+61
-5
lines changed

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

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createRule } from '../utils';
2-
import { getLangValue } from '../utils/ast-utils';
2+
import { findAttribute, getLangValue } from '../utils/ast-utils';
33
import type { SvelteScriptElement, SvelteStyleElement } from 'svelte-eslint-parser/lib/ast';
44
import { getSourceCode } from '../utils/compat';
55

@@ -11,6 +11,7 @@ export default createRule('block-lang', {
1111
category: 'Best Practices',
1212
recommended: false
1313
},
14+
fixable: 'code',
1415
schema: [
1516
{
1617
type: 'object',
@@ -88,7 +89,15 @@ export default createRule('block-lang', {
8889
loc: { line: 1, column: 1 },
8990
message: `The <script> block should be present and its lang attribute should be ${prettyPrintLangs(
9091
allowedScriptLangs
91-
)}.`
92+
)}.`,
93+
*fix(fixer) {
94+
const langAttributeText = getLangAttributeText(allowedScriptLangs, true);
95+
96+
yield fixer.insertTextAfterRange(
97+
[0, 0],
98+
`<script${langAttributeText}>\n</script>\n\n`
99+
);
100+
}
92101
});
93102
}
94103
for (const scriptNode of scriptNodes) {
@@ -97,7 +106,20 @@ export default createRule('block-lang', {
97106
node: scriptNode,
98107
message: `The lang attribute of the <script> block should be ${prettyPrintLangs(
99108
allowedScriptLangs
100-
)}.`
109+
)}.`,
110+
*fix(fixer) {
111+
const langAttribute = findAttribute(scriptNode, 'lang');
112+
const langAttributeText = getLangAttributeText(allowedScriptLangs, true);
113+
114+
if (langAttribute) {
115+
yield fixer.replaceText(langAttribute, langAttributeText.trim());
116+
} else {
117+
yield fixer.insertTextBeforeRange(
118+
[scriptNode.startTag.range[0] + 7, 0],
119+
langAttributeText
120+
);
121+
}
122+
}
101123
});
102124
}
103125
}
@@ -106,7 +128,16 @@ export default createRule('block-lang', {
106128
loc: { line: 1, column: 1 },
107129
message: `The <style> block should be present and its lang attribute should be ${prettyPrintLangs(
108130
allowedStyleLangs
109-
)}.`
131+
)}.`,
132+
*fix(fixer) {
133+
const sourceCode = getSourceCode(context);
134+
const langAttributeText = getLangAttributeText(allowedScriptLangs, true);
135+
136+
yield fixer.insertTextAfterRange(
137+
[sourceCode.text.length, sourceCode.text.length],
138+
`\n\n<style${langAttributeText}>\n</style>`
139+
);
140+
}
110141
});
111142
}
112143
for (const styleNode of styleNodes) {
@@ -115,7 +146,20 @@ export default createRule('block-lang', {
115146
node: styleNode,
116147
message: `The lang attribute of the <style> block should be ${prettyPrintLangs(
117148
allowedStyleLangs
118-
)}.`
149+
)}.`,
150+
*fix(fixer) {
151+
const langAttribute = findAttribute(styleNode, 'lang');
152+
const langAttributeText = getLangAttributeText(allowedStyleLangs, true);
153+
154+
if (langAttribute) {
155+
yield fixer.replaceText(langAttribute, langAttributeText.trim());
156+
} else {
157+
yield fixer.insertTextBeforeRange(
158+
[styleNode.startTag.range[0] + 6, 0],
159+
langAttributeText
160+
);
161+
}
162+
}
119163
});
120164
}
121165
}
@@ -139,3 +183,15 @@ function prettyPrintLangs(langs: (string | null)[]): string {
139183
nonNullLangs.length === 1 ? nonNullLangs[0] : `one of ${nonNullLangs.join(', ')}`;
140184
return hasNullText + nonNullText;
141185
}
186+
187+
/**
188+
* Returns the lang attribute text, with special handling of the `null` lang option with respect to the `prependWhitespace` argument.
189+
*/
190+
function getLangAttributeText(langs: (string | null)[], prependWhitespace: boolean): string {
191+
if (!langs.length || langs.includes(null)) return '';
192+
const [firstLang] = langs;
193+
if (langs.length === 1 && firstLang) {
194+
return `${prependWhitespace ? ' ' : ''}lang="${firstLang}"`;
195+
}
196+
return '';
197+
}

0 commit comments

Comments
 (0)