Skip to content

Commit

Permalink
Update vue/custom-event-name-casing rule to support <script setup> (
Browse files Browse the repository at this point in the history
  • Loading branch information
ota-meshi committed Jul 6, 2021
1 parent 7a03a40 commit 9b43c9f
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 32 deletions.
108 changes: 76 additions & 32 deletions lib/rules/custom-event-name-casing.js
Expand Up @@ -13,6 +13,10 @@ const utils = require('../utils')
const casing = require('../utils/casing')
const { toRegExp } = require('../utils/regexp')

/**
* @typedef {import('../utils').VueObjectData} VueObjectData
*/

// ------------------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -103,7 +107,7 @@ module.exports = {
},
/** @param {RuleContext} context */
create(context) {
/** @type {Map<ObjectExpression, {contextReferenceIds:Set<Identifier>,emitReferenceIds:Set<Identifier>}>} */
/** @type {Map<ObjectExpression|Program, {contextReferenceIds:Set<Identifier>,emitReferenceIds:Set<Identifier>}>} */
const setupContexts = new Map()
const options =
context.options.length === 1 && typeof context.options[0] !== 'string'
Expand Down Expand Up @@ -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,
{
Expand All @@ -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])
Expand Down Expand Up @@ -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)
}
Expand Down
16 changes: 16 additions & 0 deletions tests/lib/rules/custom-event-name-casing.js
Expand Up @@ -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: `
<script setup>
const emit = defineEmits({})
emit('fooBar')
emit('foo-bar')
</script>
`,
errors: [
{
message: "Custom event name 'fooBar' must be kebab-case.",
line: 4
}
]
}
]
})

0 comments on commit 9b43c9f

Please sign in to comment.