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

Commit

Permalink
Merge branch 'master' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Killian committed Mar 11, 2016
2 parents 155897c + d6fc245 commit b0abc22
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 47 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
Change Log
===

v3.5.0
---
* Stable release containing changes from the last dev release

v3.5.0-dev.1
---
* [new-rule-option] "ignore-pattern" option for `no-unused-variable` rule (#314)
* [bugfix] Fix occassional crash in `no-string-literal` rule (#906)
* [enhancement] Tweak behavior of `member-ordering` rule with regards to arrow function types in interfaces (#226)

Thanks to our contributors!
@arusakov
@Pajn
* @arusakov
* @Pajn

v3.4.0
---
Expand Down
77 changes: 55 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ Supports:
- inline disabling / enabling of rules
- integration with [grunt](https://github.com/palantir/grunt-tslint), [gulp](https://github.com/panuhorsmalahti/gulp-tslint), [atom](https://github.com/AtomLinter/linter-tslint), [sublime](https://packagecontrol.io/packages/SublimeLinter-contrib-tslint), [vim](https://github.com/scrooloose/syntastic), [eclipse](https://github.com/palantir/eclipse-tslint), [webstorm](https://www.jetbrains.com/webstorm/help/tslint.html), and more

Table of Contents
------------

- [Installation](#installation)
- [Usage](#usage)
- [Core Rules](#core-rules)
- [Rule Flags](#rule-flags)
- [Custom Rules](#custom-rules)
- [Development](#development)
- [Creating a new release](#creating-a-new-release)


Installation
------------

Expand Down Expand Up @@ -81,6 +93,14 @@ tslint accepts the following command-line options:
of characters for the max-line-length rule, or what functions to ban
for the ban rule).
-e, --exclude:
A filename or glob which indicates files to exclude from linting.
This option can be supplied multiple times if you need multiple
globs to indicate which files to exclude.
-i, --init:
Generates a tslint.json config file in the current working directory.
-o, --out:
A filename to output the results to. By default, tslint outputs to
stdout, which is usually the console where you're running it from.
Expand All @@ -103,12 +123,20 @@ tslint accepts the following command-line options:
-t, --format:
The formatter to use to format the results of the linter before
outputting it to stdout or the file passed in --out. The core
formatters are prose (human readable) and json (machine readable),
and prose is the default if this option is not used. Additional
formatters can be added and used if the --formatters-dir option
is set.
formatters are prose (human readable), json (machine readable)
and verbose. prose is the default if this option is not used. Additonal
formatters can be added and used if the --formatters-dir option is set.
--test:
Runs tslint on the specified directory and checks if tslint's output matches
the expected output in .lint files. Automatically loads the tslint.json file in the
specified directory as the configuration file for the tests. See the
full tslint documentation for more details on how this can be used to test custom rules.
--help:
-v, --version:
The current version of tslint.
-h, --help:
Prints this help message.
```

Expand Down Expand Up @@ -139,9 +167,11 @@ var ll = new Linter(fileName, contents, options);
var result = ll.lint();
```

Supported Rules
Core Rules
-----

Core rules are included in the `tslint` package.

A sample configuration file with all options is available [here](https://github.com/palantir/tslint/blob/master/docs/sample.tslint.json).

* `align` enforces vertical alignment. Rule options:
Expand Down Expand Up @@ -267,9 +297,9 @@ A sample configuration file with all options is available [here](https://github.
* `"check-type"` checks for whitespace before a variable type specification.
* `"check-typecast"` checks for whitespace between a typecast and its target.

TSLint Rule Flags
Rule Flags
-----
You can enable/disable TSLint or a subset of rules within a file with the following comment rule flags:
You may enable/disable TSLint or a subset of rules within certain lines of a file with the following comment rule flags:

* `/* tslint:disable */` - Disable all rules for the rest of the file
* `/* tslint:enable */` - Enable all rules for the rest of the file
Expand All @@ -280,16 +310,19 @@ Rules flags enable or disable rules as they are parsed. A rule is enabled or dis

For example, imagine the directive `/* tslint:disable */` on the first line of a file, `/* tslint:enable:ban class-name */` on the 10th line and `/* tslint:enable */` on the 20th. No rules will be checked between the 1st and 10th lines, only the `ban` and `class-name` rules will be checked between the 10th and 20th, and all rules will be checked for the remainder of the file.

Custom Rules (from the TypeScript community)
---------------
Custom Rules
------------

#### Custom rule sets from the community

If we don't have all the rules you're looking for, you can either write your own custom rules or use custom rules that others have developed. The repos below are a good source of custom rules:

- [ESLint rules for TSLint](https://github.com/buzinas/tslint-eslint-rules) - Improve your TSLint with the missing ESLint Rules
- [tslint-microsoft-contrib](https://github.com/Microsoft/tslint-microsoft-contrib) - A set of TSLint rules used on some Microsoft projects
- [ng2lint](https://github.com/mgechev/ng2lint) - A set of TSLint rules for static code analysis of Angular 2 TypeScript projects

#### Writing custom rules

Writing Custom Rules
------------
TSLint ships with a set of core rules that can be configured. However, users are also allowed to write their own rules, which allows them to enforce specific behavior not covered by the core of TSLint. TSLint's internal rules are itself written to be pluggable, so adding a new rule is as simple as creating a new rule file named by convention. New rules can be written in either TypeScript or Javascript; if written in TypeScript, the code must be compiled to Javascript before invoking TSLint.

Rule names are always camel-cased and *must* contain the suffix `Rule`. Let us take the example of how to write a new rule to forbid all import statements (you know, *for science*). Let us name the rule file `noImportsRule.ts`. Rules can be referenced in `tslint.json` in their kebab-case forms, so `"no-imports": true` would turn on the rule.
Expand Down Expand Up @@ -337,7 +370,7 @@ Final notes:
- Core rules cannot be overwritten with a custom implementation.
- Custom rules can also take in options just like core rules (retrieved via `this.getOptions()`).

Writing Custom Formatters
Custom Formatters
-----------------
Just like rules, additional formatters can also be supplied to TSLint via `--formatters-dir` on the CLI or `formattersDirectory` option on the library or `grunt-tslint`. Writing a new formatter is simpler than writing a new rule, as shown in the JSON formatter's code.

Expand All @@ -353,12 +386,12 @@ export class Formatter extends Lint.Formatters.AbstractFormatter {
}
```

Such custom formatters can also be written in Javascript. Additionally, formatter files are always named with the suffix `Formatter`, and referenced from TSLint without its suffix.
Such custom formatters can also be written in JavaScript. Formatter files are always named with the suffix `Formatter` and referenced from TSLint without their suffix.

Development
-----------

To develop TSLint simply clone the repository, install dependencies and run grunt:
#### Quick Start

```bash
git clone [email protected]:palantir/tslint.git
Expand All @@ -368,17 +401,17 @@ grunt

#### `next` branch

The [`next` branch of the TSLint repo](https://github.com/palantir/tslint/tree/next) tracks the latest TypeScript
compiler as a `devDependency`. This allows you to develop the linter and its rules against the latest features of the
language. Releases from this branch are published to npm with the `next` dist-tag, so you can get the latest dev
The [`next` branch of this repo](https://github.com/palantir/tslint/tree/next) tracks the latest TypeScript compiler
nightly release as a `devDependency`. This allows you to develop the linter and its rules against the latest features of the
language. Releases from this branch are published to npm with the `next` dist-tag, so you may install the latest dev
version of TSLint via `npm install tslint@next`.

Creating a new Release
Creating a new release
----------------------

1. Bump the version number in `package.json` and `src/tslint.ts`
2. Add a section for the new release in `CHANGELOG.md`
2. Add release notes in `CHANGELOG.md`
3. Run `grunt` to build the latest sources
4. Commit with message "Prepare release <version>"
4. Commit with message `Prepare release <version>`
5. Run `npm publish`
6. Create a git tag for the new release and push it
6. Create a git tag for the new release and push it ([see existing tags here](https://github.com/palantir/tslint/tags))
44 changes: 36 additions & 8 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,31 @@ export const DEFAULT_CONFIG = {
},
};

export function findConfiguration(configFile: string, inputFileLocation: string): any {
const configPath = findConfigurationPath(configFile, inputFileLocation);
const PACKAGE_DEPRECATION_MSG = "Configuration of TSLint via package.json has been deprecated, "
+ "please start using a tslint.json file instead (http://palantir.github.io/tslint/usage/tslint-json/).";

/**
* Searches for a TSLint configuration and returns the data from the config.
* @param configFile A path to a config file, this can be null if the location of a config is not known
* @param inputFileLocation A path to the current file being linted. This is the starting location
* of the search for a configuration.
* @returns A TSLint configuration object
*/
export function findConfiguration(configFile: string, inputFilePath: string): any {
const configPath = findConfigurationPath(configFile, inputFilePath);
return loadConfigurationFromPath(configPath);
}

/**
* Searches for a TSLint configuration and returns the path to it.
* Could return undefined if not configuration is found.
* @param suppliedConfigFilePath A path to an known config file supplied by a user. Pass null here if
* the location of the config file is not known and you want to search for one.
* @param inputFilePath A path to the current file being linted. This is the starting location
* of the search for a configuration.
* @returns A path to a tslint.json file, a path to a package.json file with a tslintConfig field
* or undefined if neither can be found.
*/
export function findConfigurationPath(suppliedConfigFilePath: string, inputFilePath: string) {
if (suppliedConfigFilePath != null) {
if (!fs.existsSync(suppliedConfigFilePath)) {
Expand All @@ -65,15 +85,15 @@ export function findConfigurationPath(suppliedConfigFilePath: string, inputFileP
return suppliedConfigFilePath;
}
} else {
// search for package.json with tslintConfig property
let configFilePath = findup("package.json", { cwd: inputFilePath, nocase: true });
if (configFilePath != null && require(configFilePath).tslintConfig != null) {
// search for tslint.json from input file location
let configFilePath = findup(CONFIG_FILENAME, { cwd: inputFilePath, nocase: true });
if (configFilePath != null && fs.existsSync(configFilePath)) {
return configFilePath;
}

// search for tslint.json from input file location
configFilePath = findup(CONFIG_FILENAME, { cwd: inputFilePath, nocase: true });
if (configFilePath != null && fs.existsSync(configFilePath)) {
// search for package.json with tslintConfig property
configFilePath = findup("package.json", { cwd: inputFilePath, nocase: true });
if (configFilePath != null && require(configFilePath).tslintConfig != null) {
return configFilePath;
}

Expand All @@ -91,10 +111,14 @@ export function findConfigurationPath(suppliedConfigFilePath: string, inputFileP
}
}

/**
* @returns a configuration object for TSLint loaded form the file at configFilePath
*/
export function loadConfigurationFromPath(configFilePath: string) {
if (configFilePath == null) {
return DEFAULT_CONFIG;
} else if (path.basename(configFilePath) === "package.json") {
console.warn(PACKAGE_DEPRECATION_MSG);
return require(configFilePath).tslintConfig;
} else {
let fileData = fs.readFileSync(configFilePath, "utf8");
Expand Down Expand Up @@ -128,6 +152,10 @@ export function getRelativePath(directory: string, relativeTo?: string): string
}

/**
* @param directories A path(s) to a directory of custom rules
* @param relativeTo A path that directories provided are relative to.
* For example, if the directories come from a tslint.json file, this path
* should be the path to the tslint.json file.
* @return An array of absolute paths to directories potentially containing rules
*/
export function getRulesDirectories(directories: string | string[], relativeTo?: string): string[] {
Expand Down
4 changes: 4 additions & 0 deletions src/language/walker/blockScopeAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export abstract class BlockScopeAwareRuleWalker<T, U> extends ScopeAwareRuleWalk
|| (node.parent != null
&& (node.parent.kind === ts.SyntaxKind.TryStatement
|| node.parent.kind === ts.SyntaxKind.IfStatement)
)
|| (node.kind === ts.SyntaxKind.Block && node.parent != null
&& (node.parent.kind === ts.SyntaxKind.Block
|| node.parent.kind === ts.SyntaxKind.SourceFile)
);
}
}
20 changes: 10 additions & 10 deletions src/rules/noUnusedVariableRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker {
private skipParameterDeclaration: boolean;
private skipVariableDeclaration: boolean;

private reactImport: ts.NamespaceImport;
private hasSeenJsxElement: boolean;
private ignorePattern: RegExp;
private isReactUsed: boolean;
private reactImport: ts.NamespaceImport;

constructor(sourceFile: ts.SourceFile, options: Lint.IOptions, languageService: ts.LanguageService) {
super(sourceFile, options);
Expand All @@ -52,6 +53,13 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker {
this.skipParameterDeclaration = false;
this.hasSeenJsxElement = false;
this.isReactUsed = false;

const ignorePatternOption = this.getOptions().filter((option: any) => {
return typeof option === "object" && option["ignore-pattern"] != null;
})[0];
if (ignorePatternOption != null) {
this.ignorePattern = new RegExp(ignorePatternOption["ignore-pattern"]);
}
}

public visitSourceFile(node: ts.SourceFile) {
Expand Down Expand Up @@ -288,14 +296,6 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker {
}

private isIgnored(name: string) {
const options = this.getOptions();
for (const option of options) {
if (typeof option === "object") {
const {"ignore-pattern": ignorePattern} = option;
if (ignorePattern != null) {
return new RegExp(ignorePattern).test(name);
}
}
}
return this.ignorePattern != null && this.ignorePattern.test(name);
}
}
15 changes: 12 additions & 3 deletions src/tslint-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ let processed = optimist
alias: "formatters-dir",
describe: "formatters directory",
},
"e": {
alias: "exclude",
describe: "exclude globs from path expansion",
},
"t": {
alias: "format",
default: "prose",
Expand Down Expand Up @@ -133,6 +137,11 @@ tslint accepts the following commandline options:
of characters for the max-line-length rule, or what functions to ban
for the ban rule).
-e, --exclude:
A filename or glob which indicates files to exclude from linting.
This option can be supplied multiple times if you need multiple
globs to indicate which files to exclude.
-i, --init:
Generates a tslint.json config file in the current working directory.
Expand All @@ -141,9 +150,9 @@ tslint accepts the following commandline options:
stdout, which is usually the console where you're running it from.
-r, --rules-dir:
An additional rules directory, for additional user-created rules.
An additional rules directory, for user-created rules.
tslint will always check its default rules directory, in
node_modules/tslint/build/rules, before checking the user-provided
node_modules/tslint/lib/rules, before checking the user-provided
rules directory, so rules in the user-provided rules directory
with the same name as the base rules will not be loaded.
Expand Down Expand Up @@ -221,5 +230,5 @@ const processFile = (file: string) => {
const files = argv._;

for (const file of files) {
glob.sync(file).forEach(processFile);
glob.sync(file, { ignore: argv.e }).forEach(processFile);
}
7 changes: 5 additions & 2 deletions src/tslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@
import {IFormatter} from "./language/formatter/formatter";
import {RuleFailure} from "./language/rule/rule";
import {getSourceFile} from "./language/utils";
import {findConfiguration as config, getRelativePath} from "./configuration";
import {findConfiguration, findConfigurationPath, getRelativePath, getRulesDirectories, loadConfigurationFromPath} from "./configuration";
import {EnableDisableRulesWalker} from "./enableDisableRules";
import {findFormatter} from "./formatterLoader";
import {ILinterOptions, LintResult} from "./lint";
import {loadRules} from "./ruleLoader";

class Linter {
public static VERSION = "3.5.0-dev.1";
public static findConfiguration = config;
public static findConfiguration = findConfiguration;
public static findConfigurationPath = findConfigurationPath;
public static getRulesDirectories = getRulesDirectories;
public static loadConfigurationFromPath = loadConfigurationFromPath;

private fileName: string;
private source: string;
Expand Down
9 changes: 9 additions & 0 deletions test/rules/no-shadowed-variable/test.ts.lint
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,12 @@ function testParameterDestructuring(
~~~ [shadowed variable: 'pos']
}
}


{
const simpleBlockVar = 3
}

function testSimpleBlockVar() {
const simpleBlockVar = 4
}

0 comments on commit b0abc22

Please sign in to comment.