Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix false positive for unknown emits definition in vue/require-explicit-emits rule #1756

Merged
merged 2 commits into from Jan 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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