Skip to content

Commit 17d8dbe

Browse files
committed
* rename getPropsProperties to getComponentProps
* 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 * add more tests
1 parent d19f958 commit 17d8dbe

8 files changed

+116
-76
lines changed

lib/rules/prop-name-casing.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,10 @@ function create (context) {
3636
// ----------------------------------------------------------------------
3737

3838
return utils.executeOnVue(context, (obj) => {
39-
const items = utils.getPropsProperties(obj)
40-
.props
41-
.filter(cp => cp.key.type === 'Literal' || (cp.key.type === 'Identifier' && !cp.node.computed))
39+
const props = utils.getComponentProps(obj)
40+
.filter(cp => cp.key && cp.key.type === 'Literal' || (cp.key.type === 'Identifier' && !cp.node.computed))
4241

43-
for (const item of items) {
42+
for (const item of props) {
4443
const propName = item.key.type === 'Literal' ? item.key.value : item.key.name
4544
if (typeof propName !== 'string') {
4645
// (boolean | null | number | RegExp) Literal

lib/rules/require-default-prop.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,8 @@ module.exports = {
133133
// ----------------------------------------------------------------------
134134

135135
return utils.executeOnVue(context, (obj) => {
136-
const props = utils.getPropsProperties(obj)
137-
.props
138-
.filter(prop => prop.value && !prop.node.shorthand)
136+
const props = utils.getComponentProps(obj)
137+
.filter(prop => prop.key && prop.value && !prop.node.shorthand)
139138

140139
const propsWithoutDefault = findPropsWithoutDefaultValue(props)
141140
const propsToReport = excludeBooleanProps(propsWithoutDefault)

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,10 @@ module.exports = {
7070
}
7171

7272
return utils.executeOnVueComponent(context, (obj) => {
73-
const properties = utils.getPropsProperties(obj)
74-
.props
75-
.filter(cp => cp.value)
73+
const props = utils.getComponentProps(obj)
74+
.filter(cp => cp.key && cp.value)
7675

77-
for (const p of properties) {
76+
for (const p of props) {
7877
if (isForbiddenType(p.value) || p.value.type === 'ArrayExpression') {
7978
checkPropertyNode(p.key, p.value)
8079
} else if (p.value.type === 'ObjectExpression') {

lib/rules/require-prop-types.js

+4-11
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ module.exports = {
5959
node,
6060
message: 'Prop "{{name}}" should define at least its type.',
6161
data: {
62-
name: utils.getStaticPropertyName(key)
62+
name: utils.getStaticPropertyName(key || node) || '***'
6363
}
6464
})
6565
}
@@ -70,17 +70,10 @@ module.exports = {
7070
// ----------------------------------------------------------------------
7171

7272
return utils.executeOnVue(context, (obj) => {
73-
const properties = utils.getPropsProperties(obj)
73+
const props = utils.getComponentProps(obj)
7474

75-
if (properties.type === 'ArrayExpression') {
76-
context.report({
77-
node: properties.node,
78-
message: 'Props should at least define their types.'
79-
})
80-
} else {
81-
for (const cp of properties.props) {
82-
checkProperty(cp.key, cp.value, cp.node)
83-
}
75+
for (const prop of props) {
76+
checkProperty(prop.key, prop.value, prop.node)
8477
}
8578
})
8679
}

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,10 @@ module.exports = {
8888
// ----------------------------------------------------------------------
8989

9090
return utils.executeOnVue(context, obj => {
91-
const properties = utils.getPropsProperties(obj)
92-
.props
93-
.filter(cp => cp.value && cp.value.type === 'ObjectExpression')
91+
const props = utils.getComponentProps(obj)
92+
.filter(cp => cp.key && cp.value && cp.value.type === 'ObjectExpression')
9493

95-
for (const prop of properties) {
94+
for (const prop of props) {
9695
const type = getPropertyNode(prop.value, 'type')
9796
if (!type) continue
9897

lib/utils/index.js

+6-14
Original file line numberDiff line numberDiff line change
@@ -368,9 +368,9 @@ module.exports = {
368368
/**
369369
* Get all props by looking at all component's properties
370370
* @param {ObjectExpression} componentObject Object with component definition
371-
* @return {Object} Array of props in format: { node: ASTNode, type: string, props: Array<{key: ASTNode, value: ASTNode | null, node: ASTNode}> }
371+
* @return {Array} Array of component props in format: [{key?: String, value?: ASTNode, node: ASTNod}]
372372
*/
373-
getPropsProperties (componentObject) {
373+
getComponentProps (componentObject) {
374374
const propsNode = componentObject.properties
375375
.find(p =>
376376
p.type === 'Property' &&
@@ -380,11 +380,7 @@ module.exports = {
380380
)
381381

382382
if (!propsNode) {
383-
return {
384-
node: null,
385-
type: null,
386-
props: []
387-
}
383+
return []
388384
}
389385

390386
let props
@@ -397,17 +393,13 @@ module.exports = {
397393
})
398394
} else {
399395
props = propsNode.value.elements
400-
.filter(cp => cp.type === 'Literal' && typeof cp.value === 'string')
401396
.map(cp => {
402-
return { key: cp, value: null, node: cp }
397+
const key = cp.type === 'Literal' && typeof cp.value === 'string' ? cp : null
398+
return { key, value: null, node: cp }
403399
})
404400
}
405401

406-
return {
407-
node: propsNode,
408-
type: propsNode.value.type,
409-
props: props
410-
}
402+
return props
411403
},
412404

413405
/**

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

+40-4
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,24 @@ ruleTester.run('require-prop-types', rule, {
114114
`,
115115
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
116116
},
117+
{
118+
filename: 'test.vue',
119+
code: `
120+
export default {
121+
props: []
122+
}
123+
`,
124+
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
125+
},
126+
{
127+
filename: 'test.vue',
128+
code: `
129+
export default {
130+
props: {}
131+
}
132+
`,
133+
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
134+
},
117135
{
118136
filename: 'test.vue',
119137
code: `
@@ -149,25 +167,43 @@ ruleTester.run('require-prop-types', rule, {
149167
filename: 'test.vue',
150168
code: `
151169
export default {
152-
props: ['foo']
170+
props: ['foo', bar, \`baz\`, foo()]
153171
}
154172
`,
155173
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
156174
errors: [{
157-
message: 'Props should at least define their types.',
175+
message: 'Prop "foo" should define at least its type.',
176+
line: 3
177+
}, {
178+
message: 'Prop "bar" should define at least its type.',
179+
line: 3
180+
}, {
181+
message: 'Prop "baz" should define at least its type.',
182+
line: 3
183+
}, {
184+
message: 'Prop "***" should define at least its type.',
158185
line: 3
159186
}]
160187
},
161188
{
162189
filename: 'test.js',
163190
code: `
164191
new Vue({
165-
props: ['foo']
192+
props: ['foo', bar, \`baz\`, foo()]
166193
})
167194
`,
168195
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
169196
errors: [{
170-
message: 'Props should at least define their types.',
197+
message: 'Prop "foo" should define at least its type.',
198+
line: 3
199+
}, {
200+
message: 'Prop "bar" should define at least its type.',
201+
line: 3
202+
}, {
203+
message: 'Prop "baz" should define at least its type.',
204+
line: 3
205+
}, {
206+
message: 'Prop "***" should define at least its type.',
171207
line: 3
172208
}]
173209
},

tests/lib/utils/index.js

+55-32
Original file line numberDiff line numberDiff line change
@@ -248,29 +248,46 @@ describe('getRegisteredComponents', () => {
248248
})
249249
})
250250

251-
describe('getComputedProperties', () => {
252-
let node
251+
describe('getComponentProps', () => {
252+
let props
253253

254254
const parse = function (code) {
255255
const data = babelEslint.parse(code).body[0].declarations[0].init
256-
return utils.getPropsProperties(data)
256+
return utils.getComponentProps(data)
257257
}
258258

259259
it('should return empty array when there is no props property', () => {
260-
node = parse(`const test = {
260+
props = parse(`const test = {
261261
name: 'test',
262262
data() {
263263
return {}
264264
}
265265
}`)
266266

267-
assert.notOk(node.type)
268-
assert.notOk(node.node)
269-
assert.equal(node.props.length, 0)
267+
assert.equal(props.length, 0)
268+
})
269+
270+
it('should return empty array when props property is empty array', () => {
271+
props = parse(`const test = {
272+
name: 'test',
273+
props: []
274+
}`)
275+
276+
assert.equal(props.length, 0)
277+
})
278+
279+
280+
it('should return empty array when props property is empty object array', () => {
281+
props = parse(`const test = {
282+
name: 'test',
283+
props: {}
284+
}`)
285+
286+
assert.equal(props.length, 0)
270287
})
271288

272289
it('should return computed props', () => {
273-
node = parse(`const test = {
290+
props = parse(`const test = {
274291
name: 'test',
275292
data() {
276293
return {}
@@ -284,44 +301,50 @@ describe('getComputedProperties', () => {
284301
}
285302
}`)
286303

287-
assert.ok(node.node)
288-
assert.equal(node.type, 'ObjectExpression', 'it detects correct type')
289-
assert.equal(node.props.length, 4, 'it detects all props')
304+
assert.equal(props.length, 4, 'it detects all props')
290305

291-
assert.ok(node.props[0].value)
292-
assert.ok(node.props[0].key.type === 'Identifier')
293-
assert.ok(node.props[0].node.type === 'Property')
294-
assert.ok(node.props[0].value.type === 'Identifier')
306+
assert.ok(props[0].key.type === 'Identifier')
307+
assert.ok(props[0].node.type === 'Property')
308+
assert.ok(props[0].value.type === 'Identifier')
295309

296-
assert.ok(node.props[1].value)
297-
assert.ok(node.props[1].key.type === 'Identifier')
298-
assert.ok(node.props[1].node.type === 'Property')
299-
assert.ok(node.props[1].value.type === 'ObjectExpression')
310+
assert.ok(props[1].key.type === 'Identifier')
311+
assert.ok(props[1].node.type === 'Property')
312+
assert.ok(props[1].value.type === 'ObjectExpression')
300313

301-
assert.ok(node.props[2].value)
302-
assert.ok(node.props[2].key.type === 'Identifier')
303-
assert.ok(node.props[2].node.type === 'Property')
304-
assert.ok(node.props[2].value.type === 'ArrayExpression')
314+
assert.ok(props[2].key.type === 'Identifier')
315+
assert.ok(props[2].node.type === 'Property')
316+
assert.ok(props[2].value.type === 'ArrayExpression')
305317

306-
assert.ok(node.props[3].value)
307-
assert.ok(node.props[3].key.type === node.props[3].value.type)
308-
assert.ok(node.props[3].node.type === 'Property')
318+
assert.ok(props[3].key.type === props[3].value.type)
319+
assert.ok(props[3].node.type === 'Property')
320+
assert.ok(props[3].value.type === 'Identifier')
309321
})
310322

311323
it('should return computed from array props', () => {
312-
node = parse(`const test = {
324+
props = parse(`const test = {
313325
name: 'test',
314326
data() {
315327
return {}
316328
},
317329
props: ['a', b, \`c\`, null]
318330
}`)
319331

320-
assert.ok(node.node)
321-
assert.equal(node.type, 'ArrayExpression', 'it detects correct type')
322-
assert.equal(node.props.length, 1, 'it detects all props')
332+
assert.equal(props.length, 4, 'it detects all props')
333+
334+
assert.ok(props[0].node.type === 'Literal')
335+
assert.deepEqual(props[0].key, props[0].node)
336+
assert.notOk(props[0].value)
337+
338+
assert.ok(props[1].node.type === 'Identifier')
339+
assert.notOk(props[1].key)
340+
assert.notOk(props[1].value)
341+
342+
assert.ok(props[2].node.type === 'TemplateLiteral')
343+
assert.notOk(props[2].key)
344+
assert.notOk(props[2].value)
323345

324-
assert.notOk(node.props[0].value)
325-
assert.ok(node.props[0].key.type === 'Literal')
346+
assert.ok(props[3].node.type === 'Literal')
347+
assert.notOk(props[3].key)
348+
assert.notOk(props[3].value)
326349
})
327350
})

0 commit comments

Comments
 (0)