UNPKG

eslint-plugin-fp-ts

Version:

fp-ts ESLint rules

143 lines (142 loc) 9.03 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var utils_1 = require("@typescript-eslint/utils"); var fp_ts_1 = require("fp-ts"); var function_1 = require("fp-ts/function"); var typescript_1 = __importDefault(require("typescript")); var utils_2 = require("../utils"); exports.default = (0, utils_2.createRule)({ name: "no-discarded-pure-expression", meta: { type: "problem", hasSuggestions: true, schema: [], docs: { description: "Detects pure expressions that do nothing because they're in statement position", }, messages: { pureExpressionInStatementPosition: "'{{dataType}}' is pure, so this expression does nothing in statement position. Did you forget to return it or run it?", addReturn: "return the expression", runExpression: "run the expression", discardedDataTypeJsx: "'{{jsxAttributeName}}' expects a function returning '{{expectedReturnType}}' but the expression returns a '{{dataType}}'. Did you forget to run the expression?", discardedDataTypeArgument: "The expression returns a '{{dataType}}', but the function '{{functionName}}' expects a function returning '{{expectedReturnType}}'. Did you forget to run the expression?", }, }, defaultOptions: [], create: function (context) { var _a = (0, utils_2.contextUtils)(context), isFromFpTs = _a.isFromFpTs, typeOfNode = _a.typeOfNode, parserServices = _a.parserServices; var pureDataPrefixes = ["Task", "IO"]; function isPureDataType(t) { return (isFromFpTs(t) && (0, function_1.pipe)(pureDataPrefixes, fp_ts_1.array.some(function (prefix) { var _a; return (_a = t.symbol) === null || _a === void 0 ? void 0 : _a.escapedName.toString().startsWith(prefix); }))); } function pureDataReturnType(t) { if (t.isUnion()) { return (0, function_1.pipe)(t.types, fp_ts_1.readonlyArray.findFirstMap(pureDataReturnType)); } return (0, function_1.pipe)(t.getCallSignatures(), fp_ts_1.readonlyArray.map(function (signature) { return signature.getReturnType(); }), fp_ts_1.readonlyArray.findFirst(isPureDataType)); } function voidOrUknownReturnType(t) { if (t.isUnion()) { return (0, function_1.pipe)(t.types, fp_ts_1.readonlyArray.findFirstMap(voidOrUknownReturnType)); } return (0, function_1.pipe)(t.getCallSignatures(), fp_ts_1.readonlyArray.map(function (signature) { return signature.getReturnType(); }), fp_ts_1.readonlyArray.findFirst(function (returnType) { return !!(returnType.flags & typescript_1.default.TypeFlags.Void || returnType.flags & typescript_1.default.TypeFlags.Unknown); })); } return { ExpressionStatement: function (node) { if (node.expression.type !== utils_1.AST_NODE_TYPES.AssignmentExpression) { (0, function_1.pipe)(node.expression, typeOfNode, fp_ts_1.option.filter(function (t) { if (t.isUnion()) { return (0, function_1.pipe)(t.types, fp_ts_1.array.every(isPureDataType)); } return isPureDataType(t); }), fp_ts_1.option.fold(function_1.constVoid, function (t) { context.report({ node: node.expression, messageId: "pureExpressionInStatementPosition", data: { dataType: t.isUnion() ? t.types[0].symbol.escapedName : t.symbol.escapedName, }, suggest: [ { messageId: "addReturn", fix: function (fixer) { return fixer.insertTextBefore(node.expression, "return "); }, }, { messageId: "runExpression", fix: function (fixer) { return fixer.insertTextAfter(node.expression, "()"); }, }, ], }); })); } }, JSXAttribute: function (node) { var parameterWithVoidOrUknownReturnType = function (parserServices, typeChecker) { return (0, function_1.pipe)(typeChecker.getContextualTypeForJsxAttribute(parserServices.esTreeNodeToTSNodeMap.get(node)), fp_ts_1.option.fromNullable, fp_ts_1.option.filterMap(voidOrUknownReturnType)); }; var argumentWithPureDataTypeReturnType = (0, function_1.pipe)(node, typeOfNode, fp_ts_1.option.filterMap(pureDataReturnType)); (0, function_1.pipe)(fp_ts_1.option.Do, fp_ts_1.option.bind("parserServices", parserServices), fp_ts_1.option.bind("typeChecker", function (_a) { var _b; var parserServices = _a.parserServices; return fp_ts_1.option.fromNullable((_b = parserServices.program) === null || _b === void 0 ? void 0 : _b.getTypeChecker()); }), fp_ts_1.option.bind("parameterWithVoidOrUknownReturnType", function (_a) { var parserServices = _a.parserServices, typeChecker = _a.typeChecker; return parameterWithVoidOrUknownReturnType(parserServices, typeChecker); }), fp_ts_1.option.bind("argumentWithPureDataTypeReturnType", function () { return argumentWithPureDataTypeReturnType; }), fp_ts_1.option.map(function (_a) { var argumentWithPureDataTypeReturnType = _a.argumentWithPureDataTypeReturnType, parameterWithVoidOrUknownReturnType = _a.parameterWithVoidOrUknownReturnType; return context.report({ node: node, messageId: "discardedDataTypeJsx", data: { jsxAttributeName: node.name.name, expectedReturnType: parameterWithVoidOrUknownReturnType .intrinsicName, dataType: argumentWithPureDataTypeReturnType.symbol.escapedName, }, }); })); }, CallExpression: function (node) { (0, function_1.pipe)(node.arguments, fp_ts_1.array.mapWithIndex(function (index, argumentNode) { return (0, function_1.pipe)(fp_ts_1.option.Do, fp_ts_1.option.bind("argumentType", function () { return typeOfNode(argumentNode); }), fp_ts_1.option.bind("parserServices", parserServices), fp_ts_1.option.bind("typeChecker", function (_a) { var _b; var parserServices = _a.parserServices; return fp_ts_1.option.fromNullable((_b = parserServices.program) === null || _b === void 0 ? void 0 : _b.getTypeChecker()); }), fp_ts_1.option.bind("parameterReturnType", function (_a) { var parserServices = _a.parserServices, typeChecker = _a.typeChecker; var tsNode = parserServices.esTreeNodeToTSNodeMap.get(node); return (0, function_1.pipe)(typeChecker.getContextualTypeForArgumentAtIndex(tsNode, index), fp_ts_1.option.fromNullable, fp_ts_1.option.chain(voidOrUknownReturnType)); }), fp_ts_1.option.bind("argumentReturnType", function (_a) { var argumentType = _a.argumentType; return pureDataReturnType(argumentType); }), fp_ts_1.option.map(function (_a) { var argumentReturnType = _a.argumentReturnType, parameterReturnType = _a.parameterReturnType; context.report({ node: argumentNode, messageId: "discardedDataTypeArgument", data: { functionName: (0, utils_2.prettyPrint)(node.callee), dataType: argumentReturnType.symbol.escapedName, expectedReturnType: parameterReturnType .intrinsicName, }, }); })); })); }, }; }, });