chore: update lint rules for comments

This commit is contained in:
2026-10-12 12:55:31 +05:00
parent 66b23ec3bf
commit 0e6a8464af
10 changed files with 317 additions and 48 deletions
@@ -1,8 +1,12 @@
// Tests for the conventions/comment-format rule
// (web/eslint-plugins/conventions/comment-format.js).
//
// Pure AST check (comment nodes + line counts), standard RuleTester.
// Pure AST check (comment nodes + line counts), standard RuleTester. The
// svelte pass pins the two comment kinds the token stream never sees: template
// `<!-- -->` comments (AST nodes) and CSS in `<style>` (a postcss AST); both
// need a svelte parser to exist at all.
import { RuleTester } from "eslint";
import svelteParser from "svelte-eslint-parser";
import tseslint from "typescript-eslint";
import { describe, it } from "vitest";
import commentFormat from "../conventions/comment-format.js";
@@ -17,6 +21,13 @@ const tester = new RuleTester({
},
});
const svelteTester = new RuleTester({
languageOptions: {
parser: svelteParser,
parserOptions: { parser: tseslint.parser },
},
});
const longBlock = [
"// one",
"// two",
@@ -96,3 +107,101 @@ tester.run("comment-format", asRuleModule(commentFormat), {
},
],
});
svelteTester.run("comment-format (svelte)", asRuleModule(commentFormat), {
valid: [
{
code: "<!-- why -->\n<main>Hello</main>",
filename: "Component.svelte",
options: [{ maxRatio: 1 }],
},
{
// A template comment at the cap is fine, same as in a .ts file.
code: "<!--\na\nb\nc\n-->\n<main>Hello</main>",
filename: "Component.svelte",
options: [{ maxRatio: 1 }],
},
{
// Script and template comments are separate blocks, not one run.
code: '<!-- why -->\n<main>Hello</main>\n<script lang="ts">\n// why\n</script>',
filename: "Component.svelte",
options: [{ maxRatio: 1 }],
},
{
// A CSS comment at the cap is fine, same as a script comment.
code: "<style>\n/*\na\nb\nc\n*/\n.x {\n\tcolor: red;\n}\n</style>",
filename: "Component.svelte",
options: [{ maxRatio: 1 }],
},
{
// Script and <style> comments live in different ASTs: no run across,
// so 2 + 5 lines pass where a merged block of 7 would not.
code: '<script lang="ts">\n// one\n// two\n</script>\n<style>\n/*\na\nb\nc\n*/\n.x {\n\tcolor: red;\n}\n</style>',
filename: "Component.svelte",
options: [{ maxRatio: 1 }],
},
],
invalid: [
{
// The template comment the ts pass could never see, over the cap.
code: "<!--\na\nb\nc\nd\n-->\n<main>Hello</main>",
filename: "Component.svelte",
options: [{ maxRatio: 1 }],
errors: [{ messageId: "blockTooLong" }],
},
{
// <style> is a postcss AST, so its comments are invisible to
// getAllComments(); the loc must still point at the real line.
code: "<style>\n/*\na\nb\nc\nd\n*/\n.x {\n\tcolor: red;\n}\n</style>",
filename: "Component.svelte",
options: [{ maxRatio: 1 }],
errors: [{ messageId: "blockTooLong", line: 2 }],
},
{
// A comment nested in markup is collected too (not Program.body).
code: "<div>\n\t<!--\n\ta\n\tb\n\tc\n\td\n\t-->\n</div>",
filename: "Component.svelte",
options: [{ maxRatio: 1 }],
errors: [{ messageId: "blockTooLong" }],
},
{
// Template comment lines count toward density: 2 of 4 non-blank.
code: "<!-- a -->\n<!-- b -->\n<p>x</p>\n<p>y</p>",
filename: "Component.svelte",
options: [{ maxBlockLines: 5, maxRatio: 0.4 }],
errors: [{ messageId: "tooDense" }],
},
{
// Script and template comments share one density budget.
code: '<!-- a -->\n<script lang="ts">\n// b\n</script>\n<p>c</p>',
filename: "Component.svelte",
options: [{ maxBlockLines: 5, maxRatio: 0.3 }],
errors: [{ messageId: "tooDense" }],
},
{
// CSS lines count toward density too: 2 of 8 non-blank. Consecutive
// CSS comments stay separate blocks (each one line, under the cap).
code: "<p>x</p>\n<style>\n/* a */\n/* b */\n.x {\n\tcolor: red;\n}\n</style>",
filename: "Component.svelte",
options: [{ maxBlockLines: 5, maxRatio: 0.2 }],
errors: [{ messageId: "tooDense" }],
},
{
// All three kinds over the cap: one report per block, by position.
code: "<!--\na\nb\nc\nd\ne\n-->\n<style>\n/*\nx\ny\nz\nw\nv\n*/\n.x {\n\tcolor: red;\n}\n</style>",
filename: "Component.svelte",
options: [{ maxRatio: 1 }],
errors: [
{ messageId: "blockTooLong", line: 1 },
{ messageId: "blockTooLong", line: 9 },
],
},
{
// Both violations in one file produce two reports.
code: "<!--\na\nb\nc\nd\n-->\n<p>x</p>",
filename: "Component.svelte",
options: [{ maxBlockLines: 5, maxRatio: 0.5 }],
errors: [{ messageId: "blockTooLong" }, { messageId: "tooDense" }],
},
],
});
@@ -3,12 +3,14 @@
//
// Pure AST check over comment nodes with an ASCII whitelist; string literals
// are ignored by construction (they are not comments), which the cases below
// pin down.
// pin down. .svelte gets its own pass: template `<!-- -->` comments are AST
// nodes (SvelteHTMLComment), not comment tokens, so they need a svelte parser.
import { RuleTester } from "eslint";
import svelteParser from "svelte-eslint-parser";
import tseslint from "typescript-eslint";
import { describe, it } from "vitest";
import commentsEnglish from "../conventions/comments-english.js";
import { asRuleModule } from "./helpers.js";
import { asRuleModule, svelteComponent } from "./helpers.js";
RuleTester.describe = describe;
RuleTester.it = it;
@@ -19,6 +21,13 @@ const tester = new RuleTester({
},
});
const svelteTester = new RuleTester({
languageOptions: {
parser: svelteParser,
parserOptions: { parser: tseslint.parser },
},
});
tester.run("comments-english", asRuleModule(commentsEnglish), {
valid: [
{ code: "// resize the canvas\nconst x = 1;", filename: "a.ts" },
@@ -94,3 +103,77 @@ tester.run("comments-english", asRuleModule(commentsEnglish), {
},
],
});
// Svelte components: both comment kinds are in scope. `<script>` comments
// come in as ordinary comment tokens; template `<!-- -->` comments only exist
// as SvelteHTMLComment nodes, which is the case the ts pass cannot reach.
svelteTester.run("comments-english (svelte)", asRuleModule(commentsEnglish), {
valid: [
{
code: "<!-- resize the canvas -->\n<main>Hello</main>",
filename: "Component.svelte",
},
{
code: svelteComponent("// resize the canvas"),
filename: "Component.svelte",
},
{
code: '<!-- svelte-ignore a11y_missing_attribute -->\n<main lang="en">Hello</main>',
filename: "Component.svelte",
},
{
// allowChars applies to template comments too.
code: "<!-- size 512×512 -->\n<main>Hello</main>",
filename: "Component.svelte",
options: [{ allowChars: ["×"] }],
},
{
// CSS comments in <style> are checked as well, ASCII passes.
code: '<div class="x">hi</div>\n<style>\n/* keep the row height stable */\n.x {\n\tcolor: red;\n}\n</style>',
filename: "Component.svelte",
},
],
invalid: [
{
// The template comment the ts pass could never see.
code: "<!-- русский комментарий -->\n<main>Hello</main>",
filename: "Component.svelte",
errors: [{ messageId: "nonAscii" }],
},
{
// <style> is a postcss AST, so its comments are invisible to
// getAllComments(); the loc must still point at the real line.
code: '<div class="x">hi</div>\n<style>\n/* русский комментарий в стилях */\n.x {\n\tcolor: red;\n}\n</style>',
filename: "Component.svelte",
errors: [{ messageId: "nonAscii", line: 3 }],
},
{
// All three comment kinds in one component, reported by position.
code: '<!-- раз -->\n<style>\n/* два */\n.x {\n\tcolor: red;\n}\n</style>\n<script lang="ts">\n// три\n</script>',
filename: "Component.svelte",
errors: [
{ messageId: "nonAscii", line: 1 },
{ messageId: "nonAscii", line: 3 },
{ messageId: "nonAscii", line: 9 },
],
},
{
code: svelteComponent("// ресайз холста"),
filename: "Component.svelte",
errors: [{ messageId: "nonAscii" }],
},
{
// One report per comment, script and template alike.
code: '<!-- раз -->\n<main>два</main>\n<script lang="ts">\n// три\n</script>',
filename: "Component.svelte",
errors: [{ messageId: "nonAscii" }, { messageId: "nonAscii" }],
},
{
// allowChars does not whitelist other glyphs in the same comment.
code: "<!-- 512×512 → done -->\n<main>Hello</main>",
filename: "Component.svelte",
options: [{ allowChars: ["×"] }],
errors: [{ messageId: "nonAscii" }],
},
],
});