/
githubmirror
/
eslint-plugin
Обзор
Документация
Войти
/
githubmirror
/
eslint-plugin
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/rules/editorDropPaste.ts
127 строк
4 KB
saberzero1
refactor: streamline meta.docs.url for static analysis
10 июн 2026, 16:14
10 июн 2026, 16:14
13385bc
Код
Авторство
О чём код?
import { TSESTree } from "@typescript-eslint/utils"; import { docsUrl, ruleCreator } from "../ruleCreator.js"; const EVENTS = new Set(["editor-drop", "editor-paste"]); export default ruleCreator({ meta: { type: "problem" as const, docs: { description: "Require checking `evt.defaultPrevented` and calling `evt.preventDefault()` in editor-drop/editor-paste handlers.", url: docsUrl("editor-drop-paste"), }, schema: [], messages: { missingDefaultPrevented: "Check 'evt.defaultPrevented' at the start of '{{eventName}}' handler and return early if already handled.", missingPreventDefault: "Call 'evt.preventDefault()' in '{{eventName}}' handler after handling the event.", }, }, defaultOptions: [], create(context) { return { CallExpression(node: TSESTree.CallExpression) { const eventName = getWorkspaceOnEventName(node); if (!eventName || !EVENTS.has(eventName)) { return; } const callback = node.arguments[1]; if (!callback || !isFunction(callback)) { return; } const body = getFunctionBody(callback); if (!body) { return; } const evtParam = callback.params[0]; if (!evtParam || evtParam.type !== TSESTree.AST_NODE_TYPES.Identifier) { return; } const evtName = evtParam.name; if (!hasDefaultPreventedCheck(body, evtName)) { context.report({ node: callback, messageId: "missingDefaultPrevented", data: { eventName }, }); } if (!hasPreventDefaultCall(body, evtName)) { context.report({ node: callback, messageId: "missingPreventDefault", data: { eventName }, }); } }, }; function getWorkspaceOnEventName(node: TSESTree.CallExpression): string | null { const callee = node.callee; if (callee.type !== TSESTree.AST_NODE_TYPES.MemberExpression) { return null; } if ( callee.property.type !== TSESTree.AST_NODE_TYPES.Identifier || callee.property.name !== "on" ) { return null; } const firstArg = node.arguments[0]; if ( !firstArg || firstArg.type !== TSESTree.AST_NODE_TYPES.Literal || typeof firstArg.value !== "string" ) { return null; } return firstArg.value; } function isFunction(node: TSESTree.Node): node is TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression { return ( node.type === TSESTree.AST_NODE_TYPES.ArrowFunctionExpression || node.type === TSESTree.AST_NODE_TYPES.FunctionExpression ); } function getFunctionBody(node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression): TSESTree.Statement[] | null { if (node.body.type === TSESTree.AST_NODE_TYPES.BlockStatement) { return node.body.body; } return null; } function hasDefaultPreventedCheck(statements: TSESTree.Statement[], evtName: string): boolean { const source = context.sourceCode; for (const stmt of statements) { const text = source.getText(stmt); if (text.includes(`${evtName}.defaultPrevented`)) { return true; } } return false; } function hasPreventDefaultCall(statements: TSESTree.Statement[], evtName: string): boolean { const source = context.sourceCode; for (const stmt of statements) { const text = source.getText(stmt); if (text.includes(`${evtName}.preventDefault()`)) { return true; } } return false; } }, });