import { ESLintUtils } from "@typescript-eslint/utils"; export const errorMessage = "'using' keyword is required but not used"; export default { meta: { type: "problem", docs: { description: "Ensure objects implementing UsingRequired are used with the using keyword", category: "Best Practices", recommended: false, }, schema: [], }, create(context) { const parserServices = ESLintUtils.getParserServices(context); const checker = parserServices.program.getTypeChecker(); // Function to check if a type implements the `UsingRequired` interface function implementsUsingRequired(type) { const symbol = type.getSymbol(); if (!symbol) { return false; } const declarations = symbol.getDeclarations() || []; for (const declaration of declarations) { const heritageClauses = declaration.heritageClauses || []; for (const clause of heritageClauses) { if ( clause.types.some( (typeExpression) => checker.typeToString(checker.getTypeAtLocation(typeExpression.expression)) === "UsingRequired", ) ) { return true; } } } return false; } // Function to check if a function call returns a `UsingRequired` function returnsUsingRequired(node) { if (node.type === "CallExpression") { const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node); const returnType = checker.getTypeAtLocation(tsNode); return implementsUsingRequired(returnType); } return false; } return { VariableDeclarator(node) { // Skip if `using` is already present if (node.parent.type === "VariableDeclaration" && node.parent.kind === "using") { return; } // Check if the initializer returns a `UsingRequired` if (node.init && returnsUsingRequired(node.init)) { context.report({ node, message: errorMessage, }); } }, AssignmentExpression(node) { // Check if the right-hand side returns a `UsingRequired` if (returnsUsingRequired(node.right)) { context.report({ node, message: errorMessage, }); } }, }; }, };