-
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added rxjs-no-ignored-error rule to not allow .subscribe() calls with…
…out ignoring a second parameter (handling errors), when first parameter is a function or arrow function. This could help to catch uncaught exceptions which could turn SPA apps (like Angular) in unstable state
- Loading branch information
Showing
12 changed files
with
198 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Subject } from "rxjs/Subject"; | ||
import { of } from "rxjs/Observable/of"; | ||
|
||
const subject = new Subject(); | ||
const observable = of([1, 2]); | ||
|
||
observable.subscribe(function () { }, () => 0); | ||
|
||
// When first parameter is not a function, should not trigger an error | ||
observable.subscribe(subject); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"defaultSeverity": "error", | ||
"jsRules": {}, | ||
"rules": { | ||
"rxjs-no-ignored-error": { | ||
"severity": "error" | ||
} | ||
}, | ||
"rulesDirectory": "../../build/rules" | ||
} |
6 changes: 6 additions & 0 deletions
6
fixtures/subscription-without-error-handler/fixture-observable.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { Observable } from "rxjs/Observable"; | ||
import "rxjs/add/observable/of"; | ||
|
||
const observable = Observable.of([1, 2]); | ||
observable.subscribe(() => 0); | ||
|
5 changes: 5 additions & 0 deletions
5
fixtures/subscription-without-error-handler/fixture-subject.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Subject } from "rxjs/Subject"; | ||
|
||
const subject = new Subject<number>(); | ||
subject.subscribe(() => 0); | ||
|
11 changes: 11 additions & 0 deletions
11
fixtures/subscription-without-error-handler/fixture-with-parameter.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Subject } from "rxjs/Subject"; | ||
import { Observable } from "rxjs/Observable"; | ||
import "rxjs/add/observable/of"; | ||
|
||
const observable = Observable.of(1, 2); | ||
const subject = new Subject<number>(); | ||
const handler = () => 0; | ||
// Should mark it as error | ||
observable.subscribe(handler); | ||
// Should be ok - first parameter is not a function | ||
observable.subscribe(subject); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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-observable.ts", "fixture-subject.ts", "fixture-with-parameter.ts"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"defaultSeverity": "error", | ||
"jsRules": {}, | ||
"rules": { | ||
"rxjs-no-ignored-error": { | ||
"severity": "error" | ||
} | ||
}, | ||
"rulesDirectory": "../../build/rules" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/** | ||
* @license Copyright © 2018 Alexey Petushkov. All Rights Reserved. | ||
* 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"; | ||
import { InternalSymbolName } from "typescript"; | ||
|
||
export class Rule extends Lint.Rules.TypedRule { | ||
|
||
public static metadata: Lint.IRuleMetadata = { | ||
description: "Disallows the calling of subscribe without specifying a error handler.", | ||
options: null, | ||
optionsDescription: "Not configurable.", | ||
requiresTypeInfo: true, | ||
ruleName: "rxjs-no-ignored-error", | ||
type: "functionality", | ||
typescriptOnly: true | ||
}; | ||
|
||
public static FAILURE_STRING = "Calling subscribe without a second parameter 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 && this.nodeIsLikelyAFunction(node.arguments[0])) && | ||
node.arguments.length < 2 | ||
) { | ||
this.addFailureAtNode(propertyAccessExpression.name, Rule.FAILURE_STRING); | ||
} | ||
} | ||
}); | ||
|
||
super.visitCallExpression(node); | ||
} | ||
|
||
private nodeIsLikelyAFunction(node: ts.Expression): boolean { | ||
// Fast check | ||
if (node.kind === ts.SyntaxKind.ArrowFunction || | ||
node.kind === ts.SyntaxKind.FunctionExpression | ||
) { | ||
return true; | ||
} | ||
// Check with a type checker | ||
const typeChecker = this.getTypeChecker(); | ||
const type: ts.Type = typeChecker.getTypeAtLocation(node); | ||
return couldBeType(type, "Function") || | ||
couldBeType(type, "ArrowFunction") || | ||
couldBeType(type, InternalSymbolName.Function); | ||
} | ||
} |