eslint-plugin-vue
Version:
Official ESLint plugin for Vue.js
164 lines (163 loc) • 6.83 kB
JavaScript
const require_runtime = require("../_virtual/_rolldown/runtime.js");
const require_index = require("../utils/index.js");
const require_dom_events = require("../utils/dom-events.js");
let _eslint_community_eslint_utils = require("@eslint-community/eslint-utils");
//#region lib/rules/no-shadow-native-events.ts
var import_utils = /* @__PURE__ */ require_runtime.__toESM(require_index.default);
/**
* Check if the given name matches defineEmitsNode variable name
*/
function isEmitVariableName(name, defineEmitsNode) {
const node = defineEmitsNode?.parent;
if (node?.type === "VariableDeclarator" && node.id.type === "Identifier") return name === node.id.name;
return false;
}
var no_shadow_native_events_default = {
meta: {
type: "problem",
docs: {
description: "disallow the use of event names that collide with native web event names",
url: "https://eslint.vuejs.org/rules/no-shadow-native-events.html",
categories: void 0
},
schema: [],
messages: { violation: "Avoid shadowing the native event \"{{ name }}\"." }
},
create(context) {
const setupContexts = /* @__PURE__ */ new Map();
let vueTemplateDefineData = null;
const programNode = context.sourceCode.ast;
if (import_utils.default.isScriptSetup(context)) vueTemplateDefineData = {
type: "setup",
define: programNode
};
/**
* Verify if an emit call violates the rule of not using a native dom event name.
*/
function verifyEmit(nameWithLoc) {
const name = nameWithLoc.name.toLowerCase();
if (!require_dom_events.default.includes(name)) return;
context.report({
loc: nameWithLoc.loc,
messageId: "violation",
data: { name: nameWithLoc.name }
});
}
/**
* Verify if an emit declaration violates the rule of not using a native dom event name.
*/
const verifyEmitDeclaration = (emits) => {
for (const { node, emitName } of emits) {
if (!node || !emitName || !require_dom_events.default.includes(emitName.toLowerCase())) continue;
context.report({
messageId: "violation",
data: { name: emitName },
loc: node.loc
});
}
};
const callVisitor = { CallExpression(node, info) {
const callee = import_utils.default.skipChainExpression(node.callee);
const nameWithLoc = import_utils.default.getNameParamNode(node);
if (!nameWithLoc) return;
const vueDefineNode = info ? info.node : programNode;
let emit;
if (callee.type === "MemberExpression") {
const name = import_utils.default.getStaticPropertyName(callee);
if (name === "emit" || name === "$emit") emit = {
name,
member: callee
};
}
const setupContext = setupContexts.get(vueDefineNode);
if (setupContext) {
const { contextReferenceIds, emitReferenceIds } = setupContext;
if (callee.type === "Identifier" && emitReferenceIds.has(callee)) verifyEmit(nameWithLoc);
else if (emit?.name === "emit") {
const memObject = import_utils.default.skipChainExpression(emit.member.object);
if (memObject.type === "Identifier" && contextReferenceIds.has(memObject)) verifyEmit(nameWithLoc);
}
}
if (emit?.name === "$emit") {
const memObject = import_utils.default.skipChainExpression(emit.member.object);
if (import_utils.default.isThis(memObject, context)) verifyEmit(nameWithLoc);
}
} };
const scriptSetupVisitor = import_utils.default.defineScriptSetupVisitor(context, {
onDefineEmitsEnter: (node, emits) => {
verifyEmitDeclaration(emits);
if (vueTemplateDefineData?.type === "setup") vueTemplateDefineData.defineEmits = node;
if (node.parent?.type !== "VariableDeclarator" || node.parent.init !== node) return;
const emitParam = node.parent.id;
const variable = emitParam.type === "Identifier" ? (0, _eslint_community_eslint_utils.findVariable)(import_utils.default.getScope(context, emitParam), emitParam) : null;
if (!variable) return;
const emitReferenceIds = /* @__PURE__ */ new Set();
for (const reference of variable.references) {
if (!reference.isRead()) continue;
emitReferenceIds.add(reference.identifier);
}
setupContexts.set(programNode, {
contextReferenceIds: /* @__PURE__ */ new Set(),
emitReferenceIds
});
},
...callVisitor
});
const vueVisitor = import_utils.default.defineVueVisitor(context, {
onSetupFunctionEnter(node, { node: vueNode }) {
const contextParam = node.params[1];
if (!contextParam) return;
if (contextParam.type === "RestElement") return;
if (contextParam.type === "ArrayPattern") return;
const contextReferenceIds = /* @__PURE__ */ new Set();
const emitReferenceIds = /* @__PURE__ */ new Set();
if (contextParam.type === "ObjectPattern") {
const emitProperty = import_utils.default.findAssignmentProperty(contextParam, "emit");
if (!emitProperty) return;
const emitParam = emitProperty.value;
const variable = emitParam.type === "Identifier" ? (0, _eslint_community_eslint_utils.findVariable)(import_utils.default.getScope(context, emitParam), emitParam) : null;
if (!variable) return;
for (const reference of variable.references) {
if (!reference.isRead()) continue;
emitReferenceIds.add(reference.identifier);
}
} else if (contextParam.type === "Identifier") {
const variable = (0, _eslint_community_eslint_utils.findVariable)(import_utils.default.getScope(context, contextParam), contextParam);
if (!variable) return;
for (const reference of variable.references) {
if (!reference.isRead()) continue;
contextReferenceIds.add(reference.identifier);
}
}
setupContexts.set(vueNode, {
contextReferenceIds,
emitReferenceIds
});
},
onVueObjectEnter(node) {
const emits = import_utils.default.getComponentEmitsFromOptions(node);
verifyEmitDeclaration(emits);
},
onVueObjectExit(node, { type }) {
if ((!vueTemplateDefineData || vueTemplateDefineData.type !== "export" && vueTemplateDefineData.type !== "setup") && [
"mark",
"export",
"definition"
].includes(type)) vueTemplateDefineData = {
type,
define: node
};
setupContexts.delete(node);
},
...callVisitor
});
return import_utils.default.compositingVisitors(import_utils.default.defineTemplateBodyVisitor(context, { CallExpression(node) {
const callee = import_utils.default.skipChainExpression(node.callee);
const nameWithLoc = import_utils.default.getNameParamNode(node);
if (!nameWithLoc) return;
if (callee.type === "Identifier" && (callee.name === "$emit" || vueTemplateDefineData?.defineEmits && isEmitVariableName(callee.name, vueTemplateDefineData.defineEmits))) verifyEmit(nameWithLoc);
} }, import_utils.default.compositingVisitors(scriptSetupVisitor, vueVisitor)));
}
};
//#endregion
exports.default = no_shadow_native_events_default;