Skip to content

Commit

Permalink
feat(no-ignored-notifier): Add rule.
Browse files Browse the repository at this point in the history
  • Loading branch information
cartant committed Nov 17, 2018
1 parent abe28fb commit c728059
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"test": "yarn run lint && yarn run test:build && yarn run test:mocha && yarn run test:tslint-v5 && yarn run test:tslint-v6 && yarn run test:tslint-v6-compat",
"test:build": "yarn run test:clean && tsc -p tsconfig.json",
"test:clean": "rimraf build",
"test:debug": "tslint --test ./test/v6/fixtures/issues/61/tslint.json",
"test:debug": "tslint --test ./test/v6/fixtures/no-ignored-notifier/**/tslint.json",
"test:issues": "yarn run test:clean && tsc -p tsconfig.json && tslint --test ./test/v6/fixtures/issues/**/tslint.json",
"test:mocha": "mocha build/**/*-spec.js",
"test:tslint-v5": "yarn --cwd ./test/v5 install && yarn --cwd ./test/v5 upgrade && tslint --test ./test/v5/fixtures/**/tslint.json",
Expand Down
68 changes: 68 additions & 0 deletions source/rules/rxjsNoIgnoredNotifierRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @license Use of this source code is governed by an MIT-style license that
* can be found in the LICENSE file at https://github.com/cartant/rxjs-tslint-rules
*/
/*tslint:disable:no-use-before-declare*/

import * as Lint from "tslint";
import * as ts from "typescript";
import * as tsutils from "tsutils";
import { tsquery } from "@phenomnomnominal/tsquery";
import { couldBeType } from "../support/util";

export class Rule extends Lint.Rules.TypedRule {

public static metadata: Lint.IRuleMetadata = {
description: "Disallows observables not composed from the notifier.",
options: null,
optionsDescription: "Not configurable.",
requiresTypeInfo: true,
ruleName: "rxjs-no-ignored-notifier",
type: "functionality",
typescriptOnly: true
};

public static FAILURE_STRING = "Ignoring the notifier is forbidden";

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {

const failures: Lint.RuleFailure[] = [];
const typeChecker = program.getTypeChecker();

const identifiers = tsquery(
sourceFile,
`CallExpression Identifier[name=/(repeatWhen|retryWhen)/]`
);
identifiers.forEach(identifier => {
const callExpression = identifier.parent as ts.CallExpression;
if (callExpression.arguments.length > 0) {
const type = typeChecker.getTypeAtLocation(callExpression);
if (couldBeType(type, "MonoTypeOperatorFunction")) {
const [arg] = callExpression.arguments;
if (tsutils.isArrowFunction(arg) || tsutils.isFunctionExpression(arg)) {
let fail = false;
const [parameter] = arg.parameters;
if (parameter) {
fail = tsquery(
arg.body,
`Identifier[name=${parameter.name.getText()}]`
).length === 0;
} else {
fail = true;
}
if (fail) {
failures.push(new Lint.RuleFailure(
sourceFile,
identifier.getStart(),
identifier.getStart() + identifier.getWidth(),
Rule.FAILURE_STRING,
this.ruleName
));
}
}
}
}
});
return failures;
}
}
86 changes: 86 additions & 0 deletions test/v6/fixtures/no-ignored-notifier/default/fixture.ts.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { of, range } from "rxjs";
import { repeatWhen, retryWhen } from "rxjs/operators";

const source = of(42);

const a = source.pipe(
repeatWhen(notifications => notifications)
);

const b = source.pipe(
repeatWhen(
function (notifications) {
return notifications;
}
)
);

const c = source.pipe(
repeatWhen(notifications => range(0, 3))
~~~~~~~~~~ [no-ignored-notifier]
);

const d = source.pipe(
repeatWhen(() => range(0, 3))
~~~~~~~~~~ [no-ignored-notifier]
);

const e = source.pipe(
repeatWhen(
~~~~~~~~~~ [no-ignored-notifier]
function (notifications) {
return range(0, 3);
}
)
);

const f = source.pipe(
repeatWhen(
~~~~~~~~~~ [no-ignored-notifier]
function () {
return range(0, 3);
}
)
);

const g = source.pipe(
retryWhen(errors => errors)
);

const h = source.pipe(
retryWhen(
function (errors) {
return errors;
}
)
);

const i = source.pipe(
retryWhen(errors => range(0, 3))
~~~~~~~~~ [no-ignored-notifier]
);

const j = source.pipe(
retryWhen(() => range(0, 3))
~~~~~~~~~ [no-ignored-notifier]
);

const k = source.pipe(
retryWhen(
~~~~~~~~~ [no-ignored-notifier]
function (errors) {
return range(0, 3);
}
)
);

const l = source.pipe(
retryWhen(
~~~~~~~~~ [no-ignored-notifier]
function () {
return range(0, 3);
}
)
);

[no-ignored-notifier]: Ignoring the notifier is forbidden
13 changes: 13 additions & 0 deletions test/v6/fixtures/no-ignored-notifier/default/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"baseUrl": ".",
"lib": ["es2015"],
"noEmit": true,
"paths": {
"rxjs": ["../../node_modules/rxjs"]
},
"skipLibCheck": true,
"target": "es5"
},
"include": ["fixture.ts"]
}
8 changes: 8 additions & 0 deletions test/v6/fixtures/no-ignored-notifier/default/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"defaultSeverity": "error",
"jsRules": {},
"rules": {
"rxjs-no-ignored-notifier": { "severity": "error" }
},
"rulesDirectory": "../../../../../build/rules"
}

0 comments on commit c728059

Please sign in to comment.