Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6032f21

Browse files
armano2michalsnik
authored andcommitted
Fix issues with props (#632)
* prop-name-casing: is working now with array props [literals] * prop-name-casing: reports all errors if there are non Literal keys in it * require-prop-types: reports names for types diffrent than literals * add new getPropsProperties helper to easly deal with props * Add unit test for getPropsProperties * require-default-prop: allow to use shorthand * fix false error in `require-prop-types` when is set to empty array * `require-prop-types` will return now errors about each prop from ArrayExpression
1 parent b363379 commit 6032f21

12 files changed

+292
-134
lines changed

‎.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.idea
2+
*.iml
23
/.nyc_output
34
/coverage
45
/tests/integrations/*/node_modules

‎lib/rules/prop-name-casing.js

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ const utils = require('../utils')
88
const casing = require('../utils/casing')
99
const allowedCaseOptions = ['camelCase', 'snake_case']
1010

11-
function canFixPropertyName (node, originalName) {
11+
function canFixPropertyName (node, key,originalName) {
1212
// Can not fix of computed property names & shorthand
1313
if (node.computed || node.shorthand) {
1414
return false
1515
}
16-
constkey=node.key
16+
1717
// Can not fix of unknown types
1818
if (key.type !== 'Literal' && key.type !== 'Identifier') {
1919
return false
@@ -36,42 +36,25 @@ function create (context) {
3636
// ----------------------------------------------------------------------
3737

3838
return utils.executeOnVue(context, (obj) => {
39-
const node = obj.properties.find(p =>
40-
p.type === 'Property' &&
41-
p.key.type === 'Identifier' &&
42-
p.key.name === 'props' &&
43-
(p.value.type === 'ObjectExpression' || p.value.type === 'ArrayExpression')
44-
)
45-
46-
if (!node) return
47-
48-
const items = node.value.type === 'ObjectExpression' ? node.value.properties : node.value.elements
49-
for (const item of items) {
50-
if (item.type !== 'Property') {
51-
return
52-
}
53-
if (item.computed) {
54-
if (item.key.type !== 'Literal') {
55-
// TemplateLiteral | Identifier(variable) | Expression(s)
56-
return
57-
}
58-
if (typeof item.key.value !== 'string') {
59-
// (boolean | null | number | RegExp) Literal
60-
return
61-
}
62-
}
39+
const props = utils.getComponentProps(obj)
40+
.filter(prop => prop.key && prop.key.type === 'Literal' || (prop.key.type === 'Identifier' && !prop.node.computed))
6341

42+
for (const item of props) {
6443
const propName = item.key.type === 'Literal' ? item.key.value : item.key.name
44+
if (typeof propName !== 'string') {
45+
// (boolean | null | number | RegExp) Literal
46+
continue
47+
}
6548
const convertedName = converter(propName)
6649
if (convertedName !== propName) {
6750
context.report({
68-
node: item,
51+
node: item.node,
6952
message: 'Prop "{{name}}" is not in {{caseType}}.',
7053
data: {
7154
name: propName,
7255
caseType: caseType
7356
},
74-
fix: canFixPropertyName(item, propName) ? fixer => {
57+
fix: canFixPropertyName(item.node,item.key, propName) ? fixer => {
7558
return item.key.type === 'Literal'
7659
? fixer.replaceText(item.key, item.key.raw.replace(item.key.value, convertedName))
7760
: fixer.replaceText(item.key, convertedName)

‎lib/rules/require-default-prop.js

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66

77
const utils = require('../utils')
88

9+
const NATIVE_TYPES = new Set([
10+
'String',
11+
'Number',
12+
'Boolean',
13+
'Function',
14+
'Object',
15+
'Array',
16+
'Symbol'
17+
])
18+
919
// ------------------------------------------------------------------------------
1020
// Rule Definition
1121
// ------------------------------------------------------------------------------
@@ -21,7 +31,7 @@ module.exports = {
2131
schema: []
2232
},
2333

24-
create: function (context) {
34+
create (context) {
2535
// ----------------------------------------------------------------------
2636
// Helpers
2737
// ----------------------------------------------------------------------
@@ -32,7 +42,7 @@ module.exports = {
3242
* @return {boolean}
3343
*/
3444
function propIsRequired (prop) {
35-
const propRequiredNode = utils.unwrapTypes(prop.value).properties
45+
const propRequiredNode = prop.value.properties
3646
.find(p =>
3747
p.type === 'Property' &&
3848
p.key.name === 'required' &&
@@ -49,7 +59,7 @@ module.exports = {
4959
* @return {boolean}
5060
*/
5161
function propHasDefault (prop) {
52-
const propDefaultNode = utils.unwrapTypes(prop.value).properties
62+
const propDefaultNode = prop.value.properties
5363
.find(p =>
5464
p.key &&
5565
(p.key.name === 'default' || p.key.value === 'default')
@@ -60,15 +70,14 @@ module.exports = {
6070

6171
/**
6272
* Finds all props that don't have a default value set
63-
* @param {Property} propsNode - Vue component's "props" node
73+
* @param {Array} props - Vue component's "props" node
6474
* @return {Array} Array of props without "default" value
6575
*/
66-
function findPropsWithoutDefaultValue (propsNode) {
67-
return propsNode.value.properties
68-
.filter(prop => prop.type === 'Property')
76+
function findPropsWithoutDefaultValue (props) {
77+
return props
6978
.filter(prop => {
70-
if (utils.unwrapTypes(prop.value).type !== 'ObjectExpression') {
71-
return true
79+
if (prop.value.type !== 'ObjectExpression') {
80+
return (prop.value.type!=='CallExpression'&&prop.value.type!=='Identifier')||NATIVE_TYPES.has(prop.value.name)
7281
}
7382

7483
return !propIsRequired(prop) && !propHasDefault(prop)
@@ -124,28 +133,21 @@ module.exports = {
124133
// ----------------------------------------------------------------------
125134

126135
return utils.executeOnVue(context, (obj) => {
127-
const propsNode = obj.properties
128-
.find(p =>
129-
p.type === 'Property' &&
130-
p.key.type === 'Identifier' &&
131-
p.key.name === 'props' &&
132-
p.value.type === 'ObjectExpression'
133-
)
134-
135-
if (!propsNode) return
136+
const props = utils.getComponentProps(obj)
137+
.filter(prop => prop.key && prop.value && !prop.node.shorthand)
136138

137-
const propsWithoutDefault = findPropsWithoutDefaultValue(propsNode)
139+
const propsWithoutDefault = findPropsWithoutDefaultValue(props)
138140
const propsToReport = excludeBooleanProps(propsWithoutDefault)
139141

140-
propsToReport.forEach(prop => {
142+
for(constprop ofpropsToReport) {
141143
context.report({
142-
node: prop,
144+
node: prop.node,
143145
message: `Prop '{{propName}}' requires default value to be set.`,
144146
data: {
145147
propName: prop.key.name
146148
}
147149
})
148-
})
150+
}
149151
})
150152
}
151153
}

‎lib/rules/require-prop-type-constructor.js

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,31 +70,23 @@ module.exports = {
7070
}
7171

7272
return utils.executeOnVueComponent(context, (obj) => {
73-
const node = obj.properties.find(p =>
74-
p.type === 'Property' &&
75-
p.key.type === 'Identifier' &&
76-
p.key.name === 'props' &&
77-
p.value.type === 'ObjectExpression'
78-
)
73+
const props = utils.getComponentProps(obj)
74+
.filter(prop => prop.key && prop.value)
7975

80-
if (!node) return
76+
for (const prop of props) {
77+
if (isForbiddenType(prop.value) || prop.value.type === 'ArrayExpression') {
78+
checkPropertyNode(prop.key, prop.value)
79+
} else if (prop.value.type === 'ObjectExpression') {
80+
const typeProperty = prop.value.properties.find(property =>
81+
property.type === 'Property' &&
82+
property.key.name === 'type'
83+
)
8184

82-
node.value.properties
83-
.forEach(p => {
84-
const pValue = utils.unwrapTypes(p.value)
85-
if (isForbiddenType(pValue) || pValue.type === 'ArrayExpression') {
86-
checkPropertyNode(p.key, pValue)
87-
} else if (pValue.type === 'ObjectExpression') {
88-
const typeProperty = pValue.properties.find(prop =>
89-
prop.type === 'Property' &&
90-
prop.key.name === 'type'
91-
)
85+
if (!typeProperty) continue
9286

93-
if (!typeProperty) return
94-
95-
checkPropertyNode(p.key, utils.unwrapTypes(typeProperty.value))
96-
}
97-
})
87+
checkPropertyNode(prop.key, typeProperty.value)
88+
}
89+
}
9890
})
9991
}
10092
}

‎lib/rules/require-prop-types.js

Lines changed: 22 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,26 @@ module.exports = {
4242
return Boolean(typeProperty || validatorProperty)
4343
}
4444

45-
function checkProperties (items) {
46-
for (const cp of items) {
47-
if (cp.type !== 'Property') {
48-
return
49-
}
50-
let hasType = true
51-
const cpValue = utils.unwrapTypes(cp.value)
45+
function checkProperty (key, value, node) {
46+
let hasType = true
5247

53-
if (cpValue.type === 'ObjectExpression') { // foo: {
54-
hasType = objectHasType(cpValue)
55-
} else if (cpValue.type === 'ArrayExpression') { // foo: [
56-
hasType = cpValue.elements.length > 0
57-
} else if (cpValue.type === 'FunctionExpression' || cpValue.type === 'ArrowFunctionExpression') {
58-
hasType = false
59-
}
60-
if (!hasType) {
61-
context.report({
62-
node: cp,
63-
message: 'Prop "{{name}}" should define at least its type.',
64-
data: {
65-
name: cp.key.name
66-
}
67-
})
68-
}
48+
if (!value) {
49+
hasType = false
50+
} else if (value.type === 'ObjectExpression') { // foo: {
51+
hasType = objectHasType(value)
52+
} else if (value.type === 'ArrayExpression') { // foo: [
53+
hasType = value.elements.length > 0
54+
} else if (value.type === 'FunctionExpression' || value.type === 'ArrowFunctionExpression') {
55+
hasType = false
56+
}
57+
if (!hasType) {
58+
context.report({
59+
node,
60+
message: 'Prop "{{name}}" should define at least its type.',
61+
data: {
62+
name: utils.getStaticPropertyName(key || node) || 'Unknown prop'
63+
}
64+
})
6965
}
7066
}
7167

@@ -74,24 +70,10 @@ module.exports = {
7470
// ----------------------------------------------------------------------
7571

7672
return utils.executeOnVue(context, (obj) => {
77-
const node = obj.properties
78-
.find(p =>
79-
p.type === 'Property' &&
80-
p.key.type === 'Identifier' &&
81-
p.key.name === 'props'
82-
)
73+
const props = utils.getComponentProps(obj)
8374

84-
if (!node) return
85-
86-
if (node.value.type === 'ObjectExpression') {
87-
checkProperties(node.value.properties)
88-
}
89-
90-
if (node.value.type === 'ArrayExpression') {
91-
context.report({
92-
node,
93-
message: 'Props should at least define their types.'
94-
})
75+
for (const prop of props) {
76+
checkProperty(prop.key, prop.value, prop.node)
9577
}
9678
})
9779
}

‎lib/rules/require-valid-default-prop.js

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -88,20 +88,11 @@ module.exports = {
8888
// ----------------------------------------------------------------------
8989

9090
return utils.executeOnVue(context, obj => {
91-
const props = obj.properties.find(p =>
92-
isPropertyIdentifier(p) &&
93-
p.key.name === 'props' &&
94-
p.value.type === 'ObjectExpression'
95-
)
96-
if (!props) return
97-
98-
const properties = props.value.properties.filter(p =>
99-
isPropertyIdentifier(p) &&
100-
utils.unwrapTypes(p.value).type === 'ObjectExpression'
101-
)
91+
const props = utils.getComponentProps(obj)
92+
.filter(prop => prop.key && prop.value && prop.value.type === 'ObjectExpression')
10293

103-
for (const prop of properties) {
104-
const type = getPropertyNode(utils.unwrapTypes(prop.value), 'type')
94+
for (const prop of props) {
95+
const type = getPropertyNode(prop.value, 'type')
10596
if (!type) continue
10697

10798
const typeNames = new Set(getTypes(type.value)
@@ -111,7 +102,7 @@ module.exports = {
111102
// There is no native types detected
112103
if (typeNames.size === 0) continue
113104

114-
const def = getPropertyNode(utils.unwrapTypes(prop.value), 'default')
105+
const def = getPropertyNode(prop.value, 'default')
115106
if (!def) continue
116107

117108
const defType = getValueType(def.value)

‎lib/utils/index.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,46 @@ module.exports = {
365365
return null
366366
},
367367

368+
/**
369+
* Get all props by looking at all component's properties
370+
* @param {ObjectExpression} componentObject Object with component definition
371+
* @return {Array} Array of component props in format: [{key?: String, value?: ASTNode, node: ASTNod}]
372+
*/
373+
getComponentProps (componentObject) {
374+
const propsNode = componentObject.properties
375+
.find(p =>
376+
p.type === 'Property' &&
377+
p.key.type === 'Identifier' &&
378+
p.key.name === 'props' &&
379+
(p.value.type === 'ObjectExpression' || p.value.type === 'ArrayExpression')
380+
)
381+
382+
if (!propsNode) {
383+
return []
384+
}
385+
386+
let props
387+
388+
if (propsNode.value.type === 'ObjectExpression') {
389+
props = propsNode.value.properties
390+
.filter(prop => prop.type === 'Property')
391+
.map(prop => {
392+
return { key: prop.key, value: this.unwrapTypes(prop.value), node: prop }
393+
})
394+
} else {
395+
props = propsNode.value.elements
396+
.map(prop => {
397+
const key = prop.type === 'Literal' && typeof prop.value === 'string' ? prop : null
398+
return { key, value: null, node: prop }
399+
})
400+
}
401+
402+
return props
403+
},
404+
368405
/**
369406
* Get all computed properties by looking at all component's properties
370-
* @param {ObjectExpression} Object with component definition
407+
* @param {ObjectExpression} componentObject Object with component definition
371408
* @return {Array} Array of computed properties in format: [{key: String, value: ASTNode}]
372409
*/
373410
getComputedProperties (componentObject) {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /