eslint-plugin-rxjs
Version:
ESLint rules for RxJS
111 lines (110 loc) • 4.22 kB
JavaScript
const common_tags_1 = require("common-tags");
const eslint_etc_1 = require("eslint-etc");
const utils_1 = require("../utils");
const defaultOptions = [];
const rule = (0, utils_1.ruleCreator)({
defaultOptions,
meta: {
docs: {
description: "Forbids the application of operators after `takeUntil`.",
recommended: "error",
},
fixable: undefined,
hasSuggestions: false,
messages: {
forbidden: "Applying operators after takeUntil is forbidden.",
},
schema: [
{
properties: {
alias: { type: "array", items: { type: "string" } },
allow: { type: "array", items: { type: "string" } },
},
type: "object",
description: (0, common_tags_1.stripIndent) `
An optional object with optional \`alias\` and \`allow\` properties.
The \`alias\` property is an array containing the names of operators that aliases for \`takeUntil\`.
The \`allow\` property is an array containing the names of the operators that are allowed to follow \`takeUntil\`.`,
},
],
type: "problem",
},
name: "no-unsafe-takeuntil",
create: (context, unused) => {
let checkedOperatorsRegExp = /^takeUntil$/;
const allowedOperators = [
"count",
"defaultIfEmpty",
"endWith",
"every",
"finalize",
"finally",
"isEmpty",
"last",
"max",
"min",
"publish",
"publishBehavior",
"publishLast",
"publishReplay",
"reduce",
"share",
"shareReplay",
"skipLast",
"takeLast",
"throwIfEmpty",
"toArray",
];
const [config = {}] = context.options;
const { alias, allow = allowedOperators } = config;
if (alias) {
checkedOperatorsRegExp = new RegExp(`^(${alias.concat("takeUntil").join("|")})$`);
}
const { couldBeObservable } = (0, eslint_etc_1.getTypeServices)(context);
function checkNode(node) {
const pipeCallExpression = (0, eslint_etc_1.getParent)(node);
if (!pipeCallExpression.arguments ||
!couldBeObservable(pipeCallExpression)) {
return;
}
pipeCallExpression.arguments.reduceRight((state, arg) => {
if (state === "taken") {
return state;
}
if (!(0, eslint_etc_1.isCallExpression)(arg)) {
return "disallowed";
}
let operatorName;
if ((0, eslint_etc_1.isIdentifier)(arg.callee)) {
operatorName = arg.callee.name;
}
else if ((0, eslint_etc_1.isMemberExpression)(arg.callee) &&
(0, eslint_etc_1.isIdentifier)(arg.callee.property)) {
operatorName = arg.callee.property.name;
}
else {
return "disallowed";
}
if (checkedOperatorsRegExp.test(operatorName)) {
if (state === "disallowed") {
context.report({
messageId: "forbidden",
node: arg.callee,
});
}
return "taken";
}
if (!allow.includes(operatorName)) {
return "disallowed";
}
return state;
}, "allowed");
}
return {
[`CallExpression[callee.property.name='pipe'] > CallExpression[callee.name=${checkedOperatorsRegExp}]`]: checkNode,
[`CallExpression[callee.property.name='pipe'] > CallExpression[callee.property.name=${checkedOperatorsRegExp}]`]: checkNode,
};
},
});
module.exports = rule;
;