rxjs-tslint-rules
Version:
TSLint rules for RxJS
213 lines (212 loc) • 11.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Rule = void 0;
var tslib_1 = require("tslib");
var fs = tslib_1.__importStar(require("fs"));
var path = tslib_1.__importStar(require("path"));
var Lint = tslib_1.__importStar(require("tslint"));
var tsutils = tslib_1.__importStar(require("tsutils"));
var ts = tslib_1.__importStar(require("typescript"));
var peer = tslib_1.__importStar(require("../support/peer"));
var added_walker_1 = require("../support/added-walker");
var used_walker_1 = require("../support/used-walker");
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 = {
deprecationMessage: peer.v6 && !peer.compat ? peer.v6NotNeededMessage : undefined,
description: "Enforces the importation of patched observables and operators used in the module.",
options: {
properties: {
allowElsewhere: { type: "boolean" },
allowUnused: { type: "boolean" },
file: { type: "string" },
},
type: "object",
},
optionsDescription: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n An optional object with the property `file`.\n This the path of the module - relative to the `tsconfig.json` - that imports the patched observables and operators.\n If `file` is specified, the `allowElsewhere` and `allowUnused` options can be used to configure whether or not\n patched imports are allowed in other files and whether or not unused patched imports are allowed.\n Both `allowElsewhere` and `allowUnused` default to `false`.\n If not specified, patched observables and operators must be imported in the modules in which they are used."], ["\n An optional object with the property \\`file\\`.\n This the path of the module - relative to the \\`tsconfig.json\\` - that imports the patched observables and operators.\n If \\`file\\` is specified, the \\`allowElsewhere\\` and \\`allowUnused\\` options can be used to configure whether or not\n patched imports are allowed in other files and whether or not unused patched imports are allowed.\n Both \\`allowElsewhere\\` and \\`allowUnused\\` default to \\`false\\`.\n If not specified, patched observables and operators must be imported in the modules in which they are used."]))),
requiresTypeInfo: true,
ruleName: "rxjs-add",
type: "functionality",
typescriptOnly: true,
};
Rule.FAILURE_STRING = "RxJS add import is missing";
return Rule;
}(Lint.Rules.TypedRule));
exports.Rule = Rule;
var Walker = (function (_super) {
tslib_1.__extends(Walker, _super);
function Walker() {
return _super !== null && _super.apply(this, arguments) || this;
}
Walker.initCaseSensitive = function () {
try {
fs.statSync(__filename.toLowerCase());
return false;
}
catch (_a) {
return true;
}
};
Walker.prototype.onSourceFileEnd = function () {
var _this = this;
var _a = this, addedObservables = _a.addedObservables, addedOperators = _a.addedOperators;
var failure = Rule.FAILURE_STRING;
var _b = tslib_1.__read(this.getOptions(), 1), options = _b[0];
if (options && options.file) {
var walker = this.walkFile(options.file);
addedObservables = walker.addedObservables;
addedOperators = walker.addedOperators;
failure = Rule.FAILURE_STRING + " from " + options.file;
if (this.normalizeFile(this.sourceFilePath) ===
this.normalizeFile(walker.sourceFilePath)) {
if (!options.allowUnused) {
var program = this.getProgram();
var sourceFiles = program.getSourceFiles();
var usedObservables_1 = {};
var usedOperators_1 = {};
var _loop_1 = function (i, length_1) {
var sourceFile = sourceFiles[i];
if (!sourceFile["isDeclarationFile"]) {
var sourceFileWalker_1 = new used_walker_1.UsedWalker(sourceFile, {
disabledIntervals: [],
ruleArguments: [],
ruleName: this_1.getRuleName(),
ruleSeverity: "error",
}, program);
sourceFileWalker_1.walk(sourceFile);
Object.keys(sourceFileWalker_1.usedObservables).forEach(function (key) {
sourceFileWalker_1.usedObservables[key].forEach(function (node) {
used_walker_1.UsedWalker.add(usedObservables_1, key, node);
});
});
Object.keys(sourceFileWalker_1.usedOperators).forEach(function (key) {
sourceFileWalker_1.usedOperators[key].forEach(function (node) {
used_walker_1.UsedWalker.add(usedOperators_1, key, node);
});
});
}
};
var this_1 = this;
for (var i = 0, length_1 = sourceFiles.length; i < length_1; ++i) {
_loop_1(i, length_1);
}
Object.keys(addedObservables).forEach(function (key) {
if (!usedObservables_1[key]) {
addedObservables[key].forEach(function (node) {
return _this.addFailureAtNode(tsutils.isImportDeclaration(node)
? node.moduleSpecifier
: node, "Unused patched observable in " + options.file + ": " + key);
});
}
});
Object.keys(addedOperators).forEach(function (key) {
if (!usedOperators_1[key]) {
addedOperators[key].forEach(function (node) {
return _this.addFailureAtNode(tsutils.isImportDeclaration(node)
? node.moduleSpecifier
: node, "Unused patched operator in " + options.file + ": " + key);
});
}
});
}
}
else {
if (!options.allowElsewhere) {
Object.keys(this.addedObservables).forEach(function (key) {
_this.addedObservables[key].forEach(function (node) {
return _this.addFailureAtNode(tsutils.isImportDeclaration(node) ? node.moduleSpecifier : node, "Patched observables are forbidden outside of " + options.file + ": " + key);
});
});
Object.keys(this.addedOperators).forEach(function (key) {
_this.addedOperators[key].forEach(function (node) {
return _this.addFailureAtNode(tsutils.isImportDeclaration(node) ? node.moduleSpecifier : node, "Patched operators are forbidden outside of " + options.file + ": " + key);
});
});
}
}
}
Object.keys(this.usedObservables).forEach(function (key) {
if (!addedObservables[key]) {
_this.usedObservables[key].forEach(function (node) {
return _this.addFailureAtNode(node, failure + ": " + key);
});
}
});
Object.keys(this.usedOperators).forEach(function (key) {
if (!addedOperators[key]) {
_this.usedOperators[key].forEach(function (node) {
return _this.addFailureAtNode(node, failure + ": " + key);
});
}
});
};
Walker.prototype.findSourceFile = function (file) {
var program = this.getProgram();
var rootFiles = program.getRootFileNames();
var fileDirCandidates = new Set();
var _loop_2 = function (i, length_2) {
var configFile = ts.findConfigFile(this_2.normalizeFile(path.dirname(rootFiles[i])), ts.sys.fileExists);
if (configFile && !fileDirCandidates.has(path.dirname(configFile))) {
var resolvedFile_1 = this_2.normalizeFile(path.resolve(path.dirname(configFile), file));
var sourceFile = program.getSourceFileByPath(resolvedFile_1);
if (sourceFile) {
return { value: sourceFile };
}
if (!Walker.isCaseSensitive) {
var found = program.getSourceFiles().find(function (file) {
return file["path"].toLowerCase() === resolvedFile_1.toLowerCase();
});
if (found) {
return { value: found };
}
}
fileDirCandidates.add(path.dirname(configFile));
}
};
var this_2 = this;
for (var i = 0, length_2 = rootFiles.length; i < length_2; ++i) {
var state_1 = _loop_2(i, length_2);
if (typeof state_1 === "object")
return state_1.value;
}
if (fileDirCandidates.size === 0) {
throw new Error("Cannot find 'tsconfig.json'");
}
else {
throw new Error("Cannot find an import of '" + file + "' from any of these locations: " +
("[" + Array.from(fileDirCandidates.values()).join(", ") + "]. Has it been imported?"));
}
};
Walker.prototype.normalizeFile = function (file) {
var normalized = ts["normalizeSlashes"](file);
return ts.sys.useCaseSensitiveFileNames
? normalized
: normalized.toLowerCase();
};
Walker.prototype.walkFile = function (file) {
var program = this.getProgram();
var fileWalker = Walker.fileWalkerCache.get(program);
if (!fileWalker) {
var sourceFile = this.findSourceFile(file);
fileWalker = new added_walker_1.AddedWalker(sourceFile, {
disabledIntervals: [],
ruleArguments: [],
ruleName: this.getRuleName(),
ruleSeverity: "error",
}, program);
fileWalker.walk(sourceFile);
Walker.fileWalkerCache.set(program, fileWalker);
}
return fileWalker;
};
Walker.isCaseSensitive = Walker.initCaseSensitive();
Walker.fileWalkerCache = new Map();
return Walker;
}(used_walker_1.UsedWalker));
var templateObject_1;