rxjs-tslint-rules
Version:
TSLint rules for RxJS
152 lines (151 loc) • 6.65 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 the application of operators after takeUntil.",
options: {
properties: {
alias: { type: "array", items: { type: "string" } },
allow: { type: "array", items: { type: "string" } }
},
type: "object"
},
optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n An optional object with optional `alias` and `allow` properties.\n The `alias` property is an array containing the names of operators that aliases for `takeUntil`.\n The `allow` property is an array containing the names of the operators that are allowed to follow `takeUntil`."], ["\n An optional object with optional \\`alias\\` and \\`allow\\` properties.\n The \\`alias\\` property is an array containing the names of operators that aliases for \\`takeUntil\\`.\n The \\`allow\\` property is an array containing the names of the operators that are allowed to follow \\`takeUntil\\`."]))),
requiresTypeInfo: true,
ruleName: "rxjs-no-unsafe-takeuntil",
type: "functionality",
typescriptOnly: true
};
Rule.FAILURE_STRING = "Applying operators after takeUntil is forbidden";
return Rule;
}(Lint.Rules.TypedRule));
exports.Rule = Rule;
var Walker = (function (_super) {
tslib_1.__extends(Walker, _super);
function Walker(sourceFile, options, program) {
var _this = _super.call(this, sourceFile, options, program) || this;
_this.allow = [
"count",
"defaultIfEmpty",
"endWith",
"every",
"finalize",
"finally",
"isEmpty",
"last",
"max",
"min",
"publish",
"publishBehavior",
"publishLast",
"publishReplay",
"reduce",
"share",
"shareReplay",
"skipLast",
"takeLast",
"throwIfEmpty",
"toArray"
];
_this.match = /^takeUntil$/;
var _a = tslib_1.__read(_this.getOptions(), 1), ruleOptions = _a[0];
if (ruleOptions) {
if (ruleOptions.hasOwnProperty("alias")) {
_this.match = new RegExp("^(" + ruleOptions.alias.concat("takeUntil").join("|") + ")$");
}
if (ruleOptions.hasOwnProperty("allow")) {
_this.allow = ruleOptions.allow;
}
}
return _this;
}
Walker.prototype.visitCallExpression = function (node) {
var propertyAccessExpression = node.expression;
if (tsutils.isPropertyAccessExpression(propertyAccessExpression)) {
var expression = propertyAccessExpression.expression;
var propertyName = propertyAccessExpression.name.getText();
var typeChecker = this.getTypeChecker();
var type = typeChecker.getTypeAtLocation(expression);
if (util_1.isReferenceType(type) && util_1.couldBeType(type.target, "Observable")) {
if (this.match.test(propertyName)) {
this.walkPatchedOperators(node, propertyAccessExpression.name);
}
else if (propertyName === "pipe") {
this.walkPipedOperators(node);
}
}
}
_super.prototype.visitCallExpression.call(this, node);
};
Walker.prototype.walkPatchedOperators = function (node, identifier) {
var name = undefined;
for (var parent_1 = node.parent; parent_1; parent_1 = parent_1.parent) {
if (tsutils.isCallExpression(parent_1)) {
if (name) {
if (name.getText() === "pipe") {
this.walkPipedOperators(parent_1, identifier);
}
else if (this.allow.indexOf(name.getText()) === -1) {
var typeChecker = this.getTypeChecker();
var type = typeChecker.getTypeAtLocation(parent_1);
if (util_1.isReferenceType(type) &&
util_1.couldBeType(type.target, "Observable")) {
this.addFailureAtNode(identifier, Rule.FAILURE_STRING);
return;
}
}
}
}
else if (tsutils.isPropertyAccessExpression(parent_1)) {
name = parent_1.name;
}
else {
break;
}
}
};
Walker.prototype.walkPipedOperators = function (node, identifier) {
var _this = this;
if (identifier === void 0) { identifier = null; }
var some = function (args) {
return args.some(function (arg) {
if (tsutils.isCallExpression(arg) &&
tsutils.isIdentifier(arg.expression) &&
_this.allow.indexOf(arg.expression.getText()) !== -1) {
return false;
}
return true;
});
};
if (identifier) {
if (some(node.arguments.slice(0))) {
this.addFailureAtNode(identifier, Rule.FAILURE_STRING);
}
}
else {
node.arguments.forEach(function (arg, index) {
if (tsutils.isCallExpression(arg) &&
tsutils.isIdentifier(arg.expression) &&
_this.match.test(arg.expression.text)) {
var after_1 = node.arguments.slice(index + 1);
if (some(after_1)) {
_this.addFailureAtNode(arg.expression, Rule.FAILURE_STRING);
}
}
});
}
};
return Walker;
}(Lint.ProgramAwareRuleWalker));
var templateObject_1;