Repository: sveltejs/eslint-plugin-svelte
Pull request #1235 (2025-05-20 15:24:06)

feat: support comma-separated ignore comments
This is two things:

- performance improvements to the algorithm we use for extracting ignore comments
- support for comma-separated ignore comments

We can now support (as per svelte docs):

```html
<!-- svelte-ignore code1, code2 -->
```

It also drops multi-line matching in the pattern to avoid matching this kind of funk:

```html
<!-- some
random
multi-line
content
svelte-ignore code1
more content
-->
```

changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 1c0bd24fbca6ac89ea10f3302ca37778c575137e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/43081j/eslint-plugin-svelte/new/ignore-comments-perf?filename=.changeset/curvy-steaks-jump.md&value=---%0A%22eslint-plugin-svelte%22%3A%20patch%0A---%0A%0Afeat%3A%20support%20comma-separated%20ignore%20comments%0A)


github-actions[bot]: <!-- posted by pkg.pr.new-comment.mjs -->

## Try the Instant Preview in Online Playground

[ESLint Online Playground](https://eslint-online-playground.netlify.app/?overrideDeps=%7B%22eslint-plugin-svelte%22%3A%22https%3A%2F%2Fpkg.pr.new%2Feslint-plugin-svelte%401c0bd24%22%7D#eslint-plugin-svelte%20with%20typescript)

## Install the Instant Preview to Your Local

```
npm i https://pkg.pr.new/eslint-plugin-svelte@1c0bd24
```

## Published Instant Preview Packages:

- eslint-plugin-svelte: https://pkg.pr.new/eslint-plugin-svelte@1c0bd24

[View Commit](https://github.com/sveltejs/eslint-plugin-svelte/commit/1c0bd24fbca6ac89ea10f3302ca37778c575137e)

Patch:
diff --git a/.changeset/quick-cloths-double.md b/.changeset/quick-cloths-double.md
new file mode 100644
index 0000000..bcbde12
--- /dev/null
+++ b/.changeset/quick-cloths-double.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-svelte': minor
+---
+
+Improve performance of ignore comment extraction and add support for comma-separated ignore codes
diff --git a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/ignore-comment.ts b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/ignore-comment.ts
index 2655c78..77cf5a0 100644
--- a/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/ignore-comment.ts
+++ b/packages/eslint-plugin-svelte/src/shared/svelte-compile-warns/ignore-comment.ts
@@ -1,7 +1,7 @@
 import type { AST } from 'svelte-eslint-parser';
 import type { RuleContext } from '../../types.js';
 
-const SVELTE_IGNORE_PATTERN = /^\s*svelte-ignore/m;
+const SVELTE_IGNORE_PATTERN = /^\s*svelte-ignore\s+/;
 
 /**
  * Map of legacy code -> new code
@@ -37,29 +37,45 @@ export function getSvelteIgnoreItems(context: RuleContext): (IgnoreItem | Ignore
 
 	const ignoreComments: (IgnoreItem | IgnoreItemWithoutCode)[] = [];
 	for (const comment of sourceCode.getAllComments()) {
-		const ignores = extractSvelteIgnore(comment.value, comment.range[0] + 2, comment);
-		if (ignores) {
-			ignoreComments.push(...ignores);
-		} else if (hasMissingCodeIgnore(comment.value)) {
+		const match = SVELTE_IGNORE_PATTERN.exec(comment.value);
+		if (!match) {
+			continue;
+		}
+		const codeListStart = match.index + match[0].length;
+		const codeList = comment.value.slice(codeListStart);
+		if (hasMissingCodeIgnore(codeList)) {
 			ignoreComments.push({
 				range: comment.range,
 				code: null,
 				token: comment
 			});
+		} else {
+			const ignores = extractSvelteIgnore(comment.range[0] + 2, comment, codeList, codeListStart);
+			if (ignores) {
+				ignoreComments.push(...ignores);
+			}
 		}
 	}
 	for (const token of sourceCode.ast.tokens) {
 		if (token.type === 'HTMLComment') {
 			const text = token.value.slice(4, -3);
-			const ignores = extractSvelteIgnore(text, token.range[0] + 4, token);
-			if (ignores) {
-				ignoreComments.push(...ignores);
-			} else if (hasMissingCodeIgnore(text)) {
+			const match = SVELTE_IGNORE_PATTERN.exec(text);
+			if (!match) {
+				continue;
+			}
+			const codeListStart = match.index + match[0].length;
+			const codeList = text.slice(codeListStart);
+			if (hasMissingCodeIgnore(codeList)) {
 				ignoreComments.push({
 					range: token.range,
 					code: null,
 					token
 				});
+			} else {
+				const ignores = extractSvelteIgnore(token.range[0] + 4, token, codeList, codeListStart);
+				if (ignores) {
+					ignoreComments.push(...ignores);
+				}
 			}
 		}
 	}
@@ -69,46 +85,42 @@ export function getSvelteIgnoreItems(context: RuleContext): (IgnoreItem | Ignore
 
 /** Extract svelte-ignore rule names */
 function extractSvelteIgnore(
-	text: string,
 	startIndex: number,
-	token: AST.Token | AST.Comment
+	token: AST.Token | AST.Comment,
+	codeList: string,
+	ignoreStart: number
 ): IgnoreItem[] | null {
-	const m1 = SVELTE_IGNORE_PATTERN.exec(text);
-	if (!m1) {
-		return null;
-	}
-	const ignoreStart = m1.index + m1[0].length;
-	const beforeText = text.slice(ignoreStart);
-	if (!/^\s/.test(beforeText) || !beforeText.trim()) {
-		return null;
-	}
-	let start = startIndex + ignoreStart;
-
+	const start = startIndex + ignoreStart;
 	const results: IgnoreItem[] = [];
-	for (const code of beforeText.split(/\s/)) {
-		const end = start + code.length;
-		const trimmed = code.trim();
-		if (trimmed) {
+	const separatorPattern = /\s*[\s,]\s*/g;
+	const separators = codeList.matchAll(separatorPattern);
+	let lastSeparatorEnd = 0;
+	for (const separator of separators) {
+		const code = codeList.slice(lastSeparatorEnd, separator.index);
+		if (code) {
 			results.push({
-				code: trimmed,
-				codeForV5: V5_REPLACEMENTS[trimmed] || trimmed.replace(/-/gu, '_'),
-				range: [start, end],
+				code,
+				codeForV5: V5_REPLACEMENTS[code] || code.replace(/-/gu, '_'),
+				range: [start + lastSeparatorEnd, start + separator.index],
 				token
 			});
 		}
-		start = end + 1; /* space */
+		lastSeparatorEnd = separator.index + separator[0].length;
+	}
+	if (results.length === 0) {
+		const code = codeList;
+		results.push({
+			code,
+			codeForV5: V5_REPLACEMENTS[code] || code.replace(/-/gu, '_'),
+			range: [start, start + code.length],
+			token
+		});
 	}
 
 	return results;
 }
 
 /** Checks whether given comment has missing code svelte-ignore */
-function hasMissingCodeIgnore(text: string) {
-	const m1 = SVELTE_IGNORE_PATTERN.exec(text);
-	if (!m1) {
-		return false;
-	}
-	const ignoreStart = m1.index + m1[0].length;
-	const beforeText = text.slice(ignoreStart);
-	return !beforeText.trim();
+function hasMissingCodeIgnore(codeList: string) {
+	return !codeList.trim();
 }


Test patch:
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-svelte-ignore/valid/svelte-ignore-comma-separated-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-svelte-ignore/valid/svelte-ignore-comma-separated-input.svelte
new file mode 100644
index 0000000..7e2559f
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-svelte-ignore/valid/svelte-ignore-comma-separated-input.svelte
@@ -0,0 +1,5 @@
+<!-- svelte-ignore a11y_label_has_associated_control, a11y_no_noninteractive_tabindex -->
+<div class="dropdown">
+	<label tabindex="0">Click</label>
+	<ul tabindex="0"></ul>
+</div>
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-svelte-ignore/valid/svelte-ignore-comma-separated-requirements.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-svelte-ignore/valid/svelte-ignore-comma-separated-requirements.json
new file mode 100644
index 0000000..0192b10
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-svelte-ignore/valid/svelte-ignore-comma-separated-requirements.json
@@ -0,0 +1,3 @@
+{
+	"svelte": ">=5.0.0-0"
+}