Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Update to latest tsutils #2984

Merged
merged 2 commits into from
Jul 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"resolve": "^1.3.2",
"semver": "^5.3.0",
"tslib": "^1.7.1",
"tsutils": "^2.3.0"
"tsutils": "^2.5.1"
},
"peerDependencies": {
"typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev"
Expand Down
10 changes: 6 additions & 4 deletions src/rules/deprecationRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
* limitations under the License.
*/

import { getDeclarationOfBindingElement, isBindingElement, isIdentifier, isVariableDeclaration, isVariableDeclarationList } from "tsutils";
import {
getDeclarationOfBindingElement, isBindingElement, isIdentifier, isJsDoc, isVariableDeclaration, isVariableDeclarationList,
} from "tsutils";
import * as ts from "typescript";
import * as Lint from "../index";

Expand Down Expand Up @@ -139,13 +141,13 @@ function getDeprecationFromDeclarations(declarations?: ts.Declaration[]): string
declaration = declaration.parent!;
}
for (const child of declaration.getChildren()) {
if (child.kind !== ts.SyntaxKind.JSDocComment) {
if (!isJsDoc(child)) {
break;
}
if ((child as ts.JSDoc).tags === undefined) {
if (child.tags === undefined) {
continue;
}
for (const tag of (child as ts.JSDoc).tags!) {
for (const tag of child.tags) {
if (tag.tagName.text === "deprecated") {
return tag.comment === undefined ? "" : tag.comment;
}
Expand Down
60 changes: 16 additions & 44 deletions src/rules/preferForOfRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,64 +41,36 @@ export class Rule extends Lint.Rules.AbstractRule {
}
}

interface IncrementorState {
indexVariableName: string;
arrayExpr: ts.Expression;
onlyArrayReadAccess: boolean;
}

function walk(ctx: Lint.WalkContext<void>): void {
const { sourceFile } = ctx;
const scopes: IncrementorState[] = [];

return ts.forEachChild(sourceFile, cb);

function cb(node: ts.Node): void {
switch (node.kind) {
case ts.SyntaxKind.ForStatement:
return visitForStatement(node as ts.ForStatement);
case ts.SyntaxKind.Identifier:
return visitIdentifier(node as ts.Identifier);
default:
return ts.forEachChild(node, cb);
let variables: Map<ts.Identifier, utils.VariableInfo> | undefined;

return ts.forEachChild(sourceFile, function cb(node): void {
if (utils.isForStatement(node)) {
visitForStatement(node);
}
}
return ts.forEachChild(node, cb);
});

function visitForStatement(node: ts.ForStatement): void {
const arrayNodeInfo = getForLoopHeaderInfo(node);
if (arrayNodeInfo === undefined) {
return ts.forEachChild(node, cb);
return;
}

const { indexVariable, arrayExpr } = arrayNodeInfo;
const indexVariableName = indexVariable.text;

// store `for` loop state
const state: IncrementorState = { indexVariableName, arrayExpr, onlyArrayReadAccess: true };
scopes.push(state);
ts.forEachChild(node.statement, cb);
scopes.pop();

if (state.onlyArrayReadAccess) {
ctx.addFailure(node.getStart(), node.statement.getFullStart(), Rule.FAILURE_STRING);
if (variables === undefined) {
variables = utils.collectVariableUsage(sourceFile);
}
}

function visitIdentifier(node: ts.Identifier): void {
const state = getStateForVariable(node.text);
if (state !== undefined && state.onlyArrayReadAccess && isNonSimpleIncrementorUse(node, state.arrayExpr, sourceFile)) {
state.onlyArrayReadAccess = false;
}
}

function getStateForVariable(name: string): IncrementorState | undefined {
for (let i = scopes.length - 1; i >= 0; i--) {
const scope = scopes[i];
if (scope.indexVariableName === name) {
return scope;
for (const {location} of variables.get(indexVariable)!.uses) {
if (location.pos < node.initializer!.end || location.pos >= node.end || // bail out on use outside of for loop
location.pos >= node.statement.pos && // only check uses in loop body
isNonSimpleIncrementorUse(location, arrayExpr, sourceFile)) {
return;
}
}
return undefined;
ctx.addFailure(node.getStart(sourceFile), node.statement.pos, Rule.FAILURE_STRING);
}
}

Expand Down
27 changes: 3 additions & 24 deletions src/rules/preferObjectSpreadRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
*/

import {
hasSideEffects, isCallExpression, isIdentifier, isObjectLiteralExpression, isPropertyAccessExpression,
isSpreadElement, SideEffectOptions,
hasSideEffects, isCallExpression, isExpressionValueUsed, isIdentifier, isObjectLiteralExpression,
isPropertyAccessExpression, isSpreadElement, SideEffectOptions,
} from "tsutils";
import * as ts from "typescript";

Expand Down Expand Up @@ -54,35 +54,14 @@ function walk(ctx: Lint.WalkContext<void>) {
!node.arguments.some(isSpreadElement)) {
if (node.arguments[0].kind === ts.SyntaxKind.ObjectLiteralExpression) {
ctx.addFailureAtNode(node, Rule.FAILURE_STRING, createFix(node, ctx.sourceFile));
} else if (isReturnValueUsed(node) && !hasSideEffects(node.arguments[0], SideEffectOptions.Constructor)) {
} else if (isExpressionValueUsed(node) && !hasSideEffects(node.arguments[0], SideEffectOptions.Constructor)) {
ctx.addFailureAtNode(node, Rule.ASSIGNMENT_FAILURE_STRING, createFix(node, ctx.sourceFile));
}
}
return ts.forEachChild(node, cb);
});
}

function isReturnValueUsed(node: ts.Expression): boolean {
const parent = node.parent!;
switch (parent.kind) {
case ts.SyntaxKind.VariableDeclaration:
case ts.SyntaxKind.PropertyAssignment:
case ts.SyntaxKind.PropertyDeclaration:
case ts.SyntaxKind.ReturnStatement:
case ts.SyntaxKind.BindingElement:
case ts.SyntaxKind.ArrayLiteralExpression:
return true;
case ts.SyntaxKind.BinaryExpression:
return (parent as ts.BinaryExpression).operatorToken.kind === ts.SyntaxKind.EqualsToken;
case ts.SyntaxKind.NewExpression:
case ts.SyntaxKind.CallExpression:
return (parent as ts.NewExpression | ts.CallExpression).arguments !== undefined &&
(parent as ts.NewExpression | ts.CallExpression).arguments!.indexOf(node) !== -1;
default:
return false;
}
}

function createFix(node: ts.CallExpression, sourceFile: ts.SourceFile): Lint.Fix {
const args = node.arguments;
const fix = [
Expand Down
23 changes: 23 additions & 0 deletions test/rules/prefer-for-of/test.ts.lint
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,27 @@ for (let i = 0; i < arr.length; i++) {
delete arr[i];
}

for (let i = 0; i < arr.length; ++i) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
{
let i = 1;
let x = i;
let obj = {i, x};
}
i: while(true) {
let obj = {i: 1};
break i;
}

let node = arr[i];
}

function test() {
function print() {
console.log(arr[i])
}
for (var i = 0, i < arr.length, ++i)
print();
}

[0]: Expected a 'for-of' loop instead of a 'for' loop with this simple iteration
6 changes: 6 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,12 @@ tsutils@^2.3.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.4.0.tgz#ad4ce6dba0e5a3edbddf8626b7ca040782189fea"

tsutils@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.5.1.tgz#c2001390c79eec1a5ccfa7ac12d599639683e0cf"
dependencies:
tslib "^1.7.1"

type-detect@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822"
Expand Down