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

Commit

Permalink
Rewrite rule and test it out on tslint
Browse files Browse the repository at this point in the history
  • Loading branch information
andy-hanson committed Apr 8, 2017
1 parent 46e24da commit 761e596
Show file tree
Hide file tree
Showing 40 changed files with 384 additions and 158 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"compile:scripts": "tsc -p scripts",
"compile:test": "tsc -p test",
"lint": "npm-run-all -p lint:global lint:from-bin",
"lint:global": "tslint --project test/tsconfig.json --format stylish # test includes 'src' too",
"lint:from-bin": "node bin/tslint --project test/tsconfig.json --format stylish",
"lint:global": "tslint --project test/tsconfig.json --format stylish --type-check # test includes 'src' too",
"lint:from-bin": "node bin/tslint --project test/tsconfig.json --format stylish --type-check",
"test": "npm-run-all test:pre -p test:mocha test:rules",
"test:pre": "cd ./test/config && npm install",
"test:mocha": "mocha --reporter spec --colors \"build/test/**/*Tests.js\"",
Expand Down
2 changes: 1 addition & 1 deletion src/configs/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export const RULES_EXCLUDED_FROM_ALL_CONFIG =
// Exclude typescript-only rules from jsRules, otherwise it's identical.
export const jsRules: { [key: string]: any } = {};
for (const key in rules) {
if (!Object.prototype.hasOwnProperty.call(rules, key)) {
if (!(Object.prototype.hasOwnProperty.call(rules, key) as boolean)) {
continue;
}

Expand Down
12 changes: 8 additions & 4 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* limitations under the License.
*/

// tslint:disable no-unsafe-any (TODO)

import findup = require("findup-sync");
import * as fs from "fs";
import * as path from "path";
Expand Down Expand Up @@ -99,7 +101,7 @@ export function findConfiguration(configFile: string | null, inputFilePath: stri
loadResult.results = loadConfigurationFromPath(path);
return loadResult;
} catch (error) {
throw new FatalError(`Failed to load ${path}: ${error.message}`, error);
throw new FatalError(`Failed to load ${path}: ${(error as Error).message}`, error as Error);
}
}

Expand Down Expand Up @@ -157,8 +159,8 @@ export function loadConfigurationFromPath(configFilePath?: string): IConfigurati
let rawConfigFile: any;
if (path.extname(resolvedConfigFilePath) === ".json") {
const fileContent = stripComments(fs.readFileSync(resolvedConfigFilePath)
.toString()
.replace(/^\uFEFF/, ""));
.toString()
.replace(/^\uFEFF/, ""));
rawConfigFile = JSON.parse(fileContent);
} else {
rawConfigFile = require(resolvedConfigFilePath);
Expand Down Expand Up @@ -252,7 +254,7 @@ export function extendConfigurationFile(targetConfig: IConfigurationFile,
};
}

