Skip to content

fix: false positive for containing element in svelte/no-unused-svelte-ignore #420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/heavy-cycles-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-svelte": patch
---

fix: false positive for containing element in `svelte/no-unused-svelte-ignore`
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function extractLeadingComments(
}
const astToken = token as AST.Token
if (astToken.type === "HTMLText") {
return Boolean(astToken.value.trim())
return false
}
return astToken.type !== "HTMLComment"
},
Expand Down
81 changes: 65 additions & 16 deletions src/shared/svelte-compile-warns/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { AST } from "svelte-eslint-parser"
import * as compiler from "svelte/compiler"
import type { SourceMapMappings } from "@jridgewell/sourcemap-codec"
import { decode } from "@jridgewell/sourcemap-codec"
import type { RuleContext } from "../../types"
import type { ASTNodeWithParent, RuleContext } from "../../types"
import { LinesAndColumns } from "../../utils/lines-and-columns"
import type { TransformResult } from "./transform/types"
import {
Expand All @@ -21,6 +21,18 @@ import { getLangValue } from "../../utils/ast-utils"
import path from "path"
import fs from "fs"

type WarningTargetNode =
| (AST.SvelteProgram & ASTNodeWithParent)
| (AST.SvelteElement & ASTNodeWithParent)
| (AST.SvelteStyleElement & ASTNodeWithParent)
| (AST.SvelteScriptElement["body"][number] & ASTNodeWithParent)
type IgnoreTargetNode =
| WarningTargetNode
| (AST.SvelteIfBlock & ASTNodeWithParent)
| (AST.SvelteKeyBlock & ASTNodeWithParent)
| (AST.SvelteEachBlock & ASTNodeWithParent)
| (AST.SvelteAwaitBlock & ASTNodeWithParent)

const STYLE_TRANSFORMS: Record<
string,
typeof transformWithPostCSS | undefined
Expand Down Expand Up @@ -477,21 +489,22 @@ function processIgnore(
if (!warning.code) {
continue
}
const node = getWarningNode(warning)
if (!node) {
continue
}
for (const comment of extractLeadingComments(context, node).reverse()) {
const ignoreItem = ignoreComments.find(
(item) => item.token === comment && item.code === warning.code,
)
if (ignoreItem) {
unusedIgnores.delete(ignoreItem)
remainingWarning.delete(warning)
break
let node: IgnoreTargetNode | null = getWarningNode(warning)
while (node) {
for (const comment of extractLeadingComments(context, node).reverse()) {
const ignoreItem = ignoreComments.find(
(item) => item.token === comment && item.code === warning.code,
)
if (ignoreItem) {
unusedIgnores.delete(ignoreItem)
remainingWarning.delete(warning)
break
}
}
node = getIgnoreParent(node)
}
}

// Stripped styles are ignored from compilation and cannot determine css errors.
for (const node of stripStyleElements) {
for (const comment of extractLeadingComments(context, node).reverse()) {
Expand All @@ -509,8 +522,42 @@ function processIgnore(
unusedIgnores: [...unusedIgnores],
}

/** Get ignore target parent node */
function getIgnoreParent(node: IgnoreTargetNode): IgnoreTargetNode | null {
if (
node.type !== "SvelteElement" &&
node.type !== "SvelteIfBlock" &&
node.type !== "SvelteKeyBlock" &&
node.type !== "SvelteEachBlock" &&
node.type !== "SvelteAwaitBlock"
) {
return null
}
const parent = node.parent
if (parent.type === "SvelteElseBlock") {
return parent.parent // SvelteIfBlock or SvelteEachBlock
}
if (
parent.type === "SvelteAwaitPendingBlock" ||
parent.type === "SvelteAwaitThenBlock" ||
parent.type === "SvelteAwaitCatchBlock"
) {
return parent.parent // SvelteAwaitBlock
}
if (
parent.type !== "SvelteElement" &&
parent.type !== "SvelteIfBlock" &&
parent.type !== "SvelteKeyBlock" &&
parent.type !== "SvelteEachBlock"
// && parent.type !== "SvelteAwaitBlock"
) {
return null
}
return parent
}

/** Get warning node */
function getWarningNode(warning: Warning) {
function getWarningNode(warning: Warning): WarningTargetNode | null {
const indexes = getWarningIndexes(warning)
if (indexes.start != null) {
const node = getWarningTargetNodeFromIndex(indexes.start)
Expand All @@ -534,7 +581,9 @@ function processIgnore(
/**
* Get warning target node from the given index
*/
function getWarningTargetNodeFromIndex(index: number) {
function getWarningTargetNodeFromIndex(
index: number,
): WarningTargetNode | null {
let targetNode = sourceCode.getNodeByRangeIndex(index)
while (targetNode) {
if (
Expand All @@ -548,7 +597,7 @@ function processIgnore(
targetNode.parent.type === "Program" ||
targetNode.parent.type === "SvelteScriptElement"
) {
return targetNode
return targetNode as WarningTargetNode
}
} else {
return null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- message: svelte-ignore comment is used, but not warned
line: 4
column: 24
suggestions: null
- message: svelte-ignore comment is used, but not warned
line: 4
column: 58
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div>
{#if true}
A
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{:else}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/if}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- message: svelte-ignore comment is used, but not warned
line: 4
column: 24
suggestions: null
- message: svelte-ignore comment is used, but not warned
line: 4
column: 58
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div>
{#each [] as e}
A
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{:else}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/each}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
- message: svelte-ignore comment is used, but not warned
line: 3
column: 24
suggestions: null
- message: svelte-ignore comment is used, but not warned
line: 3
column: 58
suggestions: null
- message: svelte-ignore comment is used, but not warned
line: 7
column: 24
suggestions: null
- message: svelte-ignore comment is used, but not warned
line: 7
column: 58
suggestions: null
- message: svelte-ignore comment is used, but not warned
line: 15
column: 24
suggestions: null
- message: svelte-ignore comment is used, but not warned
line: 15
column: 58
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<div>
{#await Promise.resolve(42)}
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{:then name}
<label tabindex="0">Click</label>
<ul tabindex="0" />
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{:catch name}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/await}
</div>
<div>
{#await Promise.resolve(42)}
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{:then name}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/await}
</div>
Original file line number Diff line number Diff line change
@@ -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" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
TEXT
<div class="dropdown">
<label tabindex="0">Click</label>
<ul tabindex="0" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
<!-- comment -->
<div class="dropdown">
<label tabindex="0">Click</label>
<ul tabindex="0" />
</div>
<!-- svelte-ignore a11y-label-has-associated-control -->
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<div class="dropdown">
<label tabindex="0">Click</label>
<ul tabindex="0" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#if true}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/if}
</div>
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#if true}
A
{:else}
<div />
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/if}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#key 42}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/key}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#each [] as e}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/each}
</div>
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#each [] as e}
A
{:else}
<div />
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/each}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#await Promise.resolve(42)}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/await}
</div>
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#await Promise.resolve(42)}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{:then name}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{:catch name}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/await}
</div>
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#await Promise.resolve(42)}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{:then name}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/await}
</div>
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#await Promise.resolve(42) then n}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/await}
</div>
<div>
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{#await Promise.resolve(42) catch n}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/await}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
- message: "A11y: noninteractive element cannot have nonnegative tabIndex
value(a11y-no-noninteractive-tabindex)"
line: 6
column: 5
suggestions: null
- message: "A11y: A form label must be associated with a
control.(a11y-label-has-associated-control)"
line: 6
column: 5
suggestions: null
- message: "A11y: noninteractive element cannot have nonnegative tabIndex
value(a11y-no-noninteractive-tabindex)"
line: 7
column: 5
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div>
{#if true}
A
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{:else}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/if}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
- message: "A11y: noninteractive element cannot have nonnegative tabIndex
value(a11y-no-noninteractive-tabindex)"
line: 6
column: 5
suggestions: null
- message: "A11y: A form label must be associated with a
control.(a11y-label-has-associated-control)"
line: 6
column: 5
suggestions: null
- message: "A11y: noninteractive element cannot have nonnegative tabIndex
value(a11y-no-noninteractive-tabindex)"
line: 7
column: 5
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div>
{#each [] as e}
A
<!-- svelte-ignore a11y-label-has-associated-control a11y-no-noninteractive-tabindex -->
{:else}
<label tabindex="0">Click</label>
<ul tabindex="0" />
{/each}
</div>
Loading