Skip to content

Commit 30da121

Browse files
authored
Fixed false positives when used via argument in vue/no-unused-properties (#1324)
1 parent d44fb18 commit 30da121

File tree

2 files changed

+180
-9
lines changed

2 files changed

+180
-9
lines changed

lib/rules/no-unused-properties.js

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,41 @@ module.exports = {
578578
}
579579
}
580580

581+
/**
582+
* @param {VueComponentPropertiesContainer} container
583+
* @param {UsedProps} baseUseProps
584+
*/
585+
function processUsed(container, baseUseProps) {
586+
for (const { usedNames, unknown } of iterateUsedProps(baseUseProps)) {
587+
if (unknown) {
588+
container.unknown = true
589+
return
590+
}
591+
for (const name of usedNames.names()) {
592+
container.usedNames.add(name)
593+
}
594+
}
595+
}
596+
597+
/**
598+
* @param {Expression} node
599+
* @returns {Property|null}
600+
*/
601+
function getParentProperty(node) {
602+
if (
603+
!node.parent ||
604+
node.parent.type !== 'Property' ||
605+
node.parent.value !== node
606+
) {
607+
return null
608+
}
609+
const property = node.parent
610+
if (!property.parent || property.parent.type !== 'ObjectExpression') {
611+
return null
612+
}
613+
return /** @type {Property} */ (property)
614+
}
615+
581616
const scriptVisitor = Object.assign(
582617
{},
583618
utils.defineVueVisitor(context, {
@@ -629,6 +664,61 @@ module.exports = {
629664
container.properties.push(prop)
630665
}
631666
},
667+
/** @param { (FunctionExpression | ArrowFunctionExpression) & { parent: Property }} node */
668+
'ObjectExpression > Property > :function[params.length>0]'(
669+
node,
670+
vueData
671+
) {
672+
const property = getParentProperty(node)
673+
if (!property) {
674+
return
675+
}
676+
if (property.parent === vueData.node) {
677+
if (utils.getStaticPropertyName(property) !== 'data') {
678+
return
679+
}
680+
// check { data: (vm) => vm.prop }
681+
} else {
682+
const parentProperty = getParentProperty(property.parent)
683+
if (!parentProperty) {
684+
return
685+
}
686+
if (parentProperty.parent === vueData.node) {
687+
if (utils.getStaticPropertyName(parentProperty) !== 'computed') {
688+
return
689+
}
690+
// check { computed: { foo: (vm) => vm.prop } }
691+
} else {
692+
const parentParentProperty = getParentProperty(
693+
parentProperty.parent
694+
)
695+
if (!parentParentProperty) {
696+
return
697+
}
698+
if (parentParentProperty.parent === vueData.node) {
699+
if (
700+
utils.getStaticPropertyName(parentParentProperty) !==
701+
'computed' ||
702+
utils.getStaticPropertyName(property) !== 'handler'
703+
) {
704+
return
705+
}
706+
// check { computed: { foo: { handler: (vm) => vm.prop } } }
707+
} else {
708+
return
709+
}
710+
}
711+
}
712+
713+
const paramsUsedProps = getParamsUsedProps(node)
714+
const usedProps = /** @type {ParamUsedProps} */ (paramsUsedProps.getParam(
715+
0
716+
))
717+
processUsed(
718+
getVueComponentPropertiesContainer(vueData.node),
719+
usedProps
720+
)
721+
},
632722
onSetupFunctionEnter(node, vueData) {
633723
const container = getVueComponentPropertiesContainer(vueData.node)
634724
if (node.params[0]) {
@@ -690,15 +780,7 @@ module.exports = {
690780
const container = getVueComponentPropertiesContainer(vueData.node)
691781
const usedProps = extractPatternOrThisProperties(node, context)
692782

693-
for (const { usedNames, unknown } of iterateUsedProps(usedProps)) {
694-
if (unknown) {
695-
container.unknown = true
696-
return
697-
}
698-
for (const name of usedNames.names()) {
699-
container.usedNames.add(name)
700-
}
701-
}
783+
processUsed(container, usedProps)
702784
}
703785
}),
704786
{

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

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,48 @@ tester.run('no-unused-properties', rule, {
10781078
</script>
10791079
`,
10801080
options: [{ groups: ['props', 'data'] }]
1081+
},
1082+
// contexts
1083+
{
1084+
filename: 'test.vue',
1085+
code: `
1086+
<script>
1087+
export default {
1088+
props: ['x'],
1089+
data: ({ x }) => ({
1090+
y: x
1091+
})
1092+
};
1093+
</script>
1094+
`
1095+
},
1096+
{
1097+
filename: 'test.vue',
1098+
code: `
1099+
<script>
1100+
export default {
1101+
props: ['x'],
1102+
computed: {
1103+
y: (vm) => vm.x * 2
1104+
}
1105+
};
1106+
</script>
1107+
`
1108+
},
1109+
{
1110+
filename: 'test.vue',
1111+
code: `
1112+
<script>
1113+
export default {
1114+
props: ['x'],
1115+
computed: {
1116+
y: {
1117+
handler: (vm) => vm.x * 2
1118+
}
1119+
}
1120+
};
1121+
</script>
1122+
`
10811123
}
10821124
],
10831125

@@ -1574,6 +1616,53 @@ tester.run('no-unused-properties', rule, {
15741616
})
15751617
`,
15761618
errors: ["'foo' of property found, but never used."]
1619+
},
1620+
1621+
// contexts
1622+
{
1623+
filename: 'test.vue',
1624+
code: `
1625+
<script>
1626+
export default {
1627+
props: ['x'],
1628+
data: () => ({
1629+
y: x
1630+
})
1631+
};
1632+
</script>
1633+
`,
1634+
errors: ["'x' of property found, but never used."]
1635+
},
1636+
{
1637+
filename: 'test.vue',
1638+
code: `
1639+
<script>
1640+
export default {
1641+
props: ['x'],
1642+
computed: {
1643+
[(vm) => vm.x * 2]: y
1644+
}
1645+
};
1646+
</script>
1647+
`,
1648+
errors: ["'x' of property found, but never used."]
1649+
},
1650+
{
1651+
filename: 'test.vue',
1652+
code: `
1653+
<script>
1654+
export default {
1655+
props: ['x'],
1656+
computed: {
1657+
y: {
1658+
handler: (vm) => vm.z * 2,
1659+
deep: (vm) => vm.x * 2
1660+
}
1661+
}
1662+
};
1663+
</script>
1664+
`,
1665+
errors: ["'x' of property found, but never used."]
15771666
}
15781667
]
15791668
})

0 commit comments

Comments
 (0)