Skip to content

Commit

Permalink
Added prefer-readonly rule with fixes (palantir#2896)
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh Goldberg authored and HyphnKnight committed Apr 9, 2018
1 parent 2bcefe5 commit d77a6da
Show file tree
Hide file tree
Showing 22 changed files with 766 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/configs/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const rules = {
"no-var-requires": true,
"only-arrow-functions": true,
"prefer-for-of": true,
"prefer-readonly": true,
"promise-function-async": true,
"typedef": [
true,
Expand Down
2 changes: 1 addition & 1 deletion src/language/rule/abstractRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export abstract class AbstractRule implements IRule {
protected readonly ruleSeverity: RuleSeverity;
public ruleName: string;

constructor(private options: IOptions) {
constructor(private readonly options: IOptions) {
this.ruleName = options.ruleName;
this.ruleArguments = options.ruleArguments;
this.ruleSeverity = options.ruleSeverity;
Expand Down
18 changes: 9 additions & 9 deletions src/language/rule/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export class Replacement {
}

export class RuleFailurePosition {
constructor(private position: number, private lineAndCharacter: ts.LineAndCharacter) {
constructor(private readonly position: number, private readonly lineAndCharacter: ts.LineAndCharacter) {
}

public getPosition() {
Expand Down Expand Up @@ -238,10 +238,10 @@ export type Fix = Replacement | Replacement[];
export type FixJson = ReplacementJson | ReplacementJson[];

export class RuleFailure {
private fileName: string;
private startPosition: RuleFailurePosition;
private endPosition: RuleFailurePosition;
private rawLines: string;
private readonly fileName: string;
private readonly startPosition: RuleFailurePosition;
private readonly endPosition: RuleFailurePosition;
private readonly rawLines: string;
private ruleSeverity: RuleSeverity;

public static compare(a: RuleFailure, b: RuleFailure): number {
Expand All @@ -251,12 +251,12 @@ export class RuleFailure {
return a.startPosition.getPosition() - b.startPosition.getPosition();
}

constructor(private sourceFile: ts.SourceFile,
constructor(private readonly sourceFile: ts.SourceFile,
start: number,
end: number,
private failure: string,
private ruleName: string,
private fix?: Fix) {
private readonly failure: string,
private readonly ruleName: string,
private readonly fix?: Fix) {

this.fileName = sourceFile.fileName;
this.startPosition = this.createFailurePosition(start);
Expand Down
39 changes: 39 additions & 0 deletions src/language/typeUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @license
* Copyright 2017 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as ts from "typescript";

export const typeIsOrHasBaseType = (type: ts.Type, parentType: ts.Type) => {
if (type.symbol === undefined || parentType.symbol === undefined) {
return false;
}

const typeAndBaseTypes = [type];
const ancestorTypes = type.getBaseTypes();

if (ancestorTypes !== undefined) {
typeAndBaseTypes.push(...ancestorTypes);
}

for (const baseType of typeAndBaseTypes) {
if (baseType.symbol !== undefined && baseType.symbol.name === parentType.symbol.name) {
return true;
}
}

return false;
};
2 changes: 1 addition & 1 deletion src/language/walker/blockScopeAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { ScopeAwareRuleWalker } from "./scopeAwareRuleWalker";
* are a superset of regular scopes (new block scopes are created more frequently in a program).
*/
export abstract class BlockScopeAwareRuleWalker<T, U> extends ScopeAwareRuleWalker<T> { // tslint:disable-line:deprecation
private blockScopeStack: U[];
private readonly blockScopeStack: U[];

constructor(sourceFile: ts.SourceFile, options: IOptions) {
super(sourceFile, options);
Expand Down
4 changes: 2 additions & 2 deletions src/language/walker/programAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import { IOptions } from "../rule/rule";
import { RuleWalker } from "./ruleWalker";

export class ProgramAwareRuleWalker extends RuleWalker {
private typeChecker: ts.TypeChecker;
private readonly typeChecker: ts.TypeChecker;

constructor(sourceFile: ts.SourceFile, options: IOptions, private program: ts.Program) {
constructor(sourceFile: ts.SourceFile, options: IOptions, private readonly program: ts.Program) {
super(sourceFile, options);

this.typeChecker = program.getTypeChecker();
Expand Down
10 changes: 5 additions & 5 deletions src/language/walker/ruleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import { SyntaxWalker } from "./syntaxWalker";
import { IWalker } from "./walker";

export class RuleWalker extends SyntaxWalker implements IWalker {
private limit: number;
private options?: any[];
private failures: RuleFailure[];
private ruleName: string;
private readonly limit: number;
private readonly options?: any[];
private readonly failures: RuleFailure[];
private readonly ruleName: string;

constructor(private sourceFile: ts.SourceFile, options: IOptions) {
constructor(private readonly sourceFile: ts.SourceFile, options: IOptions) {
super();

this.failures = [];
Expand Down
2 changes: 1 addition & 1 deletion src/language/walker/scopeAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import { RuleWalker } from "./ruleWalker";
* }
*/
export abstract class ScopeAwareRuleWalker<T> extends RuleWalker {
private scopeStack: T[];
private readonly scopeStack: T[];

constructor(sourceFile: ts.SourceFile, options: IOptions) {
super(sourceFile, options);
Expand Down
2 changes: 1 addition & 1 deletion src/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class Linter {
);
}

constructor(private options: ILinterOptions, private program?: ts.Program) {
constructor(private readonly options: ILinterOptions, private program?: ts.Program) {
if (typeof options !== "object") {
throw new Error(`Unknown Linter options type: ${typeof options}`);
}
Expand Down
2 changes: 1 addition & 1 deletion src/rules/noInferredEmptyObjectTypeRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class Rule extends Lint.Rules.TypedRule {
}

class NoInferredEmptyObjectTypeRule extends Lint.AbstractWalker<void> {
constructor(sourceFile: ts.SourceFile, ruleName: string, private checker: ts.TypeChecker) {
constructor(sourceFile: ts.SourceFile, ruleName: string, private readonly checker: ts.TypeChecker) {
super(sourceFile, ruleName, undefined);
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/noThisAssignmentRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class NoThisAssignmentWalker extends Lint.AbstractWalker<Options> {
ts.forEachChild(sourceFile, this.visitNode);
}

private visitNode = (node: ts.Node): void => {
private readonly visitNode = (node: ts.Node): void => {
if (utils.isVariableDeclaration(node)) {
this.visitVariableDeclaration(node);
}
Expand Down
4 changes: 2 additions & 2 deletions src/rules/noUnsafeAnyRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.TypedRule {
}

class NoUnsafeAnyWalker extends Lint.AbstractWalker<void> {
constructor(sourceFile: ts.SourceFile, ruleName: string, private checker: ts.TypeChecker) {
constructor(sourceFile: ts.SourceFile, ruleName: string, private readonly checker: ts.TypeChecker) {
super(sourceFile, ruleName, undefined);
}

Expand All @@ -57,7 +57,7 @@ class NoUnsafeAnyWalker extends Lint.AbstractWalker<void> {
}

/** Wraps `visitNode` with the correct `this` binding and discards the return value to prevent `forEachChild` from returning early */
private visitNodeCallback = (node: ts.Node) => void this.visitNode(node);
private readonly visitNodeCallback = (node: ts.Node) => void this.visitNode(node);

private visitNode(node: ts.Node, anyOk?: boolean): boolean | undefined {
switch (node.kind) {
Expand Down
2 changes: 1 addition & 1 deletion src/rules/orderedImportsRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ function parseOptions(ruleArguments: any[]): Options {
}

class Walker extends Lint.AbstractWalker<Options> {
private importsBlocks = [new ImportsBlock()];
private readonly importsBlocks = [new ImportsBlock()];
// keep a reference to the last Fix object so when the entire block is replaced, the replacement can be added
private lastFix: Lint.Replacement[] | undefined;
private nextType = ImportType.LIBRARY_IMPORT;
Expand Down
Loading

0 comments on commit d77a6da

Please sign in to comment.