Skip to content

Commit cca31ef

Browse files
committed
fix(rules): add doc to utils and fix partial migration issue
1 parent 3650a6a commit cca31ef

File tree

2 files changed

+36
-10
lines changed

2 files changed

+36
-10
lines changed

src/migrateStaticObservableMethodsRule.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
// Original author Bowen Ni
2-
// Modifications mgechev.
3-
41
import * as Lint from 'tslint';
52
import * as tsutils from 'tsutils';
63
import * as ts from 'typescript';
74
import { subtractSets, concatSets, isObservable, returnsObservable, computeInsertionIndexForImports } from './utils';
5+
86
/**
9-
* A typed TSLint rule that inspects observable chains using patched RxJs
10-
* operators and turns them into a pipeable operator chain.
7+
* A typed TSLint rule that inspects observable
8+
* static methods and turns them into function calls.
119
*/
1210
export class Rule extends Lint.Rules.TypedRule {
1311
static metadata: Lint.IRuleMetadata = {
@@ -30,7 +28,9 @@ export class Rule extends Lint.Rules.TypedRule {
3028
const sourceFile = ctx.sourceFile;
3129
const typeChecker = program.getTypeChecker();
3230
const insertionStart = computeInsertionIndexForImports(sourceFile);
33-
let rxjsOperatorImports = findImportedRxjsOperators(sourceFile);
31+
let rxjsOperatorImports = new Set<OperatorWithAlias>(
32+
Array.from(findImportedRxjsOperators(sourceFile)).map(o => OPERATOR_WITH_ALIAS_MAP[o])
33+
);
3434

3535
function checkPatchableOperatorUsage(node: ts.Node) {
3636
if (!isRxjsStaticOperatorCallExpression(node, typeChecker)) {
@@ -47,7 +47,7 @@ export class Rule extends Lint.Rules.TypedRule {
4747
const operatorName = OPERATOR_RENAMES[name] || name;
4848
const start = propAccess.getStart(sourceFile);
4949
const end = propAccess.getEnd();
50-
const operatorsToImport = new Set<string>([operatorName]);
50+
const operatorsToImport = new Set<OperatorWithAlias>([OPERATOR_WITH_ALIAS_MAP[operatorName]]);
5151
const operatorsToAdd = subtractSets(operatorsToImport, rxjsOperatorImports);
5252
const imports = createImportReplacements(operatorsToAdd, insertionStart);
5353
rxjsOperatorImports = concatSets(rxjsOperatorImports, operatorsToAdd);
@@ -137,9 +137,9 @@ function operatorAlias(operator: string) {
137137
return 'observable' + operator[0].toUpperCase() + operator.substring(1, operator.length);
138138
}
139139

140-
function createImportReplacements(operatorsToAdd: Set<string>, startIndex: number): Lint.Replacement[] {
141-
return [...Array.from(operatorsToAdd.values())].map(operator =>
142-
Lint.Replacement.appendText(startIndex, `\nimport {${operator} as ${operatorAlias(operator)}} from 'rxjs';\n`)
140+
function createImportReplacements(operatorsToAdd: Set<OperatorWithAlias>, startIndex: number): Lint.Replacement[] {
141+
return [...Array.from(operatorsToAdd.values())].map(tuple =>
142+
Lint.Replacement.appendText(startIndex, `\nimport {${tuple.operator} as ${tuple.alias}} from 'rxjs';\n`)
143143
);
144144
}
145145

@@ -180,3 +180,15 @@ const OPERATOR_RENAMES: { [key: string]: string } = {
180180
if: 'iif',
181181
fromPromise: 'from'
182182
};
183+
184+
type OperatorWithAlias = { operator: string; alias: string };
185+
type OperatorWithAliasMap = { [key: string]: OperatorWithAlias };
186+
187+
const OPERATOR_WITH_ALIAS_MAP: OperatorWithAliasMap = Array.from(RXJS_OPERATORS).reduce((a, o) => {
188+
const operatorName = OPERATOR_RENAMES[o] || o;
189+
a[operatorName] = {
190+
operator: operatorName,
191+
alias: operatorAlias(operatorName)
192+
};
193+
return a;
194+
}, {});

src/utils.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
import * as ts from 'typescript';
22
import * as tsutils from 'tsutils';
33

4+
/**
5+
* Returns a new Set that contains elements present in the {@link source} but
6+
* not present in {@link target}
7+
*/
48
export function subtractSets<T>(source: Set<T>, target: Set<T>): Set<T> {
59
return new Set([...Array.from(source.values())].filter(x => !target.has(x)));
610
}
711

12+
/**
13+
* Returns a new Set that contains union of the two input sets.
14+
*/
815
export function concatSets<T>(set1: Set<T>, set2: Set<T>): Set<T> {
916
return new Set([...Array.from(set1.values()), ...Array.from(set2.values())]);
1017
}
1118

19+
/**
20+
* Returns true if the {@link type} is an Observable or one of its sub-classes.
21+
*/
1222
export function isObservable(type: ts.Type, tc: ts.TypeChecker): boolean {
1323
if (tsutils.isTypeReference(type)) {
1424
type = type.target;
@@ -32,6 +42,10 @@ export function returnsObservable(node: ts.CallLikeExpression, tc: ts.TypeChecke
3242
return isObservable(returnType, tc);
3343
}
3444

45+
/**
46+
* Returns the index to be used for inserting import statements potentially
47+
* after a leading file overview comment (separated from the file with \n\n).
48+
*/
3549
export function computeInsertionIndexForImports(sourceFile: ts.SourceFile): number {
3650
const comments = ts.getLeadingCommentRanges(sourceFile.getFullText(), 0) || [];
3751
if (comments.length > 0) {

0 commit comments

Comments
 (0)