tslint-react-set-state-usage
Version:
TSLint rule for detection non-functional setState statements
85 lines • 3.98 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var ts = require("typescript");
var Lint = require("tslint");
var tsutils_1 = require("tsutils");
var tslintReactSetStateUsageOptions_1 = require("./tslintReactSetStateUsageOptions");
var syntaxWalkerUtils_1 = require("../utils/syntaxWalkerUtils");
var FAILURE_STRING = "Do not pass an object into setState. Use functional setState updater instead.";
var FAILURE_STRING_UPDATER_ONLY = "Do not use callback parameter in setState. Use componentDidUpdate method instead (\"" + tslintReactSetStateUsageOptions_1.OPTION_UPDATER_ONLY + "\" switch).";
var getFailureStringForAccessedMember = function (accessedMember) { return "Do not access 'this." + accessedMember + "' in setState. Use arguments from callback function instead."; };
var Rule = (function (_super) {
__extends(Rule, _super);
function Rule() {
return _super !== null && _super.apply(this, arguments) || this;
}
Rule.prototype.apply = function (sourceFile) {
var options = tslintReactSetStateUsageOptions_1.parseOptions(this.ruleArguments);
return this.applyWithFunction(sourceFile, walk, options);
};
return Rule;
}(Lint.Rules.AbstractRule));
Rule.metadata = {
description: "Requires the setState function to be called with function as the first argument and without 'this.props' nor 'this.state' access within the function.",
optionExamples: [true],
options: {
items: [
{
enum: [tslintReactSetStateUsageOptions_1.OPTION_UPDATER_ONLY],
type: "string",
},
],
maxLength: 1,
minLength: 0,
type: "array",
},
optionsDescription: "Not configurable.",
ruleName: "tslint-react-set-state-usage",
type: "functionality",
typescriptOnly: false,
};
exports.Rule = Rule;
function walk(ctx) {
var sourceFile = ctx.sourceFile, updaterOnly = ctx.options.updaterOnly;
function cb(node) {
if (syntaxWalkerUtils_1.isThisSetState(node)) {
inspectSetStateCall(node, ctx, updaterOnly);
}
else if (isThisState(node) || isThisProps(node)) {
inspectThisPropsOrStateContext(node, ctx);
}
return ts.forEachChild(node, cb);
}
return ts.forEachChild(sourceFile, cb);
}
function inspectSetStateCall(node, ctx, updaterOnly) {
var _a = node.arguments, updaterArgument = _a[0], callbackArgument = _a[1], argumentsCount = _a.length;
// Forbid object literal
var bareUpdaterArgument = syntaxWalkerUtils_1.removeParentheses(updaterArgument);
if (tsutils_1.isObjectLiteralExpression(bareUpdaterArgument)) {
ctx.addFailureAtNode(updaterArgument, FAILURE_STRING);
}
// Forbid second argument if updaterOnly flag set
if (updaterOnly && argumentsCount > 1) {
ctx.addFailureAtNode(callbackArgument, FAILURE_STRING_UPDATER_ONLY);
}
}
function inspectThisPropsOrStateContext(node, ctx) {
var setStateCall = syntaxWalkerUtils_1.getFirstSetStateAncestor(node.parent);
if (setStateCall) {
ctx.addFailureAtNode(node, getFailureStringForAccessedMember(node.name.text));
}
}
var isThisState = function (node) { return syntaxWalkerUtils_1.isThisPropertyAccess(node) && node.name.text === "state"; };
var isThisProps = function (node) { return syntaxWalkerUtils_1.isThisPropertyAccess(node) && node.name.text === "props"; };
//# sourceMappingURL=tslintReactSetStateUsageRule.js.map