eslint-plugin-fp-ts
Version:
fp-ts ESLint rules
143 lines (142 loc) • 9.03 kB
JavaScript
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,
},
});
}));
}));
},
};
},
});
;