Skip to content

Commit 63a17bd

Browse files
authored
feat(no-unused-properties): mark $props.<prop> as used (#2345)
1 parent d99f37b commit 63a17bd

File tree

2 files changed

+184
-2
lines changed

2 files changed

+184
-2
lines changed

lib/utils/property-references.js

+26-2
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,22 @@ function definePropertyReferenceExtractor(
317317
if (parent.object === node) {
318318
// `arg.foo`
319319
const name = utils.getStaticPropertyName(parent)
320-
if (name) {
320+
321+
if (
322+
name === '$props' &&
323+
parent.parent.type === 'MemberExpression'
324+
) {
325+
// `$props.arg`
326+
const propName = utils.getStaticPropertyName(parent.parent)
327+
328+
if (!propName) return unknownMemberAsUnreferenced ? NEVER : ANY
329+
330+
return new PropertyReferencesForMember(
331+
parent.parent,
332+
propName,
333+
withInTemplate
334+
)
335+
} else if (name) {
321336
return new PropertyReferencesForMember(
322337
parent,
323338
name,
@@ -655,8 +670,17 @@ function definePropertyReferenceExtractor(
655670
references.push(extractFromExpression(id, true))
656671
}
657672
} else {
673+
const referenceId =
674+
id.name === '$props' &&
675+
id.parent.type === 'MemberExpression' &&
676+
id.parent.property.type === 'Identifier'
677+
? id.parent.property
678+
: id
679+
658680
references.push(
659-
extractFromName(id.name, id, () => extractFromExpression(id, true))
681+
extractFromName(referenceId.name, referenceId, () =>
682+
extractFromExpression(referenceId, true)
683+
)
660684
)
661685
}
662686
}

tests/lib/rules/no-unused-properties.js

+158
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,19 @@ tester.run('no-unused-properties', rule, {
6767
</script>
6868
`
6969
},
70+
{
71+
filename: 'test.vue',
72+
code: `
73+
<script>
74+
export default {
75+
props: ['count'],
76+
created() {
77+
alert(this.$props.count + 1)
78+
}
79+
};
80+
</script>
81+
`
82+
},
7083
// default options
7184
{
7285
filename: 'test.vue',
@@ -139,6 +152,20 @@ tester.run('no-unused-properties', rule, {
139152
</script>
140153
`
141154
},
155+
// a property used as a template $props member expression
156+
{
157+
filename: 'test.vue',
158+
code: `
159+
<template>
160+
<div>{{ $props.count }}</div>
161+
</template>
162+
<script>
163+
export default {
164+
props: ['count']
165+
}
166+
</script>
167+
`
168+
},
142169

143170
// properties used in a template expression
144171
{
@@ -154,6 +181,20 @@ tester.run('no-unused-properties', rule, {
154181
</script>
155182
`
156183
},
184+
// properties used in a template expression as $props member expression
185+
{
186+
filename: 'test.vue',
187+
code: `
188+
<template>
189+
<div>{{ $props.count1 + $props.count2 }}</div>
190+
</template>
191+
<script>
192+
export default {
193+
props: ['count1', 'count2']
194+
};
195+
</script>
196+
`
197+
},
157198

158199
// a property used in v-if
159200
{
@@ -173,6 +214,24 @@ tester.run('no-unused-properties', rule, {
173214
</script>
174215
`
175216
},
217+
// a property used in v-if as $props member expression
218+
{
219+
filename: 'test.vue',
220+
code: `
221+
<template>
222+
<div v-if="$props.count > 0"></div>
223+
</template>
224+
<script>
225+
export default {
226+
props: {
227+
count: {
228+
type: Number
229+
}
230+
}
231+
};
232+
</script>
233+
`
234+
},
176235

177236
// a property used in v-for
178237
{
@@ -193,6 +252,25 @@ tester.run('no-unused-properties', rule, {
193252
</script>
194253
`
195254
},
255+
// a property used in v-for as $props member expression
256+
{
257+
filename: 'test.vue',
258+
code: `
259+
<template>
260+
<div v-for="color in $props.colors">{{ color }}</div>
261+
</template>
262+
<script>
263+
export default {
264+
props: {
265+
colors: {
266+
type: Array,
267+
default: () => []
268+
}
269+
}
270+
};
271+
</script>
272+
`
273+
},
196274

197275
// a property used in v-html
198276
{
@@ -208,6 +286,20 @@ tester.run('no-unused-properties', rule, {
208286
</script>
209287
`
210288
},
289+
// a property used in v-html as $props member expression
290+
{
291+
filename: 'test.vue',
292+
code: `
293+
<template>
294+
<div v-html="$props.message" />
295+
</template>
296+
<script>
297+
export default {
298+
props: ['message']
299+
};
300+
</script>
301+
`
302+
},
211303

212304
// a property passed in a component
213305
{
@@ -223,6 +315,20 @@ tester.run('no-unused-properties', rule, {
223315
</script>
224316
`
225317
},
318+
// a property passed in a component as $props member expression
319+
{
320+
filename: 'test.vue',
321+
code: `
322+
<template>
323+
<counter :count="$props.count" />
324+
</template>
325+
<script>
326+
export default {
327+
props: ['count']
328+
};
329+
</script>
330+
`
331+
},
226332

227333
// a property used in v-on
228334
{
@@ -238,6 +344,20 @@ tester.run('no-unused-properties', rule, {
238344
</script>
239345
`
240346
},
347+
// a property used in v-on as $props member expression
348+
{
349+
filename: 'test.vue',
350+
code: `
351+
<template>
352+
<button @click="alert($props.count)" />
353+
</template>
354+
<script>
355+
export default {
356+
props: ['count']
357+
};
358+
</script>
359+
`
360+
},
241361

242362
// data used in a script expression
243363
{
@@ -1196,6 +1316,21 @@ tester.run('no-unused-properties', rule, {
11961316
</script>
11971317
`
11981318
},
1319+
{
1320+
filename: 'test.vue',
1321+
code: `
1322+
<script>
1323+
export default {
1324+
props: ['x'],
1325+
computed: {
1326+
y: {
1327+
get: () => this.$props.x * 2
1328+
}
1329+
}
1330+
};
1331+
</script>
1332+
`
1333+
},
11991334

12001335
// deep data
12011336
{
@@ -1587,6 +1722,29 @@ tester.run('no-unused-properties', rule, {
15871722
}
15881723
]
15891724
},
1725+
{
1726+
filename: 'test.vue',
1727+
code: `
1728+
<template>
1729+
</template>
1730+
<script>
1731+
export default {
1732+
props: {
1733+
a: String,
1734+
},
1735+
computed: {
1736+
/** @public */
1737+
b () { return this.$props.a },
1738+
},
1739+
}
1740+
</script>`,
1741+
options: [
1742+
{
1743+
groups: ['props', 'computed'],
1744+
ignorePublicMembers: true
1745+
}
1746+
]
1747+
},
15901748

15911749
// expose
15921750
{

0 commit comments

Comments
 (0)