Skip to content

Commit 30c1e5f

Browse files
authored
feat: add ignorePropertyPatterns property and rename ignorePatterns to ignoreTypePatterns in no-unused-props rule (#1132)
1 parent 0e2e848 commit 30c1e5f

25 files changed

+213
-25
lines changed

.changeset/crazy-peas-laugh.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-svelte': minor
3+
---
4+
5+
feat: add `ignorePropertyPatterns` property and rename `ignorePatterns` to `ignoreTypePatterns` in `no-unused-props` rule. The `ignorePatterns` option existed only for a few hours and is removed by this PR. Technically, this is a breaking change, but we’ll handle it as a minor release since very few users are likely affected.

docs/rules/no-unused-props.md

+26-5
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,17 @@ Note: Properties of class types are not checked for usage, as they might be used
159159
"svelte/no-unused-props": ["error", {
160160
// Whether to check properties from imported types
161161
"checkImportedTypes": false,
162+
// Patterns to ignore when checking property types
163+
"ignoreTypePatterns": [],
162164
// Patterns to ignore when checking for unused props
163-
"ignorePatterns": []
165+
"ignorePropertyPatterns": [],
164166
}]
165167
}
166168
```
167169

168-
- `checkImportedTypes` ... Controls whether to check properties from imported types. Default is `false`.
169-
- `ignorePatterns` ... Patterns to ignore when checking for unused props. Default is an empty array.
170+
- `checkImportedTypes` ... Controls whether to check properties from types defined in external files. Default is `false`, meaning the rule only checks types defined within the component file itself. When set to `true`, the rule will also check properties from imported and extended types.
171+
- `ignoreTypePatterns` ... Regular expression patterns for type names to exclude from checks. Default is `[]` (no exclusions). Most useful when `checkImportedTypes` is `true`, allowing you to exclude specific imported types (like utility types or third-party types) from being checked.
172+
- `ignorePropertyPatterns` ... Regular expression patterns for property names to exclude from unused checks. Default is `[]` (no exclusions). Most useful when `checkImportedTypes` is `true`, allowing you to ignore specific properties from external types that shouldn't trigger warnings.
170173

171174
Examples:
172175

@@ -187,8 +190,26 @@ Examples:
187190
```svelte
188191
<!-- ✓ Good Examples -->
189192
<script lang="ts">
190-
/* eslint svelte/no-unused-props: ["error", { "ignorePatterns": ["^_"] }] */
191-
// Ignore properties starting with underscore
193+
/* eslint svelte/no-unused-props: ["error", { "ignoreTypePatterns": ["/^Internal/"] }] */
194+
// Ignore properties from types matching the pattern
195+
interface InternalConfig {
196+
secretKey: string;
197+
debugMode: boolean;
198+
}
199+
interface Props {
200+
config: InternalConfig;
201+
value: number;
202+
}
203+
let { config, value }: Props = $props();
204+
console.log(value, config.secretKey);
205+
</script>
206+
```
207+
208+
```svelte
209+
<!-- ✓ Good Examples -->
210+
<script lang="ts">
211+
/* eslint svelte/no-unused-props: ["error", { "ignorePropertyPatterns": ["/^_/"] }] */
212+
// Ignore properties with names matching the pattern
192213
interface Props {
193214
_internal: string;
194215
value: number;

packages/eslint-plugin-svelte/src/rule-types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,8 @@ type SvelteNoUnusedClassName = []|[{
535535
// ----- svelte/no-unused-props -----
536536
type SvelteNoUnusedProps = []|[{
537537
checkImportedTypes?: boolean
538-
ignorePatterns?: string[]
538+
ignoreTypePatterns?: string[]
539+
ignorePropertyPatterns?: string[]
539540
}]
540541
// ----- svelte/no-useless-mustaches -----
541542
type SvelteNoUselessMustaches = []|[{

packages/eslint-plugin-svelte/src/rules/no-unused-props.ts

+41-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { getFilename } from '../utils/compat.js';
88

99
type PropertyPath = string[];
1010

11+
let isRemovedWarningShown = false;
12+
1113
export default createRule('no-unused-props', {
1214
meta: {
1315
docs: {
@@ -23,7 +25,14 @@ export default createRule('no-unused-props', {
2325
type: 'boolean',
2426
default: false
2527
},
26-
ignorePatterns: {
28+
ignoreTypePatterns: {
29+
type: 'array',
30+
items: {
31+
type: 'string'
32+
},
33+
default: []
34+
},
35+
ignorePropertyPatterns: {
2736
type: 'array',
2837
items: {
2938
type: 'string'
@@ -61,23 +70,48 @@ export default createRule('no-unused-props', {
6170
}
6271

6372
const options = context.options[0] ?? {};
73+
74+
// TODO: Remove in v4
75+
// MEMO: `ignorePatterns` was a property that only existed from v3.2.0 to v3.2.2.
76+
// From v3.3.0, it was replaced with `ignorePropertyPatterns` and `ignoreTypePatterns`.
77+
if (options.ignorePatterns != null && !isRemovedWarningShown) {
78+
console.warn(
79+
'eslint-plugin-svelte: The `ignorePatterns` option in the `no-unused-props` rule has been removed. Please use `ignorePropertyPatterns` or/and `ignoreTypePatterns` instead.'
80+
);
81+
isRemovedWarningShown = true;
82+
}
83+
6484
const checkImportedTypes = options.checkImportedTypes ?? false;
65-
const ignorePatterns = (options.ignorePatterns ?? []).map((p: string | RegExp) => {
85+
86+
const ignoreTypePatterns = (options.ignoreTypePatterns ?? []).map((p: string | RegExp) => {
6687
if (typeof p === 'string') {
6788
return toRegExp(p);
6889
}
6990
return p;
7091
});
7192

72-
function shouldIgnore(name: string): boolean {
73-
return ignorePatterns.some((pattern: RegExp) => pattern.test(name));
93+
const ignorePropertyPatterns = (options.ignorePropertyPatterns ?? []).map(
94+
(p: string | RegExp) => {
95+
if (typeof p === 'string') {
96+
return toRegExp(p);
97+
}
98+
return p;
99+
}
100+
);
101+
102+
function shouldIgnoreProperty(name: string): boolean {
103+
return ignorePropertyPatterns.some((pattern: RegExp) => pattern.test(name));
74104
}
75105

76106
function shouldIgnoreType(type: ts.Type): boolean {
107+
function isMatched(name: string): boolean {
108+
return ignoreTypePatterns.some((pattern: RegExp) => pattern.test(name));
109+
}
110+
77111
const typeStr = typeChecker.typeToString(type);
78112
const symbol = type.getSymbol();
79113
const symbolName = symbol?.getName();
80-
return shouldIgnore(typeStr) || (symbolName ? shouldIgnore(symbolName) : false);
114+
return isMatched(typeStr) || (symbolName ? isMatched(symbolName) : false);
81115
}
82116

83117
function isInternalProperty(symbol: ts.Symbol): boolean {
@@ -223,6 +257,8 @@ export default createRule('no-unused-props', {
223257
if (!checkImportedTypes && !isInternalProperty(prop)) continue;
224258

225259
const propName = prop.getName();
260+
if (shouldIgnoreProperty(propName)) continue;
261+
226262
const currentPath = [...parentPath, propName];
227263
const currentPathStr = [...parentPath, propName].join('.');
228264

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"options": [
3+
{
4+
"checkImportedTypes": true,
5+
"ignoreTypePatterns": ["BaseProps"],
6+
"ignorePropertyPatterns": ["/^(_|baz)/"]
7+
}
8+
]
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
- message: "'base' is an unused Props property."
2+
line: 10
3+
column: 6
4+
suggestions: null
5+
- message: "'bar' in 'my_foo' is an unused property."
6+
line: 10
7+
column: 6
8+
suggestions: null
9+
- message: "'qux' is an unused Props property."
10+
line: 10
11+
column: 6
12+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script lang="ts">
2+
import type { BaseProps, FooDTO } from './shared-types';
3+
interface Props {
4+
base: BaseProps;
5+
my_foo: FooDTO;
6+
_my_bar: string;
7+
baz: string;
8+
qux: string;
9+
}
10+
let { my_foo }: Props = $props();
11+
console.log(my_foo.foo);
12+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"options": [
3+
{
4+
"ignorePropertyPatterns": ["^foo$"]
5+
}
6+
]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
- message: "'foo' is an unused Props property."
2+
line: 8
3+
column: 8
4+
suggestions: null
5+
- message: "'_foo' is an unused Props property."
6+
line: 8
7+
column: 8
8+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script lang="ts">
2+
interface Props {
3+
foo: string;
4+
_foo: string;
5+
bar: string;
6+
}
7+
8+
const { bar }: Props = $props();
9+
</script>

packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/invalid/ignored-pattern-partial-config.json

-7
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"options": [
3+
{
4+
"ignoreTypePatterns": [".*DTO$"]
5+
}
6+
]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"options": [
3+
{
4+
"checkImportedTypes": true,
5+
"ignoreTypePatterns": ["BaseProps"],
6+
"ignorePropertyPatterns": ["/^(_|baz)/"]
7+
}
8+
]
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script lang="ts">
2+
import type { BaseProps, FooDTO } from './shared-types';
3+
interface Props {
4+
base: BaseProps;
5+
my_foo: FooDTO;
6+
_my_bar: string;
7+
baz: string;
8+
}
9+
let { base, my_foo }: Props = $props();
10+
console.log(base.age, my_foo.foo, my_foo.bar);
11+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"options": [
3+
{
4+
"ignorePropertyPatterns": ["/^[#$@_~]/"]
5+
}
6+
]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script lang="ts">
2+
interface Props {
3+
_internal: string;
4+
$store: boolean;
5+
'@decorator': string;
6+
'#private': number;
7+
'~tilde': boolean;
8+
normalUsed: string;
9+
}
10+
11+
const { normalUsed }: Props = $props();
12+
console.log(normalUsed);
13+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script lang="ts">
2+
interface Props {
3+
foo: string;
4+
bar: string;
5+
}
6+
7+
const { foo, bar }: Props = $props();
8+
</script>

packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/valid/ignored-conditional-type-config.json

-7
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"options": [
3+
{
4+
"ignoreTypePatterns": ["/^Conditional/"]
5+
}
6+
]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"options": [
3+
{
4+
"ignoreTypePatterns": ["/^Internal/"]
5+
}
6+
]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script lang="ts">
2+
interface InternalConfig {
3+
secretKey: string;
4+
debugMode: boolean;
5+
}
6+
interface Props {
7+
config: InternalConfig;
8+
value: number;
9+
}
10+
let { config, value }: Props = $props();
11+
console.log(value, config.secretKey);
12+
</script>

packages/eslint-plugin-svelte/tests/fixtures/rules/no-unused-props/valid/shared-types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export interface BaseProps {
22
name: string;
3+
age: number;
34
}
45

56
export interface FooDTO {

0 commit comments

Comments
 (0)