function getHomeDir() {
function getHomeDir(): string | undefined {
const environment = global.process.env;
const paths = [
environment.USERPROFILE,
Expand All @@ -266,6 +268,8 @@ function getHomeDir() {
return homePath;
}
}

return undefined;
}

// returns the absolute path (contrary to what the name implies)
Expand Down
2 changes: 1 addition & 1 deletion src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class FatalError extends Error {
}

export function isError(possibleError: any): possibleError is Error {
return possibleError != null && possibleError.message !== undefined;
return possibleError != null && (possibleError as Error).message !== undefined;
}

export function showWarningOnce(message: string) {
Expand Down
14 changes: 7 additions & 7 deletions src/formatterLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@

import * as fs from "fs";
import * as path from "path";
import {FormatterFunction} from "./index";
import {FormatterFunction, FormatterStatic} from "./index";
import {camelize} from "./utils";

const moduleDirectory = path.dirname(module.filename);
const CORE_FORMATTERS_DIRECTORY = path.resolve(moduleDirectory, ".", "formatters");

export function findFormatter(name: string | FormatterFunction, formattersDirectory?: string) {
export function findFormatter(name: string | FormatterFunction, formattersDirectory?: string): FormatterStatic | undefined {
if (typeof name === "function") {
return name;
return name as any as FormatterStatic;
} else if (typeof name === "string") {
name = name.trim();
const camelizedName = camelize(`${name}Formatter`);
Expand All @@ -52,24 +52,24 @@ export function findFormatter(name: string | FormatterFunction, formattersDirect
}
}

function loadFormatter(...paths: string[]) {
function loadFormatter(...paths: string[]): FormatterStatic | undefined {
const formatterPath = paths.reduce((p, c) => path.join(p, c), "");
const fullPath = path.resolve(moduleDirectory, formatterPath);

if (fs.existsSync(`${fullPath}.js`)) {
const formatterModule = require(fullPath);
return formatterModule.Formatter;
return formatterModule.Formatter; // tslint:disable-line no-unsafe-any
}

return undefined;
}

function loadFormatterModule(name: string) {
function loadFormatterModule(name: string): FormatterStatic | undefined {
let src: string;
try {
src = require.resolve(name);
} catch (e) {
return undefined;
}
return require(src).Formatter;
return require(src).Formatter; // tslint:disable-line no-unsafe-any
}
4 changes: 4 additions & 0 deletions src/language/formatter/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export interface IFormatterMetadata {

export type ConsumerType = "human" | "machine";

export interface FormatterStatic {
new(): IFormatter;
}

export interface IFormatter {
/**
* Formats linter results
Expand Down
3 changes: 2 additions & 1 deletion src/language/walker/blockScopeAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import * as ts from "typescript";

import {IOptions} from "../rule/rule";
import {isBlockScopeBoundary} from "../utils";
import {ScopeAwareRuleWalker} from "./scopeAwareRuleWalker";

Expand All @@ -27,7 +28,7 @@ import {ScopeAwareRuleWalker} from "./scopeAwareRuleWalker";
export abstract class BlockScopeAwareRuleWalker<T, U> extends ScopeAwareRuleWalker<T> {
private blockScopeStack: U[];

constructor(sourceFile: ts.SourceFile, options?: any) {
constructor(sourceFile: ts.SourceFile, options: IOptions) {
super(sourceFile, options);

// initialize with global scope if file is not a module
Expand Down
3 changes: 2 additions & 1 deletion src/language/walker/scopeAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@

import * as ts from "typescript";

import {IOptions} from "../rule/rule";
import {isScopeBoundary} from "../utils";
import {RuleWalker} from "./ruleWalker";

export abstract class ScopeAwareRuleWalker<T> extends RuleWalker {
private scopeStack: T[];

constructor(sourceFile: ts.SourceFile, options?: any) {
constructor(sourceFile: ts.SourceFile, options: IOptions) {
super(sourceFile, options);

// initialize with global scope if file is not a module
Expand Down
2 changes: 1 addition & 1 deletion src/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class Linter {
if (typeof options !== "object") {
throw new Error("Unknown Linter options type: " + typeof options);
}
if ((options as any).configuration != null) {
if ((options as any).configuration != null) { // tslint:disable-line no-unsafe-any
throw new Error("ILinterOptions does not contain the property `configuration` as of version 4. " +
"Did you mean to pass the `IConfigurationFile` object to lint() ? ");
}
Expand Down
6 changes: 4 additions & 2 deletions src/ruleLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function loadRules(ruleOptionsList: IOptions[],
} else {
const ruleSpecificList = enableDisableRules || [];
ruleOptions.disabledIntervals = buildDisabledIntervalsFromSwitches(ruleSpecificList);
rules.push(new (Rule as any)(ruleOptions));
rules.push(new (Rule as any)(ruleOptions) as IRule);

if (Rule.metadata && Rule.metadata.deprecationMessage) {
showWarningOnce(`${Rule.metadata.ruleName} is deprecated. ${Rule.metadata.deprecationMessage}`);
Expand Down Expand Up @@ -127,9 +127,11 @@ function loadRule(directory: string, ruleName: string) {
const fullPath = path.join(directory, ruleName);
if (fs.existsSync(fullPath + ".js")) {
const ruleModule = require(fullPath);
// tslint:disable no-unsafe-any
if (ruleModule && ruleModule.Rule) {
return ruleModule.Rule;
}
// tslint:enable no-unsafe-any
}
return undefined;
}
Expand All @@ -155,7 +157,7 @@ function loadCachedRule(directory: string, ruleName: string, isCustomPath = fals

let Rule: typeof AbstractRule | null = null;
if (absolutePath != null) {
Rule = loadRule(absolutePath, ruleName);
Rule = loadRule(absolutePath, ruleName); // tslint:disable-line no-unsafe-any
}
cachedRules.set(fullPath, Rule);
return Rule;
Expand Down
2 changes: 1 addition & 1 deletion src/rules/banRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class Rule extends Lint.Rules.AbstractRule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
const options = this.getOptions();
const banFunctionWalker = new BanFunctionWalker(sourceFile, options);
const functionsToBan = options.ruleArguments;
const functionsToBan = options.ruleArguments as string[][];
if (functionsToBan !== undefined) {
functionsToBan.forEach((f) => banFunctionWalker.addBannedFunction(f));
}
Expand Down
2 changes: 1 addition & 1 deletion src/rules/curlyRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class CurlyWalker extends Lint.RuleWalker {
constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) {
super(sourceFile, options);

const args = this.getOptions();
const args = this.getOptions() as any[];

this.optionIgnoreSameLine = args.indexOf(OPTION_IGNORE_SAME_LINE) > -1;
}
Expand Down
2 changes: 1 addition & 1 deletion src/rules/cyclomaticComplexityRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class Rule extends Lint.Rules.AbstractRule {

private get threshold(): number {
if (this.ruleArguments[0] !== undefined) {
return this.ruleArguments[0];
return this.ruleArguments[0] as number;
}
return Rule.DEFAULT_THRESHOLD;
}
Expand Down
2 changes: 1 addition & 1 deletion src/rules/fileHeaderRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class Rule extends Lint.Rules.AbstractRule {
const { text } = sourceFile;
// ignore shebang if it exists
const offset = text.startsWith("#!") ? text.indexOf("\n") + 1 : 0;
if (!textHasComment(text, offset, new RegExp(this.ruleArguments[0]))) {
if (!textHasComment(text, offset, new RegExp(this.ruleArguments[0] as string))) {
return [new Lint.RuleFailure(sourceFile, offset, offset, Rule.FAILURE_STRING, this.ruleName)];
}
return [];
Expand Down
7 changes: 3 additions & 4 deletions src/rules/maxClassesPerFileRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,12 @@ class MaxClassesPerFileWalker extends Lint.RuleWalker {
constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) {
super(sourceFile, options);

if (options.ruleArguments[0] === undefined
|| isNaN(options.ruleArguments[0])
|| options.ruleArguments[0] < 1) {
const option = options.ruleArguments[0] as number | undefined;

if (option === undefined || isNaN(option) || option < 1) {
this.maxClassCount = 1;
} else {
this.maxClassCount = options.ruleArguments[0];
this.maxClassCount = option;
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/rules/maxFileLineCountRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ export class Rule extends Lint.Rules.AbstractRule {
}

public isEnabled(): boolean {
return super.isEnabled() && this.ruleArguments[0] > 0;
return super.isEnabled() && this.ruleArguments[0] as number > 0;
}

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
const ruleFailures: Lint.RuleFailure[] = [];
const ruleArguments = this.getOptions().ruleArguments;
const lineLimit: number = ruleArguments[0];
const lineCount: number = sourceFile.getLineStarts().length;
const lineLimit = ruleArguments[0] as number;
const lineCount = sourceFile.getLineStarts().length;
const disabledIntervals = this.getOptions().disabledIntervals;

if (lineCount > lineLimit && disabledIntervals.length === 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/rules/maxLineLengthRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.AbstractRule {
}

public isEnabled(): boolean {
return super.isEnabled() && this.ruleArguments[0] > 0;
return super.isEnabled() && this.ruleArguments[0] as number > 0;
}

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
Expand Down
7 changes: 4 additions & 3 deletions src/rules/memberOrderingRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export class MemberOrderingWalker extends Lint.RuleWalker {

constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) {
super(sourceFile, options);
this.opts = parseOptions(this.getOptions());
this.opts = parseOptions(this.getOptions() as any[]);
}

public visitClassDeclaration(node: ts.ClassDeclaration) {
Expand Down Expand Up @@ -310,11 +310,11 @@ function caseInsensitiveLess(a: string, b: string) {
}

function memberKindForConstructor(access: Access): MemberKind {
return (MemberKind as any)[access + "Constructor"];
return (MemberKind as any)[access + "Constructor"] as MemberKind;
}

function memberKindForMethodOrField(access: Access, membership: "Static" | "Instance", kind: "Method" | "Field"): MemberKind {
return (MemberKind as any)[access + membership + kind];
return (MemberKind as any)[access + membership + kind] as MemberKind;
}

const allAccess: Access[] = ["public", "protected", "private"];
Expand Down Expand Up @@ -398,6 +398,7 @@ function getOptionsJson(allOptions: any[]): { order: MemberCategoryJson[], alpha
return { order: convertFromOldStyleOptions(allOptions), alphabetize: false }; // presume allOptions to be string[]
}

// tslint:disable-next-line no-unsafe-any
return { order: categoryFromOption(firstOption[OPTION_ORDER]), alphabetize: !!firstOption[OPTION_ALPHABETIZE] };
}
function categoryFromOption(orderOption: {}): MemberCategoryJson[] {
Expand Down
5 changes: 3 additions & 2 deletions src/rules/noConsecutiveBlankLinesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ export class Rule extends Lint.Rules.AbstractRule {
* Disable the rule if the option is provided but non-numeric or less than the minimum.
*/
public isEnabled(): boolean {
return super.isEnabled() && (!this.ruleArguments[0] || this.ruleArguments[0] > 0);
const option = this.ruleArguments[0] as number | undefined;
return super.isEnabled() && (!option || option > 0);
}

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
const limit: number = this.ruleArguments[0] || Rule.DEFAULT_ALLOWED_BLANKS;
const limit = this.ruleArguments[0] as number | undefined || Rule.DEFAULT_ALLOWED_BLANKS;
return this.applyWithFunction(sourceFile, walk, limit);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/rules/noConsoleRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class Rule extends BanRule.Rule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
const options = this.getOptions();
const consoleBanWalker = new BanRule.BanFunctionWalker(sourceFile, this.getOptions());
for (const option of options.ruleArguments) {
for (const option of options.ruleArguments as string[]) {
consoleBanWalker.addBannedFunction(["console", option]);
}
return this.applyWithWalker(consoleBanWalker);
Expand Down
2 changes: 1 addition & 1 deletion src/rules/noFloatingPromisesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class Rule extends Lint.Rules.TypedRule {
public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
const walker = new NoFloatingPromisesWalker(sourceFile, this.getOptions(), program);

for (const className of this.ruleArguments) {
for (const className of this.ruleArguments as string[]) {
walker.addPromiseClass(className);
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/noImportSideEffectRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "import with explicit side-effect";

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
const patternConfig = this.ruleArguments[this.ruleArguments.length - 1];
const patternConfig = this.ruleArguments[this.ruleArguments.length - 1] as { "ignore-module": string };
const ignorePattern = patternConfig && new RegExp(patternConfig[OPTION_IGNORE_MODULE]);
return this.applyWithFunction(sourceFile, walk, ignorePattern);
}
Expand Down
6 changes: 3 additions & 3 deletions src/rules/noInferredEmptyObjectTypeRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ class NoInferredEmptyObjectTypeRule extends Lint.ProgramAwareRuleWalker {
public visitNewExpression(node: ts.NewExpression): void {
const nodeTypeArgs = node.typeArguments;
let isObjectReference: (o: ts.TypeReference) => boolean;
if ((ts as any).TypeFlags.Reference != null) {
if ((ts.TypeFlags as any).Reference != null) {
// typescript 2.0.x specific code
isObjectReference = (o: ts.TypeReference) => isTypeFlagSet(o, (ts as any).TypeFlags.Reference);
isObjectReference = (o: ts.TypeReference) => isTypeFlagSet(o, (ts.TypeFlags as any).Reference as ts.TypeFlags);
} else {
isObjectReference = (o: ts.TypeReference) => isTypeFlagSet(o, ts.TypeFlags.Object);
}
Expand Down Expand Up @@ -87,7 +87,7 @@ class NoInferredEmptyObjectTypeRule extends Lint.ProgramAwareRuleWalker {
let isAnonymous: boolean;
if (ts.ObjectFlags == null) {
// typescript 2.0.x specific code
isAnonymous = isTypeFlagSet(objType, (ts as any).TypeFlags.Anonymous);
isAnonymous = isTypeFlagSet(objType, (ts.TypeFlags as any).Anonymous as ts.TypeFlags);
} else {
isAnonymous = isObjectFlagSet(objType, ts.ObjectFlags.Anonymous);
}
Expand Down
Loading

0 comments on commit 761e596

Please sign in to comment.