Skip to content

Commit 291c6f9

Browse files
implements proposed max-props rule (#2430)
Co-authored-by: Flo Edelmann <[email protected]>
1 parent f5cb93d commit 291c6f9

File tree

5 files changed

+293
-0
lines changed

5 files changed

+293
-0
lines changed

docs/rules/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ For example:
223223
| [vue/match-component-file-name](./match-component-file-name.md) | require component name property to match its file name | :bulb: | :hammer: |
224224
| [vue/match-component-import-name](./match-component-import-name.md) | require the registered component name to match the imported component name | | :warning: |
225225
| [vue/max-lines-per-block](./max-lines-per-block.md) | enforce maximum number of lines in Vue SFC blocks | | :warning: |
226+
| [vue/max-props](./max-props.md) | enforce maximum number of props in Vue component | | :warning: |
226227
| [vue/new-line-between-multi-line-property](./new-line-between-multi-line-property.md) | enforce new lines between multi-line properties in Vue components | :wrench: | :lipstick: |
227228
| [vue/next-tick-style](./next-tick-style.md) | enforce Promise or callback style in `nextTick` | :wrench: | :hammer: |
228229
| [vue/no-bare-strings-in-template](./no-bare-strings-in-template.md) | disallow the use of bare strings in `<template>` | | :hammer: |

docs/rules/max-props.md

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/max-props
5+
description: enforce maximum number of props in Vue component
6+
---
7+
8+
# vue/max-props
9+
10+
> enforce maximum number of props in Vue component
11+
12+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> _**This rule has not been released yet.**_ </badge>
13+
14+
## :book: Rule Details
15+
16+
This rule enforces a maximum number of props in a Vue SFC, in order to aid in maintainability and reduce complexity.
17+
18+
## :wrench: Options
19+
20+
This rule takes an object, where you can specify the maximum number of props allowed in a Vue SFC.
21+
There is one property that can be specified for the object.
22+
23+
- `maxProps` ... Specify the maximum number of props in the `script` block.
24+
25+
### `{ maxProps: 1 }`
26+
27+
<eslint-code-block :rules="{'vue/max-props': ['error', { maxProps: 1 }]}">
28+
29+
```vue
30+
<!-- ✗ BAD -->
31+
<template>
32+
</template>
33+
34+
<script setup>
35+
defineProps({
36+
prop1: String,
37+
prop2: String,
38+
})
39+
</script>
40+
```
41+
42+
</eslint-code-block>
43+
44+
### `{ maxProps: 5 }`
45+
46+
<eslint-code-block :rules="{'vue/max-props': ['error', { maxProps: 5 }]}">
47+
48+
```vue
49+
<!-- ✓ GOOD -->
50+
<script>
51+
defineProps({
52+
prop1: String
53+
})
54+
</script>
55+
```
56+
57+
</eslint-code-block>
58+
59+
## :mag: Implementation
60+
61+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/max-props.js)
62+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/max-props.js)

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const plugin = {
7979
'max-attributes-per-line': require('./rules/max-attributes-per-line'),
8080
'max-len': require('./rules/max-len'),
8181
'max-lines-per-block': require('./rules/max-lines-per-block'),
82+
'max-props': require('./rules/max-props'),
8283
'multi-word-component-names': require('./rules/multi-word-component-names'),
8384
'multiline-html-element-content-newline': require('./rules/multiline-html-element-content-newline'),
8485
'multiline-ternary': require('./rules/multiline-ternary'),

lib/rules/max-props.js

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* @author kevsommer Kevin Sommer
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
const utils = require('../utils')
7+
8+
module.exports = {
9+
meta: {
10+
type: 'problem',
11+
docs: {
12+
description: 'enforce maximum number of props in Vue component',
13+
categories: undefined,
14+
url: 'https://eslint.vuejs.org/rules/max-props.html'
15+
},
16+
fixable: null,
17+
schema: [
18+
{
19+
type: 'object',
20+
properties: {
21+
maxProps: {
22+
type: 'integer',
23+
minimum: 1
24+
}
25+
},
26+
additionalProperties: false,
27+
minProperties: 1
28+
}
29+
],
30+
messages: {
31+
tooManyProps:
32+
'Component has too many props ({{propCount}}). Maximum allowed is {{limit}}.'
33+
}
34+
},
35+
/** @param {RuleContext} context */
36+
create(context) {
37+
/** @type {Record<string, number>} */
38+
const option = context.options[0] || {}
39+
40+
/**
41+
* @param {import('../utils').ComponentProp[]} props
42+
*/
43+
function checkMaxNumberOfProps(props) {
44+
if (props.length > option.maxProps && props[0].node) {
45+
context.report({
46+
node: props[0].node,
47+
messageId: 'tooManyProps',
48+
data: {
49+
propCount: props.length,
50+
limit: option.maxProps
51+
}
52+
})
53+
}
54+
}
55+
56+
return utils.compositingVisitors(
57+
utils.executeOnVue(context, (obj) => {
58+
checkMaxNumberOfProps(utils.getComponentPropsFromOptions(obj))
59+
}),
60+
utils.defineScriptSetupVisitor(context, {
61+
onDefinePropsEnter(_, props) {
62+
checkMaxNumberOfProps(props)
63+
}
64+
})
65+
)
66+
}
67+
}

tests/lib/rules/max-props.js

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/**
2+
* @author kevsommer Kevin Sommer
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const RuleTester = require('../../eslint-compat').RuleTester
8+
const rule = require('../../../lib/rules/max-props')
9+
10+
const tester = new RuleTester({
11+
languageOptions: {
12+
parser: require('vue-eslint-parser'),
13+
ecmaVersion: 2020,
14+
sourceType: 'module'
15+
}
16+
})
17+
18+
tester.run('max-props', rule, {
19+
valid: [
20+
{
21+
filename: 'test.vue',
22+
code: `
23+
<script setup>
24+
defineProps({ prop1: '', prop2: '' })
25+
</script>
26+
`,
27+
options: [{ maxProps: 5 }]
28+
},
29+
{
30+
filename: 'test.vue',
31+
code: `
32+
<script>
33+
export default {
34+
props: {
35+
prop1: String,
36+
prop2: String
37+
}
38+
}
39+
</script>
40+
`,
41+
options: [{ maxProps: 5 }]
42+
},
43+
{
44+
filename: 'test.vue',
45+
code: `
46+
<script>
47+
export default {
48+
props: {
49+
prop1: String,
50+
prop2: String,
51+
prop3: String,
52+
prop4: String,
53+
prop5: String
54+
}
55+
}
56+
</script>
57+
`,
58+
options: [{ maxProps: 5 }]
59+
},
60+
{
61+
filename: 'test.vue',
62+
code: `
63+
<script>
64+
export default {
65+
props: {}
66+
}
67+
</script>
68+
`,
69+
options: [{ maxProps: 5 }]
70+
},
71+
{
72+
filename: 'test.vue',
73+
code: `
74+
<script setup>
75+
defineProps({})
76+
</script>
77+
`,
78+
options: [{ maxProps: 5 }]
79+
},
80+
{
81+
filename: 'test.vue',
82+
code: `
83+
<script>
84+
</script>
85+
`,
86+
options: [{ maxProps: 5 }]
87+
},
88+
{
89+
filename: 'test.vue',
90+
code: `
91+
<script setup lang="ts">
92+
defineProps<{ prop1: string, prop2: string }>();
93+
</script>
94+
`,
95+
options: [{ maxProps: 5 }],
96+
languageOptions: {
97+
parser: require('vue-eslint-parser'),
98+
parserOptions: {
99+
parser: require.resolve('@typescript-eslint/parser')
100+
}
101+
}
102+
}
103+
],
104+
invalid: [
105+
{
106+
filename: 'test.vue',
107+
code: `
108+
<script setup>
109+
defineProps({ prop1: '', prop2: '' })
110+
</script>
111+
`,
112+
options: [{ maxProps: 1 }],
113+
errors: [
114+
{
115+
message: 'Component has too many props (2). Maximum allowed is 1.',
116+
line: 3
117+
}
118+
]
119+
},
120+
{
121+
filename: 'test.vue',
122+
code: `
123+
<script>
124+
export default {
125+
props: {
126+
prop1: String,
127+
prop2: String
128+
}
129+
}
130+
</script>
131+
`,
132+
options: [{ maxProps: 1 }],
133+
errors: [
134+
{
135+
message: 'Component has too many props (2). Maximum allowed is 1.',
136+
line: 5
137+
}
138+
]
139+
},
140+
{
141+
filename: 'test.vue',
142+
code: `
143+
<script setup lang="ts">
144+
defineProps<{ prop1: string, prop2: string, prop3: string }>();
145+
</script>
146+
`,
147+
options: [{ maxProps: 2 }],
148+
languageOptions: {
149+
parser: require('vue-eslint-parser'),
150+
parserOptions: {
151+
parser: require.resolve('@typescript-eslint/parser')
152+
}
153+
},
154+
errors: [
155+
{
156+
message: 'Component has too many props (3). Maximum allowed is 2.',
157+
line: 3
158+
}
159+
]
160+
}
161+
]
162+
})

0 commit comments

Comments
 (0)