diff --git a/lib/rules/custom-event-name-casing.js b/lib/rules/custom-event-name-casing.js index 39d9436e7..f59fa9c2a 100644 --- a/lib/rules/custom-event-name-casing.js +++ b/lib/rules/custom-event-name-casing.js @@ -13,6 +13,10 @@ const utils = require('../utils') const casing = require('../utils/casing') const { toRegExp } = require('../utils/regexp') +/** + * @typedef {import('../utils').VueObjectData} VueObjectData + */ + // ------------------------------------------------------------------------------ // Helpers // ------------------------------------------------------------------------------ @@ -103,7 +107,7 @@ module.exports = { }, /** @param {RuleContext} context */ create(context) { - /** @type {Map,emitReferenceIds:Set}>} */ + /** @type {Map,emitReferenceIds:Set}>} */ const setupContexts = new Map() const options = context.options.length === 1 && typeof context.options[0] !== 'string' @@ -143,6 +147,46 @@ module.exports = { }) } + const programNode = context.getSourceCode().ast + + const callVisitor = { + /** + * @param {CallExpression} node + * @param {VueObjectData} [info] + */ + CallExpression(node, info) { + const nameLiteralNode = getNameParamNode(node) + if (!nameLiteralNode) { + // cannot check + return + } + + // verify setup context + const setupContext = setupContexts.get(info ? info.node : programNode) + if (setupContext) { + const { contextReferenceIds, emitReferenceIds } = setupContext + if ( + node.callee.type === 'Identifier' && + emitReferenceIds.has(node.callee) + ) { + // verify setup(props,{emit}) {emit()} + verify(nameLiteralNode) + } else { + const emit = getCalleeMemberNode(node) + if ( + emit && + emit.name === 'emit' && + emit.member.object.type === 'Identifier' && + contextReferenceIds.has(emit.member.object) + ) { + // verify setup(props,context) {context.emit()} + verify(nameLiteralNode) + } + } + } + } + } + return utils.defineTemplateBodyVisitor( context, { @@ -159,6 +203,36 @@ module.exports = { } }, utils.compositingVisitors( + utils.defineScriptSetupVisitor(context, { + onDefineEmitsEnter(node) { + if ( + !node.parent || + node.parent.type !== 'VariableDeclarator' || + node.parent.init !== node + ) { + return + } + + const emitParam = node.parent.id + if (emitParam.type !== 'Identifier') { + return + } + // const emit = defineEmits() + const variable = findVariable(context.getScope(), emitParam) + if (!variable) { + return + } + const emitReferenceIds = new Set() + for (const reference of variable.references) { + emitReferenceIds.add(reference.identifier) + } + setupContexts.set(programNode, { + contextReferenceIds: new Set(), + emitReferenceIds + }) + }, + ...callVisitor + }), utils.defineVueVisitor(context, { onSetupFunctionEnter(node, { node: vueNode }) { const contextParam = utils.skipDefaultParamValue(node.params[1]) @@ -207,37 +281,7 @@ module.exports = { emitReferenceIds }) }, - CallExpression(node, { node: vueNode }) { - const nameLiteralNode = getNameParamNode(node) - if (!nameLiteralNode) { - // cannot check - return - } - - // verify setup context - const setupContext = setupContexts.get(vueNode) - if (setupContext) { - const { contextReferenceIds, emitReferenceIds } = setupContext - if ( - node.callee.type === 'Identifier' && - emitReferenceIds.has(node.callee) - ) { - // verify setup(props,{emit}) {emit()} - verify(nameLiteralNode) - } else { - const emit = getCalleeMemberNode(node) - if ( - emit && - emit.name === 'emit' && - emit.member.object.type === 'Identifier' && - contextReferenceIds.has(emit.member.object) - ) { - // verify setup(props,context) {context.emit()} - verify(nameLiteralNode) - } - } - } - }, + ...callVisitor, onVueObjectExit(node) { setupContexts.delete(node) } diff --git a/tests/lib/rules/custom-event-name-casing.js b/tests/lib/rules/custom-event-name-casing.js index cd857b4ce..00b76e4ed 100644 --- a/tests/lib/rules/custom-event-name-casing.js +++ b/tests/lib/rules/custom-event-name-casing.js @@ -478,6 +478,22 @@ tester.run('custom-event-name-casing', rule, { "Custom event name 'bar-baz' must be camelCase.", "Custom event name 'baz-qux' must be camelCase." ] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: [ + { + message: "Custom event name 'fooBar' must be kebab-case.", + line: 4 + } + ] } ] })