Skip to content

Commit 827ab4b

Browse files
authored
fix(max-props): count unique keys (#2683)
1 parent 487af10 commit 827ab4b

File tree

2 files changed

+95
-8
lines changed

2 files changed

+95
-8
lines changed

Diff for: lib/rules/max-props.js

+22-8
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,41 @@ module.exports = {
3939

4040
/**
4141
* @param {import('../utils').ComponentProp[]} props
42+
* @param {CallExpression | Property} node
4243
*/
43-
function checkMaxNumberOfProps(props) {
44-
if (props.length > option.maxProps && props[0].node) {
44+
function checkMaxNumberOfProps(props, node) {
45+
const uniqueProps = new Set(props.map((prop) => prop.propName))
46+
const propCount = uniqueProps.size
47+
if (propCount > option.maxProps && props[0].node) {
4548
context.report({
46-
node: props[0].node.parent,
49+
node,
4750
messageId: 'tooManyProps',
4851
data: {
49-
propCount: props.length,
52+
propCount,
5053
limit: option.maxProps
5154
}
5255
})
5356
}
5457
}
5558

5659
return utils.compositingVisitors(
57-
utils.executeOnVue(context, (obj) => {
58-
checkMaxNumberOfProps(utils.getComponentPropsFromOptions(obj))
60+
utils.executeOnVue(context, (node) => {
61+
const propsNode = node.properties.find(
62+
/** @returns {p is Property} */
63+
(p) =>
64+
p.type === 'Property' && utils.getStaticPropertyName(p) === 'props'
65+
)
66+
67+
if (!propsNode) return
68+
69+
checkMaxNumberOfProps(
70+
utils.getComponentPropsFromOptions(node),
71+
propsNode
72+
)
5973
}),
6074
utils.defineScriptSetupVisitor(context, {
61-
onDefinePropsEnter(_, props) {
62-
checkMaxNumberOfProps(props)
75+
onDefinePropsEnter(node, props) {
76+
checkMaxNumberOfProps(props, node)
6377
}
6478
})
6579
)

Diff for: tests/lib/rules/max-props.js

+73
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ tester.run('max-props', rule, {
2626
`,
2727
options: [{ maxProps: 5 }]
2828
},
29+
{
30+
filename: 'test.vue',
31+
code: `
32+
<script setup>
33+
defineProps(['prop1', 'prop2'])
34+
</script>
35+
`,
36+
options: [{ maxProps: 5 }]
37+
},
2938
{
3039
filename: 'test.vue',
3140
code: `
@@ -99,6 +108,20 @@ tester.run('max-props', rule, {
99108
parser: require.resolve('@typescript-eslint/parser')
100109
}
101110
}
111+
},
112+
{
113+
filename: 'test.vue',
114+
code: `
115+
<script setup lang="ts">
116+
defineProps<{prop1: string, prop2: string} | {prop1: number}>()
117+
</script>
118+
`,
119+
options: [{ maxProps: 2 }],
120+
languageOptions: {
121+
parserOptions: {
122+
parser: require.resolve('@typescript-eslint/parser')
123+
}
124+
}
102125
}
103126
],
104127
invalid: [
@@ -160,6 +183,56 @@ tester.run('max-props', rule, {
160183
endLine: 3
161184
}
162185
]
186+
},
187+
{
188+
filename: 'test.vue',
189+
code: `
190+
<script setup lang="ts">
191+
defineProps<{prop1: string, prop2: string} | {prop1: number, prop3: string}>()
192+
</script>
193+
`,
194+
options: [{ maxProps: 2 }],
195+
languageOptions: {
196+
parserOptions: {
197+
parser: require.resolve('@typescript-eslint/parser')
198+
}
199+
},
200+
errors: [
201+
{
202+
message: 'Component has too many props (3). Maximum allowed is 2.',
203+
line: 3,
204+
endLine: 3
205+
}
206+
]
207+
},
208+
{
209+
filename: 'test.vue',
210+
code: `
211+
<script setup lang="ts">
212+
defineProps<{
213+
prop1: string
214+
} & {
215+
prop2?: true;
216+
prop3?: never;
217+
} | {
218+
prop2?: false;
219+
prop3?: boolean;
220+
}>()
221+
</script>
222+
`,
223+
options: [{ maxProps: 2 }],
224+
languageOptions: {
225+
parserOptions: {
226+
parser: require.resolve('@typescript-eslint/parser')
227+
}
228+
},
229+
errors: [
230+
{
231+
message: 'Component has too many props (3). Maximum allowed is 2.',
232+
line: 3,
233+
endLine: 11
234+
}
235+
]
163236
}
164237
]
165238
})

0 commit comments

Comments
 (0)