Skip to content

Commit d19ea88

Browse files
authored
Fix false negatives for template literal in vue/custom-event-name-casing, vue/no-restricted-custom-event, and vue/require-explicit-emits rules (#1937)
1 parent ea158e1 commit d19ea88

6 files changed

+177
-81
lines changed

lib/rules/custom-event-name-casing.js

+24-20
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,27 @@ const { toRegExp } = require('../utils/regexp')
2424
const ALLOWED_CASE_OPTIONS = ['kebab-case', 'camelCase']
2525
const DEFAULT_CASE = 'camelCase'
2626

27+
/**
28+
* @typedef {object} NameWithLoc
29+
* @property {string} name
30+
* @property {SourceLocation} loc
31+
*/
2732
/**
2833
* Get the name param node from the given CallExpression
2934
* @param {CallExpression} node CallExpression
30-
* @returns { Literal & { value: string } | null }
35+
* @returns { NameWithLoc | null }
3136
*/
3237
function getNameParamNode(node) {
3338
const nameLiteralNode = node.arguments[0]
34-
if (
35-
!nameLiteralNode ||
36-
nameLiteralNode.type !== 'Literal' ||
37-
typeof nameLiteralNode.value !== 'string'
38-
) {
39-
// cannot check
40-
return null
39+
if (nameLiteralNode && utils.isStringLiteral(nameLiteralNode)) {
40+
const name = utils.getStringLiteralValue(nameLiteralNode)
41+
if (name != null) {
42+
return { name, loc: nameLiteralNode.loc }
43+
}
4144
}
4245

43-
return /** @type {Literal & { value: string }} */ (nameLiteralNode)
46+
// cannot check
47+
return null
4448
}
4549
/**
4650
* Get the callee member node from the given CallExpression
@@ -130,15 +134,15 @@ module.exports = {
130134
}
131135

132136
/**
133-
* @param { Literal & { value: string } } nameLiteralNode
137+
* @param { NameWithLoc } nameWithLoc
134138
*/
135-
function verify(nameLiteralNode) {
136-
const name = nameLiteralNode.value
139+
function verify(nameWithLoc) {
140+
const name = nameWithLoc.name
137141
if (isValidEventName(name) || ignores.some((re) => re.test(name))) {
138142
return
139143
}
140144
context.report({
141-
node: nameLiteralNode,
145+
loc: nameWithLoc.loc,
142146
messageId: 'unexpected',
143147
data: {
144148
name,
@@ -155,8 +159,8 @@ module.exports = {
155159
* @param {VueObjectData} [info]
156160
*/
157161
CallExpression(node, info) {
158-
const nameLiteralNode = getNameParamNode(node)
159-
if (!nameLiteralNode) {
162+
const nameWithLoc = getNameParamNode(node)
163+
if (!nameWithLoc) {
160164
// cannot check
161165
return
162166
}
@@ -170,7 +174,7 @@ module.exports = {
170174
emitReferenceIds.has(node.callee)
171175
) {
172176
// verify setup(props,{emit}) {emit()}
173-
verify(nameLiteralNode)
177+
verify(nameWithLoc)
174178
} else {
175179
const emit = getCalleeMemberNode(node)
176180
if (
@@ -180,7 +184,7 @@ module.exports = {
180184
contextReferenceIds.has(emit.member.object)
181185
) {
182186
// verify setup(props,context) {context.emit()}
183-
verify(nameLiteralNode)
187+
verify(nameWithLoc)
184188
}
185189
}
186190
}
@@ -192,13 +196,13 @@ module.exports = {
192196
{
193197
CallExpression(node) {
194198
const callee = node.callee
195-
const nameLiteralNode = getNameParamNode(node)
196-
if (!nameLiteralNode) {
199+
const nameWithLoc = getNameParamNode(node)
200+
if (!nameWithLoc) {
197201
// cannot check
198202
return
199203
}
200204
if (callee.type === 'Identifier' && callee.name === '$emit') {
201-
verify(nameLiteralNode)
205+
verify(nameWithLoc)
202206
}
203207
}
204208
},

lib/rules/no-restricted-custom-event.js

+32-27
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,28 @@ function parseOption(option) {
5656
return parsed
5757
}
5858

59+
/**
60+
* @typedef {object} NameWithLoc
61+
* @property {string} name
62+
* @property {SourceLocation} loc
63+
* @property {Range} range
64+
*/
5965
/**
6066
* Get the name param node from the given CallExpression
6167
* @param {CallExpression} node CallExpression
62-
* @returns { Literal & { value: string } | null }
68+
* @returns { NameWithLoc | null }
6369
*/
6470
function getNameParamNode(node) {
6571
const nameLiteralNode = node.arguments[0]
66-
if (
67-
!nameLiteralNode ||
68-
nameLiteralNode.type !== 'Literal' ||
69-
typeof nameLiteralNode.value !== 'string'
70-
) {
71-
// cannot check
72-
return null
72+
if (nameLiteralNode && utils.isStringLiteral(nameLiteralNode)) {
73+
const name = utils.getStringLiteralValue(nameLiteralNode)
74+
if (name != null) {
75+
return { name, loc: nameLiteralNode.loc, range: nameLiteralNode.range }
76+
}
7377
}
7478

75-
return /** @type {Literal & { value: string }} */ (nameLiteralNode)
79+
// cannot check
80+
return null
7681
}
7782
/**
7883
* Get the callee member node from the given CallExpression
@@ -134,32 +139,32 @@ module.exports = {
134139
const options = context.options.map(parseOption)
135140

136141
/**
137-
* @param { Literal & { value: string } } nameLiteralNode
142+
* @param { NameWithLoc } nameWithLoc
138143
*/
139-
function verify(nameLiteralNode) {
140-
const name = nameLiteralNode.value
144+
function verify(nameWithLoc) {
145+
const name = nameWithLoc.name
141146

142147
for (const option of options) {
143148
if (option.test(name)) {
144149
const message =
145150
option.message || `Using \`${name}\` event is not allowed.`
146151
context.report({
147-
node: nameLiteralNode,
152+
loc: nameWithLoc.loc,
148153
messageId: 'restrictedEvent',
149154
data: { message },
150155
suggest: option.suggest
151156
? [
152157
{
153158
fix(fixer) {
154159
const sourceCode = context.getSourceCode()
155-
return fixer.replaceText(
156-
nameLiteralNode,
160+
return fixer.replaceTextRange(
161+
nameWithLoc.range,
157162
`${
158-
sourceCode.text[nameLiteralNode.range[0]]
163+
sourceCode.text[nameWithLoc.range[0]]
159164
}${JSON.stringify(option.suggest)
160165
.slice(1, -1)
161166
.replace(/'/gu, "\\'")}${
162-
sourceCode.text[nameLiteralNode.range[1] - 1]
167+
sourceCode.text[nameWithLoc.range[1] - 1]
163168
}`
164169
)
165170
},
@@ -179,13 +184,13 @@ module.exports = {
179184
{
180185
CallExpression(node) {
181186
const callee = node.callee
182-
const nameLiteralNode = getNameParamNode(node)
183-
if (!nameLiteralNode) {
187+
const nameWithLoc = getNameParamNode(node)
188+
if (!nameWithLoc) {
184189
// cannot check
185190
return
186191
}
187192
if (callee.type === 'Identifier' && callee.name === '$emit') {
188-
verify(nameLiteralNode)
193+
verify(nameWithLoc)
189194
}
190195
}
191196
},
@@ -239,8 +244,8 @@ module.exports = {
239244
})
240245
},
241246
CallExpression(node, { node: vueNode }) {
242-
const nameLiteralNode = getNameParamNode(node)
243-
if (!nameLiteralNode) {
247+
const nameWithLoc = getNameParamNode(node)
248+
if (!nameWithLoc) {
244249
// cannot check
245250
return
246251
}
@@ -254,7 +259,7 @@ module.exports = {
254259
emitReferenceIds.has(node.callee)
255260
) {
256261
// verify setup(props,{emit}) {emit()}
257-
verify(nameLiteralNode)
262+
verify(nameWithLoc)
258263
} else {
259264
const emit = getCalleeMemberNode(node)
260265
if (
@@ -264,7 +269,7 @@ module.exports = {
264269
contextReferenceIds.has(emit.member.object)
265270
) {
266271
// verify setup(props,context) {context.emit()}
267-
verify(nameLiteralNode)
272+
verify(nameWithLoc)
268273
}
269274
}
270275
}
@@ -275,16 +280,16 @@ module.exports = {
275280
}),
276281
{
277282
CallExpression(node) {
278-
const nameLiteralNode = getNameParamNode(node)
279-
if (!nameLiteralNode) {
283+
const nameWithLoc = getNameParamNode(node)
284+
if (!nameWithLoc) {
280285
// cannot check
281286
return
282287
}
283288
const emit = getCalleeMemberNode(node)
284289
// verify $emit
285290
if (emit && emit.name === '$emit') {
286291
// verify this.$emit()
287-
verify(nameLiteralNode)
292+
verify(nameWithLoc)
288293
}
289294
}
290295
}

0 commit comments

Comments
 (0)