Skip to content

Commit

Permalink
Fix false positive for unknown emits definition in `vue/require-expli…
Browse files Browse the repository at this point in the history
…cit-emits` rule (#1756)

* Fix false positive for unknown emits definition in `vue/require-explicit-emits` rule

* Rename method
  • Loading branch information
ota-meshi committed Jan 8, 2022
1 parent a475176 commit 834411e
Show file tree
Hide file tree
Showing 18 changed files with 499 additions and 330 deletions.
10 changes: 4 additions & 6 deletions lib/rules/no-boolean-default.js
Expand Up @@ -7,9 +7,7 @@
const utils = require('../utils')

/**
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
* @typedef {import('../utils').ComponentProp} ComponentProp
*/

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -55,7 +53,7 @@ module.exports = {
create(context) {
const booleanType = context.options[0] || 'no-default'
/**
* @param {ComponentArrayProp | ComponentObjectProp | ComponentTypeProp} prop
* @param {ComponentProp} prop
* @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions]
*/
function processProp(prop, withDefaultsExpressions) {
Expand Down Expand Up @@ -84,7 +82,7 @@ module.exports = {
}
}
/**
* @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props
* @param {ComponentProp[]} props
* @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions]
*/
function processProps(props, withDefaultsExpressions) {
Expand Down Expand Up @@ -118,7 +116,7 @@ module.exports = {
}
return utils.compositingVisitors(
utils.executeOnVueComponent(context, (obj) => {
processProps(utils.getComponentProps(obj))
processProps(utils.getComponentPropsFromOptions(obj))
}),
utils.defineScriptSetupVisitor(context, {
onDefinePropsEnter(node, props) {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-deprecated-props-default-this.js
Expand Up @@ -96,7 +96,7 @@ module.exports = {
}
return utils.defineVueVisitor(context, {
onVueObjectEnter(node) {
for (const prop of utils.getComponentProps(node)) {
for (const prop of utils.getComponentPropsFromOptions(node)) {
if (prop.type !== 'object') {
continue
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-mutating-props.js
Expand Up @@ -297,7 +297,7 @@ module.exports = {
node,
new Set(
utils
.getComponentProps(node)
.getComponentPropsFromOptions(node)
.map((p) => p.propName)
.filter(utils.isDef)
)
Expand Down
5 changes: 3 additions & 2 deletions lib/rules/no-reserved-keys.js
Expand Up @@ -67,8 +67,9 @@ module.exports = {
return utils.compositingVisitors(
utils.defineScriptSetupVisitor(context, {
onDefinePropsEnter(_node, props) {
for (const { propName, node } of props) {
if (propName && reservedKeys.has(propName)) {
for (const prop of props) {
if (prop.propName && reservedKeys.has(prop.propName)) {
const { propName, node } = prop
context.report({
node,
messageId: 'reserved',
Expand Down
8 changes: 3 additions & 5 deletions lib/rules/no-reserved-props.js
Expand Up @@ -12,9 +12,7 @@ const utils = require('../utils')
const casing = require('../utils/casing')

/**
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
* @typedef {import('../utils').ComponentProp} ComponentProp
*/

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -67,7 +65,7 @@ module.exports = {
const reserved = new Set(RESERVED[vueVersion])

/**
* @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props
* @param {ComponentProp[]} props
*/
function processProps(props) {
for (const prop of props) {
Expand All @@ -90,7 +88,7 @@ module.exports = {
}
}),
utils.executeOnVue(context, (obj) => {
processProps(utils.getComponentProps(obj))
processProps(utils.getComponentPropsFromOptions(obj))
})
)
}
Expand Down
8 changes: 3 additions & 5 deletions lib/rules/no-restricted-props.js
Expand Up @@ -8,9 +8,7 @@ const utils = require('../utils')
const regexp = require('../utils/regexp')

/**
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
* @typedef {import('../utils').ComponentProp} ComponentProp
*/

/**
Expand Down Expand Up @@ -96,7 +94,7 @@ module.exports = {
const options = context.options.map(parseOption)

/**
* @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props
* @param {ComponentProp[]} props
* @param { { [key: string]: Property | undefined } } [withDefaultsProps]
*/
function processProps(props, withDefaultsProps) {
Expand Down Expand Up @@ -133,7 +131,7 @@ module.exports = {
}),
utils.defineVueVisitor(context, {
onVueObjectEnter(node) {
processProps(utils.getComponentProps(node))
processProps(utils.getComponentPropsFromOptions(node))
}
})
)
Expand Down
8 changes: 3 additions & 5 deletions lib/rules/prop-name-casing.js
Expand Up @@ -9,9 +9,7 @@ const casing = require('../utils/casing')
const allowedCaseOptions = ['camelCase', 'snake_case']

/**
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
* @typedef {import('../utils').ComponentProp} ComponentProp
*/

// ------------------------------------------------------------------------------
Expand All @@ -29,7 +27,7 @@ function create(context) {
// ----------------------------------------------------------------------

/**
* @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props
* @param {ComponentProp[]} props
*/
function processProps(props) {
for (const item of props) {
Expand All @@ -56,7 +54,7 @@ function create(context) {
}
}),
utils.executeOnVue(context, (obj) => {
processProps(utils.getComponentProps(obj))
processProps(utils.getComponentPropsFromOptions(obj))
})
)
}
Expand Down
7 changes: 3 additions & 4 deletions lib/rules/require-default-prop.js
Expand Up @@ -5,9 +5,8 @@
'use strict'

/**
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentProp} ComponentProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
* @typedef {ComponentObjectProp & { value: ObjectExpression} } ComponentObjectPropObject
*/

Expand Down Expand Up @@ -145,7 +144,7 @@ module.exports = {
}

/**
* @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props
* @param {ComponentProp[]} props
* @param {boolean} [withDefaults]
* @param { { [key: string]: Expression | undefined } } [withDefaultsExpressions]
*/
Expand Down Expand Up @@ -209,7 +208,7 @@ module.exports = {
}
}),
utils.executeOnVue(context, (obj) => {
processProps(utils.getComponentProps(obj))
processProps(utils.getComponentPropsFromOptions(obj))
})
)
}
Expand Down
21 changes: 9 additions & 12 deletions lib/rules/require-emit-validator.js
Expand Up @@ -7,9 +7,7 @@
const utils = require('../utils')

/**
* @typedef {import('../utils').ComponentArrayEmit} ComponentArrayEmit
* @typedef {import('../utils').ComponentObjectEmit} ComponentObjectEmit
* @typedef {import('../utils').ComponentTypeEmit} ComponentTypeEmit
* @typedef {import('../utils').ComponentEmit} ComponentEmit
*/

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -41,9 +39,13 @@ module.exports = {
// ----------------------------------------------------------------------

/**
* @param {ComponentArrayEmit|ComponentObjectEmit} emit
* @param {ComponentEmit} emit
*/
function checker({ value, node, emitName }) {
function checker(emit) {
if (emit.type !== 'object' && emit.type !== 'array') {
return
}
const { value, node, emitName } = emit
const hasType =
!!value &&
(value.type === 'ArrowFunctionExpression' ||
Expand Down Expand Up @@ -87,16 +89,11 @@ module.exports = {

return utils.compositingVisitors(
utils.executeOnVue(context, (obj) => {
utils.getComponentEmits(obj).forEach(checker)
utils.getComponentEmitsFromOptions(obj).forEach(checker)
}),
utils.defineScriptSetupVisitor(context, {
onDefineEmitsEnter(_node, emits) {
for (const emit of emits) {
if (emit.type === 'type') {
continue
}
checker(emit)
}
emits.forEach(checker)
}
})
)
Expand Down
36 changes: 19 additions & 17 deletions lib/rules/require-explicit-emits.js
Expand Up @@ -5,12 +5,8 @@
'use strict'

/**
* @typedef {import('../utils').ComponentArrayEmit} ComponentArrayEmit
* @typedef {import('../utils').ComponentObjectEmit} ComponentObjectEmit
* @typedef {import('../utils').ComponentTypeEmit} ComponentTypeEmit
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
* @typedef {import('../utils').ComponentEmit} ComponentEmit
* @typedef {import('../utils').ComponentProp} ComponentProp
* @typedef {import('../utils').VueObjectData} VueObjectData
*/

Expand Down Expand Up @@ -99,36 +95,36 @@ module.exports = {
const allowProps = !!options.allowProps
/** @type {Map<ObjectExpression | Program, { contextReferenceIds: Set<Identifier>, emitReferenceIds: Set<Identifier> }>} */
const setupContexts = new Map()
/** @type {Map<ObjectExpression | Program, (ComponentArrayEmit | ComponentObjectEmit | ComponentTypeEmit)[]>} */
/** @type {Map<ObjectExpression | Program, ComponentEmit[]>} */
const vueEmitsDeclarations = new Map()
/** @type {Map<ObjectExpression | Program, (ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]>} */
/** @type {Map<ObjectExpression | Program, ComponentProp[]>} */
const vuePropsDeclarations = new Map()

/**
* @typedef {object} VueTemplateDefineData
* @property {'export' | 'mark' | 'definition' | 'setup'} type
* @property {ObjectExpression | Program} define
* @property {(ComponentArrayEmit | ComponentObjectEmit | ComponentTypeEmit)[]} emits
* @property {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props
* @property {ComponentEmit[]} emits
* @property {ComponentProp[]} props
* @property {CallExpression} [defineEmits]
*/
/** @type {VueTemplateDefineData | null} */
let vueTemplateDefineData = null

/**
* @param {(ComponentArrayEmit | ComponentObjectEmit | ComponentTypeEmit)[]} emits
* @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props
* @param {ComponentEmit[]} emits
* @param {ComponentProp[]} props
* @param {Literal} nameLiteralNode
* @param {ObjectExpression | Program} vueDefineNode
*/
function verifyEmit(emits, props, nameLiteralNode, vueDefineNode) {
const name = `${nameLiteralNode.value}`
if (emits.some((e) => e.emitName === name)) {
if (emits.some((e) => e.emitName === name || e.emitName == null)) {
return
}
if (allowProps) {
const key = `on${capitalize(name)}`
if (props.some((e) => e.propName === key)) {
if (props.some((e) => e.propName === key || e.propName == null)) {
return
}
}
Expand Down Expand Up @@ -311,9 +307,15 @@ module.exports = {
}),
utils.defineVueVisitor(context, {
onVueObjectEnter(node) {
vueEmitsDeclarations.set(node, utils.getComponentEmits(node))
vueEmitsDeclarations.set(
node,
utils.getComponentEmitsFromOptions(node)
)
if (allowProps) {
vuePropsDeclarations.set(node, utils.getComponentProps(node))
vuePropsDeclarations.set(
node,
utils.getComponentPropsFromOptions(node)
)
}
},
onSetupFunctionEnter(node, { node: vueNode }) {
Expand Down Expand Up @@ -409,7 +411,7 @@ module.exports = {

/**
* @param {ObjectExpression|Program} define
* @param {(ComponentArrayEmit | ComponentObjectEmit | ComponentTypeEmit)[]} emits
* @param {ComponentEmit[]} emits
* @param {Literal} nameNode
* @param {RuleContext} context
* @returns {Rule.SuggestionReportDescriptor[]}
Expand Down
8 changes: 3 additions & 5 deletions lib/rules/require-prop-type-constructor.js
Expand Up @@ -8,9 +8,7 @@ const utils = require('../utils')
const { isDef } = require('../utils')

/**
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentTypeProp} ComponentTypeProp
* @typedef {import('../utils').ComponentProp} ComponentProp
*/

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -82,7 +80,7 @@ module.exports = {
)
}

/** @param {(ComponentArrayProp | ComponentObjectProp | ComponentTypeProp)[]} props */
/** @param {ComponentProp[]} props */
function verifyProps(props) {
for (const prop of props) {
if (!prop.value || prop.propName == null) {
Expand Down Expand Up @@ -110,7 +108,7 @@ module.exports = {
}
}),
utils.executeOnVueComponent(context, (obj) => {
verifyProps(utils.getComponentProps(obj))
verifyProps(utils.getComponentPropsFromOptions(obj))
})
)
}
Expand Down
16 changes: 8 additions & 8 deletions lib/rules/require-prop-types.js
Expand Up @@ -7,8 +7,7 @@
const utils = require('../utils')

/**
* @typedef {import('../utils').ComponentArrayProp} ComponentArrayProp
* @typedef {import('../utils').ComponentObjectProp} ComponentObjectProp
* @typedef {import('../utils').ComponentProp} ComponentProp
*/

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -54,9 +53,13 @@ module.exports = {
}

/**
* @param { ComponentArrayProp | ComponentObjectProp } prop
* @param {ComponentProp} prop
*/
function checkProperty({ value, node, propName }) {
function checkProperty(prop) {
if (prop.type !== 'object' && prop.type !== 'array') {
return
}
const { value, node, propName } = prop
let hasType = true

if (!value) {
Expand Down Expand Up @@ -96,15 +99,12 @@ module.exports = {
utils.defineScriptSetupVisitor(context, {
onDefinePropsEnter(_node, props) {
for (const prop of props) {
if (prop.type === 'type') {
continue
}
checkProperty(prop)
}
}
}),
utils.executeOnVue(context, (obj) => {
const props = utils.getComponentProps(obj)
const props = utils.getComponentPropsFromOptions(obj)

for (const prop of props) {
checkProperty(prop)
Expand Down

0 comments on commit 834411e

Please sign in to comment.