Skip to content

Commit 453490c

Browse files
committed
Add "require-default-prop" rule
1 parent 3db7b13 commit 453490c

File tree

3 files changed

+227
-0
lines changed

3 files changed

+227
-0
lines changed

docs/rules/require-default-prop.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Require default value for props (require-default-prop)
2+
3+
This rule requires default value to be set for each props that are not marked as `required`.
4+
5+
## Rule Details
6+
7+
Examples of **incorrect** code for this rule:
8+
9+
```js
10+
export default {
11+
props: {
12+
a: Number,
13+
b: [Number, String],
14+
c: {
15+
type: Number
16+
},
17+
d: {
18+
type: Number,
19+
required: false
20+
}
21+
}
22+
}
23+
```
24+
25+
Examples of **correct** code for this rule:
26+
27+
```js
28+
export default {
29+
props: {
30+
a: {
31+
type: Number,
32+
required: true
33+
},
34+
b: {
35+
type: Number,
36+
default: 0
37+
},
38+
c: {
39+
type: Number,
40+
default: 0,
41+
required: false
42+
}
43+
}
44+
}
45+
```

lib/rules/require-default-prop.js

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* @fileoverview Require default value for props
3+
* @author Michał Sajnóg <[email protected]> (http://github.com/michalsnik)
4+
*/
5+
'use strict'
6+
7+
const utils = require('../utils')
8+
9+
// ------------------------------------------------------------------------------
10+
// Rule Definition
11+
// ------------------------------------------------------------------------------
12+
13+
module.exports = {
14+
meta: {
15+
docs: {
16+
description: 'Require default value for props',
17+
category: 'Best Practices',
18+
recommended: false
19+
},
20+
fixable: null, // or "code" or "whitespace"
21+
schema: []
22+
},
23+
24+
create: function (context) {
25+
// ----------------------------------------------------------------------
26+
// Helpers
27+
// ----------------------------------------------------------------------
28+
29+
/**
30+
* Checks if the passed prop is required
31+
* @param {Property} prop - Property AST node for a single prop
32+
* @return {boolean}
33+
*/
34+
function propIsRequired (prop) {
35+
const propRequiredNode = prop.value.properties
36+
.find(p =>
37+
p.key.name === 'required' &&
38+
p.value.type === 'Literal' &&
39+
p.value.value === true
40+
)
41+
42+
return Boolean(propRequiredNode)
43+
}
44+
45+
/**
46+
* Checks if the passed prop has a defualt value
47+
* @param {Property} prop - Property AST node for a single prop
48+
* @return {boolean}
49+
*/
50+
function propHasDefault (prop) {
51+
const propDefaultNode = prop.value.properties
52+
.find(p => p.key.name === 'default')
53+
54+
return Boolean(propDefaultNode)
55+
}
56+
57+
/**
58+
* Finds all props that don't have a default value set
59+
* @param {Property} propsNode - Vue component's "props" node
60+
* @return {boolean}
61+
*/
62+
function findPropsWithoutDefaultValue (propsNode) {
63+
return propsNode.value.properties
64+
.filter(prop => {
65+
if (prop.value.type !== 'ObjectExpression') return true
66+
67+
return !propIsRequired(prop) && !propHasDefault(prop)
68+
})
69+
}
70+
71+
// ----------------------------------------------------------------------
72+
// Public
73+
// ----------------------------------------------------------------------
74+
75+
return utils.executeOnVue(context, (obj) => {
76+
const propsNode = obj.properties
77+
.find(p =>
78+
p.type === 'Property' &&
79+
p.key.type === 'Identifier' &&
80+
p.key.name === 'props'
81+
)
82+
83+
if (!propsNode || propsNode.value.type !== 'ObjectExpression') return
84+
85+
const propsWithoutDefault = findPropsWithoutDefaultValue(propsNode)
86+
87+
propsWithoutDefault.forEach(prop => {
88+
context.report({
89+
node: prop,
90+
message: `Prop '{{propName}}' requires default value to be set.`,
91+
data: {
92+
propName: prop.key.name
93+
}
94+
})
95+
})
96+
})
97+
}
98+
}
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* @fileoverview Require default value for props
3+
* @author Michał Sajnóg <[email protected]> (http://github.com/michalsnik)
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const rule = require('../../../lib/rules/require-default-prop')
12+
const RuleTester = require('eslint').RuleTester
13+
const parserOptions = { ecmaVersion: 6, sourceType: 'module' }
14+
15+
// ------------------------------------------------------------------------------
16+
// Tests
17+
// ------------------------------------------------------------------------------
18+
19+
const ruleTester = new RuleTester()
20+
ruleTester.run('require-default-prop', rule, {
21+
22+
valid: [
23+
{
24+
filename: 'test.vue',
25+
code: `
26+
export default {
27+
props: {
28+
a: {
29+
type: Number,
30+
required: true
31+
},
32+
b: {
33+
type: Number,
34+
default: 0
35+
},
36+
c: {
37+
type: Number,
38+
default: 0,
39+
required: false
40+
},
41+
// eslint-disable-next-line require-default-prop
42+
d: Number
43+
}
44+
}
45+
`,
46+
parserOptions
47+
}
48+
],
49+
50+
invalid: [
51+
{
52+
filename: 'test.vue',
53+
code: `
54+
export default {
55+
props: {
56+
a: Number,
57+
b: [Number, String],
58+
c: {
59+
type: Number
60+
},
61+
d: {
62+
type: Number,
63+
required: false
64+
}
65+
}
66+
}
67+
`,
68+
parserOptions,
69+
errors: [{
70+
message: `Prop 'a' requires default value to be set.`,
71+
line: 4
72+
}, {
73+
message: `Prop 'b' requires default value to be set.`,
74+
line: 5
75+
}, {
76+
message: `Prop 'c' requires default value to be set.`,
77+
line: 6
78+
}, {
79+
message: `Prop 'd' requires default value to be set.`,
80+
line: 9
81+
}]
82+
}
83+
]
84+
})

0 commit comments

Comments
 (0)