routie dev init since i didn't adhere to any proper guidance up until now
This commit is contained in:
+308
@@ -0,0 +1,308 @@
|
||||
const require_runtime = require('../_virtual/_rolldown/runtime.js');
|
||||
const require_index = require('../utils/index.js');
|
||||
const require_casing = require('../utils/casing.js');
|
||||
let _eslint_community_eslint_utils = require("@eslint-community/eslint-utils");
|
||||
|
||||
//#region lib/rules/require-explicit-emits.ts
|
||||
var import_utils = /* @__PURE__ */ require_runtime.__toESM(require_index.default);
|
||||
const FIX_EMITS_AFTER_OPTIONS = new Set([
|
||||
"setup",
|
||||
"data",
|
||||
"computed",
|
||||
"watch",
|
||||
"methods",
|
||||
"template",
|
||||
"render",
|
||||
"renderError",
|
||||
"beforeCreate",
|
||||
"created",
|
||||
"beforeMount",
|
||||
"mounted",
|
||||
"beforeUpdate",
|
||||
"updated",
|
||||
"activated",
|
||||
"deactivated",
|
||||
"beforeUnmount",
|
||||
"unmounted",
|
||||
"beforeDestroy",
|
||||
"destroyed",
|
||||
"renderTracked",
|
||||
"renderTriggered",
|
||||
"errorCaptured"
|
||||
]);
|
||||
/**
|
||||
* Get the name param node from the given CallExpression
|
||||
*/
|
||||
function getNameParamNode(node) {
|
||||
const nameLiteralNode = node.arguments[0];
|
||||
if (nameLiteralNode && import_utils.default.isStringLiteral(nameLiteralNode)) {
|
||||
const name = import_utils.default.getStringLiteralValue(nameLiteralNode);
|
||||
if (name != null) return {
|
||||
name,
|
||||
loc: nameLiteralNode.loc,
|
||||
range: nameLiteralNode.range
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
var require_explicit_emits_default = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
docs: {
|
||||
description: "require `emits` option with name triggered by `$emit()`",
|
||||
categories: ["vue3-strongly-recommended"],
|
||||
url: "https://eslint.vuejs.org/rules/require-explicit-emits.html"
|
||||
},
|
||||
fixable: null,
|
||||
hasSuggestions: true,
|
||||
schema: [{
|
||||
type: "object",
|
||||
properties: { allowProps: { type: "boolean" } },
|
||||
additionalProperties: false
|
||||
}],
|
||||
messages: {
|
||||
missing: "The \"{{name}}\" event has been triggered but not declared on {{emitsKind}}.",
|
||||
addOneOption: "Add the \"{{name}}\" to {{emitsKind}}.",
|
||||
addArrayEmitsOption: "Add the {{emitsKind}} with array syntax and define \"{{name}}\" event.",
|
||||
addObjectEmitsOption: "Add the {{emitsKind}} with object syntax and define \"{{name}}\" event."
|
||||
}
|
||||
},
|
||||
create(context) {
|
||||
const allowProps = !!(context.options[0] || {}).allowProps;
|
||||
const setupContexts = /* @__PURE__ */ new Map();
|
||||
const vueEmitsDeclarations = /* @__PURE__ */ new Map();
|
||||
const vuePropsDeclarations = /* @__PURE__ */ new Map();
|
||||
let emitParamName = "";
|
||||
let vueTemplateDefineData = null;
|
||||
function verifyEmit(emits, props, nameWithLoc, vueDefineNode) {
|
||||
const name = nameWithLoc.name;
|
||||
if (emits.some((e) => e.emitName === name || e.emitName == null)) return;
|
||||
if (allowProps) {
|
||||
const key = `on${require_casing.capitalize(name)}`;
|
||||
if (props.some((e) => e.propName === key || e.propName == null)) return;
|
||||
}
|
||||
context.report({
|
||||
loc: nameWithLoc.loc,
|
||||
messageId: "missing",
|
||||
data: {
|
||||
name,
|
||||
emitsKind: vueDefineNode.type === "ObjectExpression" ? "`emits` option" : "`defineEmits`"
|
||||
},
|
||||
suggest: buildSuggest(vueDefineNode, emits, nameWithLoc, context)
|
||||
});
|
||||
}
|
||||
const programNode = context.sourceCode.ast;
|
||||
if (import_utils.default.isScriptSetup(context)) vueTemplateDefineData = {
|
||||
type: "setup",
|
||||
define: programNode,
|
||||
emits: [],
|
||||
props: []
|
||||
};
|
||||
const callVisitor = { CallExpression(node, info) {
|
||||
const callee = import_utils.default.skipChainExpression(node.callee);
|
||||
const nameWithLoc = getNameParamNode(node);
|
||||
if (!nameWithLoc) return;
|
||||
const vueDefineNode = info ? info.node : programNode;
|
||||
const emitsDeclarations = vueEmitsDeclarations.get(vueDefineNode);
|
||||
if (!emitsDeclarations) return;
|
||||
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(emitsDeclarations, vuePropsDeclarations.get(vueDefineNode) || [], nameWithLoc, vueDefineNode);
|
||||
else if (emit && emit.name === "emit") {
|
||||
const memObject = import_utils.default.skipChainExpression(emit.member.object);
|
||||
if (memObject.type === "Identifier" && contextReferenceIds.has(memObject)) verifyEmit(emitsDeclarations, vuePropsDeclarations.get(vueDefineNode) || [], nameWithLoc, vueDefineNode);
|
||||
}
|
||||
}
|
||||
if (emit && emit.name === "$emit") {
|
||||
const memObject = import_utils.default.skipChainExpression(emit.member.object);
|
||||
if (import_utils.default.isThis(memObject, context)) verifyEmit(emitsDeclarations, vuePropsDeclarations.get(vueDefineNode) || [], nameWithLoc, vueDefineNode);
|
||||
}
|
||||
} };
|
||||
return import_utils.default.defineTemplateBodyVisitor(context, { CallExpression(node) {
|
||||
const callee = import_utils.default.skipChainExpression(node.callee);
|
||||
const nameWithLoc = getNameParamNode(node);
|
||||
if (!nameWithLoc) return;
|
||||
if (!vueTemplateDefineData) return;
|
||||
if (callee.type === "Identifier" && (callee.name === "$emit" || callee.name === emitParamName)) verifyEmit(vueTemplateDefineData.emits, vueTemplateDefineData.props, nameWithLoc, vueTemplateDefineData.define);
|
||||
} }, import_utils.default.compositingVisitors(import_utils.default.defineScriptSetupVisitor(context, {
|
||||
onDefineEmitsEnter(node, emits) {
|
||||
vueEmitsDeclarations.set(programNode, emits);
|
||||
if (vueTemplateDefineData && vueTemplateDefineData.type === "setup") {
|
||||
vueTemplateDefineData.emits = emits;
|
||||
vueTemplateDefineData.defineEmits = node;
|
||||
}
|
||||
if (!node.parent || node.parent.type !== "VariableDeclarator" || node.parent.init !== node) return;
|
||||
const emitParam = node.parent.id;
|
||||
if (emitParam.type !== "Identifier") return;
|
||||
emitParamName = emitParam.name;
|
||||
const variable = (0, _eslint_community_eslint_utils.findVariable)(import_utils.default.getScope(context, emitParam), emitParam);
|
||||
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
|
||||
});
|
||||
},
|
||||
onDefinePropsEnter(_node, props) {
|
||||
if (allowProps) {
|
||||
vuePropsDeclarations.set(programNode, props);
|
||||
if (vueTemplateDefineData && vueTemplateDefineData.type === "setup") vueTemplateDefineData.props = props;
|
||||
}
|
||||
},
|
||||
...callVisitor
|
||||
}), import_utils.default.defineVueVisitor(context, {
|
||||
onVueObjectEnter(node) {
|
||||
vueEmitsDeclarations.set(node, import_utils.default.getComponentEmitsFromOptions(node));
|
||||
if (allowProps) vuePropsDeclarations.set(node, import_utils.default.getComponentPropsFromOptions(node));
|
||||
},
|
||||
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
|
||||
});
|
||||
},
|
||||
...callVisitor,
|
||||
onVueObjectExit(node, { type }) {
|
||||
const emits = vueEmitsDeclarations.get(node);
|
||||
if ((!vueTemplateDefineData || vueTemplateDefineData.type !== "export" && vueTemplateDefineData.type !== "setup") && emits && (type === "mark" || type === "export" || type === "definition")) vueTemplateDefineData = {
|
||||
type,
|
||||
define: node,
|
||||
emits,
|
||||
props: vuePropsDeclarations.get(node) || []
|
||||
};
|
||||
setupContexts.delete(node);
|
||||
vueEmitsDeclarations.delete(node);
|
||||
vuePropsDeclarations.delete(node);
|
||||
}
|
||||
})));
|
||||
}
|
||||
};
|
||||
function buildSuggest(define, emits, nameWithLoc, context) {
|
||||
const emitsKind = define.type === "ObjectExpression" ? "`emits` option" : "`defineEmits`";
|
||||
const lastEmit = emits.filter((e) => e.type === "array" || e.type === "object").at(-1);
|
||||
if (lastEmit) return [{
|
||||
messageId: "addOneOption",
|
||||
data: {
|
||||
name: nameWithLoc.name,
|
||||
emitsKind
|
||||
},
|
||||
fix(fixer) {
|
||||
if (lastEmit.type === "array") return fixer.insertTextAfter(lastEmit.node, `, '${nameWithLoc.name}'`);
|
||||
else if (lastEmit.type === "object") return fixer.insertTextAfter(lastEmit.node, `, '${nameWithLoc.name}': null`);
|
||||
else return null;
|
||||
}
|
||||
}];
|
||||
if (define.type !== "ObjectExpression") return [];
|
||||
const object = define;
|
||||
const propertyNodes = object.properties.filter(import_utils.default.isProperty);
|
||||
const emitsOption = propertyNodes.find((p) => import_utils.default.getStaticPropertyName(p) === "emits");
|
||||
if (emitsOption) {
|
||||
const sourceCode = context.sourceCode;
|
||||
const emitsOptionValue = emitsOption.value;
|
||||
if (emitsOptionValue.type === "ArrayExpression") {
|
||||
const leftBracket = sourceCode.getFirstToken(emitsOptionValue, _eslint_community_eslint_utils.isOpeningBracketToken);
|
||||
return [{
|
||||
messageId: "addOneOption",
|
||||
data: {
|
||||
name: `${nameWithLoc.name}`,
|
||||
emitsKind
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(leftBracket, `'${nameWithLoc.name}'${emitsOptionValue.elements.length > 0 ? "," : ""}`);
|
||||
}
|
||||
}];
|
||||
} else if (emitsOptionValue.type === "ObjectExpression") {
|
||||
const leftBrace = sourceCode.getFirstToken(emitsOptionValue, _eslint_community_eslint_utils.isOpeningBraceToken);
|
||||
return [{
|
||||
messageId: "addOneOption",
|
||||
data: {
|
||||
name: `${nameWithLoc.name}`,
|
||||
emitsKind
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(leftBrace, `'${nameWithLoc.name}': null${emitsOptionValue.properties.length > 0 ? "," : ""}`);
|
||||
}
|
||||
}];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
const sourceCode = context.sourceCode;
|
||||
const afterOptionNode = propertyNodes.find((p) => FIX_EMITS_AFTER_OPTIONS.has(import_utils.default.getStaticPropertyName(p) || ""));
|
||||
return [{
|
||||
messageId: "addArrayEmitsOption",
|
||||
data: {
|
||||
name: `${nameWithLoc.name}`,
|
||||
emitsKind
|
||||
},
|
||||
fix(fixer) {
|
||||
if (afterOptionNode) return fixer.insertTextAfter(sourceCode.getTokenBefore(afterOptionNode), `\nemits: ['${nameWithLoc.name}'],`);
|
||||
const lastPropertyNode = object.properties.at(-1);
|
||||
if (lastPropertyNode) {
|
||||
const before = propertyNodes.at(-1) || lastPropertyNode;
|
||||
return fixer.insertTextAfter(before, `,\nemits: ['${nameWithLoc.name}']`);
|
||||
} else {
|
||||
const objectLeftBrace = sourceCode.getFirstToken(object, _eslint_community_eslint_utils.isOpeningBraceToken);
|
||||
const objectRightBrace = sourceCode.getLastToken(object, _eslint_community_eslint_utils.isClosingBraceToken);
|
||||
return fixer.insertTextAfter(objectLeftBrace, `\nemits: ['${nameWithLoc.name}']${objectLeftBrace.loc.end.line < objectRightBrace.loc.start.line ? "" : "\n"}`);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
messageId: "addObjectEmitsOption",
|
||||
data: {
|
||||
name: `${nameWithLoc.name}`,
|
||||
emitsKind
|
||||
},
|
||||
fix(fixer) {
|
||||
if (afterOptionNode) return fixer.insertTextAfter(sourceCode.getTokenBefore(afterOptionNode), `\nemits: {'${nameWithLoc.name}': null},`);
|
||||
const lastPropertyNode = object.properties.at(-1);
|
||||
if (lastPropertyNode) {
|
||||
const before = propertyNodes.at(-1) || lastPropertyNode;
|
||||
return fixer.insertTextAfter(before, `,\nemits: {'${nameWithLoc.name}': null}`);
|
||||
} else {
|
||||
const objectLeftBrace = sourceCode.getFirstToken(object, _eslint_community_eslint_utils.isOpeningBraceToken);
|
||||
const objectRightBrace = sourceCode.getLastToken(object, _eslint_community_eslint_utils.isClosingBraceToken);
|
||||
return fixer.insertTextAfter(objectLeftBrace, `\nemits: {'${nameWithLoc.name}': null}${objectLeftBrace.loc.end.line < objectRightBrace.loc.start.line ? "" : "\n"}`);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
//#endregion
|
||||
exports.default = require_explicit_emits_default;
|
||||
Reference in New Issue
Block a user