rxjs-tslint-rules
Version:
TSLint rules for RxJS
146 lines (145 loc) • 6.68 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var Lint = require("tslint");
var tsutils = require("tsutils");
var util_1 = require("../support/util");
var Rule = (function (_super) {
tslib_1.__extends(Rule, _super);
function Rule() {
return _super !== null && _super.apply(this, arguments) || this;
}
Rule.prototype.applyWithProgram = function (sourceFile, program) {
return this.applyWithWalker(new Walker(sourceFile, this.getOptions(), program));
};
Rule.metadata = {
description: "Disallows unsafe first/take usage in effects and epics.",
options: {
properties: {
observable: {
oneOf: [
{ type: "string" },
{ type: "array", items: { type: "string" } }
]
}
},
type: "object"
},
optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n An optional object with an optional `observable` property.\n The property can be specifed as a regular expression string or as an array of words and is used to identify the action observables from which effects and epics are composed."], ["\n An optional object with an optional \\`observable\\` property.\n The property can be specifed as a regular expression string or as an array of words and is used to identify the action observables from which effects and epics are composed."]))),
requiresTypeInfo: true,
ruleName: "rxjs-no-unsafe-first",
type: "functionality",
typescriptOnly: true
};
Rule.FAILURE_STRING = "Unsafe first usage in effects and epics is forbidden";
return Rule;
}(Lint.Rules.TypedRule));
exports.Rule = Rule;
var Walker = (function (_super) {
tslib_1.__extends(Walker, _super);
function Walker(sourceFile, rawOptions, program) {
var _this = _super.call(this, sourceFile, rawOptions, program) || this;
var _a = tslib_1.__read(_this.getOptions(), 1), options = _a[0];
if (options && (options.allow || options.disallow)) {
_this.observableRegExp = new RegExp(options.observable || Walker.DEFAULT_OBSERVABLE, "i");
}
else {
_this.observableRegExp = new RegExp(Walker.DEFAULT_OBSERVABLE, "i");
}
return _this;
}
Walker.prototype.visitCallExpression = function (node) {
var propertyAccessExpression = node.expression;
if (tsutils.isPropertyAccessExpression(propertyAccessExpression)) {
var observableExpression = propertyAccessExpression.expression;
var observableIdentifier = undefined;
if (tsutils.isIdentifier(observableExpression)) {
observableIdentifier = observableExpression;
}
else if (tsutils.isPropertyAccessExpression(observableExpression)) {
observableIdentifier = observableExpression.name;
}
if (observableIdentifier &&
this.observableRegExp.test(observableIdentifier.getText())) {
var propertyName = propertyAccessExpression.name.getText();
var typeChecker = this.getTypeChecker();
var type = typeChecker.getTypeAtLocation(observableExpression);
if (util_1.isReferenceType(type) &&
Walker.METHODS_REGEXP.test(propertyName) &&
util_1.couldBeType(type.target, "Observable")) {
switch (propertyName) {
case "ofType":
this.walkPatchedTypes(node);
break;
case "pipe":
this.walkPipedTypes(node);
break;
default:
break;
}
}
}
}
_super.prototype.visitCallExpression.call(this, node);
};
Walker.prototype.walkPatchedOperators = function (node) {
var name = undefined;
for (var parent_1 = node.parent; parent_1; parent_1 = parent_1.parent) {
if (tsutils.isCallExpression(parent_1)) {
if (name) {
switch (name.getText()) {
case "first":
this.addFailureAtNode(name, Rule.FAILURE_STRING);
break;
case "take":
this.addFailureAtNode(name, Rule.FAILURE_STRING);
break;
case "pipe":
this.walkPipedOperators(parent_1);
break;
default:
break;
}
}
}
else if (tsutils.isPropertyAccessExpression(parent_1)) {
name = parent_1.name;
}
else {
break;
}
}
};
Walker.prototype.walkPatchedTypes = function (node) {
this.walkPatchedOperators(node);
};
Walker.prototype.walkPipedOperators = function (node) {
var _this = this;
node.arguments.forEach(function (arg) {
if (tsutils.isCallExpression(arg)) {
var expression = arg.expression;
if (tsutils.isIdentifier(expression) &&
(expression.getText() === "first" || expression.getText() === "take")) {
_this.addFailureAtNode(expression, Rule.FAILURE_STRING);
}
}
});
};
Walker.prototype.walkPipedTypes = function (node) {
var _this = this;
node.arguments.forEach(function (arg) {
if (tsutils.isCallExpression(arg)) {
var expression = arg.expression;
if (tsutils.isIdentifier(expression) &&
expression.getText() === "ofType") {
_this.walkPipedOperators(node);
}
}
});
};
Walker.METHODS_REGEXP = /(ofType|pipe)/;
Walker.DEFAULT_OBSERVABLE = String.raw(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["action(s|$)?"], ["action(s|\\$)?"])));
return Walker;
}(Lint.ProgramAwareRuleWalker));
exports.Walker = Walker;
var templateObject_1, templateObject_2;