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 a7f95ce

Browse files
Fixed vue/no-unused-properties, vue/require-valid-default-prop, vue/require-default-prop and vue/no-multiple-objects-in-class rules crash on sparse arrays. (#1242)
1 parent 8c981ea commit a7f95ce

File tree

10 files changed

+119
-57
lines changed

10 files changed

+119
-57
lines changed

‎lib/rules/no-multiple-objects-in-class.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const { defineTemplateBodyVisitor } = require('../utils')
2121
*/
2222
function countObjectExpression(node) {
2323
return node.value.expression.elements.filter(
24-
(element) => element.type === 'ObjectExpression'
24+
(element) => element&&element.type === 'ObjectExpression'
2525
).length
2626
}
2727

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

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*/
1111

1212
const utils = require('../utils')
13+
const { isDef } = require('../utils')
1314

1415
const NATIVE_TYPES = new Set([
1516
'String',
@@ -99,16 +100,21 @@ module.exports = {
99100
/**
100101
* Detects whether given value node is a Boolean type
101102
* @param {Expression | Pattern} value
102-
* @return {Boolean}
103+
* @return {boolean}
103104
*/
104105
function isValueNodeOfBooleanType(value) {
105-
return (
106-
(value.type === 'Identifier' && value.name === 'Boolean') ||
107-
(value.type === 'ArrayExpression' &&
108-
value.elements.length === 1 &&
109-
value.elements[0].type === 'Identifier' &&
110-
value.elements[0].name === 'Boolean')
111-
)
106+
if (value.type === 'Identifier' && value.name === 'Boolean') {
107+
return true
108+
}
109+
if (value.type === 'ArrayExpression') {
110+
const elements = value.elements.filter(isDef)
111+
return (
112+
elements.length === 1 &&
113+
elements[0].type === 'Identifier' &&
114+
elements[0].name === 'Boolean'
115+
)
116+
}
117+
return false
112118
}
113119

114120
/**

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
'use strict'
66

77
const utils = require('../utils')
8+
const { isDef } = require('../utils')
89

910
// ------------------------------------------------------------------------------
1011
// Rule Definition
@@ -49,10 +50,11 @@ module.exports = {
4950
*/
5051
function checkPropertyNode(propName, node) {
5152
/** @type {ESNode[]} */
52-
const nodes = node.type === 'ArrayExpression' ? node.elements : [node]
53+
const nodes =
54+
node.type === 'ArrayExpression' ? node.elements.filter(isDef) : [node]
5355

5456
nodes
55-
.filter((prop) => prop&&isForbiddenType(prop))
57+
.filter((prop) => isForbiddenType(prop))
5658
.forEach((prop) =>
5759
context.report({
5860
node: prop,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ function getTypes(node) {
5858
return node.elements
5959
.filter(
6060
/**
61-
* @param {Expression | SpreadElement} item
61+
* @param {Expression | SpreadElement | null} item
6262
* @returns {item is Identifier}
6363
*/
64-
(item) => item.type === 'Identifier'
64+
(item) => item!=null&&item.type === 'Identifier'
6565
)
6666
.map((item) => item.name)
6767
}

‎lib/utils/index.js‎

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -737,29 +737,27 @@ module.exports = {
737737
}
738738
})
739739
} else {
740-
return propsNode.value.elements
741-
.filter((prop) => prop)
742-
.map((prop) => {
743-
if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') {
744-
const propName = getStringLiteralValue(prop)
745-
if (propName != null) {
746-
return {
747-
type: 'array',
748-
key: prop,
749-
propName,
750-
value: null,
751-
node: prop
752-
}
740+
return propsNode.value.elements.filter(isDef).map((prop) => {
741+
if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') {
742+
const propName = getStringLiteralValue(prop)
743+
if (propName != null) {
744+
return {
745+
type: 'array',
746+
key: prop,
747+
propName,
748+
value: null,
749+
node: prop
753750
}
754751
}
755-
return {
756-
type: 'array',
757-
key: null,
758-
propName: null,
759-
value: null,
760-
node: prop
761-
}
762-
})
752+
}
753+
return {
754+
type: 'array',
755+
key: null,
756+
propName: null,
757+
value: null,
758+
node: prop
759+
}
760+
})
763761
}
764762
},
765763

@@ -810,29 +808,27 @@ module.exports = {
810808
}
811809
})
812810
} else {
813-
return emitsNode.value.elements
814-
.filter((prop) => prop)
815-
.map((prop) => {
816-
if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') {
817-
const emitName = getStringLiteralValue(prop)
818-
if (emitName != null) {
819-
return {
820-
type: 'array',
821-
key: prop,
822-
emitName,
823-
value: null,
824-
node: prop
825-
}
811+
return emitsNode.value.elements.filter(isDef).map((prop) => {
812+
if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') {
813+
const emitName = getStringLiteralValue(prop)
814+
if (emitName != null) {
815+
return {
816+
type: 'array',
817+
key: prop,
818+
emitName,
819+
value: null,
820+
node: prop
826821
}
827822
}
828-
return {
829-
type: 'array',
830-
key: null,
831-
emitName: null,
832-
value: null,
833-
node: prop
834-
}
835-
})
823+
}
824+
return {
825+
type: 'array',
826+
key: null,
827+
emitName: null,
828+
value: null,
829+
node: prop
830+
}
831+
})
836832
}
837833
},
838834

