diff --git a/lib/rules/no-multiple-objects-in-class.js b/lib/rules/no-multiple-objects-in-class.js
index f2a170641..cf930ebec 100644
--- a/lib/rules/no-multiple-objects-in-class.js
+++ b/lib/rules/no-multiple-objects-in-class.js
@@ -21,7 +21,7 @@ const { defineTemplateBodyVisitor } = require('../utils')
*/
function countObjectExpression(node) {
return node.value.expression.elements.filter(
- (element) => element.type === 'ObjectExpression'
+ (element) => element && element.type === 'ObjectExpression'
).length
}
diff --git a/lib/rules/require-default-prop.js b/lib/rules/require-default-prop.js
index ff014ca8f..ec73e369b 100644
--- a/lib/rules/require-default-prop.js
+++ b/lib/rules/require-default-prop.js
@@ -10,6 +10,7 @@
*/
const utils = require('../utils')
+const { isDef } = require('../utils')
const NATIVE_TYPES = new Set([
'String',
@@ -99,16 +100,21 @@ module.exports = {
/**
* Detects whether given value node is a Boolean type
* @param {Expression | Pattern} value
- * @return {Boolean}
+ * @return {boolean}
*/
function isValueNodeOfBooleanType(value) {
- return (
- (value.type === 'Identifier' && value.name === 'Boolean') ||
- (value.type === 'ArrayExpression' &&
- value.elements.length === 1 &&
- value.elements[0].type === 'Identifier' &&
- value.elements[0].name === 'Boolean')
- )
+ if (value.type === 'Identifier' && value.name === 'Boolean') {
+ return true
+ }
+ if (value.type === 'ArrayExpression') {
+ const elements = value.elements.filter(isDef)
+ return (
+ elements.length === 1 &&
+ elements[0].type === 'Identifier' &&
+ elements[0].name === 'Boolean'
+ )
+ }
+ return false
}
/**
diff --git a/lib/rules/require-prop-type-constructor.js b/lib/rules/require-prop-type-constructor.js
index 1104c7a33..0f94f0f2c 100644
--- a/lib/rules/require-prop-type-constructor.js
+++ b/lib/rules/require-prop-type-constructor.js
@@ -5,6 +5,7 @@
'use strict'
const utils = require('../utils')
+const { isDef } = require('../utils')
// ------------------------------------------------------------------------------
// Rule Definition
@@ -49,10 +50,11 @@ module.exports = {
*/
function checkPropertyNode(propName, node) {
/** @type {ESNode[]} */
- const nodes = node.type === 'ArrayExpression' ? node.elements : [node]
+ const nodes =
+ node.type === 'ArrayExpression' ? node.elements.filter(isDef) : [node]
nodes
- .filter((prop) => prop && isForbiddenType(prop))
+ .filter((prop) => isForbiddenType(prop))
.forEach((prop) =>
context.report({
node: prop,
diff --git a/lib/rules/require-valid-default-prop.js b/lib/rules/require-valid-default-prop.js
index a6b2ca95e..a0444db08 100644
--- a/lib/rules/require-valid-default-prop.js
+++ b/lib/rules/require-valid-default-prop.js
@@ -58,10 +58,10 @@ function getTypes(node) {
return node.elements
.filter(
/**
- * @param {Expression | SpreadElement} item
+ * @param {Expression | SpreadElement | null} item
* @returns {item is Identifier}
*/
- (item) => item.type === 'Identifier'
+ (item) => item != null && item.type === 'Identifier'
)
.map((item) => item.name)
}
diff --git a/lib/utils/index.js b/lib/utils/index.js
index 085c596ad..0a6f7bf33 100644
--- a/lib/utils/index.js
+++ b/lib/utils/index.js
@@ -737,29 +737,27 @@ module.exports = {
}
})
} else {
- return propsNode.value.elements
- .filter((prop) => prop)
- .map((prop) => {
- if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') {
- const propName = getStringLiteralValue(prop)
- if (propName != null) {
- return {
- type: 'array',
- key: prop,
- propName,
- value: null,
- node: prop
- }
+ return propsNode.value.elements.filter(isDef).map((prop) => {
+ if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') {
+ const propName = getStringLiteralValue(prop)
+ if (propName != null) {
+ return {
+ type: 'array',
+ key: prop,
+ propName,
+ value: null,
+ node: prop
}
}
- return {
- type: 'array',
- key: null,
- propName: null,
- value: null,
- node: prop
- }
- })
+ }
+ return {
+ type: 'array',
+ key: null,
+ propName: null,
+ value: null,
+ node: prop
+ }
+ })
}
},
@@ -810,29 +808,27 @@ module.exports = {
}
})
} else {
- return emitsNode.value.elements
- .filter((prop) => prop)
- .map((prop) => {
- if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') {
- const emitName = getStringLiteralValue(prop)
- if (emitName != null) {
- return {
- type: 'array',
- key: prop,
- emitName,
- value: null,
- node: prop
- }
+ return emitsNode.value.elements.filter(isDef).map((prop) => {
+ if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') {
+ const emitName = getStringLiteralValue(prop)
+ if (emitName != null) {
+ return {
+ type: 'array',
+ key: prop,
+ emitName,
+ value: null,
+ node: prop
}
}
- return {
- type: 'array',
- key: null,
- emitName: null,
- value: null,
- node: prop
- }
- })
+ }
+ return {
+ type: 'array',
+ key: null,
+ emitName: null,
+ value: null,
+ node: prop
+ }
+ })
}
},
@@ -1109,7 +1105,10 @@ module.exports = {
*/
*iterateArrayExpression(node, groupName) {
for (const item of node.elements) {
- if (item.type === 'Literal' || item.type === 'TemplateLiteral') {
+ if (
+ item &&
+ (item.type === 'Literal' || item.type === 'TemplateLiteral')
+ ) {
const name = getStringLiteralValue(item)
if (name) {
yield { type: 'array', name, groupName, node: item }
diff --git a/tests/lib/rules/no-multiple-objects-in-class.js b/tests/lib/rules/no-multiple-objects-in-class.js
index 45f1b721d..64ce82b0a 100644
--- a/tests/lib/rules/no-multiple-objects-in-class.js
+++ b/tests/lib/rules/no-multiple-objects-in-class.js
@@ -43,6 +43,17 @@ ruleTester.run('no-multiple-objects-in-class', rule, {
type: 'VAttribute'
}
]
+ },
+
+ // sparse array
+ {
+ code: ``,
+ errors: [
+ {
+ message: 'Unexpected multiple objects. Merge objects.',
+ type: 'VAttribute'
+ }
+ ]
}
]
})
diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js
index c5796e752..355fb8df7 100644
--- a/tests/lib/rules/no-unused-properties.js
+++ b/tests/lib/rules/no-unused-properties.js
@@ -981,6 +981,21 @@ tester.run('no-unused-properties', rule, {
}
`,
options: [{ groups: ['props', 'setup'] }]
+ },
+
+ // sparse array
+ {
+ filename: 'test.vue',
+ code: `
+
+ {{ count }}
+
+
+ `
}
],
diff --git a/tests/lib/rules/require-default-prop.js b/tests/lib/rules/require-default-prop.js
index ce292774e..cdc0f4170 100644
--- a/tests/lib/rules/require-default-prop.js
+++ b/tests/lib/rules/require-default-prop.js
@@ -179,6 +179,21 @@ ruleTester.run('require-default-prop', rule, {
}
}
`
+ },
+
+ // sparse array
+ {
+ filename: 'test.vue',
+ code: `
+ export default {
+ props: {
+ a: {
+ type: [,Boolean]
+ },
+ b: [,Boolean],
+ }
+ }
+ `
}
],
diff --git a/tests/lib/rules/require-valid-default-prop.js b/tests/lib/rules/require-valid-default-prop.js
index 9f8ff7275..2617e1460 100644
--- a/tests/lib/rules/require-valid-default-prop.js
+++ b/tests/lib/rules/require-valid-default-prop.js
@@ -181,6 +181,20 @@ ruleTester.run('require-valid-default-prop', rule, {
}
}`,
parserOptions
+ },
+
+ // sparse array
+ {
+ filename: 'test.vue',
+ code: `export default {
+ props: {
+ foo: {
+ type: [,Object, Number],
+ default: 10
+ }
+ }
+ }`,
+ parserOptions
}
],
diff --git a/typings/eslint-plugin-vue/util-types/ast/es-ast.ts b/typings/eslint-plugin-vue/util-types/ast/es-ast.ts
index 701de116d..035c113f4 100644
--- a/typings/eslint-plugin-vue/util-types/ast/es-ast.ts
+++ b/typings/eslint-plugin-vue/util-types/ast/es-ast.ts
@@ -298,7 +298,7 @@ export interface ThisExpression extends HasParentNode {
}
export interface ArrayExpression extends HasParentNode {
type: 'ArrayExpression'
- elements: (Expression | SpreadElement)[]
+ elements: (Expression | SpreadElement | null)[]
}
export interface ObjectExpression extends HasParentNode {
type: 'ObjectExpression'