Skip to content

Commit

Permalink
feat(no-ignored-subscribe): Add rule.
Browse files Browse the repository at this point in the history
  • Loading branch information
cartant committed Jan 29, 2018
1 parent 3b80b1d commit 37dd346
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 0 deletions.
4 changes: 4 additions & 0 deletions fixtures/subscription-with-arguments/fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { of } from "rxjs/Observable/of";

const observable = of([1, 2]);
observable.subscribe(value => console.log(value));
13 changes: 13 additions & 0 deletions fixtures/subscription-with-arguments/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"]
}
10 changes: 10 additions & 0 deletions fixtures/subscription-with-arguments/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"defaultSeverity": "error",
"jsRules": {},
"rules": {
"rxjs-no-ignored-subscribe": {
"severity": "error"
}
},
"rulesDirectory": "../../build/rules"
}
4 changes: 4 additions & 0 deletions fixtures/subscription-without-arguments/fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { of } from "rxjs/Observable/of";

const observable = of([1, 2]);
observable.subscribe();
13 changes: 13 additions & 0 deletions fixtures/subscription-without-arguments/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"]
}
10 changes: 10 additions & 0 deletions fixtures/subscription-without-arguments/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"defaultSeverity": "error",
"jsRules": {},
"rules": {
"rxjs-no-ignored-subscribe": {
"severity": "error"
}
},
"rulesDirectory": "../../build/rules"
}
25 changes: 25 additions & 0 deletions source/fixtures-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,33 +482,58 @@ describe("fixtures", function (): void {
});

describe("subscription related rules", () => {

describe("subscription-without-error-handler", () => {

it("should effect an 'rxjs-no-ignored-error' error on Observable", () => {
const result = lint("subscription-without-error-handler", "tslint.json", "fixture-observable.ts");
expect(result).to.have.property("errorCount", 1);
expect(result.failures[0]).to.have.property("ruleName", "rxjs-no-ignored-error");
});
});

describe("subscription-without-error-handler", () => {

it("should effect an 'rxjs-no-ignored-error' error on Observable's ancestors", () => {
const result = lint("subscription-without-error-handler", "tslint.json", "fixture-subject.ts");
expect(result).to.have.property("errorCount", 1);
expect(result.failures[0]).to.have.property("ruleName", "rxjs-no-ignored-error");
});
});

describe("subscription-without-error-handler", () => {

it("should effect an 'rxjs-no-ignored-error' error even if first parameter is a funciton variable", () => {
const result = lint("subscription-without-error-handler", "tslint.json", "fixture-with-parameter.ts");
expect(result).to.have.property("errorCount", 1);
expect(result.failures[0]).to.have.property("ruleName", "rxjs-no-ignored-error");
});
});

describe("subscription-with-error-handler", () => {

it("should not produce errors", () => {
const result = lint("subscription-with-error-handler", "tslint.json");
expect(result).to.have.property("errorCount", 0);
});
});

describe("subscription-with-arguments", () => {

it("should not effect an error", () => {
const result = lint("subscription-with-arguments", "tslint.json");
expect(result).to.have.property("errorCount", 0);
});
});

describe("subscription-without-arguments", () => {

it("should effect an 'rxjs-no-ignored-subscribe' error", () => {
const result = lint("subscription-without-arguments", "tslint.json");
expect(result).to.have.property("errorCount", 1);
expect(result.failures[0]).to.have.property("ruleName", "rxjs-no-ignored-subscribe");
});
});
});

function lint(dir: string, configFileName?: string, fixtureFileName?: string): LintResult {
Expand Down
57 changes: 57 additions & 0 deletions source/rules/rxjsNoIgnoredSubscribeRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @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 { couldBeType, isReferenceType } from "../support/util";

export class Rule extends Lint.Rules.TypedRule {

public static metadata: Lint.IRuleMetadata = {
description: "Disallows the calling of subscribe without specifying arguments.",
options: null,
optionsDescription: "Not configurable.",
requiresTypeInfo: true,
ruleName: "rxjs-no-ignored-subscribe",
type: "functionality",
typescriptOnly: true
};

public static FAILURE_STRING = "Calling subscribe without arguments is forbidden";

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

return this.applyWithWalker(new Walker(sourceFile, this.getOptions(), program));
}
}

export class Walker extends Lint.ProgramAwareRuleWalker {

protected visitCallExpression(node: ts.CallExpression): void {

node.forEachChild((child) => {

if (child.kind === ts.SyntaxKind.PropertyAccessExpression) {

const propertyAccessExpression = child as ts.PropertyAccessExpression;
const name = propertyAccessExpression.name.getText();
const typeChecker = this.getTypeChecker();
const type = typeChecker.getTypeAtLocation(propertyAccessExpression.expression);

if ((name === "subscribe") &&
isReferenceType(type) &&
couldBeType(type.target, "Observable") &&
(node.arguments.length === 0)
) {
this.addFailureAtNode(propertyAccessExpression.name, Rule.FAILURE_STRING);
}
}
});

super.visitCallExpression(node);
}
}

0 comments on commit 37dd346

Please sign in to comment.