@@ -1109,7 +1105,10 @@ module.exports = {
11091105
*/
11101106
*iterateArrayExpression(node, groupName) {
11111107
for (const item of node.elements) {
1112-
if (item.type === 'Literal' || item.type === 'TemplateLiteral') {
1108+
if (
1109+
item &&
1110+
(item.type === 'Literal' || item.type === 'TemplateLiteral')
1111+
) {
11131112
const name = getStringLiteralValue(item)
11141113
if (name) {
11151114
yield { type: 'array', name, groupName, node: item }

‎tests/lib/rules/no-multiple-objects-in-class.js‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ ruleTester.run('no-multiple-objects-in-class', rule, {
4343
type: 'VAttribute'
4444
}
4545
]
46+
},
47+
48+
// sparse array
49+
{
50+
code: `<template><div v-bind:class="[,{'foo': isFoo}, {'bar': isBar}]" /></template>`,
51+
errors: [
52+
{
53+
message: 'Unexpected multiple objects. Merge objects.',
54+
type: 'VAttribute'
55+
}
56+
]
4657
}
4758
]
4859
})

‎tests/lib/rules/no-unused-properties.js‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,21 @@ tester.run('no-unused-properties', rule, {
981981
}
982982
</script>`,
983983
options: [{ groups: ['props', 'setup'] }]
984+
},
985+
986+
// sparse array
987+
{
988+
filename: 'test.vue',
989+
code: `
990+
<template>
991+
<div>{{ count }}</div>
992+
</template>
993+
<script>
994+
export default {
995+
props: [, 'count']
996+
}
997+
</script>
998+
`
984999
}
9851000
],
9861001

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,21 @@ ruleTester.run('require-default-prop', rule, {
179179
}
180180
}
181181
`
182+
},
183+
184+
// sparse array
185+
{
186+
filename: 'test.vue',
187+
code: `
188+
export default {
189+
props: {
190+
a: {
191+
type: [,Boolean]
192+
},
193+
b: [,Boolean],
194+
}
195+
}
196+
`
182197
}
183198
],
184199

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,20 @@ ruleTester.run('require-valid-default-prop', rule, {
181181
}
182182
}`,
183183
parserOptions
184+
},
185+
186+
// sparse array
187+
{
188+
filename: 'test.vue',
189+
code: `export default {
190+
props: {
191+
foo: {
192+
type: [,Object, Number],
193+
default: 10
194+
}
195+
}
196+
}`,
197+
parserOptions
184198
}
185199
],
186200

‎typings/eslint-plugin-vue/util-types/ast/es-ast.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ export interface ThisExpression extends HasParentNode {
298298
}
299299
export interface ArrayExpression extends HasParentNode {
300300
type: 'ArrayExpression'
301-
elements: (Expression | SpreadElement)[]
301+
elements: (Expression | SpreadElement|null)[]
302302
}
303303
export interface ObjectExpression extends HasParentNode {
304304
type: 'ObjectExpression'

0 commit comments

Comments
(0)

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