UNPKG

@sapphire/eslint-plugin-result

Version:
157 lines (149 loc) 5.72 kB
'use strict'; var utils = require('@typescript-eslint/utils'); var tsutils = require('tsutils'); var ts = require('typescript'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var ts__default = /*#__PURE__*/_interopDefault(ts); var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) { if (typeof require !== "undefined") return require.apply(this, arguments); throw Error('Dynamic require of "' + x + '" is not supported'); }); var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function __require2() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; // src/configs/recommended.ts var recommendedConfig; var init_recommended = __esm({ "src/configs/recommended.ts"() { recommendedConfig = { plugins: ["@sapphire/eslint-plugin-result"], rules: { "@sapphire/result/no-discard-result": "error" } }; } }); function getSapphireResultType(service, checker) { const file = service.program?.getSourceFile(resultPath); const resultNode = file?.statements.find((node) => ts__default.default.isTypeAliasDeclaration(node) && node.name.getText() === "Result"); if (resultNode) { return checker.getTypeAtLocation(resultNode); } return null; } function unwrapPotentialPromiseType(checker, node, type = checker.getTypeAtLocation(node)) { if (tsutils.isUnionType(type)) { const { ...copy } = type; copy.types = type.types.filter((subtype) => Boolean(subtype)); if (copy.types.length === 1) { return unwrapPotentialPromiseType(checker, node, copy.types[0]); } copy.types = copy.types.map((subtype) => unwrapPotentialPromiseType(checker, node, subtype)); return copy; } if (tsutils.isThenableType(checker, node)) { return checker.getTypeArguments(type)[0]; } return type; } function functionHasResultLikeReturnType(service, checker, node) { const functionDeclaration = checker.getResolvedSignature(node); if (!functionDeclaration) { return false; } const returnType = unwrapPotentialPromiseType(checker, node); const resultType = getSapphireResultType(service, checker); if (!returnType || !returnType.aliasSymbol || !resultType?.aliasSymbol) { return false; } return Reflect.get(returnType.aliasSymbol, "id") === Reflect.get(resultType.aliasSymbol, "id"); } function isDiscardedResult(callExpressionNode) { if (callExpressionNode.parent?.type === utils.AST_NODE_TYPES.UnaryExpression && callExpressionNode.parent.operator === "void") { return false; } if (callExpressionNode.parent?.type === utils.AST_NODE_TYPES.VariableDeclarator) { return false; } if (callExpressionNode.parent?.type === utils.AST_NODE_TYPES.AssignmentExpression) { return false; } if (callExpressionNode.parent?.type === utils.AST_NODE_TYPES.CallExpression) { return false; } if (callExpressionNode.parent?.type === utils.AST_NODE_TYPES.SequenceExpression) { return isDiscardedResult(callExpressionNode.parent); } if (callExpressionNode.parent?.type === utils.AST_NODE_TYPES.AwaitExpression) { return isDiscardedResult(callExpressionNode.parent); } if (callExpressionNode.parent?.type === utils.AST_NODE_TYPES.ConditionalExpression) { return isDiscardedResult(callExpressionNode.parent); } if (callExpressionNode.parent?.type === utils.AST_NODE_TYPES.LogicalExpression) { return isDiscardedResult(callExpressionNode.parent); } return true; } var messages, resultPath, noDiscardResult; var init_no_discard_result = __esm({ "src/rules/no-discard-result.ts"() { messages = { discardedResult: "This function returns a Result, but its return value is being discarded." }; resultPath = __require.resolve("@sapphire/result").split("/").slice(0, -1).concat("index.d.ts").join("/"); __name(getSapphireResultType, "getSapphireResultType"); __name(unwrapPotentialPromiseType, "unwrapPotentialPromiseType"); __name(functionHasResultLikeReturnType, "functionHasResultLikeReturnType"); __name(isDiscardedResult, "isDiscardedResult"); noDiscardResult = utils.ESLintUtils.RuleCreator.withoutDocs({ meta: { messages, type: "problem", schema: [] }, defaultOptions: [], create: (context) => { return { CallExpression(callExpressionNode) { const service = utils.ESLintUtils.getParserServices(context); const checker = service.program.getTypeChecker(); if (!functionHasResultLikeReturnType(service, checker, service.esTreeNodeToTSNodeMap.get(callExpressionNode))) { return; } if (isDiscardedResult(callExpressionNode)) { context.report({ messageId: "discardedResult", node: callExpressionNode }); } } }; } }); } }); // src/index.ts var require_src = __commonJS({ "src/index.ts"(exports, module) { init_recommended(); init_no_discard_result(); var eslintPluginResult = { rules: { "no-discard-result": noDiscardResult }, configs: { recommended: recommendedConfig } }; module.exports = eslintPluginResult; } }); var index = require_src(); module.exports = index;