diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 6179039e4b1..00000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "eslint:recommended", - "env": { - "node": true - }, - "rules": { - "comma-dangle": ["error", "always-multiline"] - } -} diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..d21f050c4e8 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ +#### PR checklist + +- [ ] Addresses an existing issue: #0000 +- [ ] New feature, bugfix, or enhancement + - [ ] Includes tests +- [ ] Documentation update + +#### What changes did you make? + +(give an overview) + +#### Is there anything you'd like reviewers to focus on? + +(optional) diff --git a/.gitignore b/.gitignore index 6cebaca4f5b..7b4feb5fd1c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,12 @@ /build/ /docs/site/ /scripts/*.js +/scripts/*.js.map /lib/ +/test/executable/tslint.json node_modules/ tscommand*.txt +npm-debug.log # created by grunt-ts for faster compiling typings/.basedir.ts diff --git a/.npmignore b/.npmignore index fe6cf8753f5..d76bbd86186 100644 --- a/.npmignore +++ b/.npmignore @@ -11,10 +11,10 @@ .vscode appveyor.yml circle.yml -Gruntfile.js tslint.json /build/ /docs/ +/scripts/ /src/ /test/ tscommand*.txt diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000000..a3906afe938 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,89 @@ +{ + "version": "0.1.0", + "configurations": [ + { + "name": "Debug CLI", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/build/src/tslint-cli.js", + "stopOnEntry": false, + "args": [], + "cwd": "${workspaceRoot}", + "preLaunchTask": "tsc", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "console": "internalConsole", + "sourceMaps": true, + "outFiles": [], + "outDir": "${workspaceRoot}/build" + }, + { + "name": "Debug Mocha Tests", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "stopOnEntry": false, + "args": ["--reporter", "spec", "--colors", "--no-timeouts", "build/test/**/*Tests.js", "build/test/assert.js"], + "cwd": "${workspaceRoot}", + "preLaunchTask": "tsc", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "console": "internalConsole", + "sourceMaps": true, + "outFiles": [], + "outDir": "${workspaceRoot}/build" + }, + { + "name": "Debug Rule Tests", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/test/ruleTestRunner.ts", + "stopOnEntry": false, + "args": ["run", "test"], + "cwd": "${workspaceRoot}", + "preLaunchTask": "tsc", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "console": "internalConsole", + "sourceMaps": true, + "outFiles": [], + "outDir": "${workspaceRoot}/build" + }, + { + "name": "Debug Document Generation", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/scripts/buildDocs.ts", + "stopOnEntry": false, + "args": ["run", "test"], + "cwd": "${workspaceRoot}", + "preLaunchTask": "tsc", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "console": "internalConsole", + "sourceMaps": true, + "outFiles": [], + "outDir": "${workspaceRoot}/build" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 214c37a251d..aa07ee373b5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,5 +17,8 @@ "build", "lib", "node_modules" - ] + ], + + // Always use project's provided typescript compiler version + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5a7f3b3425a..f3aafc3f3d3 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,19 +1,11 @@ -// Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team -// ${file}: the current opened file -// ${fileBasename}: the current opened file's basename -// ${fileDirname}: the current opened file's dirname -// ${fileExtname}: the current opened file's extension -// ${cwd}: the current working directory of the spawned process - -// A task runner that calls scripts/tsc-wrapper.js. The wrapper script traverses -// up the file system until a valid `tsconfig.json` is found, and runs `tsc` from -// node_modules with that path as the root -{ - "version": "0.1.0", - "command": "${workspaceRoot}/scripts/tsc-wrapper.js", - "isShellCommand": true, - "showOutput": "silent", - "args": ["${workspaceRoot}", "${fileDirname}"], - "problemMatcher": "$tsc" -} +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "tsc", + "isShellCommand": true, + "args": ["-w", "-p", "test"], + "showOutput": "silent", + "isWatching": true, + "problemMatcher": "$tsc-watch" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e6e000ccc5d..849622ab17d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,139 @@ Change Log === +v4.0.2 +--- +* [enhancement] Don't exit when a rule can't be found. Print as a warning instead (#1771) +* [api-change] Allow 3rd party apps to see exception when the config is invalid (#1764) +* [bugfix] Don't flag a property named as empty string as not needing quotes in an object literal (#1762) +* [bugfix] Report correct number of fixes done by --fix (#1767) +* [bugfix] Fix false positives and exceptions in `prefer-for-of` (#1758) +* [bugfix] Fix `adjacent-overload-signatures` false positive when a static function has the same name (#1772) + +Thanks to our contributors! +* @gustavderdrache + +v4.0.1 +--- +* [bugfix] Removed `no-unused-variable` rule from recommended config, as it was causing spurious deprecation warnings. + +v4.0.0-dev.2 +--- +* Include latest v4.0.0 changes + +v4.0.0 +--- +* **BREAKING CHANGES** + * [api-change] Minor changes to the library API. See this PR for changes and upgrade instructions (#1720) + * [removed-rule] Removed `no-unreachable` rule; covered by compiler (#661) + * [enhancement] Changed order of applied configuration files for the `extends` array to make it more intuitive. (#1503) + * [enhancement] Changed TypeScript peer dependency to >= 2.0.0 (#1710) +* [new-rule] `completed-docs` rule added (#1644) +* [new-fixer] `ordered-imports` auto fixed (#1640) +* [new-fixer] `arrow-parens` auto fixed (#1731) +* [rule-change] `indent` rule now ignores template strings (#1611) +* [new-rule-option] `object-literal-key-quotes` adds the options `consistent` and `consistent-as-needed` (#1733) +* [enhancement] `--fix` option added to automatically fix selected rules (#1697) +* [enhancement] Updated recommend rules (#1717) +* [enhancement] `adjacent-overload-signatures` now works with classes, source files, modules, and namespaces (#1707) +* [enhancement] Users are notified if they are using an old TSLint version (#1696) +* [bugfix] Lint `.jsx` files if `jsRules` are configured (#1714) +* [bugfix] Command line glob patterns now handle single quotes (#1679) + +Thanks to our contributors! +* Andrii Dieiev +* Andy +* Chris Barr +* Davie Schoots +* Jordan Hawker +* Josh Goldberg +* Stepan Riha +* Yuichi Nukiyama + +v4.0.0-dev.1 +--- +* **BREAKING CHANGES** + * [enhancement] The `semicolon` rule now disallows semicolons in multi-line bound class methods + (to get the v3 behavior, use the `ignore-bound-class-methods` option) (#1643) + * [removed-rule] Removed `use-strict` rule (#678) + * [removed-rule] Removed `label-undefined` rule; covered by compiler (#1614) + * [enhancement] Renamed `no-constructor-vars` to `no-parameter-properties` (#1296) + * [rule-change] The `orderedImports` rule now sorts relative modules below non-relative modules (#1640) +* **Deprecated** + * [deprecated] `no-unused-variable` rule. This is checked by the TypeScript v2 compiler using the flags [`--noUnusedParameters` and `--noUnusedLocals`](https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#flag-unused-declarations-with---nounusedparameters-and---nounusedlocals). (#1481) +* [enhancement] Lint .js files (#1515) +* [new-fixer] `no-var-keyword` replaces `var` with `let` (#1547) +* [new-fixer] `trailing-comma` auto fixed (#1546) +* [new-fixer] `no-unused-variable` auto fixed for imports (#1568) +* [new-fixer] `semicolon` auto fixed (#1423) +* [new-rule] `max-classes-per-file` rule added (#1666) +* [new-rule-option] `no-consecutive-blank-lines` rule now accepts a number value indicating max blank lines (#1650) +* [new-rule-option] `ordered-inputs` rule option `input-sources-order` accepts value `any` (#1602) +* [bugfix] `no-empty` rule fixed when parameter has readonly modifier +* [bugfix] `no-namespace` rule: do not flag nested or .d.ts namespaces (#1571) + +Thanks to our contributors! + +* Alex Eagle +* Andrii Dieiev +* Ben Coveney +* Boris Aranovich +* Chris Barr +* Cyril Gandon +* Evgeniy Zhukovskiy +* Jay Anslow +* Kunal Marwaha +* Martin Probst +* Mingye Wang +* Raghav Katyal +* Sean Dawson +* Yuichi Nukiyama +* jakpaw + +v4.0.0-dev.0 +--- +* **BREAKING CHANGES** + * [enhancement] Drop support for configuration via package.json (#1579) + * [removed-rule] Removed `no-duplicate-key` rule; covered by compiler (#1109) + * [enhancement] Call formatter once for all file results. Format output may be different (#656) + * [rule-change] `trailing-comma` supports function declarations, expressions, and types (#1486) + * [rule-change] `object-literal-sort-keys` now sorts quoted keys (#1529) + * [rule-change] `semicolon` now processes type aliases (#1475) + * [rule-change] `no-var-keyword` now rejects `export var` statements (#1256) + * [rule-change] `semicolon` now requires semicolon for function declaration with no body (#1447) +* [new-formatter] `fileslist` formatter writes a list of files with errors without position or error type specifics (#1558) +* [new-rule] `cyclomaticComplexity`, enforces a threshold of cyclomatic complexity.] (#1464) +* [new-rule] `prefer-for-of`, which errors when `for(var x of y)` can be used instead of `for(var i = 0; i < y.length; i++)` (#1335) +* [new-rule] `array-type`, which can require using either `T[]' or 'Array' for arrays (#1498) +* [rule-change] `object-literal-sort-keys` checks multiline objects only (#1642) +* [rule-change] `ban` rule now can ban global functions (#327) +* [bugfix] always write lint result, even if using formatter (#1353) +* [bugfix] npm run test:bin fails on Windows (#1635) +* [bugfix] Don't enforce trailing spaces on newlines in typedef-whitespace rule (#1531) +* [bugfix] `jsdoc` rule should not match arbitrary comments (#1543) +* [bugfix] `one-line` rule errors when declaring wildcard ambient modules (#1425) + +Thanks to our contributors! + +* Alex Eagle +* Andrii Dieiev +* Andy Hanson +* Ben Coveney +* Boris Aranovich +* Chris Barr +* Christian Dreher +* Claas Augner +* Josh Goldberg +* Martin Probst +* Mike Deverell +* Nina Hartmann +* Satoshi Amemiya +* Scott Wu +* Steve Van Opstal +* Umar Bolatov +* Vladimir Matveev +* Yui + v3.15.1 --- * Enabled additional rules in `tslint:latest` configuration (#1506) @@ -80,6 +213,10 @@ Thanks to our contributors! * @janaagaard75 * @mprobst +v3.12.0-dev.2 +--- +* [enhancement] Support TypeScript v2.0.0-dev builds + v3.12.1 --- * Stable release containing changes from the last dev release (v3.12.0-dev.1) diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index e8acf9fa740..00000000000 --- a/Gruntfile.js +++ /dev/null @@ -1,127 +0,0 @@ -"use strict"; - -var checkBinTest; -if (process.platform === "win32") { - checkBinTest = []; -} else { - checkBinTest = ["run:testBin"]; -} - -module.exports = function (grunt) { - grunt.initConfig({ - pkg: grunt.file.readJSON("package.json"), - - eslint: { - target: [ - "Gruntfile.js", - "test/files/formatters/*.js", - ], - }, - - clean: { - core: ["lib/**/*.js", "lib/**/*.d.ts"], - scripts: ["scripts/*.js"], - test: ["build/", "test/config/node_modules/"], - }, - - mochaTest: { - test: { - options: { - reporter: "spec", - }, - src: ["build/test/**/*Tests.js", "build/test/assert.js"], - }, - }, - - run: { - testBin: { - cmd: "./test/check-bin.sh", - options: {quiet: Infinity}, - }, - testRules: { - args: ["./build/test/ruleTestRunner.js"], - }, - docs: { - cmd: "node", - args: ["buildDocs.js"], - options: {cwd: "./scripts/"}, - }, - }, - - tslint: { - src: [ - "src/*.ts", - "src/configs/**/*.ts", - "src/formatters/**/*.ts", - "src/language/**/*.ts", - "src/rules/**/*.ts", - "src/test/**/*.ts", - ], - scripts: [ - "scripts/**/*.ts", - ], - test: [ - "test/**/*.ts", - "!test/**/*.test.ts", - "!test/typings/**/*.ts", - ], - }, - - ts: { - core: { - tsconfig: "src/tsconfig.json", - }, - scripts: { - tsconfig: "scripts/tsconfig.json", - }, - test: { - tsconfig: "test/tsconfig.json", - }, - }, - - "npm-command": { - test: { - options: { - cwd: "./test/config", - }, - }, - }, - }); - - // load NPM tasks - grunt.loadNpmTasks("grunt-contrib-clean"); - grunt.loadNpmTasks("grunt-eslint"); - grunt.loadNpmTasks("grunt-mocha-test"); - grunt.loadNpmTasks("grunt-run"); - grunt.loadNpmTasks("grunt-tslint"); - grunt.loadNpmTasks("grunt-ts"); - grunt.loadNpmTasks("grunt-npm-command"); - - // register custom tasks - grunt.registerTask("core", [ - "clean:core", - "ts:core", - "tslint:src", - ]); - grunt.registerTask("scripts", [ - "clean:scripts", - "ts:scripts", - "tslint:scripts", - ]); - grunt.registerTask("test", [ - "clean:test", - "npm-command:test", - "ts:test", - "tslint:test", - "mochaTest", - "run:testRules", - ].concat(checkBinTest)); - // generates new docs metadata files - grunt.registerTask("docs", [ - "default", - "run:docs", - ]); - - // create default task - grunt.registerTask("default", ["eslint", "core", "scripts", "test"]); -}; diff --git a/LICENSE b/LICENSE index 402690572fd..8dada3edaf5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -179,7 +178,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" + boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -187,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2014 Palantir Technologies + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 6a8c8323968..662d9c150e9 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ TSLint supports: - custom formatters (failure reporters) - inline disabling / enabling of rules - configuration presets (`tslint:latest`, `tslint-react`, etc.) & composition +- automatic fixing of formatting & style violations - integration with [msbuild](https://github.com/joshuakgoldberg/tslint.msbuild), [grunt](https://github.com/palantir/grunt-tslint), [gulp](https://github.com/panuhorsmalahti/gulp-tslint), [atom](https://github.com/AtomLinter/linter-tslint), [eclipse](https://github.com/palantir/eclipse-tslint), [emacs](http://flycheck.org), [sublime](https://packagecontrol.io/packages/SublimeLinter-contrib-tslint), [vim](https://github.com/scrooloose/syntastic), [visual studio](https://visualstudiogallery.msdn.microsoft.com/6edc26d4-47d8-4987-82ee-7c820d79be1d), [vscode](https://marketplace.visualstudio.com/items?itemName=eg2.tslint), [webstorm](https://www.jetbrains.com/webstorm/help/tslint.html), and more Table of Contents @@ -22,6 +23,7 @@ Table of Contents - [Installation](#installation) - [Usage](#usage) - [Core Rules](#core-rules) +- [Core Formatters](#core-formatters) - [Rule Flags](#rule-flags) - [Custom Rules](#custom-rules) - [Development](#development) @@ -78,9 +80,15 @@ The configuration file specifies which rules are enabled and their options. Thes "extends": "tslint:latest", "rules": { /* - * Any rules specified here will override those from the base config we are extending + * Any rules specified here will override those from the base config we are extending. */ - "no-constructor-vars": true + "curly": true + }, + "jsRules": { + /* + * Any rules specified here will override those from the base config we are extending. + */ + "curly": true }, "rulesDirectory": [ /* @@ -107,16 +115,17 @@ Options: ``` -c, --config configuration file +-e, --exclude exclude globs from path expansion +--fix fixes linting errors for select rules (this may overwrite linted files) --force return status code 0 even if there are lint errors -h, --help display detailed help -i, --init generate a tslint.json config file in the current working directory -o, --out output file +--project tsconfig.json file -r, --rules-dir rules directory -s, --formatters-dir formatters directory --e, --exclude exclude globs from path expansion --t, --format output format (prose, json, verbose, pmd, msbuild, checkstyle) [default: "prose"] +-t, --format output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist) [default: "prose"] --test test that tslint produces the correct output for the specified directory ---project path to tsconfig.json file --type-check enable type checking when linting a project -v, --version current version ``` @@ -144,6 +153,9 @@ tslint accepts the following command-line options: This option can be supplied multiple times if you need multiple globs to indicate which files to exclude. +--fix: + Fixes linting errors for select rules. This may overwrite linted files. + --force: Return status code 0 even if there are any lint errors. Useful while running as npm script. @@ -202,9 +214,9 @@ tslint accepts the following command-line options: #### Library -```javascript -const Linter = require("tslint"); -const fs = require("fs"); +```js +import { Linter } from "tslint"; +import * as fs from "fs"; const fileName = "Specify file name"; const configuration = { @@ -229,7 +241,7 @@ const result = linter.lint(); To enable rules that work with the type checker, a TypeScript program object must be passed to the linter when using the programmatic API. Helper functions are provided to create a program from a `tsconfig.json` file. A project directory can be specified if project files do not lie in the same directory as the `tsconfig.json` file. -```javascript +```js const program = Linter.createProgram("tsconfig.json", "projectDir/"); const files = Linter.getFileNames(program); const results = files.map(file => { @@ -246,22 +258,19 @@ Core Rules ----- [back to ToC ↑](#table-of-contents) +_Rules_ encode logic for syntactic & semantic checks of TypeScript source code. + [See the TSLint website for a list of core rules included in the `tslint` package.] (http://palantir.github.io/tslint/rules/) Core Formatters ----- +[back to ToC ↑](#table-of-contents) -Formatters are used to format the results of the linter before outputting it to stdout or -the configured output file. The core formatters are: +_Formatters_ allow for transformation of lint results into various forms before outputting to stdout or a file. -- __prose__: human readable (default) -- __json__: machine readable -- __verbose__: human readable (includes rule names) -- __pmd__ -- __msbuild__ -- __checkstyle__ -- __vso__ +[See the TSLint website for a list of core formatters included in the `tslint` package.] +(http://palantir.github.io/tslint/formatters/) Rule Flags ----- @@ -303,26 +312,30 @@ If we don't have all the rules you're looking for, you can either write your own 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. +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 are referenced in `tslint.json` with their kebab-cased identifer, so `"no-imports": true` would configure the rule. -Now, let us first write the rule in TypeScript. A few things to note: -- We import `tslint/lib/lint` to get the whole `Lint` namespace instead of just the `Linter` class. -- The exported class must always be named `Rule` and extend from `Lint.Rules.AbstractRule`. +__Important conventions__: +* Rule identifiers are always kebab-cased. +* Rule files are always camel-cased (`camelCasedRule.ts`). +* Rule files *must* contain the suffix `Rule`. +* The exported class must always be named `Rule` and extend from `Lint.Rules.AbstractRule`. -```typescript +Now, let us first write the rule in TypeScript: + +```ts import * as ts from "typescript"; -import * as Lint from "tslint/lib/lint"; +import { Rules, RuleFailure, RuleWalker } from "tslint"; -export class Rule extends Lint.Rules.AbstractRule { +export class Rule extends Rules.AbstractRule { public static FAILURE_STRING = "import statement forbidden"; - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + public apply(sourceFile: ts.SourceFile): RuleFailure[] { return this.applyWithWalker(new NoImportsWalker(sourceFile, this.getOptions())); } } // The walker takes care of all the work. -class NoImportsWalker extends Lint.RuleWalker { +class NoImportsWalker extends RuleWalker { public visitImportDeclaration(node: ts.ImportDeclaration) { // create a failure at the current position this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); @@ -338,11 +351,13 @@ Given a walker, TypeScript's parser visits the AST using the visitor pattern. So We still need to hook up this new rule to TSLint. First make sure to compile `noImportsRule.ts`: ```bash -tsc -m commonjs --noImplicitAny noImportsRule.ts node_modules/tslint/lib/tslint.d.ts +tsc --noImplicitAny noImportsRule.ts ``` Then, if using the CLI, provide the directory that contains this rule as an option to `--rules-dir`. If using TSLint as a library or via `grunt-tslint`, the `options` hash must contain `"rulesDirectory": "..."`. If you run the linter, you'll see that we have now successfully banned all import statements via TSLint! +Finally, enable each custom rule in your [`tslint.json` config file](https://palantir.github.io/tslint/usage/tslint-json/) config file. + Final notes: - Core rules cannot be overwritten with a custom implementation. @@ -356,11 +371,11 @@ Just like rules, additional formatters can also be supplied to TSLint via `--for ```typescript import * as ts from "typescript"; -import * as Lint from "tslint/lib/lint"; +import { Formatters, RuleFailure } from "tslint"; -export class Formatter extends Lint.Formatters.AbstractFormatter { - public format(failures: Lint.RuleFailure[]): string { - var failuresJSON = failures.map((failure: Lint.RuleFailure) => failure.toJson()); +export class Formatter extends Formatters.AbstractFormatter { + public format(failures: RuleFailure[]): string { + var failuresJSON = failures.map((failure: RuleFailure) => failure.toJson()); return JSON.stringify(failuresJSON); } } @@ -375,9 +390,10 @@ Development #### Quick Start ```bash -git clone git@github.com:palantir/tslint.git +git clone git@github.com:palantir/tslint.git --config core.autocrlf=input --config core.eol=lf npm install -grunt +npm run compile +npm run test ``` #### `next` branch @@ -393,7 +409,7 @@ Creating a new release 1. Bump the version number in `package.json` and `src/tslintMulti.ts` 2. Add release notes in `CHANGELOG.md` -3. Run `grunt` to build the latest sources +3. `npm run verify` to build the latest sources 4. Commit with message `Prepare release ` 5. Run `npm publish` 6. Create a git tag for the new release and push it ([see existing tags here](https://github.com/palantir/tslint/tags)) diff --git a/TypeScriptNotice.txt b/TypeScriptNotice.txt deleted file mode 100644 index 3707ec2b970..00000000000 --- a/TypeScriptNotice.txt +++ /dev/null @@ -1,172 +0,0 @@ -/****************************************************************************** -This project incorporates material and code from the Microsoft TypeScript project: -http://www.typescriptlang.org/ licensed under the Apache Version 2.0 License - -Relevant notice and copyright provisions for TypeScript are below. - -**************************************************************/ - - - -/* ***************************************************************************** -Copyright (c) Microsoft Corporation. All rights reserved. -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 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED -WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, -MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions -and limitations under the License. -***************************************************************************** */ - - -/*----------------- TypeScript ThirdPartyNotices ------------------------------------------------------- - -The TypeScript software is based on or incorporates material and code from the projects listed below -(collectively "Third Party Code"). Microsoft is not the original author of the -Third Party Code. The original copyright notice and the license, under which -Microsoft received such Third Party Code, are set forth below. Such license and -notices are provided for informational purposes only. Microsoft licenses the Third -Party Code to you under the terms of the Apache 2.0 License. -All Third Party Code licensed by Microsoft 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 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR -CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions and -limitations under the License. ---------------------------------------------- -Third Party Code Components --------------------------------------------- ----- Mozilla Developer Code--------- -The following Mozilla Developer Code is under Public Domain as updated after Aug. 20, 2012, see, https://developer.mozilla.org/en-US/docs/Project:Copyrights -1. Array filter Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter -Any copyright is dedicated to the Public Domain. - -2. Array forEach Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach -Any copyright is dedicated to the Public Domain. - -3. Array indexOf Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf -Any copyright is dedicated to the Public Domain. - -4. Array map Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map -Any copyright is dedicated to the Public Domain. - -5. Array Reduce Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/Reduce -Any copyright is dedicated to the Public Domain. - -6. String Trim Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/Trim -Any copyright is dedicated to the Public Domain. - -7. Date now Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/now -Any copyright is dedicated to the Public Domain. - -------------JSON2 Script------------------------ -json2.js 2012-10-08 -Public Domain. -NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. -See, http://www.JSON.org/js.html - ---------------r.js---------------------- -Copyright (c) 2010-2011 Dojo Foundation. All Rights Reserved. -Originally License under MIT License -------------------------------------------------------------------------- -Provided for Informational Purposes Only -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------------- - -------------- End of ThirdPartyNotices --------------------------------------------------- */ - - - - - - -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of this License; and - -You must cause any modified files to carry prominent notices stating that You changed the files; and - -You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - -If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/appveyor.yml b/appveyor.yml index 4d741e89158..7cfb2bbfa21 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,19 +1,16 @@ environment: matrix: - - nodejs_version: "0.10" - - nodejs_version: "0.12" - nodejs_version: "4.2" - - nodejs_version: "5.0" + - nodejs_version: "5.7" + - nodejs_version: "6.1" install: - ps: Install-Product node $env:nodejs_version - npm install - - npm install -g grunt-cli test_script: - node --version - npm --version - - grunt --version - - grunt + - npm run verify -build: off \ No newline at end of file +build: off diff --git a/circle.yml b/circle.yml index 745e2896336..1387283aaff 100644 --- a/circle.yml +++ b/circle.yml @@ -4,7 +4,10 @@ general: - gh-pages dependencies: pre: - - case $CIRCLE_NODE_INDEX in 0) nvm use 0.10 ;; 1) nvm use 0.12 ;; 2) nvm use 4.2 ;; 3) nvm use 5.5 ;; esac + - case $CIRCLE_NODE_INDEX in 0) nvm use 4.2 ;; 1) nvm use 5.7 ;; 2) nvm use 6.1 ;; esac +test: + override: + - npm run verify deployment: npm-latest: # match semver tag (e.g. 3.12.7) diff --git a/custom-typings/resolve.d.ts b/custom-typings/resolve.d.ts deleted file mode 100644 index 31ab1a0d164..00000000000 --- a/custom-typings/resolve.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -declare module "resolve" { - interface ResolveOptions { - basedir?: string; - extensions?: string[]; - paths?: string[]; - moduleDirectory?: string | string[]; - } - interface AsyncResolveOptions extends ResolveOptions { - package?: any; - readFile?: Function; - isFile?: (file: string, cb: Function) => void; - packageFilter?: Function; - pathFilter?: Function; - } - interface SyncResolveOptions extends ResolveOptions { - readFile?: Function; - isFile?: (file: string) => boolean; - packageFilter?: Function; - } - interface ResolveFunction { - (id: string, cb: (err: any, res: string, pkg: any) => void): void; - (id: string, opts: AsyncResolveOptions, cb: (err: any, res: string, pkg: any) => void): void; - sync(id: string, opts?: SyncResolveOptions): string; - isCore(pkg: any): any; - } - - const resolve: ResolveFunction; - export = resolve; -} diff --git a/docs/_data/formatters.json b/docs/_data/formatters.json new file mode 100644 index 00000000000..c3541f5d75c --- /dev/null +++ b/docs/_data/formatters.json @@ -0,0 +1,62 @@ +[ + { + "formatterName": "checkstyle", + "description": "Formats errors as through they were Checkstyle output.", + "descriptionDetails": "\nImitates the XMLLogger from Checkstyle 4.3. All failures have the 'warning' severity.", + "sample": "\n\n\n \n \n \n", + "consumer": "machine" + }, + { + "formatterName": "filesList", + "description": "Lists files containing lint errors.", + "sample": "directory/myFile.ts", + "consumer": "machine" + }, + { + "formatterName": "json", + "description": "Formats errors as simple JSON.", + "sample": "\n[\n {\n \"endPosition\": {\n \"character\": 13,\n \"line\": 0,\n \"position\": 13\n },\n \"failure\": \"Missing semicolon\",\n \"fix\": {\n \"innerRuleName\": \"semicolon\",\n \"innerReplacements\": [\n {\n \"innerStart\": 13,\n \"innerLength\": 0,\n \"innerText\": \";\"\n }\n ]\n },\n \"name\": \"myFile.ts\",\n \"ruleName\": \"semicolon\",\n \"startPosition\": {\n \"character\": 13,\n \"line\": 0,\n \"position\": 13\n }\n }\n]", + "consumer": "machine" + }, + { + "formatterName": "msbuild", + "description": "Formats errors for consumption by msbuild.", + "descriptionDetails": "\nThe output is compatible with both msbuild and Visual Studio. All failures have the\n'warning' severity.", + "sample": "myFile.ts(1,14): warning: Missing semicolon", + "consumer": "machine" + }, + { + "formatterName": "pmd", + "description": "Formats errors as through they were PMD output.", + "descriptionDetails": "Imitates the XML output from PMD. All errors have a priority of 1.", + "sample": "\n\n \n \n \n", + "consumer": "machine" + }, + { + "formatterName": "prose", + "description": "The default formatter which outputs simple human-readable messages.", + "sample": "myFile.ts[1, 14]: Missing semicolon", + "consumer": "human" + }, + { + "formatterName": "stylish", + "description": "Human-readable formatter which creates stylish messages.", + "descriptionDetails": "\nThe output matches that produced by eslint's stylish formatter. Its readability\nenhanced through spacing and colouring", + "sample": "\nmyFile.ts\n1:14 semicolon Missing semicolon", + "consumer": "human" + }, + { + "formatterName": "verbose", + "description": "The human-readable formatter which includes the rule name in messages.", + "descriptionDetails": "The output is the same as the prose formatter with the rule name included", + "sample": "(semicolon) myFile.ts[1, 14]: Missing semicolon", + "consumer": "human" + }, + { + "formatterName": "vso", + "description": "Formats output as VSO/TFS logging commands.", + "descriptionDetails": "\nIntegrates with Visual Studio Online and Team Foundation Server by outputting errors\nas 'warning' logging commands.", + "sample": "##vso[task.logissue type=warning;sourcepath=myFile.ts;linenumber=1;columnnumber=14;code=semicolon;]Missing semicolon", + "consumer": "machine" + } +] \ No newline at end of file diff --git a/docs/_data/rules.json b/docs/_data/rules.json index e67982e42a4..61d5c2d6c0b 100644 --- a/docs/_data/rules.json +++ b/docs/_data/rules.json @@ -7,7 +7,9 @@ "optionExamples": [ "true" ], - "type": "typescript" + "rationale": "Improves readability and organization by grouping naturally related items together.", + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "align", @@ -30,7 +32,28 @@ "optionExamples": [ "[true, \"parameters\", \"statements\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false + }, + { + "ruleName": "array-type", + "description": "Requires using either 'T[]' or 'Array' for arrays.", + "optionsDescription": "\nOne of the following arguments must be provided:\n\n* `\"array\"` enforces use of `T[]` for all types T.\n* `\"generic\"` enforces use of `Array` for all types T.\n* `\"array-simple\"` enforces use of `T[]` if `T` is a simple type (primitive or type reference).", + "options": { + "type": "string", + "enum": [ + "array", + "generic", + "array-simple" + ] + }, + "optionExamples": [ + "[true, array]", + "[true, generic]", + "[true, array-simple]" + ], + "type": "style", + "typescriptOnly": true }, { "ruleName": "arrow-parens", @@ -41,34 +64,29 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "ban", - "description": "Bans the use of specific functions.", - "descriptionDetails": "At this time, there is no way to disable global methods with this rule.", - "optionsDescription": "A list of `['object', 'method', 'optional explanation here']` which ban `object.method()`.", + "description": "Bans the use of specific functions or global methods.", + "optionsDescription": "\nA list of `['object', 'method', 'optional explanation here']` or `['globalMethod']` which ban `object.method()` \nor respectively `globalMethod()`.", "options": { "type": "list", "listType": { "type": "array", - "arrayMembers": [ - { - "type": "string" - }, - { - "type": "string" - }, - { - "type": "string" - } - ] + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3 } }, "optionExamples": [ - "[true, [\"someObject\", \"someFunction\"], [\"someObject\", \"otherFunction\", \"Optional explanation\"]]" + "[true, [\"someGlobalMethod\"], [\"someObject\", \"someFunction\"], \n [\"someObject\", \"otherFunction\", \"Optional explanation\"]]" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "class-name", @@ -79,7 +97,8 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "comment-format", @@ -102,7 +121,31 @@ "optionExamples": [ "[true, \"check-space\", \"check-lowercase\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false + }, + { + "ruleName": "completed-docs", + "description": "Enforces documentation for important items be filled out.", + "optionsDescription": "\nEither `true` to enable for all, or any of\n`[\"classes\", \"functions\", \"methods\", \"properties\"]\nto choose individual ones.`", + "options": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "classes", + "functions", + "methods", + "properties" + ] + } + }, + "optionExamples": [ + "true", + "[true, [\"classes\", \"functions\"]" + ], + "type": "style", + "typescriptOnly": false }, { "ruleName": "curly", @@ -113,7 +156,25 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false + }, + { + "ruleName": "cyclomatic-complexity", + "description": "Enforces a threshold of cyclomatic complexity.", + "descriptionDetails": "\nCyclomatic complexity is assessed for each function of any type. A starting value of 1\nis assigned and this value is then incremented for every statement which can branch the\ncontrol flow within the function. The following statements and expressions contribute\nto cyclomatic complexity:\n* `catch`\n* `if` and `? :`\n* `||` and `&&` due to short-circuit evaluation\n* `for`, `for in` and `for of` loops\n* `while` and `do while` loops", + "rationale": "\nCyclomatic complexity is a code metric which indicates the level of complexity in a\nfunction. High cyclomatic complexity indicates confusing code which may be prone to\nerrors or difficult to modify.", + "optionsDescription": "\nAn optional upper limit for cyclomatic complexity can be specified. If no limit option\nis provided a default value of $(Rule.DEFAULT_THRESHOLD) will be used.", + "options": { + "type": "number", + "minimum": "$(Rule.MINIMUM_THRESHOLD)" + }, + "optionExamples": [ + "true", + "[true, 20]" + ], + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "eofline", @@ -124,7 +185,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "file-header", @@ -134,9 +196,10 @@ "type": "string" }, "optionExamples": [ - "\"true\", \"Copyright \\d{4}\"" + "[true, \"Copyright \\\\d{4}\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "forin", @@ -147,7 +210,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "indent", @@ -164,7 +228,8 @@ "optionExamples": [ "[true, \"spaces\"]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "interface-name", @@ -182,7 +247,8 @@ "[true, \"always-prefix\"]", "[true, \"never-prefix\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": true }, { "ruleName": "jsdoc-format", @@ -194,7 +260,8 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "label-position", @@ -206,19 +273,8 @@ "optionExamples": [ "true" ], - "type": "functionality" - }, - { - "ruleName": "label-undefined", - "description": "Checks that labels are defined before usage.", - "descriptionDetails": "This rule is now implemented in the TypeScript compiler and does not need to be used.", - "rationale": "Using `break` or `continue` to go to an out-of-scope label is an error in JS.", - "optionsDescription": "Not configurable.", - "options": null, - "optionExamples": [ - "true" - ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "linebreak-style", @@ -235,7 +291,32 @@ "[true, \"LF\"]", "[true, \"CRLF\"]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false + }, + { + "ruleName": "max-classes-per-file", + "description": "\nA file may not contain more than the specified number of classes", + "rationale": "\nEnsures that files have a single responsibility so that that classes each exist in their own files", + "optionsDescription": "\nThe one required argument is an integer indicating the maximum number of classes that can appear in a file.", + "options": { + "type": "array", + "items": [ + { + "type": "number", + "minimum": 1 + } + ], + "additionalItems": false, + "minLength": 1, + "maxLength": 2 + }, + "optionExamples": [ + "[true, 1]", + "[true, 5]" + ], + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "max-file-line-count", @@ -249,7 +330,8 @@ "optionExamples": [ "[true, 300]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "max-line-length", @@ -263,7 +345,8 @@ "optionExamples": [ "[true, 120]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "member-access", @@ -286,7 +369,8 @@ "true", "[true, \"check-accessor\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "member-ordering", @@ -336,7 +420,8 @@ "optionExamples": [ "[true, { \"order\": \"fields-first\" }]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "new-parens", @@ -347,7 +432,8 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "no-angle-bracket-type-assertion", @@ -358,7 +444,8 @@ "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": true }, { "ruleName": "no-any", @@ -369,7 +456,8 @@ "optionExamples": [ "true" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "no-arg", @@ -380,7 +468,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-bitwise", @@ -392,7 +481,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-conditional-assignment", @@ -404,18 +494,24 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-consecutive-blank-lines", - "description": "Disallows more than one blank line in a row.", + "description": "Disallows one or more blank lines in a row.", "rationale": "Helps maintain a readable style in your codebase.", - "optionsDescription": "Not configurable.", - "options": {}, + "optionsDescription": "\nAn optional number of maximum allowed sequential blanks can be specified. If no value\nis provided, a default of $(Rule.DEFAULT_ALLOWED_BLANKS) will be used.", + "options": { + "type": "number", + "minimum": "$(Rule.MINIMUM_ALLOWED_BLANKS)" + }, "optionExamples": [ - "true" + "true", + "[true, 2]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "no-console", @@ -431,18 +527,8 @@ "optionExamples": [ "[true, \"log\", \"error\"]" ], - "type": "functionality" - }, - { - "ruleName": "no-constructor-vars", - "description": "Disallows parameter properties.", - "rationale": "\nParameter properties can be confusing to those new to TS as they are less explicit\nthan other ways of declaring and initializing class members.", - "optionsDescription": "Not configurable.", - "options": null, - "optionExamples": [ - "true" - ], - "type": "style" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-construct", @@ -454,7 +540,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-debugger", @@ -465,7 +552,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-default-export", @@ -477,18 +565,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" - }, - { - "ruleName": "no-duplicate-key", - "description": "Disallows duplicate keys in object literals.", - "rationale": "\nThere is no good reason to define an object literal with the same key twice.\nThis rule is now implemented in the TypeScript compiler and does not need to be used.", - "optionsDescription": "Not configurable.", - "options": null, - "optionExamples": [ - "true" - ], - "type": "functionality" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "no-duplicate-variable", @@ -500,7 +578,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-empty", @@ -512,7 +591,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-eval", @@ -523,7 +603,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-for-in-array", @@ -535,7 +616,8 @@ "true" ], "requiresTypeInfo": true, - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-inferrable-types", @@ -557,7 +639,8 @@ "true", "[true, \"ignore-params\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "no-internal-module", @@ -568,7 +651,8 @@ "optionExamples": [ "true" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "no-invalid-this", @@ -590,7 +674,8 @@ "true", "[true, \"check-function-in-method\"]" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-mergeable-namespace", @@ -600,7 +685,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": true }, { "ruleName": "no-namespace", @@ -623,7 +709,8 @@ "true", "[true, \"allow-declarations\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "no-null-keyword", @@ -634,7 +721,20 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false + }, + { + "ruleName": "no-parameter-properties", + "description": "Disallows parameter properties in class constructors.", + "rationale": "\nParameter properties can be confusing to those new to TS as they are less explicit\nthan other ways of declaring and initializing class members.", + "optionsDescription": "Not configurable.", + "options": null, + "optionExamples": [ + "true" + ], + "type": "style", + "typescriptOnly": true }, { "ruleName": "no-reference", @@ -645,7 +745,8 @@ "optionExamples": [ "true" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": false }, { "ruleName": "no-require-imports", @@ -656,7 +757,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "no-shadowed-variable", @@ -667,7 +769,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-string-literal", @@ -678,7 +781,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-switch-case-fall-through", @@ -690,7 +794,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-trailing-whitespace", @@ -701,18 +806,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" - }, - { - "ruleName": "no-unreachable", - "description": "Disallows unreachable code after `break`, `catch`, `throw`, and `return` statements.", - "rationale": "Unreachable code is often indication of a logic error.", - "optionsDescription": "Not configurable.", - "options": null, - "optionExamples": [ - "true" - ], - "type": "functionality" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "no-unsafe-finally", @@ -724,7 +819,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-unused-expression", @@ -736,7 +832,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-unused-new", @@ -748,10 +845,12 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-unused-variable", + "deprecationMessage": "Use the tsc compiler options --noUnusedParameters and --noUnusedLocals instead.", "description": "Disallows unused imports, variables, functions and private class members.", "optionsDescription": "\nThree optional arguments may be optionally provided:\n\n* `\"check-parameters\"` disallows unused function and constructor parameters.\n * NOTE: this option is experimental and does not work with classes\n that use abstract method declarations, among other things.\n* `\"react\"` relaxes the rule for a namespace import named `React`\n(from either the module `\"react\"` or `\"react/addons\"`).\nAny JSX expression in the file will be treated as a usage of `React`\n(because it expands to `React.createElement `).\n* `{\"ignore-pattern\": \"pattern\"}` where pattern is a case-sensitive regexp.\nVariable names that match the pattern will be ignored.", "options": { @@ -783,7 +882,8 @@ "[true, \"react\"]", "[true, {\"ignore-pattern\": \"^_\"}]" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": true }, { "ruleName": "no-use-before-declare", @@ -794,7 +894,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-var-keyword", @@ -805,7 +906,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "no-var-requires", @@ -816,34 +918,40 @@ "optionExamples": [ "true" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "object-literal-key-quotes", "description": "Enforces consistent object literal property quote style.", "descriptionDetails": "\nObject literal property names can be defined in two ways: using literals or using strings.\nFor example, these two objects are equivalent:\n\nvar object1 = {\n property: true\n};\n\nvar object2 = {\n \"property\": true\n};\n\nIn many cases, it doesn’t matter if you choose to use an identifier instead of a string\nor vice-versa. Even so, you might decide to enforce a consistent style in your code.\n\nThis rules lets you enforce consistent quoting of property names. Either they should always\nbe quoted (default behavior) or quoted only as needed (\"as-needed\").", - "optionsDescription": "\nPossible settings are:\n\n* `\"always\"`: Property names should always be quoted. (This is the default.)\n* `\"as-needed\"`: Only property names which require quotes may be quoted (e.g. those with spaces in them).\n\nFor ES6, computed property names (`{[name]: value}`) and methods (`{foo() {}}`) never need\nto be quoted.", + "optionsDescription": "\nPossible settings are:\n\n* `\"always\"`: Property names should always be quoted. (This is the default.)\n* `\"as-needed\"`: Only property names which require quotes may be quoted (e.g. those with spaces in them).\n* `\"consistent\"`: Property names should either all be quoted or unquoted.\n* `\"consistent-as-needed\"`: If any property name requires quotes, then all properties must be quoted. Otherwise, no \nproperty names may be quoted.\n\nFor ES6, computed property names (`{[name]: value}`) and methods (`{foo() {}}`) never need\nto be quoted.", "options": { "type": "string", "enum": [ "always", - "as-needed" + "as-needed", + "consistent", + "consistent-as-needed" ] }, "optionExamples": [ "[true, \"as-needed\"]", "[true, \"always\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "object-literal-shorthand", "description": "Enforces use of ES6 object literal shorthand when possible.", + "optionsDescription": "Not configurable.", "options": null, "optionExamples": [ "true" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "object-literal-sort-keys", @@ -854,7 +962,8 @@ "optionExamples": [ "true" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "one-line", @@ -878,7 +987,8 @@ "optionExamples": [ "[true, \"check-catch\", \"check-finally\", \"check-else\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "one-variable-per-declaration", @@ -899,7 +1009,8 @@ "true", "[true, \"ignore-for-loop\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "only-arrow-functions", @@ -921,13 +1032,14 @@ "true", "[true, \"allow-declarations\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": false }, { "ruleName": "ordered-imports", "description": "Requires that import statements be alphabetized.", - "descriptionDetails": "\nEnforce a consistent ordering for ES6 imports:\n- Named imports must be alphabetized (i.e. \"import {A, B, C} from \"foo\";\")\n - The exact ordering can be controled by the named-imports-order option.\n - \"longName as name\" imports are ordered by \"longName\".\n- Import sources must be alphabetized within groups, i.e.:\n import * as foo from \"a\";\n import * as bar from \"b\";\n- Groups of imports are delineated by blank lines. You can use these to group imports\n however you like, e.g. by first- vs. third-party or thematically.", - "optionsDescription": "\nYou may set the `\"import-sources-order\"` option to control the ordering of source\nimports (the `\"foo\"` in `import {A, B, C} from \"foo\"`).\n\nPossible values for `\"import-sources-order\"` are:\n* `\"case-insensitive'`: Correct order is `\"Bar\"`, `\"baz\"`, `\"Foo\"`. (This is the default.)\n* `\"lowercase-first\"`: Correct order is `\"baz\"`, `\"Bar\"`, `\"Foo\"`.\n* `\"lowercase-last\"`: Correct order is `\"Bar\"`, `\"Foo\"`, `\"baz\"`.\n\nYou may set the `\"named-imports-order\"` option to control the ordering of named\nimports (the `{A, B, C}` in `import {A, B, C} from \"foo\"`).\n\nPossible values for `\"named-imports-order\"` are:\n\n* `\"case-insensitive'`: Correct order is `{A, b, C}`. (This is the default.)\n* `\"lowercase-first\"`: Correct order is `{b, A, C}`.\n* `\"lowercase-last\"`: Correct order is `{A, C, b}`.\n\n ", + "descriptionDetails": "\nEnforce a consistent ordering for ES6 imports:\n- Named imports must be alphabetized (i.e. \"import {A, B, C} from \"foo\";\")\n - The exact ordering can be controlled by the named-imports-order option.\n - \"longName as name\" imports are ordered by \"longName\".\n- Import sources must be alphabetized within groups, i.e.:\n import * as foo from \"a\";\n import * as bar from \"b\";\n- Groups of imports are delineated by blank lines. You can use these to group imports\n however you like, e.g. by first- vs. third-party or thematically.", + "optionsDescription": "\nYou may set the `\"import-sources-order\"` option to control the ordering of source\nimports (the `\"foo\"` in `import {A, B, C} from \"foo\"`).\n\nPossible values for `\"import-sources-order\"` are:\n* `\"case-insensitive'`: Correct order is `\"Bar\"`, `\"baz\"`, `\"Foo\"`. (This is the default.)\n* `\"lowercase-first\"`: Correct order is `\"baz\"`, `\"Bar\"`, `\"Foo\"`.\n* `\"lowercase-last\"`: Correct order is `\"Bar\"`, `\"Foo\"`, `\"baz\"`.\n* `\"any\"`: Allow any order.\n\nYou may set the `\"named-imports-order\"` option to control the ordering of named\nimports (the `{A, B, C}` in `import {A, B, C} from \"foo\"`).\n\nPossible values for `\"named-imports-order\"` are:\n\n* `\"case-insensitive'`: Correct order is `{A, b, C}`. (This is the default.)\n* `\"lowercase-first\"`: Correct order is `{b, A, C}`.\n* `\"lowercase-last\"`: Correct order is `{A, C, b}`.\n* `\"any\"`: Allow any order.\n\n ", "options": { "type": "object", "properties": { @@ -936,7 +1048,8 @@ "enum": [ "case-insensitive", "lowercase-first", - "lowercase-last" + "lowercase-last", + "any" ] }, "named-imports-order": { @@ -944,7 +1057,8 @@ "enum": [ "case-insensitive", "lowercase-first", - "lowercase-last" + "lowercase-last", + "any" ] } }, @@ -954,7 +1068,20 @@ "true", "[true, {\"import-sources-order\": \"lowercase-last\", \"named-imports-order\": \"lowercase-first\"}]" ], - "type": "style" + "type": "style", + "typescriptOnly": false + }, + { + "ruleName": "prefer-for-of", + "description": "Recommends a 'for-of' loop over a standard 'for' loop if the index is only used to access the array being iterated.", + "rationale": "A for(... of ...) loop is easier to implement and read when the index is not needed.", + "optionsDescription": "Not configurable.", + "options": null, + "optionExamples": [ + "true" + ], + "type": "typescript", + "typescriptOnly": false }, { "ruleName": "quotemark", @@ -979,7 +1106,8 @@ "[true, \"single\", \"avoid-escape\"]", "[true, \"single\", \"jsx-double\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "radix", @@ -990,7 +1118,8 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "restrict-plus-operands", @@ -1001,12 +1130,13 @@ "true" ], "type": "functionality", + "typescriptOnly": false, "requiresTypeInfo": true }, { "ruleName": "semicolon", "description": "Enforces consistent semicolon usage at the end of every statement.", - "optionsDescription": "\nOne of the following arguments must be provided:\n\n* `\"always\"` enforces semicolons at the end of every statement.\n* `\"never\"` disallows semicolons at the end of every statement except for when they are necessary.\n\nThe following arguments may be optionaly provided:\n* `\"ignore-interfaces\"` skips checking semicolons at the end of interface members.", + "optionsDescription": "\nOne of the following arguments must be provided:\n\n* `\"always\"` enforces semicolons at the end of every statement.\n* `\"never\"` disallows semicolons at the end of every statement except for when they are necessary.\n\nThe following arguments may be optionaly provided:\n* `\"ignore-interfaces\"` skips checking semicolons at the end of interface members.\n* `\"ignore-bound-class-methods\"` skips checking semicolons at the end of bound class methods.", "options": { "type": "array", "items": [ @@ -1029,9 +1159,11 @@ "optionExamples": [ "[true, \"always\"]", "[true, \"never\"]", - "[true, \"always\", \"ignore-interfaces\"]" + "[true, \"always\", \"ignore-interfaces\"]", + "[true, \"always\", \"ignore-bound-class-methods\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "switch-default", @@ -1041,12 +1173,13 @@ "optionExamples": [ "true" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "trailing-comma", - "description": "Requires or disallows trailing commas in array and object literals, destructuring assignments and named imports.", - "optionsDescription": "\nOne argument which is an object with the keys `multiline` and `singleline`.\nBoth should be set to either `\"always\"` or `\"never\"`.\n\n* `\"multiline\"` checks multi-line object literals.\n* `\"singleline\"` checks single-line object literals.\n\nA array is considered \"multiline\" if its closing bracket is on a line\nafter the last array element. The same general logic is followed for\nobject literals and named import statements.", + "description": "\nRequires or disallows trailing commas in array and object literals, destructuring assignments, function and tuple typings,\nnamed imports and function parameters.", + "optionsDescription": "\nOne argument which is an object with the keys `multiline` and `singleline`.\nBoth should be set to either `\"always\"` or `\"never\"`.\n\n* `\"multiline\"` checks multi-line object literals.\n* `\"singleline\"` checks single-line object literals.\n\nA array is considered \"multiline\" if its closing bracket is on a line\nafter the last array element. The same general logic is followed for\nobject literals, function and tuple typings, named import statements\nand function parameters.", "options": { "type": "object", "properties": { @@ -1070,7 +1203,8 @@ "optionExamples": [ "[true, {\"multiline\": \"always\", \"singleline\": \"never\"}]" ], - "type": "maintainability" + "type": "maintainability", + "typescriptOnly": false }, { "ruleName": "triple-equals", @@ -1093,7 +1227,8 @@ "[true, \"allow-null-check\"]", "[true, \"allow-undefined-check\"]" ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "typedef", @@ -1119,7 +1254,8 @@ "optionExamples": [ "[true, \"call-signature\", \"parameter\", \"member-variable-declaration\"]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "typedef-whitespace", @@ -1227,7 +1363,8 @@ "optionExamples": [ "\n[\n true,\n {\n \"call-signature\": \"nospace\",\n \"index-signature\": \"nospace\",\n \"parameter\": \"nospace\",\n \"property-declaration\": \"nospace\",\n \"variable-declaration\": \"nospace\"\n },\n {\n \"call-signature\": \"onespace\",\n \"index-signature\": \"onespace\",\n \"parameter\": \"onespace\",\n \"property-declaration\": \"onespace\",\n \"variable-declaration\": \"onespace\"\n }\n]" ], - "type": "typescript" + "type": "typescript", + "typescriptOnly": true }, { "ruleName": "use-isnan", @@ -1238,28 +1375,8 @@ "optionExamples": [ "true" ], - "type": "functionality" - }, - { - "ruleName": "use-strict", - "description": "Requires using ECMAScript 5's strict mode.", - "optionsDescription": "\nTwo arguments may be optionally provided:\n\n* `check-module` checks that all top-level modules are using strict mode.\n* `check-function` checks that all top-level functions are using strict mode.", - "options": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "check-module", - "check-function" - ] - }, - "minLength": 0, - "maxLength": 2 - }, - "optionExamples": [ - "[true, \"check-module\"]" - ], - "type": "functionality" + "type": "functionality", + "typescriptOnly": false }, { "ruleName": "variable-name", @@ -1283,7 +1400,8 @@ "optionExamples": [ "[true, \"ban-keywords\", \"check-format\", \"allow-leading-underscore\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false }, { "ruleName": "whitespace", @@ -1310,6 +1428,7 @@ "optionExamples": [ "[true, \"check-branch\", \"check-operator\", \"check-typecast\"]" ], - "type": "style" + "type": "style", + "typescriptOnly": false } ] \ No newline at end of file diff --git a/docs/_includes/header.html b/docs/_includes/header.html index bc984d1b418..32a83ccfef0 100644 --- a/docs/_includes/header.html +++ b/docs/_includes/header.html @@ -6,6 +6,7 @@ diff --git a/docs/_layouts/formatter.html b/docs/_layouts/formatter.html new file mode 100644 index 00000000000..f230db51c88 --- /dev/null +++ b/docs/_layouts/formatter.html @@ -0,0 +1,11 @@ +--- +layout: page +--- +{{page.description | markdownify}} +{% if page.descriptionDetails %} + {{page.descriptionDetails | markdownify}} +{% endif %} +{% if page.sample %} +
Sample Output
+
{{page.sample | xml_escape | markdownify}}
+{% endif %} diff --git a/docs/_posts/2016-11-17-new-for-4.0.md b/docs/_posts/2016-11-17-new-for-4.0.md new file mode 100644 index 00000000000..2bbf2404c95 --- /dev/null +++ b/docs/_posts/2016-11-17-new-for-4.0.md @@ -0,0 +1,86 @@ +--- +layout: post +title: "TSLint 4.0 Released" +date: 2016-11-17 15:19:00 +--- + +TSLint 4.0 has been released! With this release comes a few exciting [changes][0]. Some of the highlights: + +* **Fixers**. Do you dread turning on a new rule because of all of the new errors? For some of the most common issues, we'll fix them for you. To use this feature, run `tslint` with the `--fix` option. Rules that support the `--fix` feature: + * [array-type][2] + * [arrow-parens][3] + * [no-unused-variable][4] (for imports) + * [no-var-keyword][5] + * [ordered-imports][6] + * [semicolon][7] + * [trailing-comma][8] + + +* **Linting `.js` files**. *A much-requested feature from our community*. Simplify your toolset by running the same rules you know and love on your .js and .jsx files. Just add a `jsRules` [section][9] to your `tslint.json` file, and TSLint will lint your JavaScript files. + +* **TypeScript 2.0+ required**. This lets us deprecate/remove rules that are checked by the compiler. Problematic code that once violated these rules now cause compilation errors in `tsc`: + * no-duplicate-key + * no-unreachable + * no-unused-variable + + +* **Node.js API Change**. [Moved and renamed][11] some things to make more sense. Get it all when you use `import * as TSLint from "tslint"`. + +* **[Recommended Rules Updated][12]** + * [adjacent-overload-signatures][13] + * [array-type][14] + * [arrow-parens][15] + * [max-classes-per-file][16] + * [no-unsafe-finally][17] + * [object-literal-key-quotes][18] (as needed) + * [object-literal-shorthand][19] + * [only-arrow-functions][20] + * [ordered-imports][21] + * [prefer-for-of][22] + + +* **Other rules you might find handy**: + * [completed-docs][23] + * [cyclomatic-complexity][24] + +--- + +## Create your own fixer ## +To create your own fixer, instantiate a `Fix` object and pass it in as an argument to `addFailure`. + +This snippet updates the [sample custom rule][25] by adding a fixer which replaces the offending import statement with an empty string: + +```typescript +// create a fixer for this failure +const replacement = new Lint.Replacement(node.getStart(), node.getWidth(), ""); +const fix = new Lint.Fix("no-imports", [replacement]); + +this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING, fix)); +``` + +[0]: https://github.com/palantir/tslint/releases +[1]: https://github.com/palantir/tslint/blob/master/CHANGELOG.md +[2]: {{ site.baseurl }}/rules/array-type +[3]: {{ site.baseurl }}/rules/arrow-parens +[4]: {{ site.baseurl }}/rules/no-unused-variable +[5]: {{ site.baseurl }}/rules/no-var-keyword +[6]: {{ site.baseurl }}/rules/ordered-imports +[7]: {{ site.baseurl }}/rules/semicolon +[8]: {{ site.baseurl }}/rules/trailing-comma +[9]: https://raw.githubusercontent.com/palantir/tslint/master/src/configs/recommended.ts +[10]: {{ site.baseurl }}/usage/third-party-tools/ +[11]: https://github.com/palantir/tslint/pull/1720 +[12]: https://github.com/palantir/tslint/pull/1717/files#diff-6e3940e8ec3d59837c4435f32975ed2c +[13]: {{ site.baseurl }}/rules/adjacent-overload-signatures +[14]: {{ site.baseurl }}/rules/array-type +[15]: {{ site.baseurl }}/rules/arrow-parens +[16]: {{ site.baseurl }}/rules/max-classes-per-file +[17]: {{ site.baseurl }}/rules/no-unsafe-finally +[18]: {{ site.baseurl }}/rules/object-literal-key-quotes +[19]: {{ site.baseurl }}/rules/object-literal-shorthand +[20]: {{ site.baseurl }}/rules/only-arrow-functions +[21]: {{ site.baseurl }}/rules/ordered-imports +[22]: {{ site.baseurl }}/rules/prefer-for-of +[23]: {{ site.baseurl }}/rules/completed-docs +[24]: {{ site.baseurl }}/rules/cyclomatic-complexity +[25]: {{ site.baseurl }}/develop/custom-rules diff --git a/docs/develop/contributing/index.md b/docs/develop/contributing/index.md index 56586310848..f78a059839f 100644 --- a/docs/develop/contributing/index.md +++ b/docs/develop/contributing/index.md @@ -4,12 +4,13 @@ title: Contributing permalink: /develop/contributing/ --- -To develop TSLint simply clone the repository, install dependencies and run grunt: +To develop TSLint simply clone the repository and install dependencies: ```bash -git clone git@github.com:palantir/tslint.git +git clone git@github.com:palantir/tslint.git --config core.autocrlf=input --config core.eol=lf npm install -grunt +npm run compile +npm run test ``` #### `next` branch @@ -17,4 +18,4 @@ grunt 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 -version of TSLint via `npm install tslint@next`. \ No newline at end of file +version of TSLint via `npm install tslint@next`. diff --git a/docs/develop/custom-formatters/index.md b/docs/develop/custom-formatters/index.md index a88daad73ca..173c8e3f868 100644 --- a/docs/develop/custom-formatters/index.md +++ b/docs/develop/custom-formatters/index.md @@ -8,7 +8,7 @@ Just like [custom rules][0], additional formatters can also be supplied to TSLin ```ts import * as ts from "typescript"; -import * as Lint from "tslint/lib/lint"; +import * as Lint from "tslint"; export class Formatter extends Lint.Formatters.AbstractFormatter { public format(failures: Lint.RuleFailure[]): string { diff --git a/docs/develop/custom-rules/index.md b/docs/develop/custom-rules/index.md index b8a39ee1c39..36806f85425 100644 --- a/docs/develop/custom-rules/index.md +++ b/docs/develop/custom-rules/index.md @@ -3,20 +3,21 @@ title: Custom Rules layout: page permalink: "/develop/custom-rules/" --- -TSLint ships with a set of core rules that can be configured. However, users are also enabled 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 registering them with TSLint. - -__Important conventions__: Rule identifiers are always kebab-cased. Their implementation files are always `camelCasedRule.ts` and *must* contain the suffix `Rule`. +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. 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 are referenced in `tslint.json` with their kebab-cased identifer, so `"no-imports": true` would configure the rule. -Now, let us first write the rule in TypeScript. A few things to note: - -- We import `tslint/lib/lint` to get the whole `Lint` namespace instead of just the `Linter` class. +__Important conventions__: +- Rule identifiers are always kebab-cased. +- Rule files are always camel-cased (`camelCasedRule.ts`). +- Rule files *must* contain the suffix `Rule`. - The exported class must always be named `Rule` and extend from `Lint.Rules.AbstractRule`. -```ts +Now, let us first write the rule in TypeScript: + +```typescript import * as ts from "typescript"; -import * as Lint from "tslint/lib/lint"; +import * as Lint from "tslint"; export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING = "import statement forbidden"; @@ -50,9 +51,24 @@ Then, if using the CLI, provide the directory that contains this rule as an opti Finally, add a line to your [`tslint.json` config file][0] for each of your custom rules. +--- + +Now that you're written a rule to detect problems, let's modify it to *fix* them. + +Instantiate a `Fix` object and pass it in as an argument to `addFailure`. This snippet replaces the offending import statement with an empty string: + +```typescript +// create a fixer for this failure +const replacement = new Lint.Replacement(node.getStart(), node.getWidth(), ""); +const fix = new Lint.Fix("no-imports", [replacement]); + +// create a failure at the current position +this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING, fix)); +``` +--- 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()`). -[0]: {{site.baseurl | append: "/usage/tslint-json/"}} \ No newline at end of file +[0]: {{site.baseurl | append: "/usage/tslint-json/"}} diff --git a/docs/develop/docs/index.md b/docs/develop/docs/index.md index e586b66fa05..6b4be4412b9 100644 --- a/docs/develop/docs/index.md +++ b/docs/develop/docs/index.md @@ -9,10 +9,10 @@ It is maintained in the [`/docs` directory][2] of TSLint. To contribute to the docs, whether it be better styling, functionality, or content, just create a PR as you would for any code contribution. #### Updating Rule Documentation #### -The [documentation for rules][3] is automatically generated from the metadata supplied by each rule in its corresponding `.tsx` file. +The [documentation for rules][3] is automatically generated from the metadata supplied by each rule in its corresponding `.ts` file. If you'd like to help improve documentation for them, simply file a PR improving a rule's metadata and a project collaborator will take care of regenerating the docs site once your PR is merged. -Running the `grunt docs` command will regenerate the rules docs based off of the metadata provided in the code. This is normally done each release so that the public docs site is up to date with the latest release. +Running the `npm run docs` command will regenerate the rules docs based off of the metadata provided in the code. This is normally done each release so that the public docs site is up to date with the latest release. #### Creating New Pages #### To create a new page, follow the pattern of existing pages. You'll also need to add appropriate metadata in the `_data/*_sidebar.json` data file if you want it to show up in a sidebar. diff --git a/docs/formatters/checkstyle/index.html b/docs/formatters/checkstyle/index.html new file mode 100644 index 00000000000..227de4fe73e --- /dev/null +++ b/docs/formatters/checkstyle/index.html @@ -0,0 +1,18 @@ +--- +formatterName: checkstyle +description: Formats errors as through they were Checkstyle output. +descriptionDetails: |- + + Imitates the XMLLogger from Checkstyle 4.3. All failures have the 'warning' severity. +sample: |- + + + + + + + +consumer: machine +layout: formatter +title: 'Formatter: checkstyle' +--- \ No newline at end of file diff --git a/docs/formatters/filesList/index.html b/docs/formatters/filesList/index.html new file mode 100644 index 00000000000..355edf42f8a --- /dev/null +++ b/docs/formatters/filesList/index.html @@ -0,0 +1,8 @@ +--- +formatterName: filesList +description: Lists files containing lint errors. +sample: directory/myFile.ts +consumer: machine +layout: formatter +title: 'Formatter: filesList' +--- \ No newline at end of file diff --git a/docs/formatters/index.html b/docs/formatters/index.html new file mode 100644 index 00000000000..a7d085cb007 --- /dev/null +++ b/docs/formatters/index.html @@ -0,0 +1,13 @@ +--- +layout: page +title: Formatters +permalink: /formatters/ +menu: main +order: 2 +--- +
    + {% assign formatters = site.data.formatters | sort: "name" %} + {% for formatter in formatters %} +
  • {{formatter.formatterName}} - {{formatter.description | markdownify | remove:"

    " | remove: "

    "}}
  • + {% endfor %} +
\ No newline at end of file diff --git a/docs/formatters/json/index.html b/docs/formatters/json/index.html new file mode 100644 index 00000000000..be794e27a62 --- /dev/null +++ b/docs/formatters/json/index.html @@ -0,0 +1,36 @@ +--- +formatterName: json +description: Formats errors as simple JSON. +sample: |- + + [ + { + "endPosition": { + "character": 13, + "line": 0, + "position": 13 + }, + "failure": "Missing semicolon", + "fix": { + "innerRuleName": "semicolon", + "innerReplacements": [ + { + "innerStart": 13, + "innerLength": 0, + "innerText": ";" + } + ] + }, + "name": "myFile.ts", + "ruleName": "semicolon", + "startPosition": { + "character": 13, + "line": 0, + "position": 13 + } + } + ] +consumer: machine +layout: formatter +title: 'Formatter: json' +--- \ No newline at end of file diff --git a/docs/formatters/msbuild/index.html b/docs/formatters/msbuild/index.html new file mode 100644 index 00000000000..9478c0b2805 --- /dev/null +++ b/docs/formatters/msbuild/index.html @@ -0,0 +1,12 @@ +--- +formatterName: msbuild +description: Formats errors for consumption by msbuild. +descriptionDetails: |- + + The output is compatible with both msbuild and Visual Studio. All failures have the + 'warning' severity. +sample: 'myFile.ts(1,14): warning: Missing semicolon' +consumer: machine +layout: formatter +title: 'Formatter: msbuild' +--- \ No newline at end of file diff --git a/docs/formatters/pmd/index.html b/docs/formatters/pmd/index.html new file mode 100644 index 00000000000..6ebb32c7f4c --- /dev/null +++ b/docs/formatters/pmd/index.html @@ -0,0 +1,15 @@ +--- +formatterName: pmd +description: Formats errors as through they were PMD output. +descriptionDetails: Imitates the XML output from PMD. All errors have a priority of 1. +sample: |- + + + + + + +consumer: machine +layout: formatter +title: 'Formatter: pmd' +--- \ No newline at end of file diff --git a/docs/formatters/prose/index.html b/docs/formatters/prose/index.html new file mode 100644 index 00000000000..054e16dd3dd --- /dev/null +++ b/docs/formatters/prose/index.html @@ -0,0 +1,8 @@ +--- +formatterName: prose +description: The default formatter which outputs simple human-readable messages. +sample: 'myFile.ts[1, 14]: Missing semicolon' +consumer: human +layout: formatter +title: 'Formatter: prose' +--- \ No newline at end of file diff --git a/docs/formatters/stylish/index.html b/docs/formatters/stylish/index.html new file mode 100644 index 00000000000..6bcc4671f9b --- /dev/null +++ b/docs/formatters/stylish/index.html @@ -0,0 +1,15 @@ +--- +formatterName: stylish +description: Human-readable formatter which creates stylish messages. +descriptionDetails: |- + + The output matches that produced by eslint's stylish formatter. Its readability + enhanced through spacing and colouring +sample: |- + + myFile.ts + 1:14 semicolon Missing semicolon +consumer: human +layout: formatter +title: 'Formatter: stylish' +--- \ No newline at end of file diff --git a/docs/formatters/verbose/index.html b/docs/formatters/verbose/index.html new file mode 100644 index 00000000000..ad2fd1d4c29 --- /dev/null +++ b/docs/formatters/verbose/index.html @@ -0,0 +1,9 @@ +--- +formatterName: verbose +description: The human-readable formatter which includes the rule name in messages. +descriptionDetails: The output is the same as the prose formatter with the rule name included +sample: '(semicolon) myFile.ts[1, 14]: Missing semicolon' +consumer: human +layout: formatter +title: 'Formatter: verbose' +--- \ No newline at end of file diff --git a/docs/formatters/vso/index.html b/docs/formatters/vso/index.html new file mode 100644 index 00000000000..33e0e2c1db5 --- /dev/null +++ b/docs/formatters/vso/index.html @@ -0,0 +1,12 @@ +--- +formatterName: vso +description: Formats output as VSO/TFS logging commands. +descriptionDetails: |- + + Integrates with Visual Studio Online and Team Foundation Server by outputting errors + as 'warning' logging commands. +sample: '##vso[task.logissue type=warning;sourcepath=myFile.ts;linenumber=1;columnnumber=14;code=semicolon;]Missing semicolon' +consumer: machine +layout: formatter +title: 'Formatter: vso' +--- \ No newline at end of file diff --git a/docs/rules/adjacent-overload-signatures/index.html b/docs/rules/adjacent-overload-signatures/index.html index d518c87ec36..3506700140c 100644 --- a/docs/rules/adjacent-overload-signatures/index.html +++ b/docs/rules/adjacent-overload-signatures/index.html @@ -5,8 +5,10 @@ options: null optionExamples: - 'true' +rationale: Improves readability and organization by grouping naturally related items together. type: typescript -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: adjacent-overload-signatures' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/align/index.html b/docs/rules/align/index.html index 966ce1556f1..f42a1421e39 100644 --- a/docs/rules/align/index.html +++ b/docs/rules/align/index.html @@ -22,6 +22,9 @@ optionExamples: - '[true, "parameters", "statements"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: align' optionsJSON: |- { "type": "array", @@ -36,6 +39,4 @@ "minLength": 1, "maxLength": 3 } -layout: rule -title: 'Rule: align' --- \ No newline at end of file diff --git a/docs/rules/array-type/index.html b/docs/rules/array-type/index.html new file mode 100644 index 00000000000..5a5cfe27139 --- /dev/null +++ b/docs/rules/array-type/index.html @@ -0,0 +1,34 @@ +--- +ruleName: array-type +description: 'Requires using either ''T[]'' or ''Array'' for arrays.' +optionsDescription: |- + + One of the following arguments must be provided: + + * `"array"` enforces use of `T[]` for all types T. + * `"generic"` enforces use of `Array` for all types T. + * `"array-simple"` enforces use of `T[]` if `T` is a simple type (primitive or type reference). +options: + type: string + enum: + - array + - generic + - array-simple +optionExamples: + - '[true, array]' + - '[true, generic]' + - '[true, array-simple]' +type: style +typescriptOnly: true +layout: rule +title: 'Rule: array-type' +optionsJSON: |- + { + "type": "string", + "enum": [ + "array", + "generic", + "array-simple" + ] + } +--- \ No newline at end of file diff --git a/docs/rules/arrow-parens/index.html b/docs/rules/arrow-parens/index.html index 0d356c11994..e77c46b1d1a 100644 --- a/docs/rules/arrow-parens/index.html +++ b/docs/rules/arrow-parens/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: arrow-parens' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/ban/index.html b/docs/rules/ban/index.html index 279cc53ec8a..f3005766579 100644 --- a/docs/rules/ban/index.html +++ b/docs/rules/ban/index.html @@ -1,37 +1,36 @@ --- ruleName: ban -description: Bans the use of specific functions. -descriptionDetails: 'At this time, there is no way to disable global methods with this rule.' -optionsDescription: 'A list of `[''object'', ''method'', ''optional explanation here'']` which ban `object.method()`.' +description: Bans the use of specific functions or global methods. +optionsDescription: |- + + A list of `['object', 'method', 'optional explanation here']` or `['globalMethod']` which ban `object.method()` + or respectively `globalMethod()`. options: type: list listType: type: array - arrayMembers: - - type: string - - type: string - - type: string + items: + type: string + minLength: 1 + maxLength: 3 optionExamples: - - '[true, ["someObject", "someFunction"], ["someObject", "otherFunction", "Optional explanation"]]' + - |- + [true, ["someGlobalMethod"], ["someObject", "someFunction"], + ["someObject", "otherFunction", "Optional explanation"]] type: functionality +typescriptOnly: false +layout: rule +title: 'Rule: ban' optionsJSON: |- { "type": "list", "listType": { "type": "array", - "arrayMembers": [ - { - "type": "string" - }, - { - "type": "string" - }, - { - "type": "string" - } - ] + "items": { + "type": "string" + }, + "minLength": 1, + "maxLength": 3 } } -layout: rule -title: 'Rule: ban' --- \ No newline at end of file diff --git a/docs/rules/class-name/index.html b/docs/rules/class-name/index.html index 43fdc02f882..0ae19d6e8be 100644 --- a/docs/rules/class-name/index.html +++ b/docs/rules/class-name/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: class-name' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/comment-format/index.html b/docs/rules/comment-format/index.html index 1e170990e20..cbc4b7813a0 100644 --- a/docs/rules/comment-format/index.html +++ b/docs/rules/comment-format/index.html @@ -23,6 +23,9 @@ optionExamples: - '[true, "check-space", "check-lowercase"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: comment-format' optionsJSON: |- { "type": "array", @@ -37,6 +40,4 @@ "minLength": 1, "maxLength": 3 } -layout: rule -title: 'Rule: comment-format' --- \ No newline at end of file diff --git a/docs/rules/completed-docs/index.html b/docs/rules/completed-docs/index.html new file mode 100644 index 00000000000..128a663d3db --- /dev/null +++ b/docs/rules/completed-docs/index.html @@ -0,0 +1,38 @@ +--- +ruleName: completed-docs +description: Enforces documentation for important items be filled out. +optionsDescription: |- + + Either `true` to enable for all, or any of + `["classes", "functions", "methods", "properties"] + to choose individual ones.` +options: + type: array + items: + type: string + enum: + - classes + - functions + - methods + - properties +optionExamples: + - 'true' + - '[true, ["classes", "functions"]' +type: style +typescriptOnly: false +layout: rule +title: 'Rule: completed-docs' +optionsJSON: |- + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "classes", + "functions", + "methods", + "properties" + ] + } + } +--- \ No newline at end of file diff --git a/docs/rules/curly/index.html b/docs/rules/curly/index.html index 1ce4a8eedac..5e9075da7fe 100644 --- a/docs/rules/curly/index.html +++ b/docs/rules/curly/index.html @@ -17,7 +17,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: curly' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/cyclomatic-complexity/index.html b/docs/rules/cyclomatic-complexity/index.html new file mode 100644 index 00000000000..4eddc29446d --- /dev/null +++ b/docs/rules/cyclomatic-complexity/index.html @@ -0,0 +1,39 @@ +--- +ruleName: cyclomatic-complexity +description: Enforces a threshold of cyclomatic complexity. +descriptionDetails: |- + + Cyclomatic complexity is assessed for each function of any type. A starting value of 1 + is assigned and this value is then incremented for every statement which can branch the + control flow within the function. The following statements and expressions contribute + to cyclomatic complexity: + * `catch` + * `if` and `? :` + * `||` and `&&` due to short-circuit evaluation + * `for`, `for in` and `for of` loops + * `while` and `do while` loops +rationale: |- + + Cyclomatic complexity is a code metric which indicates the level of complexity in a + function. High cyclomatic complexity indicates confusing code which may be prone to + errors or difficult to modify. +optionsDescription: |- + + An optional upper limit for cyclomatic complexity can be specified. If no limit option + is provided a default value of $(Rule.DEFAULT_THRESHOLD) will be used. +options: + type: number + minimum: $(Rule.MINIMUM_THRESHOLD) +optionExamples: + - 'true' + - '[true, 20]' +type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: cyclomatic-complexity' +optionsJSON: |- + { + "type": "number", + "minimum": "$(Rule.MINIMUM_THRESHOLD)" + } +--- \ No newline at end of file diff --git a/docs/rules/eofline/index.html b/docs/rules/eofline/index.html index 81ddde9865e..985298840d8 100644 --- a/docs/rules/eofline/index.html +++ b/docs/rules/eofline/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: eofline' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/file-header/index.html b/docs/rules/file-header/index.html index 188c64955fc..7cc981b6bb8 100644 --- a/docs/rules/file-header/index.html +++ b/docs/rules/file-header/index.html @@ -5,12 +5,13 @@ options: type: string optionExamples: - - '"true", "Copyright \d{4}"' + - '[true, "Copyright \\d{4}"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: file-header' optionsJSON: |- { "type": "string" } -layout: rule -title: 'Rule: file-header' --- \ No newline at end of file diff --git a/docs/rules/forin/index.html b/docs/rules/forin/index.html index 9ec8b7baa00..e41a69c1068 100644 --- a/docs/rules/forin/index.html +++ b/docs/rules/forin/index.html @@ -18,7 +18,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: forin' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/indent/index.html b/docs/rules/indent/index.html index 5962ea11c0a..28d55c314b5 100644 --- a/docs/rules/indent/index.html +++ b/docs/rules/indent/index.html @@ -19,6 +19,9 @@ optionExamples: - '[true, "spaces"]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: indent' optionsJSON: |- { "type": "string", @@ -27,6 +30,4 @@ "spaces" ] } -layout: rule -title: 'Rule: indent' --- \ No newline at end of file diff --git a/docs/rules/interface-name/index.html b/docs/rules/interface-name/index.html index 81a93b61162..91375f2a0ec 100644 --- a/docs/rules/interface-name/index.html +++ b/docs/rules/interface-name/index.html @@ -17,6 +17,9 @@ - '[true, "always-prefix"]' - '[true, "never-prefix"]' type: style +typescriptOnly: true +layout: rule +title: 'Rule: interface-name' optionsJSON: |- { "type": "string", @@ -25,6 +28,4 @@ "never-prefix" ] } -layout: rule -title: 'Rule: interface-name' --- \ No newline at end of file diff --git a/docs/rules/jsdoc-format/index.html b/docs/rules/jsdoc-format/index.html index de7cd5e2731..269ceab1b0a 100644 --- a/docs/rules/jsdoc-format/index.html +++ b/docs/rules/jsdoc-format/index.html @@ -15,7 +15,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: jsdoc-format' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/label-position/index.html b/docs/rules/label-position/index.html index bd706278995..d82ae64eab8 100644 --- a/docs/rules/label-position/index.html +++ b/docs/rules/label-position/index.html @@ -12,7 +12,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: label-position' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/label-undefined/index.html b/docs/rules/label-undefined/index.html deleted file mode 100644 index 4876b9c2486..00000000000 --- a/docs/rules/label-undefined/index.html +++ /dev/null @@ -1,14 +0,0 @@ ---- -ruleName: label-undefined -description: Checks that labels are defined before usage. -descriptionDetails: This rule is now implemented in the TypeScript compiler and does not need to be used. -rationale: Using `break` or `continue` to go to an out-of-scope label is an error in JS. -optionsDescription: Not configurable. -options: null -optionExamples: - - 'true' -type: functionality -optionsJSON: 'null' -layout: rule -title: 'Rule: label-undefined' ---- \ No newline at end of file diff --git a/docs/rules/linebreak-style/index.html b/docs/rules/linebreak-style/index.html index f5c695c8072..363c990858e 100644 --- a/docs/rules/linebreak-style/index.html +++ b/docs/rules/linebreak-style/index.html @@ -16,6 +16,9 @@ - '[true, "LF"]' - '[true, "CRLF"]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: linebreak-style' optionsJSON: |- { "type": "string", @@ -24,6 +27,4 @@ "CRLF" ] } -layout: rule -title: 'Rule: linebreak-style' --- \ No newline at end of file diff --git a/docs/rules/max-classes-per-file/index.html b/docs/rules/max-classes-per-file/index.html new file mode 100644 index 00000000000..985d4d6824a --- /dev/null +++ b/docs/rules/max-classes-per-file/index.html @@ -0,0 +1,40 @@ +--- +ruleName: max-classes-per-file +description: |- + + A file may not contain more than the specified number of classes +rationale: |- + + Ensures that files have a single responsibility so that that classes each exist in their own files +optionsDescription: |- + + The one required argument is an integer indicating the maximum number of classes that can appear in a file. +options: + type: array + items: + - type: number + minimum: 1 + additionalItems: false + minLength: 1 + maxLength: 2 +optionExamples: + - '[true, 1]' + - '[true, 5]' +type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: max-classes-per-file' +optionsJSON: |- + { + "type": "array", + "items": [ + { + "type": "number", + "minimum": 1 + } + ], + "additionalItems": false, + "minLength": 1, + "maxLength": 2 + } +--- \ No newline at end of file diff --git a/docs/rules/max-file-line-count/index.html b/docs/rules/max-file-line-count/index.html index bdb39e39c5d..88556799827 100644 --- a/docs/rules/max-file-line-count/index.html +++ b/docs/rules/max-file-line-count/index.html @@ -12,11 +12,12 @@ optionExamples: - '[true, 300]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: max-file-line-count' optionsJSON: |- { "type": "number", "minimum": "1" } -layout: rule -title: 'Rule: max-file-line-count' --- \ No newline at end of file diff --git a/docs/rules/max-line-length/index.html b/docs/rules/max-line-length/index.html index e11807c5528..fdd451fce6a 100644 --- a/docs/rules/max-line-length/index.html +++ b/docs/rules/max-line-length/index.html @@ -13,11 +13,12 @@ optionExamples: - '[true, 120]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: max-line-length' optionsJSON: |- { "type": "number", "minimum": "1" } -layout: rule -title: 'Rule: max-line-length' --- \ No newline at end of file diff --git a/docs/rules/member-access/index.html b/docs/rules/member-access/index.html index 006c20c4dfd..ae5c4991013 100644 --- a/docs/rules/member-access/index.html +++ b/docs/rules/member-access/index.html @@ -21,6 +21,9 @@ - 'true' - '[true, "check-accessor"]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: member-access' optionsJSON: |- { "type": "array", @@ -34,6 +37,4 @@ "minLength": 0, "maxLength": 2 } -layout: rule -title: 'Rule: member-access' --- \ No newline at end of file diff --git a/docs/rules/member-ordering/index.html b/docs/rules/member-ordering/index.html index 3ea91700dbe..295ced8cb52 100644 --- a/docs/rules/member-ordering/index.html +++ b/docs/rules/member-ordering/index.html @@ -60,6 +60,9 @@ optionExamples: - '[true, { "order": "fields-first" }]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: member-ordering' optionsJSON: |- { "type": "object", @@ -101,6 +104,4 @@ }, "additionalProperties": false } -layout: rule -title: 'Rule: member-ordering' --- \ No newline at end of file diff --git a/docs/rules/new-parens/index.html b/docs/rules/new-parens/index.html index d1cdf11ab25..58aa3916f69 100644 --- a/docs/rules/new-parens/index.html +++ b/docs/rules/new-parens/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: new-parens' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-angle-bracket-type-assertion/index.html b/docs/rules/no-angle-bracket-type-assertion/index.html index 36bf52bb044..7353488bdba 100644 --- a/docs/rules/no-angle-bracket-type-assertion/index.html +++ b/docs/rules/no-angle-bracket-type-assertion/index.html @@ -11,7 +11,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-angle-bracket-type-assertion' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-any/index.html b/docs/rules/no-any/index.html index 08a9394329b..9e96a7e560a 100644 --- a/docs/rules/no-any/index.html +++ b/docs/rules/no-any/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: typescript -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-any' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-arg/index.html b/docs/rules/no-arg/index.html index 388c3194d36..a49b3401ff5 100644 --- a/docs/rules/no-arg/index.html +++ b/docs/rules/no-arg/index.html @@ -11,7 +11,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-arg' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-bitwise/index.html b/docs/rules/no-bitwise/index.html index e7dbe9f6bf5..9c83ca93d89 100644 --- a/docs/rules/no-bitwise/index.html +++ b/docs/rules/no-bitwise/index.html @@ -17,7 +17,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-bitwise' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-conditional-assignment/index.html b/docs/rules/no-conditional-assignment/index.html index c38f9119579..b7bdc4041ef 100644 --- a/docs/rules/no-conditional-assignment/index.html +++ b/docs/rules/no-conditional-assignment/index.html @@ -12,7 +12,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-conditional-assignment' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-consecutive-blank-lines/index.html b/docs/rules/no-consecutive-blank-lines/index.html index 1e9ec855f7b..180294b281f 100644 --- a/docs/rules/no-consecutive-blank-lines/index.html +++ b/docs/rules/no-consecutive-blank-lines/index.html @@ -1,13 +1,24 @@ --- ruleName: no-consecutive-blank-lines -description: Disallows more than one blank line in a row. +description: Disallows one or more blank lines in a row. rationale: Helps maintain a readable style in your codebase. -optionsDescription: Not configurable. -options: {} +optionsDescription: |- + + An optional number of maximum allowed sequential blanks can be specified. If no value + is provided, a default of $(Rule.DEFAULT_ALLOWED_BLANKS) will be used. +options: + type: number + minimum: $(Rule.MINIMUM_ALLOWED_BLANKS) optionExamples: - 'true' + - '[true, 2]' type: style -optionsJSON: '{}' +typescriptOnly: false layout: rule title: 'Rule: no-consecutive-blank-lines' +optionsJSON: |- + { + "type": "number", + "minimum": "$(Rule.MINIMUM_ALLOWED_BLANKS)" + } --- \ No newline at end of file diff --git a/docs/rules/no-console/index.html b/docs/rules/no-console/index.html index d8066eeee0d..3a04d5c29f2 100644 --- a/docs/rules/no-console/index.html +++ b/docs/rules/no-console/index.html @@ -10,6 +10,9 @@ optionExamples: - '[true, "log", "error"]' type: functionality +typescriptOnly: false +layout: rule +title: 'Rule: no-console' optionsJSON: |- { "type": "array", @@ -17,6 +20,4 @@ "type": "string" } } -layout: rule -title: 'Rule: no-console' --- \ No newline at end of file diff --git a/docs/rules/no-construct/index.html b/docs/rules/no-construct/index.html index a1f54fb6aba..d7f937db798 100644 --- a/docs/rules/no-construct/index.html +++ b/docs/rules/no-construct/index.html @@ -12,7 +12,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-construct' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-debugger/index.html b/docs/rules/no-debugger/index.html index 409c7ae3534..a3133012e5f 100644 --- a/docs/rules/no-debugger/index.html +++ b/docs/rules/no-debugger/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-debugger' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-default-export/index.html b/docs/rules/no-default-export/index.html index ab17c9c46b6..8e7a279a2a7 100644 --- a/docs/rules/no-default-export/index.html +++ b/docs/rules/no-default-export/index.html @@ -12,7 +12,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-default-export' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-duplicate-key/index.html b/docs/rules/no-duplicate-key/index.html deleted file mode 100644 index cae244b5058..00000000000 --- a/docs/rules/no-duplicate-key/index.html +++ /dev/null @@ -1,16 +0,0 @@ ---- -ruleName: no-duplicate-key -description: Disallows duplicate keys in object literals. -rationale: |- - - There is no good reason to define an object literal with the same key twice. - This rule is now implemented in the TypeScript compiler and does not need to be used. -optionsDescription: Not configurable. -options: null -optionExamples: - - 'true' -type: functionality -optionsJSON: 'null' -layout: rule -title: 'Rule: no-duplicate-key' ---- \ No newline at end of file diff --git a/docs/rules/no-duplicate-variable/index.html b/docs/rules/no-duplicate-variable/index.html index 26dbce48ecb..3dee824d2ce 100644 --- a/docs/rules/no-duplicate-variable/index.html +++ b/docs/rules/no-duplicate-variable/index.html @@ -14,7 +14,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-duplicate-variable' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-empty/index.html b/docs/rules/no-empty/index.html index 46a17a83dad..5fe4cc64ff0 100644 --- a/docs/rules/no-empty/index.html +++ b/docs/rules/no-empty/index.html @@ -8,7 +8,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-empty' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-eval/index.html b/docs/rules/no-eval/index.html index 30feb3c6ba6..63f08fba017 100644 --- a/docs/rules/no-eval/index.html +++ b/docs/rules/no-eval/index.html @@ -11,7 +11,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-eval' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-for-in-array/index.html b/docs/rules/no-for-in-array/index.html index ac33d240bb1..781e895234f 100644 --- a/docs/rules/no-for-in-array/index.html +++ b/docs/rules/no-for-in-array/index.html @@ -21,7 +21,8 @@ - 'true' requiresTypeInfo: true type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-for-in-array' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-inferrable-types/index.html b/docs/rules/no-inferrable-types/index.html index 1a01bde98cc..4518dc603e5 100644 --- a/docs/rules/no-inferrable-types/index.html +++ b/docs/rules/no-inferrable-types/index.html @@ -20,6 +20,9 @@ - 'true' - '[true, "ignore-params"]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: no-inferrable-types' optionsJSON: |- { "type": "array", @@ -32,6 +35,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: no-inferrable-types' --- \ No newline at end of file diff --git a/docs/rules/no-internal-module/index.html b/docs/rules/no-internal-module/index.html index 95a3965c86f..5092d8ef529 100644 --- a/docs/rules/no-internal-module/index.html +++ b/docs/rules/no-internal-module/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: typescript -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-internal-module' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-invalid-this/index.html b/docs/rules/no-invalid-this/index.html index 1126670a835..fb2d3d34ed2 100644 --- a/docs/rules/no-invalid-this/index.html +++ b/docs/rules/no-invalid-this/index.html @@ -19,6 +19,9 @@ - 'true' - '[true, "check-function-in-method"]' type: functionality +typescriptOnly: false +layout: rule +title: 'Rule: no-invalid-this' optionsJSON: |- { "type": "array", @@ -31,6 +34,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: no-invalid-this' --- \ No newline at end of file diff --git a/docs/rules/no-mergeable-namespace/index.html b/docs/rules/no-mergeable-namespace/index.html index be0ab94e3b1..ca24c662893 100644 --- a/docs/rules/no-mergeable-namespace/index.html +++ b/docs/rules/no-mergeable-namespace/index.html @@ -6,7 +6,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-mergeable-namespace' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-namespace/index.html b/docs/rules/no-namespace/index.html index fe69cd32512..d29ecbf5262 100644 --- a/docs/rules/no-namespace/index.html +++ b/docs/rules/no-namespace/index.html @@ -23,6 +23,9 @@ - 'true' - '[true, "allow-declarations"]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: no-namespace' optionsJSON: |- { "type": "array", @@ -35,6 +38,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: no-namespace' --- \ No newline at end of file diff --git a/docs/rules/no-null-keyword/index.html b/docs/rules/no-null-keyword/index.html index 6bb6bb71e6f..c4c46d69f8d 100644 --- a/docs/rules/no-null-keyword/index.html +++ b/docs/rules/no-null-keyword/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-null-keyword' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-constructor-vars/index.html b/docs/rules/no-parameter-properties/index.html similarity index 64% rename from docs/rules/no-constructor-vars/index.html rename to docs/rules/no-parameter-properties/index.html index d2fc9e99326..bac7fbb8f6e 100644 --- a/docs/rules/no-constructor-vars/index.html +++ b/docs/rules/no-parameter-properties/index.html @@ -1,6 +1,6 @@ --- -ruleName: no-constructor-vars -description: Disallows parameter properties. +ruleName: no-parameter-properties +description: Disallows parameter properties in class constructors. rationale: |- Parameter properties can be confusing to those new to TS as they are less explicit @@ -10,7 +10,8 @@ optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: true layout: rule -title: 'Rule: no-constructor-vars' +title: 'Rule: no-parameter-properties' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-reference/index.html b/docs/rules/no-reference/index.html index d77be60532e..85ff055965e 100644 --- a/docs/rules/no-reference/index.html +++ b/docs/rules/no-reference/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: typescript -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-reference' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-require-imports/index.html b/docs/rules/no-require-imports/index.html index b17524c8951..0791ef11775 100644 --- a/docs/rules/no-require-imports/index.html +++ b/docs/rules/no-require-imports/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-require-imports' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-shadowed-variable/index.html b/docs/rules/no-shadowed-variable/index.html index d6b60ae4316..c9b41de6420 100644 --- a/docs/rules/no-shadowed-variable/index.html +++ b/docs/rules/no-shadowed-variable/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-shadowed-variable' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-string-literal/index.html b/docs/rules/no-string-literal/index.html index 9db77bb7810..c4472e65b53 100644 --- a/docs/rules/no-string-literal/index.html +++ b/docs/rules/no-string-literal/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-string-literal' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-switch-case-fall-through/index.html b/docs/rules/no-switch-case-fall-through/index.html index 52ddb72588a..e6ff8459f6d 100644 --- a/docs/rules/no-switch-case-fall-through/index.html +++ b/docs/rules/no-switch-case-fall-through/index.html @@ -33,7 +33,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-switch-case-fall-through' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-trailing-whitespace/index.html b/docs/rules/no-trailing-whitespace/index.html index 6a2291ced17..eef2dc69bf4 100644 --- a/docs/rules/no-trailing-whitespace/index.html +++ b/docs/rules/no-trailing-whitespace/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-trailing-whitespace' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-unsafe-finally/index.html b/docs/rules/no-unsafe-finally/index.html index e630ded10c4..1d6e46900c8 100644 --- a/docs/rules/no-unsafe-finally/index.html +++ b/docs/rules/no-unsafe-finally/index.html @@ -16,7 +16,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-unsafe-finally' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-unused-expression/index.html b/docs/rules/no-unused-expression/index.html index e44c9eb01ef..82075de330a 100644 --- a/docs/rules/no-unused-expression/index.html +++ b/docs/rules/no-unused-expression/index.html @@ -13,7 +13,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-unused-expression' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-unused-new/index.html b/docs/rules/no-unused-new/index.html index f2add294cb5..4508b8fb8c6 100644 --- a/docs/rules/no-unused-new/index.html +++ b/docs/rules/no-unused-new/index.html @@ -13,7 +13,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-unused-new' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-unused-variable/index.html b/docs/rules/no-unused-variable/index.html index b892b4d3518..abb1bd4e72a 100644 --- a/docs/rules/no-unused-variable/index.html +++ b/docs/rules/no-unused-variable/index.html @@ -1,5 +1,6 @@ --- ruleName: no-unused-variable +deprecationMessage: Use the tsc compiler options --noUnusedParameters and --noUnusedLocals instead. description: 'Disallows unused imports, variables, functions and private class members.' optionsDescription: |- @@ -33,6 +34,9 @@ - '[true, "react"]' - '[true, {"ignore-pattern": "^_"}]' type: functionality +typescriptOnly: true +layout: rule +title: 'Rule: no-unused-variable' optionsJSON: |- { "type": "array", @@ -59,6 +63,4 @@ "minLength": 0, "maxLength": 3 } -layout: rule -title: 'Rule: no-unused-variable' --- \ No newline at end of file diff --git a/docs/rules/no-use-before-declare/index.html b/docs/rules/no-use-before-declare/index.html index e590931e298..d2c24056758 100644 --- a/docs/rules/no-use-before-declare/index.html +++ b/docs/rules/no-use-before-declare/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-use-before-declare' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-var-keyword/index.html b/docs/rules/no-var-keyword/index.html index 5fb0d769b0a..addab8d448c 100644 --- a/docs/rules/no-var-keyword/index.html +++ b/docs/rules/no-var-keyword/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: no-var-keyword' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/no-var-requires/index.html b/docs/rules/no-var-requires/index.html index d0d6dd071b8..ecbbca8fe5a 100644 --- a/docs/rules/no-var-requires/index.html +++ b/docs/rules/no-var-requires/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: typescript -optionsJSON: 'null' +typescriptOnly: true layout: rule title: 'Rule: no-var-requires' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/object-literal-key-quotes/index.html b/docs/rules/object-literal-key-quotes/index.html index 016e463b16f..66b593d1860 100644 --- a/docs/rules/object-literal-key-quotes/index.html +++ b/docs/rules/object-literal-key-quotes/index.html @@ -25,6 +25,9 @@ * `"always"`: Property names should always be quoted. (This is the default.) * `"as-needed"`: Only property names which require quotes may be quoted (e.g. those with spaces in them). + * `"consistent"`: Property names should either all be quoted or unquoted. + * `"consistent-as-needed"`: If any property name requires quotes, then all properties must be quoted. Otherwise, no + property names may be quoted. For ES6, computed property names (`{[name]: value}`) and methods (`{foo() {}}`) never need to be quoted. @@ -33,18 +36,23 @@ enum: - always - as-needed + - consistent + - consistent-as-needed optionExamples: - '[true, "as-needed"]' - '[true, "always"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: object-literal-key-quotes' optionsJSON: |- { "type": "string", "enum": [ "always", - "as-needed" + "as-needed", + "consistent", + "consistent-as-needed" ] } -layout: rule -title: 'Rule: object-literal-key-quotes' --- \ No newline at end of file diff --git a/docs/rules/object-literal-shorthand/index.html b/docs/rules/object-literal-shorthand/index.html index 3917afade21..1a6ca8708e8 100644 --- a/docs/rules/object-literal-shorthand/index.html +++ b/docs/rules/object-literal-shorthand/index.html @@ -1,11 +1,13 @@ --- ruleName: object-literal-shorthand description: Enforces use of ES6 object literal shorthand when possible. +optionsDescription: Not configurable. options: null optionExamples: - 'true' type: style -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: object-literal-shorthand' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/object-literal-sort-keys/index.html b/docs/rules/object-literal-sort-keys/index.html index 74c54296cf7..44dcc1850e8 100644 --- a/docs/rules/object-literal-sort-keys/index.html +++ b/docs/rules/object-literal-sort-keys/index.html @@ -7,7 +7,8 @@ optionExamples: - 'true' type: maintainability -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: object-literal-sort-keys' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/one-line/index.html b/docs/rules/one-line/index.html index ed9bb4b3ba7..646e89b8d56 100644 --- a/docs/rules/one-line/index.html +++ b/docs/rules/one-line/index.html @@ -25,6 +25,9 @@ optionExamples: - '[true, "check-catch", "check-finally", "check-else"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: one-line' optionsJSON: |- { "type": "array", @@ -41,6 +44,4 @@ "minLength": 0, "maxLength": 5 } -layout: rule -title: 'Rule: one-line' --- \ No newline at end of file diff --git a/docs/rules/one-variable-per-declaration/index.html b/docs/rules/one-variable-per-declaration/index.html index f90487ea783..327b8b59f65 100644 --- a/docs/rules/one-variable-per-declaration/index.html +++ b/docs/rules/one-variable-per-declaration/index.html @@ -18,6 +18,9 @@ - 'true' - '[true, "ignore-for-loop"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: one-variable-per-declaration' optionsJSON: |- { "type": "array", @@ -30,6 +33,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: one-variable-per-declaration' --- \ No newline at end of file diff --git a/docs/rules/only-arrow-functions/index.html b/docs/rules/only-arrow-functions/index.html index 7d5adbd6f63..f88c10f5bbb 100644 --- a/docs/rules/only-arrow-functions/index.html +++ b/docs/rules/only-arrow-functions/index.html @@ -20,6 +20,9 @@ - 'true' - '[true, "allow-declarations"]' type: typescript +typescriptOnly: false +layout: rule +title: 'Rule: only-arrow-functions' optionsJSON: |- { "type": "array", @@ -32,6 +35,4 @@ "minLength": 0, "maxLength": 1 } -layout: rule -title: 'Rule: only-arrow-functions' --- \ No newline at end of file diff --git a/docs/rules/ordered-imports/index.html b/docs/rules/ordered-imports/index.html index 8a87a1b21b2..78d7a0a5466 100644 --- a/docs/rules/ordered-imports/index.html +++ b/docs/rules/ordered-imports/index.html @@ -5,7 +5,7 @@ Enforce a consistent ordering for ES6 imports: - Named imports must be alphabetized (i.e. "import {A, B, C} from "foo";") - - The exact ordering can be controled by the named-imports-order option. + - The exact ordering can be controlled by the named-imports-order option. - "longName as name" imports are ordered by "longName". - Import sources must be alphabetized within groups, i.e.: import * as foo from "a"; @@ -21,6 +21,7 @@ * `"case-insensitive'`: Correct order is `"Bar"`, `"baz"`, `"Foo"`. (This is the default.) * `"lowercase-first"`: Correct order is `"baz"`, `"Bar"`, `"Foo"`. * `"lowercase-last"`: Correct order is `"Bar"`, `"Foo"`, `"baz"`. + * `"any"`: Allow any order. You may set the `"named-imports-order"` option to control the ordering of named imports (the `{A, B, C}` in `import {A, B, C} from "foo"`). @@ -30,6 +31,7 @@ * `"case-insensitive'`: Correct order is `{A, b, C}`. (This is the default.) * `"lowercase-first"`: Correct order is `{b, A, C}`. * `"lowercase-last"`: Correct order is `{A, C, b}`. + * `"any"`: Allow any order. options: @@ -41,17 +43,22 @@ - case-insensitive - lowercase-first - lowercase-last + - any named-imports-order: type: string enum: - case-insensitive - lowercase-first - lowercase-last + - any additionalProperties: false optionExamples: - 'true' - '[true, {"import-sources-order": "lowercase-last", "named-imports-order": "lowercase-first"}]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: ordered-imports' optionsJSON: |- { "type": "object", @@ -61,7 +68,8 @@ "enum": [ "case-insensitive", "lowercase-first", - "lowercase-last" + "lowercase-last", + "any" ] }, "named-imports-order": { @@ -69,12 +77,11 @@ "enum": [ "case-insensitive", "lowercase-first", - "lowercase-last" + "lowercase-last", + "any" ] } }, "additionalProperties": false } -layout: rule -title: 'Rule: ordered-imports' --- \ No newline at end of file diff --git a/docs/rules/prefer-for-of/index.html b/docs/rules/prefer-for-of/index.html new file mode 100644 index 00000000000..182c695e16f --- /dev/null +++ b/docs/rules/prefer-for-of/index.html @@ -0,0 +1,14 @@ +--- +ruleName: prefer-for-of +description: Recommends a 'for-of' loop over a standard 'for' loop if the index is only used to access the array being iterated. +rationale: A for(... of ...) loop is easier to implement and read when the index is not needed. +optionsDescription: Not configurable. +options: null +optionExamples: + - 'true' +type: typescript +typescriptOnly: false +layout: rule +title: 'Rule: prefer-for-of' +optionsJSON: 'null' +--- \ No newline at end of file diff --git a/docs/rules/quotemark/index.html b/docs/rules/quotemark/index.html index 1163f9023f9..19eb51583cd 100644 --- a/docs/rules/quotemark/index.html +++ b/docs/rules/quotemark/index.html @@ -27,6 +27,9 @@ - '[true, "single", "avoid-escape"]' - '[true, "single", "jsx-double"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: quotemark' optionsJSON: |- { "type": "array", @@ -43,6 +46,4 @@ "minLength": 0, "maxLength": 5 } -layout: rule -title: 'Rule: quotemark' --- \ No newline at end of file diff --git a/docs/rules/radix/index.html b/docs/rules/radix/index.html index 33209320a3b..f951cffb6ac 100644 --- a/docs/rules/radix/index.html +++ b/docs/rules/radix/index.html @@ -11,7 +11,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: radix' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/restrict-plus-operands/index.html b/docs/rules/restrict-plus-operands/index.html index 902b433010a..1a20bb14ee8 100644 --- a/docs/rules/restrict-plus-operands/index.html +++ b/docs/rules/restrict-plus-operands/index.html @@ -6,8 +6,9 @@ optionExamples: - 'true' type: functionality +typescriptOnly: false requiresTypeInfo: true -optionsJSON: 'null' layout: rule title: 'Rule: restrict-plus-operands' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/semicolon/index.html b/docs/rules/semicolon/index.html index 5bbb10c22e4..095bfb1ee96 100644 --- a/docs/rules/semicolon/index.html +++ b/docs/rules/semicolon/index.html @@ -10,6 +10,7 @@ The following arguments may be optionaly provided: * `"ignore-interfaces"` skips checking semicolons at the end of interface members. + * `"ignore-bound-class-methods"` skips checking semicolons at the end of bound class methods. options: type: array items: @@ -25,7 +26,11 @@ - '[true, "always"]' - '[true, "never"]' - '[true, "always", "ignore-interfaces"]' + - '[true, "always", "ignore-bound-class-methods"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: semicolon' optionsJSON: |- { "type": "array", @@ -46,6 +51,4 @@ ], "additionalItems": false } -layout: rule -title: 'Rule: semicolon' --- \ No newline at end of file diff --git a/docs/rules/switch-default/index.html b/docs/rules/switch-default/index.html index f6bc874814a..4bfa95371fa 100644 --- a/docs/rules/switch-default/index.html +++ b/docs/rules/switch-default/index.html @@ -6,7 +6,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: switch-default' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/trailing-comma/index.html b/docs/rules/trailing-comma/index.html index ef0150a62c8..c2e2aeeb843 100644 --- a/docs/rules/trailing-comma/index.html +++ b/docs/rules/trailing-comma/index.html @@ -1,6 +1,9 @@ --- ruleName: trailing-comma -description: 'Requires or disallows trailing commas in array and object literals, destructuring assignments and named imports.' +description: |- + + Requires or disallows trailing commas in array and object literals, destructuring assignments, function and tuple typings, + named imports and function parameters. optionsDescription: |- One argument which is an object with the keys `multiline` and `singleline`. @@ -11,7 +14,8 @@ A array is considered "multiline" if its closing bracket is on a line after the last array element. The same general logic is followed for - object literals and named import statements. + object literals, function and tuple typings, named import statements + and function parameters. options: type: object properties: @@ -29,6 +33,9 @@ optionExamples: - '[true, {"multiline": "always", "singleline": "never"}]' type: maintainability +typescriptOnly: false +layout: rule +title: 'Rule: trailing-comma' optionsJSON: |- { "type": "object", @@ -50,6 +57,4 @@ }, "additionalProperties": false } -layout: rule -title: 'Rule: trailing-comma' --- \ No newline at end of file diff --git a/docs/rules/triple-equals/index.html b/docs/rules/triple-equals/index.html index 5ad73c8c86d..1fdfe98e5b8 100644 --- a/docs/rules/triple-equals/index.html +++ b/docs/rules/triple-equals/index.html @@ -21,6 +21,9 @@ - '[true, "allow-null-check"]' - '[true, "allow-undefined-check"]' type: functionality +typescriptOnly: false +layout: rule +title: 'Rule: triple-equals' optionsJSON: |- { "type": "array", @@ -34,6 +37,4 @@ "minLength": 0, "maxLength": 2 } -layout: rule -title: 'Rule: triple-equals' --- \ No newline at end of file diff --git a/docs/rules/typedef-whitespace/index.html b/docs/rules/typedef-whitespace/index.html index db7134d3dfb..8fcd3b63087 100644 --- a/docs/rules/typedef-whitespace/index.html +++ b/docs/rules/typedef-whitespace/index.html @@ -55,6 +55,9 @@ } ] type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: typedef-whitespace' optionsJSON: |- { "type": "array", @@ -154,6 +157,4 @@ ], "additionalItems": false } -layout: rule -title: 'Rule: typedef-whitespace' --- \ No newline at end of file diff --git a/docs/rules/typedef/index.html b/docs/rules/typedef/index.html index 727f9ed08b6..67ca7f977f2 100644 --- a/docs/rules/typedef/index.html +++ b/docs/rules/typedef/index.html @@ -29,6 +29,9 @@ optionExamples: - '[true, "call-signature", "parameter", "member-variable-declaration"]' type: typescript +typescriptOnly: true +layout: rule +title: 'Rule: typedef' optionsJSON: |- { "type": "array", @@ -47,6 +50,4 @@ "minLength": 0, "maxLength": 7 } -layout: rule -title: 'Rule: typedef' --- \ No newline at end of file diff --git a/docs/rules/use-isnan/index.html b/docs/rules/use-isnan/index.html index 2c3dbc2a07e..848ec439738 100644 --- a/docs/rules/use-isnan/index.html +++ b/docs/rules/use-isnan/index.html @@ -10,7 +10,8 @@ optionExamples: - 'true' type: functionality -optionsJSON: 'null' +typescriptOnly: false layout: rule title: 'Rule: use-isnan' +optionsJSON: 'null' --- \ No newline at end of file diff --git a/docs/rules/use-strict/index.html b/docs/rules/use-strict/index.html deleted file mode 100644 index a90611acb6b..00000000000 --- a/docs/rules/use-strict/index.html +++ /dev/null @@ -1,37 +0,0 @@ ---- -ruleName: use-strict -description: Requires using ECMAScript 5's strict mode. -optionsDescription: |- - - Two arguments may be optionally provided: - - * `check-module` checks that all top-level modules are using strict mode. - * `check-function` checks that all top-level functions are using strict mode. -options: - type: array - items: - type: string - enum: - - check-module - - check-function - minLength: 0 - maxLength: 2 -optionExamples: - - '[true, "check-module"]' -type: functionality -optionsJSON: |- - { - "type": "array", - "items": { - "type": "string", - "enum": [ - "check-module", - "check-function" - ] - }, - "minLength": 0, - "maxLength": 2 - } -layout: rule -title: 'Rule: use-strict' ---- \ No newline at end of file diff --git a/docs/rules/variable-name/index.html b/docs/rules/variable-name/index.html index f7220338766..0808782623f 100644 --- a/docs/rules/variable-name/index.html +++ b/docs/rules/variable-name/index.html @@ -26,6 +26,9 @@ optionExamples: - '[true, "ban-keywords", "check-format", "allow-leading-underscore"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: variable-name' optionsJSON: |- { "type": "array", @@ -42,6 +45,4 @@ "minLength": 0, "maxLength": 5 } -layout: rule -title: 'Rule: variable-name' --- \ No newline at end of file diff --git a/docs/rules/whitespace/index.html b/docs/rules/whitespace/index.html index 4e591aa49a2..259fd6a8e02 100644 --- a/docs/rules/whitespace/index.html +++ b/docs/rules/whitespace/index.html @@ -30,6 +30,9 @@ optionExamples: - '[true, "check-branch", "check-operator", "check-typecast"]' type: style +typescriptOnly: false +layout: rule +title: 'Rule: whitespace' optionsJSON: |- { "type": "array", @@ -48,6 +51,4 @@ "minLength": 0, "maxLength": 7 } -layout: rule -title: 'Rule: whitespace' --- \ No newline at end of file diff --git a/docs/usage/cli/index.md b/docs/usage/cli/index.md index 52c6cf62f37..6992d54d605 100644 --- a/docs/usage/cli/index.md +++ b/docs/usage/cli/index.md @@ -30,15 +30,18 @@ Options: ``` -c, --config configuration file +-e, --exclude exclude globs from path expansion +--fix Fixes linting errors for select rules. This may overwrite linted files --force return status code 0 even if there are lint errors -h, --help display detailed help -i, --init generate a tslint.json config file in the current working directory -o, --out output file +--project tsconfig.json file -r, --rules-dir rules directory -s, --formatters-dir formatters directory --e, --exclude exclude globs from path expansion --t, --format output format (prose, json, verbose, pmd, msbuild, checkstyle, vso) [default: "prose"] +-t, --format output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist) [default: "prose"] --test test that tslint produces the correct output for the specified directory +--type-check enable type checking when linting a project -v, --version current version ``` @@ -54,7 +57,7 @@ tslint accepts the following command-line options: to the rules. If no option is specified, the config file named tslint.json is used, so long as it exists in the path. The format of the file is { rules: { /* rules list */ } }, - where /* rules list */ is a key: value comma-seperated list of + where /* rules list */ is a key: value comma-separated list of rulename: rule-options pairs. Rule-options can be either a boolean true/false value denoting whether the rule is used or not, or a list [boolean, ...] where the boolean provides the same role @@ -68,6 +71,9 @@ tslint accepts the following command-line options: This option can be supplied multiple times if you need multiple globs to indicate which files to exclude. +--fix: + Fixes linting errors for select rules. This may overwrite linted files. + --force: Return status code 0 even if there are any lint errors. Useful while running as npm script. @@ -109,6 +115,14 @@ tslint accepts the following command-line options: 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. +--project: + The location of a tsconfig.json file that will be used to determine which + files will be linted. + +--type-check + Enables the type checker when running linting rules. --project must be + specified in order to enable type checking. + -v, --version: The current version of tslint. diff --git a/docs/usage/tslint-json/index.md b/docs/usage/tslint-json/index.md index 4d2bd202f41..0b3e3135ee0 100644 --- a/docs/usage/tslint-json/index.md +++ b/docs/usage/tslint-json/index.md @@ -20,7 +20,8 @@ A path(s) to a directory of [custom rules][2]. This will always be treated as a * `rules?: any`: Pairs of keys and values where each key is a rule name and each value is the configuration for that rule. If a rule takes no options, you can simply set its value to a boolean, either `true` or `false`, to enable or disable it. If a rule takes options, you set its value to an array where the first value is a boolean indicating if the rule is enabled and the next values are options handled by the rule. -Not all possible rules are listed here, be sure to [check out the full list][3]. +Not all possible rules are listed here, be sure to [check out the full list][3]. These rules are applied to `.ts` and `.tsx` files. +* `jsRules?: any`: Same format as `rules`. These rules are applied to `.js` and `.jsx` files. `tslint.json` configuration files may have JavaScript-style `// single-line` and `/* multi-line */` comments in them (even though this is technically invalid JSON). If this confuses your syntax highlighter, you may want to switch it to JavaScript format. @@ -57,6 +58,24 @@ An example `tslint.json` file might look like this: "check-separator", "check-type" ] + }, + "jsRules": { + "indent": [true, "spaces"], + "no-duplicate-variable": true, + "no-eval": true, + "no-trailing-whitespace": true, + "one-line": [true, "check-open-brace", "check-whitespace"], + "quotemark": [true, "double"], + "semicolon": false, + "triple-equals": [true, "allow-null-check"], + "variable-name": [true, "ban-keywords"], + "whitespace": [true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ] } } ``` diff --git a/package.json b/package.json index 91e9fb2a455..0a5f8b5775a 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "tslint", - "version": "4.0.0-dev", + "version": "4.0.2", "description": "An extensible static analysis linter for the TypeScript language", "bin": { "tslint": "./bin/tslint" }, - "main": "./lib/tslint", - "typings": "./lib/tslint", + "main": "./lib/index.js", + "typings": "./lib/index.d.ts", "repository": { "type": "git", "url": "https://github.com/palantir/tslint.git" @@ -17,39 +17,57 @@ "linter" ], "scripts": { - "test": "grunt" + "clean": "npm-run-all -p clean:core clean:test", + "clean:core": "rimraf lib", + "clean:test": "rimraf build && rimraf test/config/node_modules", + "docs": "node scripts/buildDocs.js", + "compile": "npm-run-all -p compile:core compile:test -s compile:scripts", + "compile:core": "tsc -p src", + "compile:scripts": "tsc -p scripts", + "compile:test": "tsc -p test", + "lint": "npm-run-all -p lint:core lint:test", + "lint:core": "tslint \"src/**/*.ts\"", + "lint:test": "tslint \"test/**/*.ts\" -e \"test/**/*.test.ts\"", + "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\" build/test/assert.js", + "test:rules": "node ./build/test/ruleTestRunner.js", + "verify": "npm-run-all clean compile lint test docs" }, "dependencies": { "colors": "^1.1.2", - "diff": "^2.2.1", + "diff": "^3.0.1", "findup-sync": "~0.3.0", - "glob": "^7.0.3", + "glob": "^7.1.1", "optimist": "~0.6.0", "resolve": "^1.1.7", - "underscore.string": "^3.3.4" + "underscore.string": "^3.3.4", + "update-notifier": "^1.0.2" }, "devDependencies": { + "@types/chai": "^3.4.34", + "@types/colors": "^0.6.33", + "@types/diff": "0.0.31", + "@types/findup-sync": "^0.3.29", + "@types/glob": "^5.0.30", + "@types/js-yaml": "^3.5.28", + "@types/mocha": "^2.2.32", + "@types/node": "^6.0.45", + "@types/optimist": "0.0.29", + "@types/resolve": "0.0.4", + "@types/underscore": "^1.7.33", + "@types/underscore.string": "0.0.30", "chai": "^3.0.0", - "grunt": "^1.0.1", - "grunt-cli": "^1.2.0", - "grunt-contrib-clean": "^1.0.0", - "grunt-eslint": "^18.1.0", - "grunt-mocha-test": "^0.12.7", - "grunt-npm-command": "^0.1.2", - "grunt-run": "~0.6.0", - "grunt-ts": "^5.1.0", - "grunt-tslint": "latest", - "js-yaml": "^3.4.6", - "mocha": "^2.2.5", + "js-yaml": "^3.6.1", + "mocha": "^3.1.0", + "npm-run-all": "^3.1.0", + "rimraf": "^2.5.4", "tslint": "latest", "tslint-test-config-non-relative": "file:test/external/tslint-test-config-non-relative", - "typescript": "1.8.10" + "typescript": "2.0.10" }, "peerDependencies": { - "typescript": ">=1.7.3" + "typescript": ">=2.0.0" }, - "license": "Apache-2.0", - "typescript": { - "definition": "lib/tslint.d.ts" - } + "license": "Apache-2.0" } diff --git a/scripts/buildDocs.ts b/scripts/buildDocs.ts index 337164c3a5b..937928927b5 100644 --- a/scripts/buildDocs.ts +++ b/scripts/buildDocs.ts @@ -36,49 +36,144 @@ import * as glob from "glob"; import * as yaml from "js-yaml"; import * as path from "path"; -import {AbstractRule} from "../lib/language/rule/abstractRule"; +import {IFormatterMetadata} from "../lib/language/formatter/formatter"; import {IRuleMetadata} from "../lib/language/rule/rule"; +type Metadata = IRuleMetadata | IFormatterMetadata; +type Documented = { metadata: Metadata }; + +interface IDocumentation { + /** + * File name for the json data file listing. + */ + dataFileName: string; + + /** + * Exported item name from each file. + */ + exportName: string; + + /** + * Pattern matching files to be documented. + */ + globPattern: string; + + /** + * Key of the item's name within the metadata object. + */ + nameMetadataKey: string; + + /** + * Function to generate individual documentation pages. + */ + pageGenerator: (metadata: any) => string; + + /** + * Documentation subdirectory to output to. + */ + subDirectory: string; +} + const DOCS_DIR = "../docs"; -const DOCS_RULE_DIR = path.join(DOCS_DIR, "rules"); -const rulePaths = glob.sync("../lib/rules/*Rule.js"); -const rulesJson: IRuleMetadata[] = []; -for (const rulePath of rulePaths) { +process.chdir("./scripts"); + +/** + * Documentation definition for rule modules. + */ +const ruleDocumentation: IDocumentation = { + dataFileName: "rules.json", + exportName: "Rule", + globPattern: "../lib/rules/*Rule.js", + nameMetadataKey: "ruleName", + pageGenerator: generateRuleFile, + subDirectory: path.join(DOCS_DIR, "rules"), +}; + +/** + * Documentation definition for formatter modules. + */ +const formatterDocumentation: IDocumentation = { + dataFileName: "formatters.json", + exportName: "Formatter", + globPattern: "../lib/formatters/*Formatter.js", + nameMetadataKey: "formatterName", + pageGenerator: generateFormatterFile, + subDirectory: path.join(DOCS_DIR, "formatters"), +}; + +/** + * Builds complete documentation. + */ +function buildDocumentation(documentation: IDocumentation) { + // Create each module's documentation file. + const paths = glob.sync(documentation.globPattern); + const metadataJson = paths.map((path: string) => { + return buildSingleModuleDocumentation(documentation, path); + }); + + // Create a data file with details of every module. + buildDocumentationDataFile(documentation, metadataJson); +} + +/** + * Produces documentation for a single file/module. + */ +function buildSingleModuleDocumentation(documentation: IDocumentation, modulePath: string): Metadata { + // Load the module. // tslint:disable-next-line:no-var-requires - const ruleModule = require(rulePath); - const Rule = ruleModule.Rule as typeof AbstractRule; - if (Rule != null && Rule.metadata != null) { - const { metadata } = Rule; - const fileData = generateRuleFile(metadata); - const fileDirectory = path.join(DOCS_RULE_DIR, metadata.ruleName); - - // write file for each specific rule + const module = require(modulePath); + const DocumentedItem = module[documentation.exportName] as Documented; + if (DocumentedItem != null && DocumentedItem.metadata != null) { + // Build the module's page. + const { metadata } = DocumentedItem; + const fileData = documentation.pageGenerator(metadata); + + // Ensure a directory exists and write the module's file. + const moduleName = (metadata as any)[documentation.nameMetadataKey]; + const fileDirectory = path.join(documentation.subDirectory, moduleName); if (!fs.existsSync(fileDirectory)) { fs.mkdirSync(fileDirectory); } fs.writeFileSync(path.join(fileDirectory, "index.html"), fileData); - rulesJson.push(metadata); + return metadata; } } -// write overall data file, this is used to generate the index page for the rules -const fileData = JSON.stringify(rulesJson, undefined, 2); -fs.writeFileSync(path.join(DOCS_DIR, "_data", "rules.json"), fileData); +function buildDocumentationDataFile(documentation: IDocumentation, metadataJson: any[]) { + const dataJson = JSON.stringify(metadataJson, undefined, 2); + fs.writeFileSync(path.join(DOCS_DIR, "_data", documentation.dataFileName), dataJson); +} + +/** + * Generates Jekyll data from any item's metadata. + */ +function generateJekyllData(metadata: any, type: string, name: string): any { + return Object.assign({}, metadata, { + layout: type.toLowerCase(), + title: `${type}: ${name}`, + }); +} /** - * Based off a rule's metadata, generates a string Jekyll "HTML" file + * Based off a rule's metadata, generates a Jekyll "HTML" file * that only consists of a YAML front matter block. */ -function generateRuleFile(metadata: IRuleMetadata) { - const yamlData: any = {}; - // TODO: Use Object.assign when Node 0.12 support is dropped (#1181) - for (const key of Object.keys(metadata)) { - yamlData[key] = ( metadata)[key]; - } +function generateRuleFile(metadata: IRuleMetadata): string { + const yamlData = generateJekyllData(metadata, "Rule", metadata.ruleName); yamlData.optionsJSON = JSON.stringify(metadata.options, undefined, 2); - yamlData.layout = "rule"; - yamlData.title = `Rule: ${metadata.ruleName}`; return `---\n${yaml.safeDump(yamlData, {lineWidth: 140})}---`; } + +/** + * Based off a formatter's metadata, generates a Jekyll "HTML" file + * that only consists of a YAML front matter block. + */ +function generateFormatterFile(metadata: IFormatterMetadata): string { + const yamlData = generateJekyllData(metadata, "Formatter", metadata.formatterName); + return `---\n${yaml.safeDump(yamlData, {lineWidth: 140})}---`; +} + +buildDocumentation(ruleDocumentation); +buildDocumentation(formatterDocumentation); diff --git a/scripts/custom-typings.d.ts b/scripts/custom-typings.d.ts new file mode 100644 index 00000000000..9788f1bee3c --- /dev/null +++ b/scripts/custom-typings.d.ts @@ -0,0 +1,4 @@ +// Node v4+ support Object.assign +interface ObjectConstructor { + assign(target: any, ...sources: any[]): any; +} diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json index cd7a2427adb..a0ebb235e95 100644 --- a/scripts/tsconfig.json +++ b/scripts/tsconfig.json @@ -1,31 +1,11 @@ { - "version": "1.8.0", + "version": "2.0.10", "compilerOptions": { "module": "commonjs", "noImplicitAny": true, - "declaration": false, - "sourceMap": false, - "target": "es5", - "outDir": "." - }, - "atom": { - "rewriteTsconfig": false - }, - "filesGlob": [ - "../typings/**/*.d.ts", - "./*.ts" - ], - "files": [ - "../typings/colors/colors.d.ts", - "../typings/diff/diff.d.ts", - "../typings/findup-sync/findup-sync.d.ts", - "../typings/glob/glob.d.ts", - "../typings/js-yaml/js-yaml.d.ts", - "../typings/minimatch/minimatch.d.ts", - "../typings/node/node.d.ts", - "../typings/optimist/optimist.d.ts", - "../typings/underscore.string/underscore.string.d.ts", - "../typings/underscore/underscore.d.ts", - "buildDocs.ts" - ] -} \ No newline at end of file + "noUnusedParameters": true, + "noUnusedLocals": true, + "sourceMap": true, + "target": "es5" + } +} diff --git a/src/configs/latest.ts b/src/configs/latest.ts index 3579a7245e8..a6523eb76c1 100644 --- a/src/configs/latest.ts +++ b/src/configs/latest.ts @@ -16,16 +16,6 @@ */ export const rules = { - "adjacent-overload-signatures": true, - "cyclomatic-complexity": false, - "no-unsafe-finally": true, - "object-literal-key-quotes": [true, "as-needed"], - "object-literal-shorthand": true, - "only-arrow-functions": [true, "allow-declarations"], - "ordered-imports": [true, { - "import-sources-order": "case-insensitive", - "named-imports-order": "lowercase-last", - }], }; // work around "extends" being a keyword diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts index d0195bd59da..a1f4dac224b 100644 --- a/src/configs/recommended.ts +++ b/src/configs/recommended.ts @@ -17,22 +17,26 @@ /* tslint:disable:object-literal-key-quotes */ export const rules = { + "adjacent-overload-signatures": true, "align": [true, "parameters", "statements", ], + "array-type": [true, "array-simple"], + "arrow-parens": true, "class-name": true, "comment-format": [true, "check-space", ], "curly": true, + "cyclomatic-complexity": false, "eofline": true, "forin": true, "indent": [true, "spaces"], "interface-name": [true, "always-prefix"], "jsdoc-format": true, "label-position": true, - "label-undefined": true, + "max-classes-per-file": [true, 1], "max-line-length": [true, 120], "member-access": true, "member-ordering": [true, @@ -53,27 +57,26 @@ export const rules = { "trace", ], "no-construct": true, - "no-constructor-vars": false, "no-debugger": true, - "no-duplicate-key": true, - "no-duplicate-variable": true, "no-empty": true, "no-eval": true, "no-internal-module": true, "no-namespace": true, + "no-parameter-properties": false, "no-reference": true, "no-shadowed-variable": true, "no-string-literal": true, "no-switch-case-fall-through": false, "no-trailing-whitespace": true, - "no-unreachable": true, + "no-unsafe-finally": true, "no-unused-expression": true, "no-unused-new": true, - "no-unused-variable": [true, "react"], // disable this rule as it is very heavy performance-wise and not that useful "no-use-before-declare": false, "no-var-keyword": true, "no-var-requires": true, + "object-literal-key-quotes": [true, "consistent-as-needed"], + "object-literal-shorthand": true, "object-literal-sort-keys": true, "one-line": [true, "check-catch", @@ -85,6 +88,12 @@ export const rules = { "one-variable-per-declaration": [true, "ignore-for-loop", ], + "only-arrow-functions": [true, "allow-declarations"], + "ordered-imports": [true, { + "import-sources-order": "case-insensitive", + "named-imports-order": "case-insensitive", + }], + "prefer-for-of": true, "quotemark": [true, "double", "avoid-escape"], "radix": true, "semicolon": [true, "always"], @@ -127,4 +136,81 @@ export const rules = { "check-typecast", ], }; +export const jsRules = { + "align": [true, + "parameters", + "statements", + ], + "class-name": true, + "curly": true, + "eofline": true, + "forin": true, + "indent": [true, "spaces"], + "jsdoc-format": true, + "label-position": true, + "max-line-length": [true, 120], + "new-parens": true, + "no-arg": true, + "no-bitwise": true, + "no-conditional-assignment": true, + "no-consecutive-blank-lines": true, + "no-console": [true, + "debug", + "info", + "log", + "time", + "timeEnd", + "trace", + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-reference": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-switch-case-fall-through": false, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-unused-new": true, + // disable this rule as it is very heavy performance-wise and not that useful + "no-use-before-declare": false, + "object-literal-sort-keys": true, + "one-line": [true, + "check-catch", + "check-else", + "check-finally", + "check-open-brace", + "check-whitespace", + ], + "one-variable-per-declaration": [true, + "ignore-for-loop", + ], + "quotemark": [true, "double", "avoid-escape"], + "radix": true, + "semicolon": [true, "always"], + "switch-default": true, + "trailing-comma": [true, + { + "multiline": "always", + "singleline": "never", + }, + ], + "triple-equals": [true, "allow-null-check"], + "use-isnan": true, + "variable-name": [true, + "ban-keywords", + "check-format", + "allow-pascal-case", + ], + "whitespace": [true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast", + ], +}; /* tslint:enable:object-literal-key-quotes */ diff --git a/src/configuration.ts b/src/configuration.ts index e9039169c90..1f699b587f4 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -19,11 +19,13 @@ import findup = require("findup-sync"); import * as fs from "fs"; import * as path from "path"; import * as resolve from "resolve"; +import { FatalError } from "./error"; import {arrayify, objectify, stripComments} from "./utils"; export interface IConfigurationFile { extends?: string | string[]; + jsRules?: any; linterOptions?: { typeCheck?: boolean, }; @@ -31,15 +33,40 @@ export interface IConfigurationFile { rules?: any; } +export interface IConfigurationLoadResult { + path: string; + results?: IConfigurationFile; +} + export const CONFIG_FILENAME = "tslint.json"; /* tslint:disable:object-literal-key-quotes */ export const DEFAULT_CONFIG = { - "rules": { + "jsRules": { "class-name": true, "comment-format": [true, "check-space"], "indent": [true, "spaces"], "no-duplicate-variable": true, "no-eval": true, + "no-trailing-whitespace": true, + "no-unsafe-finally": true, + "one-line": [true, "check-open-brace", "check-whitespace"], + "quotemark": [true, "double"], + "semicolon": [true, "always"], + "triple-equals": [true, "allow-null-check"], + "variable-name": [true, "ban-keywords"], + "whitespace": [true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + ], + }, + "rules": { + "class-name": true, + "comment-format": [true, "check-space"], + "indent": [true, "spaces"], + "no-eval": true, "no-internal-module": true, "no-trailing-whitespace": true, "no-unsafe-finally": true, @@ -76,11 +103,18 @@ const BUILT_IN_CONFIG = /^tslint:(.*)$/; * @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 + * @returns Load status for a TSLint configuration object */ -export function findConfiguration(configFile: string, inputFilePath: string): IConfigurationFile { - const configPath = findConfigurationPath(configFile, inputFilePath); - return loadConfigurationFromPath(configPath); +export function findConfiguration(configFile: string, inputFilePath: string): IConfigurationLoadResult { + const path = findConfigurationPath(configFile, inputFilePath); + const loadResult: IConfigurationLoadResult = { path }; + + try { + loadResult.results = loadConfigurationFromPath(path); + return loadResult; + } catch (error) { + throw new FatalError(`Failed to load ${path}: ${error.message}`, error); + } } /** @@ -148,14 +182,14 @@ export function loadConfigurationFromPath(configFilePath: string): IConfiguratio const configFileDir = path.dirname(resolvedConfigFilePath); configFile.rulesDirectory = getRulesDirectories(configFile.rulesDirectory, configFileDir); - configFile.extends = arrayify(configFile.extends); + // load configurations, in order, using their identifiers or relative paths + // apply the current configuration last by placing it last in this array + const configs = arrayify(configFile.extends).map((name) => { + const nextConfigFilePath = resolveConfigurationPath(name, configFileDir); + return loadConfigurationFromPath(nextConfigFilePath); + }).concat([configFile]); - for (const name of configFile.extends) { - const baseConfigFilePath = resolveConfigurationPath(name, configFileDir); - const baseConfigFile = loadConfigurationFromPath(baseConfigFilePath); - configFile = extendConfigurationFile(configFile, baseConfigFile); - } - return configFile; + return configs.reduce(extendConfigurationFile, {}); } } @@ -189,20 +223,29 @@ function resolveConfigurationPath(filePath: string, relativeTo?: string) { } } -export function extendConfigurationFile(config: IConfigurationFile, baseConfig: IConfigurationFile): IConfigurationFile { +export function extendConfigurationFile(targetConfig: IConfigurationFile, + nextConfigSource: IConfigurationFile): IConfigurationFile { let combinedConfig: IConfigurationFile = {}; - const baseRulesDirectory = arrayify(baseConfig.rulesDirectory); - const configRulesDirectory = arrayify(config.rulesDirectory); - combinedConfig.rulesDirectory = configRulesDirectory.concat(baseRulesDirectory); + const configRulesDirectory = arrayify(targetConfig.rulesDirectory); + const nextConfigRulesDirectory = arrayify(nextConfigSource.rulesDirectory); + combinedConfig.rulesDirectory = configRulesDirectory.concat(nextConfigRulesDirectory); - combinedConfig.rules = {}; - for (const name of Object.keys(objectify(baseConfig.rules))) { - combinedConfig.rules[name] = baseConfig.rules[name]; - } - for (const name of Object.keys(objectify(config.rules))) { - combinedConfig.rules[name] = config.rules[name]; - } + const combineProperties = (targetProperty: any, nextProperty: any) => { + let combinedProperty: any = {}; + for (const name of Object.keys(objectify(targetProperty))) { + combinedProperty[name] = targetProperty[name]; + } + // next config source overwrites the target config object + for (const name of Object.keys(objectify(nextProperty))) { + combinedProperty[name] = nextProperty[name]; + } + return combinedProperty; + }; + + combinedConfig.rules = combineProperties(targetConfig.rules, nextConfigSource.rules); + combinedConfig.jsRules = combineProperties(targetConfig.jsRules, nextConfigSource.jsRules); + combinedConfig.linterOptions = combineProperties(targetConfig.linterOptions, nextConfigSource.linterOptions); return combinedConfig; } diff --git a/src/enableDisableRules.ts b/src/enableDisableRules.ts index b67ca86b43a..ae9f42dec9e 100644 --- a/src/enableDisableRules.ts +++ b/src/enableDisableRules.ts @@ -48,7 +48,7 @@ export class EnableDisableRulesWalker extends SkippableTokenAwareRuleWalker { private getStartOfLinePosition(node: ts.SourceFile, position: number, lineOffset = 0) { return node.getPositionOfLineAndCharacter( - node.getLineAndCharacterOfPosition(position).line + lineOffset, 0 + node.getLineAndCharacterOfPosition(position).line + lineOffset, 0, ); } @@ -73,7 +73,7 @@ export class EnableDisableRulesWalker extends SkippableTokenAwareRuleWalker { rulesList = commentTextParts[1].split(/\s+/).slice(1); // remove empty items and potential comment end. - rulesList = rulesList.filter(item => !!item && item.indexOf("*/") === -1); + rulesList = rulesList.filter((item) => !!item && item.indexOf("*/") === -1); // potentially there were no items, so default to `all`. rulesList = rulesList.length > 0 ? rulesList : ["all"]; diff --git a/src/error.ts b/src/error.ts new file mode 100644 index 00000000000..f18aacd485c --- /dev/null +++ b/src/error.ts @@ -0,0 +1,40 @@ +/** + * @license + * Copyright 2016 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. + */ + +/** + * Generic error typing for EcmaScript errors + * Define `Error` here to avoid using `Error` from @types/node. + * Using the `node` version causes a compilation error when this code is used as an npm library if @types/node is not already imported. + */ +export declare class Error { + public name?: string; + public message: string; + public stack?: string; + constructor(message?: string); +} + +/** + * Used to exit the program and display a friendly message without the callstack. + */ +export class FatalError extends Error { + public static NAME = "FatalError"; + constructor(public message: string, public innerError?: Error) { + super(message); + this.name = FatalError.NAME; + this.stack = new Error().stack; + } +} diff --git a/src/formatters/applyFixesFormatter.ts b/src/formatters/applyFixesFormatter.ts deleted file mode 100644 index 036a0a86f64..00000000000 --- a/src/formatters/applyFixesFormatter.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {AbstractFormatter} from "../language/formatter/abstractFormatter"; -import {Fix, RuleFailure} from "../language/rule/rule"; -import * as fs from "fs"; - -export class Formatter extends AbstractFormatter { - public format(failures: RuleFailure[]): string { - const files: {[file: string]: boolean} = {}; - failures.map(f => files[f.getFileName()] = true); - const log: string[] = []; - for (const file of Object.keys(files)) { - log.push(`Applying fixes to ${file}`); - let content = fs.readFileSync(file, {encoding: "utf-8"}); - const fixes = failures.filter(f => f.getFileName() === file).map(f => f.getFix()).filter(f => !!f); - content = Fix.applyAll(content, fixes); - fs.writeFileSync(file, content, {encoding: "utf-8"}); - } - log.push("All done. Remember to test the changes, as not all fixes preserve semantics."); - return log.join("\n") + "\n"; - } -} diff --git a/src/formatters/checkstyleFormatter.ts b/src/formatters/checkstyleFormatter.ts index 6a49dd46e4c..3360b409bed 100644 --- a/src/formatters/checkstyleFormatter.ts +++ b/src/formatters/checkstyleFormatter.ts @@ -1,7 +1,27 @@ import {AbstractFormatter} from "../language/formatter/abstractFormatter"; +import {IFormatterMetadata} from "../language/formatter/formatter"; import {RuleFailure} from "../language/rule/rule"; +import * as Utils from "../utils"; + export class Formatter extends AbstractFormatter { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: IFormatterMetadata = { + formatterName: "checkstyle", + description: "Formats errors as through they were Checkstyle output.", + descriptionDetails: Utils.dedent` + Imitates the XMLLogger from Checkstyle 4.3. All failures have the 'warning' severity.`, + sample: Utils.dedent` + + + + + + `, + consumer: "machine", + }; + /* tslint:enable:object-literal-sort-keys */ + public format(failures: RuleFailure[]): string { let output = ''; diff --git a/src/formatters/fileslistFormatter.ts b/src/formatters/fileslistFormatter.ts index 27c26c7a7cf..eb1bb58c3ab 100644 --- a/src/formatters/fileslistFormatter.ts +++ b/src/formatters/fileslistFormatter.ts @@ -16,9 +16,19 @@ */ import {AbstractFormatter} from "../language/formatter/abstractFormatter"; +import {IFormatterMetadata} from "../language/formatter/formatter"; import {RuleFailure} from "../language/rule/rule"; export class Formatter extends AbstractFormatter { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: IFormatterMetadata = { + formatterName: "filesList", + description: "Lists files containing lint errors.", + sample: "directory/myFile.ts", + consumer: "machine", + }; + /* tslint:enable:object-literal-sort-keys */ + public format(failures: RuleFailure[]): string { if (failures.length === 0) { return ""; diff --git a/src/formatters/jsonFormatter.ts b/src/formatters/jsonFormatter.ts index f0114b1a82d..917ffd8a2f5 100644 --- a/src/formatters/jsonFormatter.ts +++ b/src/formatters/jsonFormatter.ts @@ -16,9 +16,48 @@ */ import {AbstractFormatter} from "../language/formatter/abstractFormatter"; +import {IFormatterMetadata} from "../language/formatter/formatter"; import {RuleFailure} from "../language/rule/rule"; +import * as Utils from "../utils"; + export class Formatter extends AbstractFormatter { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: IFormatterMetadata = { + formatterName: "json", + description: "Formats errors as simple JSON.", + sample: Utils.dedent` + [ + { + "endPosition": { + "character": 13, + "line": 0, + "position": 13 + }, + "failure": "Missing semicolon", + "fix": { + "innerRuleName": "semicolon", + "innerReplacements": [ + { + "innerStart": 13, + "innerLength": 0, + "innerText": ";" + } + ] + }, + "name": "myFile.ts", + "ruleName": "semicolon", + "startPosition": { + "character": 13, + "line": 0, + "position": 13 + } + } + ]`, + consumer: "machine", + }; + /* tslint:enable:object-literal-sort-keys */ + public format(failures: RuleFailure[]): string { const failuresJSON = failures.map((failure) => failure.toJson()); return JSON.stringify(failuresJSON); diff --git a/src/formatters/msbuildFormatter.ts b/src/formatters/msbuildFormatter.ts index 2830a2e1a5c..2457d1d82b9 100644 --- a/src/formatters/msbuildFormatter.ts +++ b/src/formatters/msbuildFormatter.ts @@ -14,19 +14,37 @@ * limitations under the License. */ +import {camelize} from "underscore.string"; + import {AbstractFormatter} from "../language/formatter/abstractFormatter"; +import {IFormatterMetadata} from "../language/formatter/formatter"; import {RuleFailure} from "../language/rule/rule"; +import * as Utils from "../utils"; + export class Formatter extends AbstractFormatter { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: IFormatterMetadata = { + formatterName: "msbuild", + description: "Formats errors for consumption by msbuild.", + descriptionDetails: Utils.dedent` + The output is compatible with both msbuild and Visual Studio. All failures have the + 'warning' severity.`, + sample: "myFile.ts(1,14): warning: Missing semicolon", + consumer: "machine", + }; + /* tslint:enable:object-literal-sort-keys */ + public format(failures: RuleFailure[]): string { const outputLines = failures.map((failure: RuleFailure) => { const fileName = failure.getFileName(); const failureString = failure.getFailure(); + const camelizedRule = camelize(failure.getRuleName()); const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const positionTuple = `(${lineAndCharacter.line + 1},${lineAndCharacter.character + 1})`; - return `${fileName}${positionTuple}: warning: ${failureString}`; + return `${fileName}${positionTuple}: warning ${camelizedRule}: ${failureString}`; }); return outputLines.join("\n") + "\n"; diff --git a/src/formatters/pmdFormatter.ts b/src/formatters/pmdFormatter.ts index 33acda65771..7494e31c642 100644 --- a/src/formatters/pmdFormatter.ts +++ b/src/formatters/pmdFormatter.ts @@ -16,9 +16,27 @@ */ import {AbstractFormatter} from "../language/formatter/abstractFormatter"; +import {IFormatterMetadata} from "../language/formatter/formatter"; import {RuleFailure} from "../language/rule/rule"; +import * as Utils from "../utils"; + export class Formatter extends AbstractFormatter { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: IFormatterMetadata = { + formatterName: "pmd", + description: "Formats errors as through they were PMD output.", + descriptionDetails: "Imitates the XML output from PMD. All errors have a priority of 1.", + sample: Utils.dedent` + + + + + `, + consumer: "machine", + }; + /* tslint:enable:object-literal-sort-keys */ + public format(failures: RuleFailure[]): string { let output = ""; diff --git a/src/formatters/proseFormatter.ts b/src/formatters/proseFormatter.ts index 132623b0306..b70024a4fa0 100644 --- a/src/formatters/proseFormatter.ts +++ b/src/formatters/proseFormatter.ts @@ -16,15 +16,43 @@ */ import {AbstractFormatter} from "../language/formatter/abstractFormatter"; +import {IFormatterMetadata} from "../language/formatter/formatter"; import {RuleFailure} from "../language/rule/rule"; export class Formatter extends AbstractFormatter { - public format(failures: RuleFailure[]): string { - if (failures.length === 0) { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: IFormatterMetadata = { + formatterName: "prose", + description: "The default formatter which outputs simple human-readable messages.", + sample: "myFile.ts[1, 14]: Missing semicolon", + consumer: "human", + }; + /* tslint:enable:object-literal-sort-keys */ + + public format(failures: RuleFailure[], fixes?: RuleFailure[]): string { + if (failures.length === 0 && (!fixes || fixes.length === 0)) { return ""; } - const outputLines = failures.map((failure: RuleFailure) => { + let fixLines: string[] = []; + if (fixes) { + let perFileFixes: { [fileName: string]: number } = {}; + for (const fix of fixes) { + if (perFileFixes[fix.getFileName()] == null) { + perFileFixes[fix.getFileName()] = 1; + } else { + perFileFixes[fix.getFileName()]++; + } + } + + Object.keys(perFileFixes).forEach((fixedFile: string) => { + const fixCount = perFileFixes[fixedFile]; + fixLines.push(`Fixed ${fixCount} error(s) in ${fixedFile}`); + }); + fixLines.push(""); // add a blank line between fixes and failures + } + + let errorLines = failures.map((failure: RuleFailure) => { const fileName = failure.getFileName(); const failureString = failure.getFailure(); @@ -34,6 +62,6 @@ export class Formatter extends AbstractFormatter { return `${fileName}${positionTuple}: ${failureString}`; }); - return outputLines.join("\n") + "\n"; + return fixLines.concat(errorLines).join("\n") + "\n"; } } diff --git a/src/formatters/stylishFormatter.ts b/src/formatters/stylishFormatter.ts index bb35cf0d7f2..f9ea5f75ffe 100644 --- a/src/formatters/stylishFormatter.ts +++ b/src/formatters/stylishFormatter.ts @@ -16,11 +16,28 @@ */ import {AbstractFormatter} from "../language/formatter/abstractFormatter"; +import {IFormatterMetadata} from "../language/formatter/formatter"; import {RuleFailure} from "../language/rule/rule"; import * as colors from "colors"; +import * as Utils from "../utils"; + export class Formatter extends AbstractFormatter { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: IFormatterMetadata = { + formatterName: "stylish", + description: "Human-readable formatter which creates stylish messages.", + descriptionDetails: Utils.dedent` + The output matches that produced by eslint's stylish formatter. Its readability + enhanced through spacing and colouring`, + sample: Utils.dedent` + myFile.ts + 1:14 semicolon Missing semicolon`, + consumer: "human", + }; + /* tslint:enable:object-literal-sort-keys */ + public format(failures: RuleFailure[]): string { if (typeof failures[0] === "undefined") { return "\n"; @@ -42,12 +59,13 @@ export class Formatter extends AbstractFormatter { currentFile = fileName; } - const failureString = failure.getFailure(); + let failureString = failure.getFailure(); + failureString = colors.yellow(failureString); // Rule let ruleName = failure.getRuleName(); ruleName = this.pad(ruleName, ruleMaxSize); - ruleName = colors.yellow(ruleName); + ruleName = colors.grey(ruleName); // Lines const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); diff --git a/src/formatters/verboseFormatter.ts b/src/formatters/verboseFormatter.ts index cfa57ddbef1..fad23a9fad0 100644 --- a/src/formatters/verboseFormatter.ts +++ b/src/formatters/verboseFormatter.ts @@ -16,9 +16,20 @@ */ import {AbstractFormatter} from "../language/formatter/abstractFormatter"; +import {IFormatterMetadata} from "../language/formatter/formatter"; import {RuleFailure} from "../language/rule/rule"; export class Formatter extends AbstractFormatter { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: IFormatterMetadata = { + formatterName: "verbose", + description: "The human-readable formatter which includes the rule name in messages.", + descriptionDetails: "The output is the same as the prose formatter with the rule name included", + sample: "(semicolon) myFile.ts[1, 14]: Missing semicolon", + consumer: "human", + }; + /* tslint:enable:object-literal-sort-keys */ + public format(failures: RuleFailure[]): string { const outputLines = failures.map((failure: RuleFailure) => { const fileName = failure.getFileName(); diff --git a/src/formatters/vsoFormatter.ts b/src/formatters/vsoFormatter.ts index 3692bf6f201..d1dcc6baab3 100644 --- a/src/formatters/vsoFormatter.ts +++ b/src/formatters/vsoFormatter.ts @@ -15,9 +15,24 @@ */ import {AbstractFormatter} from "../language/formatter/abstractFormatter"; +import {IFormatterMetadata} from "../language/formatter/formatter"; import {RuleFailure} from "../language/rule/rule"; +import * as Utils from "../utils"; + export class Formatter extends AbstractFormatter { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: IFormatterMetadata = { + formatterName: "vso", + description: "Formats output as VSO/TFS logging commands.", + descriptionDetails: Utils.dedent` + Integrates with Visual Studio Online and Team Foundation Server by outputting errors + as 'warning' logging commands.`, + sample: "##vso[task.logissue type=warning;sourcepath=myFile.ts;linenumber=1;columnnumber=14;code=semicolon;]Missing semicolon", + consumer: "machine", + }; + /* tslint:enable:object-literal-sort-keys */ + public format(failures: RuleFailure[]): string { const outputLines = failures.map((failure: RuleFailure) => { const fileName = failure.getFileName(); diff --git a/src/lint.ts b/src/index.ts similarity index 61% rename from src/lint.ts rename to src/index.ts index 35f3a1af219..faf6ede9279 100644 --- a/src/lint.ts +++ b/src/index.ts @@ -15,13 +15,15 @@ * limitations under the License. */ -import * as configuration from "./configuration"; -import * as formatters from "./formatters"; +import * as Configuration from "./configuration"; +import * as Formatters from "./formatters"; import {RuleFailure} from "./language/rule/rule"; -import * as rules from "./rules"; -import * as test from "./test"; -import * as linter from "./tslint"; -import * as utils from "./utils"; +import * as Linter from "./linter"; +import * as Rules from "./rules"; +import * as Test from "./test"; +import * as Utils from "./utils"; + +export { Configuration, Formatters, Linter, Rules, Test, Utils }; export * from "./language/rule/rule"; export * from "./enableDisableRules"; @@ -32,34 +34,16 @@ export * from "./language/languageServiceHost"; export * from "./language/walker"; export * from "./language/formatter/formatter"; -export var Configuration = configuration; -export var Formatters = formatters; -export var Linter = linter; -export var Rules = rules; -export var Test = test; -export var Utils = utils; - export interface LintResult { failureCount: number; failures: RuleFailure[]; + fixes?: RuleFailure[]; format: string | Function; output: string; } -export interface ILinterOptionsRaw { - configuration?: any; - formatter?: string | Function; - formattersDirectory?: string; - rulesDirectory?: string | string[]; -} - -export interface ILinterOptions extends ILinterOptionsRaw { - configuration: any; - formatter: string | Function; - rulesDirectory: string | string[]; -} - -export interface IMultiLinterOptions { +export interface ILinterOptions { + fix: boolean; formatter?: string | Function; formattersDirectory?: string; rulesDirectory?: string | string[]; diff --git a/src/language/formatter/abstractFormatter.ts b/src/language/formatter/abstractFormatter.ts index 6294a2c2c23..404f072ec08 100644 --- a/src/language/formatter/abstractFormatter.ts +++ b/src/language/formatter/abstractFormatter.ts @@ -16,8 +16,9 @@ */ import {RuleFailure} from "../rule/rule"; -import {IFormatter} from "./formatter"; +import {IFormatter, IFormatterMetadata} from "./formatter"; export abstract class AbstractFormatter implements IFormatter { + public static metadata: IFormatterMetadata; public abstract format(failures: RuleFailure[]): string; } diff --git a/src/language/formatter/formatter.ts b/src/language/formatter/formatter.ts index 433255ab293..7801a9a510b 100644 --- a/src/language/formatter/formatter.ts +++ b/src/language/formatter/formatter.ts @@ -17,6 +17,40 @@ import {RuleFailure} from "../rule/rule"; +export interface IFormatterMetadata { + /** + * The name of the formatter. + */ + formatterName: string; + + /** + * A short, one line description of what the formatter does. + */ + description: string; + + /** + * More elaborate details about the formatter. + */ + descriptionDetails?: string; + + /** + * Sample output from the formatter. + */ + sample: string; + + /** + * Sample output from the formatter. + */ + consumer: ConsumerType; +} + +export type ConsumerType = "human" | "machine"; + export interface IFormatter { - format(failures: RuleFailure[]): string; + /** + * Formats linter results + * @param {RuleFailure[]} failures Linter errors that were not fixed + * @param {RuleFailure[]} fixes Fixed linter errors. Available when the `--fix` argument is used on the command line + */ + format(failures: RuleFailure[], fixes?: RuleFailure[]): string; } diff --git a/src/language/rule/abstractRule.ts b/src/language/rule/abstractRule.ts index 08c3b11bdd3..94a0ed38125 100644 --- a/src/language/rule/abstractRule.ts +++ b/src/language/rule/abstractRule.ts @@ -17,9 +17,8 @@ import * as ts from "typescript"; -import {IOptions} from "../../lint"; import {RuleWalker} from "../walker/ruleWalker"; -import {IDisabledInterval, IRule, IRuleMetadata, RuleFailure} from "./rule"; +import {IDisabledInterval, IOptions, IRule, IRuleMetadata, RuleFailure} from "./rule"; export abstract class AbstractRule implements IRule { public static metadata: IRuleMetadata; diff --git a/src/language/rule/rule.ts b/src/language/rule/rule.ts index 75627cc15d3..c44cb3f96e1 100644 --- a/src/language/rule/rule.ts +++ b/src/language/rule/rule.ts @@ -30,6 +30,11 @@ export interface IRuleMetadata { */ type: RuleType; + /** + * A rule deprecation message, if applicable. + */ + deprecationMessage?: string; + /** * A short, one line description of what the rule does. */ @@ -43,7 +48,7 @@ export interface IRuleMetadata { /** * An explanation of the available options for the rule. */ - optionsDescription?: string; + optionsDescription: string; /** * Schema of the options the rule accepts. @@ -67,6 +72,11 @@ export interface IRuleMetadata { * Whether or not the rule requires type info to run. */ requiresTypeInfo?: boolean; + + /** + * Whether or not the rule use for TypeScript only. If `false`, this rule may be used with .js files. + */ + typescriptOnly: boolean; } export type RuleType = "functionality" | "maintainability" | "style" | "typescript"; diff --git a/src/language/rule/typedRule.ts b/src/language/rule/typedRule.ts index ca2e9a6aa0a..4c5777b4f21 100644 --- a/src/language/rule/typedRule.ts +++ b/src/language/rule/typedRule.ts @@ -18,9 +18,14 @@ import * as ts from "typescript"; import {AbstractRule} from "./abstractRule"; -import {RuleFailure} from "./rule"; +import {IRule, RuleFailure} from "./rule"; export abstract class TypedRule extends AbstractRule { + + public static isTypedRule(rule: IRule): rule is TypedRule { + return "applyWithProgram" in rule; + } + public apply(sourceFile: ts.SourceFile, languageService: ts.LanguageService): RuleFailure[] { // if no program is given to the linter, throw an error throw new Error(`${this.getOptions().ruleName} requires type checking`); diff --git a/src/language/utils.ts b/src/language/utils.ts index 90d9715ccba..2a33a7a6fe9 100644 --- a/src/language/utils.ts +++ b/src/language/utils.ts @@ -29,8 +29,7 @@ export function getSourceFile(fileName: string, source: string): ts.SourceFile { getCanonicalFileName: (filename: string) => filename, getCurrentDirectory: () => "", getDefaultLibFileName: () => "lib.d.ts", - // TODO: include this field when compiling with TS 2.0 - // getDirectories: (path: string) => [], + getDirectories: (_path: string) => [], getNewLine: () => "\n", getSourceFile: (filenameToGet: string) => { if (filenameToGet === normalizedName) { @@ -49,6 +48,7 @@ export function getSourceFile(fileName: string, source: string): ts.SourceFile { export function createCompilerOptions(): ts.CompilerOptions { return { + allowJs: true, noResolve: true, target: ts.ScriptTarget.ES5, }; @@ -118,6 +118,13 @@ export function getBindingElementVariableDeclaration(node: ts.BindingElement): t return currentParent; } +/** + * @returns true if some ancestor of `node` satisfies `predicate`, including `node` itself. + */ +export function someAncestor(node: ts.Node, predicate: (n: ts.Node) => boolean): boolean { + return predicate(node) || (node.parent && someAncestor(node.parent, predicate)); +} + /** * Bitwise check for node flags. */ @@ -128,7 +135,7 @@ export function isNodeFlagSet(node: ts.Node, flagToCheck: ts.NodeFlags): boolean } /** - * Returns true if decl is a nested module declaration, i.e. represents a segment of a dotted module path. + * @returns true if decl is a nested module declaration, i.e. represents a segment of a dotted module path. */ export function isNestedModuleDeclaration(decl: ts.ModuleDeclaration) { // in a declaration expression like 'module a.b.c' - 'a' is the top level module declaration node and 'b' and 'c' diff --git a/src/language/walker/programAwareRuleWalker.ts b/src/language/walker/programAwareRuleWalker.ts index 6b29e1fdcd4..9fc9b678ca1 100644 --- a/src/language/walker/programAwareRuleWalker.ts +++ b/src/language/walker/programAwareRuleWalker.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import {IOptions} from "../../lint"; +import {IOptions} from "../rule/rule"; import {RuleWalker} from "./ruleWalker"; export class ProgramAwareRuleWalker extends RuleWalker { diff --git a/src/language/walker/ruleWalker.ts b/src/language/walker/ruleWalker.ts index bd9a9162eb5..7c17dee7602 100644 --- a/src/language/walker/ruleWalker.ts +++ b/src/language/walker/ruleWalker.ts @@ -17,8 +17,7 @@ import * as ts from "typescript"; -import {IOptions} from "../../lint"; -import {Fix, IDisabledInterval, Replacement, RuleFailure} from "../rule/rule"; +import {Fix, IDisabledInterval, IOptions, Replacement, RuleFailure} from "../rule/rule"; import {doesIntersect} from "../utils"; import {SyntaxWalker} from "./syntaxWalker"; diff --git a/src/language/walker/skippableTokenAwareRuleWalker.ts b/src/language/walker/skippableTokenAwareRuleWalker.ts index a374fad746d..e3a6e6857ce 100644 --- a/src/language/walker/skippableTokenAwareRuleWalker.ts +++ b/src/language/walker/skippableTokenAwareRuleWalker.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import {IOptions} from "../../lint"; +import {IOptions} from "../rule/rule"; import {RuleWalker} from "./ruleWalker"; export class SkippableTokenAwareRuleWalker extends RuleWalker { diff --git a/src/linter.ts b/src/linter.ts new file mode 100644 index 00000000000..e522288f358 --- /dev/null +++ b/src/linter.ts @@ -0,0 +1,223 @@ +/** + * @license + * Copyright 2013 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 fs from "fs"; +import * as ts from "typescript"; + +import { + DEFAULT_CONFIG, + findConfiguration, + findConfigurationPath, + getRelativePath, + getRulesDirectories, + IConfigurationFile, + loadConfigurationFromPath, +} from "./configuration"; +import { EnableDisableRulesWalker } from "./enableDisableRules"; +import { findFormatter } from "./formatterLoader"; +import { ILinterOptions, LintResult } from "./index"; +import { IFormatter } from "./language/formatter/formatter"; +import { Fix, IRule, RuleFailure } from "./language/rule/rule"; +import { TypedRule } from "./language/rule/typedRule"; +import * as utils from "./language/utils"; +import { loadRules } from "./ruleLoader"; +import { arrayify, dedent } from "./utils"; + +/** + * Linter that can lint multiple files in consecutive runs. + */ +class Linter { + public static VERSION = "4.0.2"; + + public static findConfiguration = findConfiguration; + public static findConfigurationPath = findConfigurationPath; + public static getRulesDirectories = getRulesDirectories; + public static loadConfigurationFromPath = loadConfigurationFromPath; + + private failures: RuleFailure[] = []; + private fixes: RuleFailure[] = []; + + /** + * Creates a TypeScript program object from a tsconfig.json file path and optional project directory. + */ + public static createProgram(configFile: string, projectDirectory?: string): ts.Program { + if (projectDirectory === undefined) { + const lastSeparator = configFile.lastIndexOf("/"); + if (lastSeparator < 0) { + projectDirectory = "."; + } else { + projectDirectory = configFile.substring(0, lastSeparator + 1); + } + } + + const { config } = ts.readConfigFile(configFile, ts.sys.readFile); + const parseConfigHost = { + fileExists: fs.existsSync, + readDirectory: ts.sys.readDirectory, + useCaseSensitiveFileNames: true, + }; + const parsed = ts.parseJsonConfigFileContent(config, parseConfigHost, projectDirectory); + const host = ts.createCompilerHost(parsed.options, true); + const program = ts.createProgram(parsed.fileNames, parsed.options, host); + + return program; + } + + /** + * Returns a list of source file names from a TypeScript program. This includes all referenced + * files and excludes declaration (".d.ts") files. + */ + public static getFileNames(program: ts.Program): string[] { + return program.getSourceFiles().map((s) => s.fileName).filter((l) => l.substr(-5) !== ".d.ts"); + } + + constructor(private options: ILinterOptions, private program?: ts.Program) { + if (typeof options !== "object") { + throw new Error("Unknown Linter options type: " + typeof options); + } + if (( options).configuration != null) { + throw new Error("ILinterOptions does not contain the property `configuration` as of version 4. " + + "Did you mean to pass the `IConfigurationFile` object to lint() ? "); + } + } + + public lint(fileName: string, source?: string, configuration: IConfigurationFile = DEFAULT_CONFIG): void { + const enabledRules = this.getEnabledRules(fileName, source, configuration); + let sourceFile = this.getSourceFile(fileName, source); + let hasLinterRun = false; + let fileFailures: RuleFailure[] = []; + + if (this.options.fix) { + for (let rule of enabledRules) { + let ruleFailures = this.applyRule(rule, sourceFile); + const fixes = ruleFailures.map((f) => f.getFix()).filter((f) => !!f); + source = fs.readFileSync(fileName, { encoding: "utf-8" }); + if (fixes.length > 0) { + this.fixes = this.fixes.concat(ruleFailures); + source = Fix.applyAll(source, fixes); + fs.writeFileSync(fileName, source, { encoding: "utf-8" }); + + // reload AST if file is modified + sourceFile = this.getSourceFile(fileName, source); + } + fileFailures = fileFailures.concat(ruleFailures); + } + hasLinterRun = true; + } + + // make a 1st pass or make a 2nd pass if there were any fixes because the positions may be off + if (!hasLinterRun || this.fixes.length > 0) { + fileFailures = []; + for (let rule of enabledRules) { + const ruleFailures = this.applyRule(rule, sourceFile); + if (ruleFailures.length > 0) { + fileFailures = fileFailures.concat(ruleFailures); + } + } + } + this.failures = this.failures.concat(fileFailures); + } + + public getResult(): LintResult { + let formatter: IFormatter; + const formattersDirectory = getRelativePath(this.options.formattersDirectory); + + const formatterName = this.options.formatter || "prose"; + const Formatter = findFormatter(formatterName, formattersDirectory); + if (Formatter) { + formatter = new Formatter(); + } else { + throw new Error(`formatter '${formatterName}' not found`); + } + + const output = formatter.format(this.failures, this.fixes); + + return { + failureCount: this.failures.length, + failures: this.failures, + fixes: this.fixes, + format: formatterName, + output, + }; + } + + private applyRule(rule: IRule, sourceFile: ts.SourceFile) { + let ruleFailures: RuleFailure[] = []; + if (this.program && TypedRule.isTypedRule(rule)) { + ruleFailures = rule.applyWithProgram(sourceFile, this.program); + } else { + ruleFailures = rule.apply(sourceFile); + } + let fileFailures: RuleFailure[] = []; + for (let ruleFailure of ruleFailures) { + if (!this.containsRule(this.failures, ruleFailure)) { + fileFailures.push(ruleFailure); + } + } + return fileFailures; + } + + private getEnabledRules(fileName: string, source?: string, configuration: IConfigurationFile = DEFAULT_CONFIG): IRule[] { + const sourceFile = this.getSourceFile(fileName, source); + + // walk the code first to find all the intervals where rules are disabled + const rulesWalker = new EnableDisableRulesWalker(sourceFile, { + disabledIntervals: [], + ruleName: "", + }); + rulesWalker.walk(sourceFile); + const enableDisableRuleMap = rulesWalker.enableDisableRuleMap; + + const rulesDirectories = arrayify(this.options.rulesDirectory) + .concat(arrayify(configuration.rulesDirectory)); + const isJs = /\.jsx?$/i.test(fileName); + const configurationRules = isJs ? configuration.jsRules : configuration.rules; + let configuredRules = loadRules(configurationRules, enableDisableRuleMap, rulesDirectories, isJs); + + return configuredRules.filter((r) => r.isEnabled()); + } + + private getSourceFile(fileName: string, source?: string) { + let sourceFile: ts.SourceFile; + if (this.program) { + sourceFile = this.program.getSourceFile(fileName); + // check if the program has been type checked + if (sourceFile && !("resolvedModules" in sourceFile)) { + throw new Error("Program must be type checked before linting"); + } + } else { + sourceFile = utils.getSourceFile(fileName, source); + } + + if (sourceFile === undefined) { + const INVALID_SOURCE_ERROR = dedent` + Invalid source file: ${fileName}. Ensure that the files supplied to lint have a .ts, .tsx, .js or .jsx extension. + `; + throw new Error(INVALID_SOURCE_ERROR); + } + return sourceFile; + } + + private containsRule(rules: RuleFailure[], rule: RuleFailure) { + return rules.some((r) => r.equals(rule)); + } +} + +// tslint:disable-next-line:no-namespace +namespace Linter { } + +export = Linter; diff --git a/src/ruleLoader.ts b/src/ruleLoader.ts index de2634c4849..7c6cebb5047 100644 --- a/src/ruleLoader.ts +++ b/src/ruleLoader.ts @@ -21,9 +21,11 @@ import {camelize} from "underscore.string"; import {getRulesDirectories} from "./configuration"; import {IDisabledInterval, IRule} from "./language/rule/rule"; +import {dedent} from "./utils"; const moduleDirectory = path.dirname(module.filename); const CORE_RULES_DIRECTORY = path.resolve(moduleDirectory, ".", "rules"); +const shownDeprecations: string[] = []; export interface IEnableDisablePosition { isEnabled: boolean; @@ -32,9 +34,11 @@ export interface IEnableDisablePosition { export function loadRules(ruleConfiguration: {[name: string]: any}, enableDisableRuleMap: {[rulename: string]: IEnableDisablePosition[]}, - rulesDirectories?: string | string[]): IRule[] { + rulesDirectories?: string | string[], + isJs?: boolean): IRule[] { const rules: IRule[] = []; const notFoundRules: string[] = []; + const notAllowedInJsRules: string[] = []; for (const ruleName in ruleConfiguration) { if (ruleConfiguration.hasOwnProperty(ruleName)) { @@ -43,27 +47,47 @@ export function loadRules(ruleConfiguration: {[name: string]: any}, if (Rule == null) { notFoundRules.push(ruleName); } else { - const all = "all"; // make the linter happy until we can turn it on and off - const allList = (all in enableDisableRuleMap ? enableDisableRuleMap[all] : []); - const ruleSpecificList = (ruleName in enableDisableRuleMap ? enableDisableRuleMap[ruleName] : []); - const disabledIntervals = buildDisabledIntervalsFromSwitches(ruleSpecificList, allList); - rules.push(new Rule(ruleName, ruleValue, disabledIntervals)); + if (isJs && Rule.metadata && Rule.metadata.typescriptOnly != null && Rule.metadata.typescriptOnly) { + notAllowedInJsRules.push(ruleName); + } else { + const all = "all"; // make the linter happy until we can turn it on and off + const allList = (all in enableDisableRuleMap ? enableDisableRuleMap[all] : []); + const ruleSpecificList = (ruleName in enableDisableRuleMap ? enableDisableRuleMap[ruleName] : []); + const disabledIntervals = buildDisabledIntervalsFromSwitches(ruleSpecificList, allList); + rules.push(new Rule(ruleName, ruleValue, disabledIntervals)); + + if (Rule.metadata && Rule.metadata.deprecationMessage && shownDeprecations.indexOf(Rule.metadata.ruleName) === -1) { + console.warn(`${Rule.metadata.ruleName} is deprecated. ${Rule.metadata.deprecationMessage}`); + shownDeprecations.push(Rule.metadata.ruleName); + } + } } } } if (notFoundRules.length > 0) { - const ERROR_MESSAGE = ` + const warning = dedent` Could not find implementations for the following rules specified in the configuration: - ${notFoundRules.join("\n")} + ${notFoundRules.join("\n ")} Try upgrading TSLint and/or ensuring that you have all necessary custom rules installed. If TSLint was recently upgraded, you may have old rules configured which need to be cleaned up. `; - throw new Error(ERROR_MESSAGE); - } else { - return rules; + console.warn(warning); } + if (notAllowedInJsRules.length > 0) { + const warning = dedent` + Following rules specified in configuration couldn't be applied to .js or .jsx files: + ${notAllowedInJsRules.join("\n ")} + Make sure to exclude them from "jsRules" section of your tslint.json. + `; + + console.warn(warning); + } + if (rules.length === 0) { + console.warn("No valid rules have been specified"); + } + return rules; } export function findRule(name: string, rulesDirectories?: string | string[]) { diff --git a/src/rules/adjacentOverloadSignaturesRule.ts b/src/rules/adjacentOverloadSignaturesRule.ts index 2c5b711d467..918aab31031 100644 --- a/src/rules/adjacentOverloadSignaturesRule.ts +++ b/src/rules/adjacentOverloadSignaturesRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { @@ -28,11 +28,15 @@ export class Rule extends Lint.Rules.AbstractRule { optionsDescription: "Not configurable.", options: null, optionExamples: ["true"], + rationale: "Improves readability and organization by grouping naturally related items together.", type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (name: string) => `All '${name}' signatures should be adjacent`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `All '${name}' signatures should be adjacent`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new AdjacentOverloadSignaturesWalker(sourceFile, this.getOptions())); @@ -40,34 +44,67 @@ export class Rule extends Lint.Rules.AbstractRule { } class AdjacentOverloadSignaturesWalker extends Lint.RuleWalker { + public visitSourceFile(node: ts.SourceFile) { + this.visitStatements(node.statements); + super.visitSourceFile(node); + } + + public visitModuleDeclaration(node: ts.ModuleDeclaration) { + const { body } = node; + if (body && body.kind === ts.SyntaxKind.ModuleBlock) { + this.visitStatements((body as ts.ModuleBlock).statements); + } + super.visitModuleDeclaration(node); + } public visitInterfaceDeclaration(node: ts.InterfaceDeclaration): void { - this.checkNode(node); + this.checkOverloadsAdjacent(node.members, (member) => { + return getTextOfPropertyName(member); + }); super.visitInterfaceDeclaration(node); } - public visitTypeLiteral(node: ts.TypeLiteralNode): void { - this.checkNode(node); + public visitClassDeclaration(node: ts.ClassDeclaration) { + this.visitMembers(node.members); + super.visitClassDeclaration(node); + } + + public visitTypeLiteral(node: ts.TypeLiteralNode) { + this.visitMembers(node.members); super.visitTypeLiteral(node); } - public checkNode(node: ts.TypeLiteralNode | ts.InterfaceDeclaration) { - let last: string = undefined; - const seen: { [name: string]: boolean } = {}; - for (const member of node.members) { - if (member.name !== undefined) { - const methodName = getTextOfPropertyName(member.name); - if (methodName !== undefined) { - if (seen[methodName] && last !== methodName) { - this.addFailure(this.createFailure(member.getStart(), member.getWidth(), - Rule.FAILURE_STRING_FACTORY(methodName))); - } - last = methodName; - seen[methodName] = true; - } + private visitStatements(statements: ts.Statement[]) { + this.checkOverloadsAdjacent(statements, (statement) => { + if (statement.kind === ts.SyntaxKind.FunctionDeclaration) { + const name = (statement as ts.FunctionDeclaration).name; + return name && name.text; } else { - last = undefined; + return undefined; } + }); + } + + private visitMembers(members: Array) { + this.checkOverloadsAdjacent(members, (member) => { + return getTextOfPropertyName(member); + }); + } + + /** 'getOverloadName' may return undefined for nodes that cannot be overloads, e.g. a `const` declaration. */ + private checkOverloadsAdjacent(overloads: T[], getOverloadName: (node: T) => string | undefined) { + let last: string | undefined = undefined; + const seen: { [name: string]: true } = Object.create(null); + for (const node of overloads) { + const name = getOverloadName(node); + if (name !== undefined) { + if (name in seen && last !== name) { + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), + Rule.FAILURE_STRING_FACTORY(name))); + } + seen[name] = true; + } + last = name; } } } @@ -76,18 +113,27 @@ function isLiteralExpression(node: ts.Node): node is ts.LiteralExpression { return node.kind === ts.SyntaxKind.StringLiteral || node.kind === ts.SyntaxKind.NumericLiteral; } -function getTextOfPropertyName(name: ts.PropertyName): string { - switch (name.kind) { +function getTextOfPropertyName(node: ts.InterfaceDeclaration | ts.TypeElement | ts.ClassElement): string { + let nameText: string; + if (node.name == null) { + return null; + } + switch (node.name.kind) { case ts.SyntaxKind.Identifier: - return (name as ts.Identifier).text; + nameText = (node.name as ts.Identifier).text; + break; case ts.SyntaxKind.ComputedPropertyName: - const { expression } = (name as ts.ComputedPropertyName); + const { expression } = (node.name as ts.ComputedPropertyName); if (isLiteralExpression(expression)) { - return expression.text; + nameText = expression.text; } + break; default: - if (isLiteralExpression(name)) { - return name.text; + if (isLiteralExpression(node.name)) { + nameText = ( node.name).text; } } + + const suffix = Lint.hasModifier(node.modifiers, ts.SyntaxKind.StaticKeyword) ? " __static__" : ""; + return nameText + suffix; } diff --git a/src/rules/alignRule.ts b/src/rules/alignRule.ts index 40327a20731..44bb0aa7256 100644 --- a/src/rules/alignRule.ts +++ b/src/rules/alignRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -42,6 +42,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "parameters", "statements"]'], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -60,7 +61,7 @@ export class Rule extends Lint.Rules.AbstractRule { type SourcePosition = { line: number; character: number; -} +}; class AlignWalker extends Lint.RuleWalker { public visitConstructorDeclaration(node: ts.ConstructorDeclaration) { diff --git a/src/rules/arrayTypeRule.ts b/src/rules/arrayTypeRule.ts index 256e6cb1098..7b294c9e1d2 100644 --- a/src/rules/arrayTypeRule.ts +++ b/src/rules/arrayTypeRule.ts @@ -1,6 +1,6 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ARRAY = "array"; const OPTION_GENERIC = "generic"; @@ -23,6 +23,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: [`[true, ${OPTION_ARRAY}]`, `[true, ${OPTION_GENERIC}]`, `[true, ${OPTION_ARRAY_SIMPLE}]`], type: "style", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/arrowParensRule.ts b/src/rules/arrowParensRule.ts index 01fa2bd5341..ea877d5d9a1 100644 --- a/src/rules/arrowParensRule.ts +++ b/src/rules/arrowParensRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,6 +29,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -57,8 +58,10 @@ class ArrowParensWalker extends Lint.RuleWalker { } if ((firstToken.kind !== ts.SyntaxKind.OpenParenToken || lastToken.kind !== ts.SyntaxKind.CloseParenToken) - && !isGenerics && node.flags !== ts.NodeFlags.Async) { - this.addFailure(this.createFailure(position, width, Rule.FAILURE_STRING)); + && !isGenerics && node.flags !== ts.NodeFlags.Async) { + + const fix = new Lint.Fix(Rule.metadata.ruleName, [new Lint.Replacement(position, width, `(${parameter.getText()})`)]); + this.addFailure(this.createFailure(position, width, Rule.FAILURE_STRING, fix)); } } super.visitArrowFunction(node); diff --git a/src/rules/banRule.ts b/src/rules/banRule.ts index c0667ce45d8..341f7276026 100644 --- a/src/rules/banRule.ts +++ b/src/rules/banRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -39,12 +39,13 @@ export class Rule extends Lint.Rules.AbstractRule { optionExamples: [`[true, ["someGlobalMethod"], ["someObject", "someFunction"], ["someObject", "otherFunction", "Optional explanation"]]`], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ public static FAILURE_STRING_FACTORY = (expression: string, messageAddition?: string) => { return `Calls to '${expression}' are not allowed.${messageAddition ? " " + messageAddition : ""}`; - }; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { const options = this.getOptions(); @@ -101,7 +102,7 @@ export class BanFunctionWalker extends Lint.RuleWalker { const failure = this.createFailure( expression.getStart(), expression.getWidth(), - Rule.FAILURE_STRING_FACTORY(`${leftSideExpression}.${rightSideExpression}`, bannedFunction[2]) + Rule.FAILURE_STRING_FACTORY(`${leftSideExpression}.${rightSideExpression}`, bannedFunction[2]), ); this.addFailure(failure); } diff --git a/src/rules/classNameRule.ts b/src/rules/classNameRule.ts index fb31837c796..802fdbf41a0 100644 --- a/src/rules/classNameRule.ts +++ b/src/rules/classNameRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,6 +29,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/commentFormatRule.ts b/src/rules/commentFormatRule.ts index 76c920d53c4..c51689d56d7 100644 --- a/src/rules/commentFormatRule.ts +++ b/src/rules/commentFormatRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_SPACE = "check-space"; const OPTION_LOWERCASE = "check-lowercase"; @@ -47,6 +47,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "check-space", "check-lowercase"]'], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -117,11 +118,11 @@ function startsWith(commentText: string, changeCase: (str: string) => string) { } function startsWithLowercase(commentText: string) { - return startsWith(commentText, c => c.toLowerCase()); + return startsWith(commentText, (c) => c.toLowerCase()); } function startsWithUppercase(commentText: string) { - return startsWith(commentText, c => c.toUpperCase()); + return startsWith(commentText, (c) => c.toUpperCase()); } function startsWithSpace(commentText: string) { diff --git a/src/rules/completedDocsRule.ts b/src/rules/completedDocsRule.ts new file mode 100644 index 00000000000..a43ad746ac2 --- /dev/null +++ b/src/rules/completedDocsRule.ts @@ -0,0 +1,121 @@ +/** + * @license + * Copyright 2013 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"; + +import * as Lint from "../index"; + +export class Rule extends Lint.Rules.TypedRule { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: Lint.IRuleMetadata = { + ruleName: "completed-docs", + description: "Enforces documentation for important items be filled out.", + optionsDescription: Lint.Utils.dedent` + Either \`true\` to enable for all, or any of + \`["classes", "functions", "methods", "properties"] + to choose individual ones.\``, + options: { + type: "array", + items: { + type: "string", + enum: ["classes", "functions", "methods", "properties"], + }, + }, + optionExamples: ["true", `[true, ["classes", "functions"]`], + type: "style", + typescriptOnly: false, + }; + /* tslint:enable:object-literal-sort-keys */ + + public static FAILURE_STRING_EXIST = " must have documentation."; + + public static ARGUMENT_CLASSES = "classes"; + public static ARGUMENT_FUNCTIONS = "functions"; + public static ARGUMENT_METHODS = "methods"; + public static ARGUMENT_PROPERTIES = "properties"; + + public static defaultArguments = [ + Rule.ARGUMENT_CLASSES, + Rule.ARGUMENT_FUNCTIONS, + Rule.ARGUMENT_METHODS, + Rule.ARGUMENT_PROPERTIES, + ]; + + public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] { + const options = this.getOptions(); + const completedDocsWalker = new CompletedDocsWalker(sourceFile, options, program); + + const nodesToCheck = this.getNodesToCheck(options.ruleArguments); + completedDocsWalker.setNodesToCheck(nodesToCheck); + + return this.applyWithWalker(completedDocsWalker); + } + + private getNodesToCheck(ruleArguments: string[]) { + return ruleArguments.length === 0 ? Rule.defaultArguments : ruleArguments; + } +} + +export class CompletedDocsWalker extends Lint.ProgramAwareRuleWalker { + private nodesToCheck: { [i: string]: boolean } = {}; + + public setNodesToCheck(nodesToCheck: string[]): void { + for (const nodeType of nodesToCheck) { + this.nodesToCheck[nodeType] = true; + } + } + + public visitClassDeclaration(node: ts.ClassDeclaration): void { + this.checkComments(node, Rule.ARGUMENT_CLASSES); + super.visitClassDeclaration(node); + } + + public visitFunctionDeclaration(node: ts.FunctionDeclaration): void { + this.checkComments(node, Rule.ARGUMENT_FUNCTIONS); + super.visitFunctionDeclaration(node); + } + + public visitPropertyDeclaration(node: ts.PropertyDeclaration): void { + this.checkComments(node, Rule.ARGUMENT_PROPERTIES); + super.visitPropertyDeclaration(node); + } + + public visitMethodDeclaration(node: ts.MethodDeclaration): void { + this.checkComments(node, Rule.ARGUMENT_METHODS); + super.visitMethodDeclaration(node); + } + + private checkComments(node: ts.Declaration, nodeToCheck: string): void { + if (!this.nodesToCheck[nodeToCheck]) { + return; + } + + const comments = this.getTypeChecker().getSymbolAtLocation(node.name).getDocumentationComment(); + + if (comments.map((comment) => comment.text).join("").trim() === "") { + this.addFailure(this.createDocumentationFailure(node, nodeToCheck)); + } + } + + private createDocumentationFailure(node: ts.Declaration, nodeToCheck: string): Lint.RuleFailure { + const start = node.getStart(); + const width = node.getText().split(/\r|\n/g)[0].length; + const description = nodeToCheck[0].toUpperCase() + nodeToCheck.substring(1) + Rule.FAILURE_STRING_EXIST; + + return this.createFailure(start, width, description); + } +} diff --git a/src/rules/curlyRule.ts b/src/rules/curlyRule.ts index 8a053bd149f..bcddb77b349 100644 --- a/src/rules/curlyRule.ts +++ b/src/rules/curlyRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -38,6 +38,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -82,7 +83,7 @@ class CurlyWalker extends Lint.RuleWalker { this.addFailure(this.createFailure( node.getStart(), node.thenStatement.getEnd() - node.getStart(), - Rule.IF_FAILURE_STRING + Rule.IF_FAILURE_STRING, )); } @@ -96,7 +97,7 @@ class CurlyWalker extends Lint.RuleWalker { this.addFailure(this.createFailure( elseKeywordNode.getStart(), node.elseStatement.getEnd() - elseKeywordNode.getStart(), - Rule.ELSE_FAILURE_STRING + Rule.ELSE_FAILURE_STRING, )); } diff --git a/src/rules/cyclomaticComplexityRule.ts b/src/rules/cyclomaticComplexityRule.ts index 9e1f89bad7d..ddefdee516f 100644 --- a/src/rules/cyclomaticComplexityRule.ts +++ b/src/rules/cyclomaticComplexityRule.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import * as Lint from "../lint"; import * as ts from "typescript"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { @@ -50,13 +50,17 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["true", "[true, 20]"], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ - public static ANONYMOUS_FAILURE_STRING = (expected: number, actual: number) => - `The function has a cyclomatic complexity of ${actual} which is higher than the threshold of ${expected}`; - public static NAMED_FAILURE_STRING = (expected: number, actual: number, name: string) => - `The function ${name} has a cyclomatic complexity of ${actual} which is higher than the threshold of ${expected}`; + public static ANONYMOUS_FAILURE_STRING = (expected: number, actual: number) => { + return `The function has a cyclomatic complexity of ${actual} which is higher than the threshold of ${expected}`; + } + + public static NAMED_FAILURE_STRING = (expected: number, actual: number, name: string) => { + return `The function ${name} has a cyclomatic complexity of ${actual} which is higher than the threshold of ${expected}`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new CyclomaticComplexityWalker(sourceFile, this.getOptions(), this.threshold)); diff --git a/src/rules/eoflineRule.ts b/src/rules/eoflineRule.ts index c835290abb5..65753975df1 100644 --- a/src/rules/eoflineRule.ts +++ b/src/rules/eoflineRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,6 +29,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ public static FAILURE_STRING = "file should end with a newline"; diff --git a/src/rules/fileHeaderRule.ts b/src/rules/fileHeaderRule.ts index 63d42683770..1434482e00c 100644 --- a/src/rules/fileHeaderRule.ts +++ b/src/rules/fileHeaderRule.ts @@ -1,6 +1,6 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -13,6 +13,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "Copyright \\\\d{4}"]'], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/forinRule.ts b/src/rules/forinRule.ts index 7c6f6e5f2a4..2459cabf43d 100644 --- a/src/rules/forinRule.ts +++ b/src/rules/forinRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -39,6 +39,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/indentRule.ts b/src/rules/indentRule.ts index 0cda08317de..5cdb939da04 100644 --- a/src/rules/indentRule.ts +++ b/src/rules/indentRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_USE_TABS = "tabs"; const OPTION_USE_SPACES = "spaces"; @@ -41,6 +41,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "spaces"]'], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -76,10 +77,11 @@ class IndentWalker extends Lint.RuleWalker { } let endOfComment = -1; + let endOfTemplateString = -1; const scanner = ts.createScanner(ts.ScriptTarget.ES5, false, ts.LanguageVariant.Standard, node.text); for (let lineStart of node.getLineStarts()) { - if (lineStart < endOfComment) { - // skip checking lines inside multi-line comments + if (lineStart < endOfComment || lineStart < endOfTemplateString) { + // skip checking lines inside multi-line comments or template strings continue; } @@ -103,6 +105,27 @@ class IndentWalker extends Lint.RuleWalker { const commentRanges = ts.getTrailingCommentRanges(node.text, lineStart); if (commentRanges) { endOfComment = commentRanges[commentRanges.length - 1].end; + } else { + let scanType = currentScannedType; + + // scan until we reach end of line, skipping over template strings + while (scanType !== ts.SyntaxKind.NewLineTrivia && scanType !== ts.SyntaxKind.EndOfFileToken) { + if (scanType === ts.SyntaxKind.NoSubstitutionTemplateLiteral) { + // template string without expressions - skip past it + endOfTemplateString = scanner.getStartPos() + scanner.getTokenText().length; + } else if (scanType === ts.SyntaxKind.TemplateHead) { + // find end of template string containing expressions... + while (scanType !== ts.SyntaxKind.TemplateTail && scanType !== ts.SyntaxKind.EndOfFileToken) { + scanType = scanner.scan(); + if (scanType === ts.SyntaxKind.CloseBraceToken) { + scanType = scanner.reScanTemplateToken(); + } + } + // ... and skip past it + endOfTemplateString = scanner.getStartPos() + scanner.getTokenText().length; + } + scanType = scanner.scan(); + } } if (currentScannedType === ts.SyntaxKind.SingleLineCommentTrivia diff --git a/src/rules/interfaceNameRule.ts b/src/rules/interfaceNameRule.ts index c2ac0f54145..5cea37f4c65 100644 --- a/src/rules/interfaceNameRule.ts +++ b/src/rules/interfaceNameRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ALWAYS = "always-prefix"; const OPTION_NEVER = "never-prefix"; @@ -39,6 +39,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: [`[true, "${OPTION_ALWAYS}"]`, `[true, "${OPTION_NEVER}"]`], type: "style", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/jsdocFormatRule.ts b/src/rules/jsdocFormatRule.ts index d3b486d4919..40e8f172804 100644 --- a/src/rules/jsdocFormatRule.ts +++ b/src/rules/jsdocFormatRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -36,6 +36,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/labelPositionRule.ts b/src/rules/labelPositionRule.ts index e55474110fd..30650f1af87 100644 --- a/src/rules/labelPositionRule.ts +++ b/src/rules/labelPositionRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -33,6 +33,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/labelUndefinedRule.ts b/src/rules/labelUndefinedRule.ts deleted file mode 100644 index 54df05d9c33..00000000000 --- a/src/rules/labelUndefinedRule.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @license - * Copyright 2013 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"; - -import * as Lint from "../lint"; - -export class Rule extends Lint.Rules.AbstractRule { - /* tslint:disable:object-literal-sort-keys */ - public static metadata: Lint.IRuleMetadata = { - ruleName: "label-undefined", - description: "Checks that labels are defined before usage.", - descriptionDetails: "This rule is now implemented in the TypeScript compiler and does not need to be used.", - rationale: "Using `break` or `continue` to go to an out-of-scope label is an error in JS.", - optionsDescription: "Not configurable.", - options: null, - optionExamples: ["true"], - type: "functionality", - }; - /* tslint:enable:object-literal-sort-keys */ - - public static FAILURE_STRING = "undefined label: '"; - - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new LabelUndefinedWalker(sourceFile, this.getOptions())); - } -} - -class LabelUndefinedWalker extends Lint.ScopeAwareRuleWalker<{[key: string]: any}> { - public createScope(): {[key: string]: any} { - return {}; - } - - public visitLabeledStatement(node: ts.LabeledStatement) { - const label = node.label.text; - const currentScope = this.getCurrentScope(); - - currentScope[label] = true; - super.visitLabeledStatement(node); - } - - public visitBreakStatement(node: ts.BreakOrContinueStatement) { - this.validateLabelAt(node.label, node.getStart(), node.getChildAt(0).getWidth()); - super.visitBreakStatement(node); - } - - public visitContinueStatement(node: ts.BreakOrContinueStatement) { - this.validateLabelAt(node.label, node.getStart(), node.getChildAt(0).getWidth()); - super.visitContinueStatement(node); - } - - private validateLabelAt(label: ts.Identifier, position: number, width: number) { - const currentScope = this.getCurrentScope(); - - if (label != null && !currentScope[label.text]) { - const failureString = Rule.FAILURE_STRING + label.text + "'"; - const failure = this.createFailure(position, width, failureString); - this.addFailure(failure); - } - } -} diff --git a/src/rules/linebreakStyleRule.ts b/src/rules/linebreakStyleRule.ts index 4fcc62ec381..a8cff31c5f7 100644 --- a/src/rules/linebreakStyleRule.ts +++ b/src/rules/linebreakStyleRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_LINEBREAK_STYLE_CRLF = "CRLF"; const OPTION_LINEBREAK_STYLE_LF = "LF"; @@ -38,6 +38,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: [`[true, "${OPTION_LINEBREAK_STYLE_LF}"]`, `[true, "${OPTION_LINEBREAK_STYLE_CRLF}"]`], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -52,7 +53,7 @@ export class Rule extends Lint.Rules.AbstractRule { sourceFile.languageVersion, false, sourceFile.languageVariant, - sourceFile.getFullText() + sourceFile.getFullText(), ); const linebreakStyle = this.getOptions().ruleArguments[0] || OPTION_LINEBREAK_STYLE_LF; diff --git a/src/rules/maxClassesPerFileRule.ts b/src/rules/maxClassesPerFileRule.ts new file mode 100644 index 00000000000..04b4a933ccc --- /dev/null +++ b/src/rules/maxClassesPerFileRule.ts @@ -0,0 +1,73 @@ +import * as ts from "typescript"; +import * as Lint from "../index"; + +export class Rule extends Lint.Rules.AbstractRule { + + /* tslint:disable:object-literal-sort-keys */ + public static metadata: Lint.IRuleMetadata = { + ruleName: "max-classes-per-file", + description: Lint.Utils.dedent` + A file may not contain more than the specified number of classes`, + rationale: Lint.Utils.dedent` + Ensures that files have a single responsibility so that that classes each exist in their own files`, + optionsDescription: Lint.Utils.dedent` + The one required argument is an integer indicating the maximum number of classes that can appear in a file.`, + options: { + type: "array", + items: [ + { + type: "number", + minimum: 1, + }, + ], + additionalItems: false, + minLength: 1, + maxLength: 2, + }, + optionExamples: ["[true, 1]", "[true, 5]"], + type: "maintainability", + typescriptOnly: false, + }; + /* tslint:enable:object-literal-sort-keys */ + + public static FAILURE_STRING_FACTORY = (maxCount: number): string => { + const maxClassWord = maxCount === 1 ? "class per file is" : "classes per file are"; + return `A maximum of ${maxCount} ${maxClassWord} allowed`; + } + + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker(new MaxClassesPerFileWalker(sourceFile, this.getOptions())); + } +} + +class MaxClassesPerFileWalker extends Lint.RuleWalker { + private classCount = 0; + private maxClassCount: number; + + constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) { + super(sourceFile, options); + + this.maxClassCount = options.ruleArguments[0]; + if (isNaN(this.maxClassCount) || this.maxClassCount < 1) { + this.maxClassCount = 1; + } + } + + public visitClassDeclaration(node: ts.ClassDeclaration) { + this.increaseClassCount(node); + super.visitClassDeclaration(node); + } + + public visitClassExpression(node: ts.ClassExpression) { + this.increaseClassCount(node); + super.visitClassExpression(node); + } + + private increaseClassCount(node: ts.ClassExpression | ts.ClassDeclaration) { + this.classCount++; + if (this.classCount > this.maxClassCount) { + const msg = Rule.FAILURE_STRING_FACTORY(this.maxClassCount); + this.addFailure(this.createFailure(node.getStart(), node.getWidth(), msg)); + } + } +} diff --git a/src/rules/maxFileLineCountRule.ts b/src/rules/maxFileLineCountRule.ts index 3d9982c42bb..641800d2b11 100644 --- a/src/rules/maxFileLineCountRule.ts +++ b/src/rules/maxFileLineCountRule.ts @@ -14,8 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as Lint from "../lint"; import * as ts from "typescript"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -32,6 +32,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["[true, 300]"], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -39,7 +40,7 @@ export class Rule extends Lint.Rules.AbstractRule { let msg = `This file has ${lineCount} lines, which exceeds the maximum of ${lineLimit} lines allowed. `; msg += `Consider breaking this file up into smaller parts`; return msg; - }; + } public isEnabled(): boolean { if (super.isEnabled()) { diff --git a/src/rules/maxLineLengthRule.ts b/src/rules/maxLineLengthRule.ts index 2fa48b520e8..d46730c2624 100644 --- a/src/rules/maxLineLengthRule.ts +++ b/src/rules/maxLineLengthRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -35,12 +35,13 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["[true, 120]"], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ public static FAILURE_STRING_FACTORY = (lineLimit: number) => { return `Exceeds maximum line length of ${lineLimit}`; - }; + } public isEnabled(): boolean { if (super.isEnabled()) { diff --git a/src/rules/memberAccessRule.ts b/src/rules/memberAccessRule.ts index 61bb205ae23..8fef76d20f3 100644 --- a/src/rules/memberAccessRule.ts +++ b/src/rules/memberAccessRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -41,6 +41,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["true", '[true, "check-accessor"]'], type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ @@ -100,7 +101,7 @@ export class MemberAccessWalker extends Lint.RuleWalker { node.modifiers, ts.SyntaxKind.PublicKeyword, ts.SyntaxKind.PrivateKeyword, - ts.SyntaxKind.ProtectedKeyword + ts.SyntaxKind.ProtectedKeyword, ); if (!hasAnyVisibilityModifiers) { diff --git a/src/rules/memberOrderingRule.ts b/src/rules/memberOrderingRule.ts index 614070f4f5b..9b4201f4cce 100644 --- a/src/rules/memberOrderingRule.ts +++ b/src/rules/memberOrderingRule.ts @@ -16,7 +16,7 @@ */ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; /* start old options */ const OPTION_VARIABLES_BEFORE_FUNCTIONS = "variables-before-functions"; @@ -127,6 +127,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, { "order": "fields-first" }]'], type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { @@ -275,11 +276,11 @@ export class MemberOrderingWalker extends Lint.RuleWalker { super.visitPropertySignature(node); } - public visitTypeLiteral(node: ts.TypeLiteralNode) { + public visitTypeLiteral(_node: ts.TypeLiteralNode) { // don't call super from here -- we want to skip the property declarations in type literals } - public visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { + public visitObjectLiteralExpression(_node: ts.ObjectLiteralExpression) { // again, don't call super here - object literals can have methods, // and we don't wan't to check these } @@ -298,7 +299,7 @@ export class MemberOrderingWalker extends Lint.RuleWalker { const failure = this.createFailure( node.getStart(), node.getWidth(), - `Declaration of ${toString(currentMember)} not allowed to appear after declaration of ${toString(this.previousMember)}` + `Declaration of ${toString(currentMember)} not allowed to appear after declaration of ${toString(this.previousMember)}`, ); this.addFailure(failure); } @@ -367,7 +368,7 @@ export class MemberOrderingWalker extends Lint.RuleWalker { this.addFailure(this.createFailure( node.getStart(), node.getWidth(), - errorLine1 + errorLine1, )); } else { // keep track of last good node diff --git a/src/rules/newParensRule.ts b/src/rules/newParensRule.ts index a39cb0eda60..7feae34434f 100644 --- a/src/rules/newParensRule.ts +++ b/src/rules/newParensRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,6 +29,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noAngleBracketTypeAssertionRule.ts b/src/rules/noAngleBracketTypeAssertionRule.ts index 854467336c7..ebf381c52a3 100644 --- a/src/rules/noAngleBracketTypeAssertionRule.ts +++ b/src/rules/noAngleBracketTypeAssertionRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -32,6 +32,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "style", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noAnyRule.ts b/src/rules/noAnyRule.ts index a0b602dc707..7346f151838 100644 --- a/src/rules/noAnyRule.ts +++ b/src/rules/noAnyRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,6 +29,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noArgRule.ts b/src/rules/noArgRule.ts index 8b34f8437ef..4adb5d727db 100644 --- a/src/rules/noArgRule.ts +++ b/src/rules/noArgRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -32,6 +32,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noBitwiseRule.ts b/src/rules/noBitwiseRule.ts index 4a5b0a74795..bb69045394d 100644 --- a/src/rules/noBitwiseRule.ts +++ b/src/rules/noBitwiseRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -37,6 +37,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noConditionalAssignmentRule.ts b/src/rules/noConditionalAssignmentRule.ts index b59d87fed40..89ad7ff898e 100644 --- a/src/rules/noConditionalAssignmentRule.ts +++ b/src/rules/noConditionalAssignmentRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -33,6 +33,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noConsecutiveBlankLinesRule.ts b/src/rules/noConsecutiveBlankLinesRule.ts index b3208e117ab..fffa18ee7bf 100644 --- a/src/rules/noConsecutiveBlankLinesRule.ts +++ b/src/rules/noConsecutiveBlankLinesRule.ts @@ -17,22 +17,47 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { + public static DEFAULT_ALLOWED_BLANKS = 1; + public static MINIMUM_ALLOWED_BLANKS = 1; + /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { ruleName: "no-consecutive-blank-lines", - description: "Disallows more than one blank line in a row.", + description: "Disallows one or more blank lines in a row.", rationale: "Helps maintain a readable style in your codebase.", - optionsDescription: "Not configurable.", - options: {}, - optionExamples: ["true"], + optionsDescription: Lint.Utils.dedent` + An optional number of maximum allowed sequential blanks can be specified. If no value + is provided, a default of $(Rule.DEFAULT_ALLOWED_BLANKS) will be used.`, + options: { + type: "number", + minimum: "$(Rule.MINIMUM_ALLOWED_BLANKS)", + }, + optionExamples: ["true", "[true, 2]"], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING = "Consecutive blank lines are forbidden"; + public static FAILURE_STRING_FACTORY(allowed: number) { + return allowed === 1 + ? "Consecutive blank lines are forbidden" + : `Exceeds the ${allowed} allowed consecutive blank lines`; + }; + + /** + * Disable the rule if the option is provided but non-numeric or less than the minimum. + */ + public isEnabled(): boolean { + if (!super.isEnabled()) { + return false; + } + const options = this.getOptions(); + const allowedBlanks = options.ruleArguments && options.ruleArguments[0] || Rule.DEFAULT_ALLOWED_BLANKS; + return typeof allowedBlanks === "number" && allowedBlanks >= Rule.MINIMUM_ALLOWED_BLANKS; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoConsecutiveBlankLinesWalker(sourceFile, this.getOptions())); @@ -43,6 +68,9 @@ class NoConsecutiveBlankLinesWalker extends Lint.SkippableTokenAwareRuleWalker { public visitSourceFile(node: ts.SourceFile) { super.visitSourceFile(node); + const options = this.getOptions(); + const allowedBlanks = options && options[0] || Rule.DEFAULT_ALLOWED_BLANKS; + const failureMessage = Rule.FAILURE_STRING_FACTORY(allowedBlanks); const sourceFileText = node.getFullText(); const soureFileLines = sourceFileText.split(/\n/); @@ -62,10 +90,11 @@ class NoConsecutiveBlankLinesWalker extends Lint.SkippableTokenAwareRuleWalker { lastVal = line; } sequences - .filter((arr) => arr.length > 1).map((arr) => arr[0]) + .filter((arr) => arr.length > allowedBlanks) + .map((arr) => arr[0]) .forEach((startLineNum: number) => { let startCharPos = node.getPositionOfLineAndCharacter(startLineNum + 1, 0); - this.addFailure(this.createFailure(startCharPos, 1, Rule.FAILURE_STRING)); + this.addFailure(this.createFailure(startCharPos, 1, failureMessage)); }); } } diff --git a/src/rules/noConsoleRule.ts b/src/rules/noConsoleRule.ts index 8c9f83fb52c..e024123a764 100644 --- a/src/rules/noConsoleRule.ts +++ b/src/rules/noConsoleRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; import * as BanRule from "./banRule"; export class Rule extends BanRule.Rule { @@ -33,6 +33,7 @@ export class Rule extends BanRule.Rule { }, optionExamples: [`[true, "log", "error"]`], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noConstructRule.ts b/src/rules/noConstructRule.ts index b9fc89a19fa..f687688f0e6 100644 --- a/src/rules/noConstructRule.ts +++ b/src/rules/noConstructRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -33,6 +33,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noDebuggerRule.ts b/src/rules/noDebuggerRule.ts index a4b5a5130ba..85703395895 100644 --- a/src/rules/noDebuggerRule.ts +++ b/src/rules/noDebuggerRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,6 +29,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noDefaultExportRule.ts b/src/rules/noDefaultExportRule.ts index be65e9273cb..ae9c7bcdd05 100644 --- a/src/rules/noDefaultExportRule.ts +++ b/src/rules/noDefaultExportRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -33,6 +33,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noDuplicateKeyRule.ts b/src/rules/noDuplicateKeyRule.ts deleted file mode 100644 index 9f8973f72ab..00000000000 --- a/src/rules/noDuplicateKeyRule.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @license - * Copyright 2013 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"; - -import * as Lint from "../lint"; - -export class Rule extends Lint.Rules.AbstractRule { - /* tslint:disable:object-literal-sort-keys */ - public static metadata: Lint.IRuleMetadata = { - ruleName: "no-duplicate-key", - description: "Disallows duplicate keys in object literals.", - rationale: Lint.Utils.dedent` - There is no good reason to define an object literal with the same key twice. - This rule is now implemented in the TypeScript compiler and does not need to be used.`, - optionsDescription: "Not configurable.", - options: null, - optionExamples: ["true"], - type: "functionality", - }; - /* tslint:enable:object-literal-sort-keys */ - - public static FAILURE_STRING_FACTORY = (name: string) => `Duplicate key '${name}'`; - - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new NoDuplicateKeyWalker(sourceFile, this.getOptions())); - } -} - -class NoDuplicateKeyWalker extends Lint.RuleWalker { - private objectKeysStack: {[key: string]: boolean}[] = []; - - public visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { - this.objectKeysStack.push(Object.create(null)); - super.visitObjectLiteralExpression(node); - this.objectKeysStack.pop(); - } - - public visitPropertyAssignment(node: ts.PropertyAssignment) { - const objectKeys = this.objectKeysStack[this.objectKeysStack.length - 1]; - const keyNode = node.name; - - if (keyNode.kind === ts.SyntaxKind.Identifier) { - const key = ( keyNode).text; - if (objectKeys[key]) { - const failureString = Rule.FAILURE_STRING_FACTORY(key); - this.addFailure(this.createFailure(keyNode.getStart(), keyNode.getWidth(), failureString)); - } else { - objectKeys[key] = true; - } - } - - super.visitPropertyAssignment(node); - } -} diff --git a/src/rules/noDuplicateVariableRule.ts b/src/rules/noDuplicateVariableRule.ts index 17c7694d625..7dc9473bfdb 100644 --- a/src/rules/noDuplicateVariableRule.ts +++ b/src/rules/noDuplicateVariableRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -34,10 +34,13 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (name: string) => `Duplicate variable: '${name}'`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `Duplicate variable: '${name}'`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoDuplicateVariableWalker(sourceFile, this.getOptions())); @@ -71,11 +74,11 @@ class NoDuplicateVariableWalker extends Lint.BlockScopeAwareRuleWalker<{}, Scope this.visitBlock(node.block); } - public visitMethodSignature(node: ts.SignatureDeclaration) { + public visitMethodSignature(_node: ts.SignatureDeclaration) { // don't call super, we don't want to walk method signatures either } - public visitTypeLiteral(node: ts.TypeLiteralNode) { + public visitTypeLiteral(_node: ts.TypeLiteralNode) { // don't call super, we don't want to walk the inside of type nodes } diff --git a/src/rules/noEmptyRule.ts b/src/rules/noEmptyRule.ts index d3a3e20e536..d6dbbe1b695 100644 --- a/src/rules/noEmptyRule.ts +++ b/src/rules/noEmptyRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -30,6 +30,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -67,7 +68,8 @@ class BlockWalker extends Lint.RuleWalker { param.modifiers, ts.SyntaxKind.PrivateKeyword, ts.SyntaxKind.ProtectedKeyword, - ts.SyntaxKind.PublicKeyword + ts.SyntaxKind.PublicKeyword, + ts.SyntaxKind.ReadonlyKeyword, ); if (hasPropertyAccessModifier) { diff --git a/src/rules/noEvalRule.ts b/src/rules/noEvalRule.ts index 9e6ee898efb..a2c4194dc0f 100644 --- a/src/rules/noEvalRule.ts +++ b/src/rules/noEvalRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -32,6 +32,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noForInArrayRule.ts b/src/rules/noForInArrayRule.ts index 94151f4dcdc..2c335a58d9f 100644 --- a/src/rules/noForInArrayRule.ts +++ b/src/rules/noForInArrayRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.TypedRule { /* tslint:disable:object-literal-sort-keys */ @@ -43,6 +43,7 @@ export class Rule extends Lint.Rules.TypedRule { optionExamples: ["true"], requiresTypeInfo: true, type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noInferrableTypesRule.ts b/src/rules/noInferrableTypesRule.ts index 99ee2f28f9f..79c918d9cc8 100644 --- a/src/rules/noInferrableTypesRule.ts +++ b/src/rules/noInferrableTypesRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_IGNORE_PARMS = "ignore-params"; @@ -43,10 +43,13 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["true", `[true, "${OPTION_IGNORE_PARMS}"]`], type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (type: string) => `LHS type (${type}) inferred by RHS expression, remove type annotation`; + public static FAILURE_STRING_FACTORY = (type: string) => { + return `LHS type (${type}) inferred by RHS expression, remove type annotation`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoInferrableTypesWalker(sourceFile, this.getOptions())); diff --git a/src/rules/noInternalModuleRule.ts b/src/rules/noInternalModuleRule.ts index 4e890d05ded..751a4e8a75f 100644 --- a/src/rules/noInternalModuleRule.ts +++ b/src/rules/noInternalModuleRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,6 +29,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noInvalidThisRule.ts b/src/rules/noInvalidThisRule.ts index c98a22d7d45..12e8f2c7ea0 100644 --- a/src/rules/noInvalidThisRule.ts +++ b/src/rules/noInvalidThisRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; interface Scope { inClass: boolean; @@ -48,6 +48,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["true", `[true, "${OPTION_FUNCTION_IN_METHOD}"]`], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noMergeableNamespaceRule.ts b/src/rules/noMergeableNamespaceRule.ts index 1ffdfc05b13..680dc278f31 100644 --- a/src/rules/noMergeableNamespaceRule.ts +++ b/src/rules/noMergeableNamespaceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -28,6 +28,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "maintainability", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noNamespaceRule.ts b/src/rules/noNamespaceRule.ts index 980fd1adc47..0113eb1d8dd 100644 --- a/src/rules/noNamespaceRule.ts +++ b/src/rules/noNamespaceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -43,6 +43,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["true", '[true, "allow-declarations"]'], type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ @@ -54,12 +55,30 @@ export class Rule extends Lint.Rules.AbstractRule { } class NoNamespaceWalker extends Lint.RuleWalker { + public visitSourceFile(node: ts.SourceFile) { + // Ignore all .d.ts files by returning and not walking their ASTs. + // .d.ts declarations do not have the Ambient flag set, but are still declarations. + if (this.hasOption("allow-declarations") && node.fileName.match(/\.d\.ts$/)) { + return; + } + this.walkChildren(node); + } + public visitModuleDeclaration(decl: ts.ModuleDeclaration) { super.visitModuleDeclaration(decl); + // declare module 'foo' {} is an external module, not a namespace. - if (decl.name.kind === ts.SyntaxKind.StringLiteral) { return; } - if (Lint.isNodeFlagSet(decl, ts.NodeFlags.Ambient) && this.hasOption("allow-declarations")) { return; } - if (Lint.isNestedModuleDeclaration(decl)) { return; } + if (decl.name.kind === ts.SyntaxKind.StringLiteral) { + return; + } + if (this.hasOption("allow-declarations") + && Lint.someAncestor(decl, (n) => Lint.isNodeFlagSet(n, ts.NodeFlags.Ambient))) { + return; + } + if (Lint.isNestedModuleDeclaration(decl)) { + return; + } + this.addFailure(this.createFailure(decl.getStart(), decl.getWidth(), Rule.FAILURE_STRING)); } } diff --git a/src/rules/noNullKeywordRule.ts b/src/rules/noNullKeywordRule.ts index b49ea822c01..6592c1640d1 100644 --- a/src/rules/noNullKeywordRule.ts +++ b/src/rules/noNullKeywordRule.ts @@ -19,7 +19,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -33,6 +33,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -46,8 +47,18 @@ export class Rule extends Lint.Rules.AbstractRule { class NullWalker extends Lint.RuleWalker { public visitNode(node: ts.Node) { super.visitNode(node); - if (node.kind === ts.SyntaxKind.NullKeyword) { + if (node.kind === ts.SyntaxKind.NullKeyword && !isPartOfType(node)) { this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); } } } + +function isPartOfType({ parent }: ts.Node) { + while (parent != null) { + if (ts.SyntaxKind.FirstTypeNode <= parent.kind && parent.kind <= ts.SyntaxKind.LastTypeNode) { + return true; + } + parent = parent.parent; + } + return false; +} diff --git a/src/rules/noConstructorVarsRule.ts b/src/rules/noParameterPropertiesRule.ts similarity index 79% rename from src/rules/noConstructorVarsRule.ts rename to src/rules/noParameterPropertiesRule.ts index 446bb1e1138..d4ee70be800 100644 --- a/src/rules/noConstructorVarsRule.ts +++ b/src/rules/noParameterPropertiesRule.ts @@ -17,13 +17,13 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { - ruleName: "no-constructor-vars", - description: "Disallows parameter properties.", + ruleName: "no-parameter-properties", + description: "Disallows parameter properties in class constructors.", rationale: Lint.Utils.dedent` Parameter properties can be confusing to those new to TS as they are less explicit than other ways of declaring and initializing class members.`, @@ -31,17 +31,20 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "style", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (ident: string) => `Property '${ident}' cannot be declared in the constructor`; + public static FAILURE_STRING_FACTORY = (ident: string) => { + return `Property '${ident}' cannot be declared in the constructor`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new NoConstructorVarsWalker(sourceFile, this.getOptions())); + return this.applyWithWalker(new NoParameterPropertiesWalker(sourceFile, this.getOptions())); } } -export class NoConstructorVarsWalker extends Lint.RuleWalker { +export class NoParameterPropertiesWalker extends Lint.RuleWalker { public visitConstructorDeclaration(node: ts.ConstructorDeclaration) { const parameters = node.parameters; for (let parameter of parameters) { diff --git a/src/rules/noReferenceRule.ts b/src/rules/noReferenceRule.ts index fcac6e8d74d..e20e38744c3 100644 --- a/src/rules/noReferenceRule.ts +++ b/src/rules/noReferenceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -31,6 +31,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "typescript", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noRequireImportsRule.ts b/src/rules/noRequireImportsRule.ts index f5aac5109e8..45031cc4fc8 100644 --- a/src/rules/noRequireImportsRule.ts +++ b/src/rules/noRequireImportsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,6 +29,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noShadowedVariableRule.ts b/src/rules/noShadowedVariableRule.ts index 8d32fd53705..6b2ffa0057e 100644 --- a/src/rules/noShadowedVariableRule.ts +++ b/src/rules/noShadowedVariableRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,10 +29,13 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (name: string) => `Shadowed variable: '${name}'`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `Shadowed variable: '${name}'`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoShadowedVariableWalker(sourceFile, this.getOptions())); @@ -71,23 +74,23 @@ class NoShadowedVariableWalker extends Lint.BlockScopeAwareRuleWalker `${name} statements in finally blocks are forbidden.`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `${name} statements in finally blocks are forbidden.`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoReturnInFinallyScopeAwareWalker(sourceFile, this.getOptions())); @@ -80,7 +79,7 @@ interface IFinallyScope { /** * A collection of `break` or `continue` labels in this scope. */ - labels: Array; + labels: string[]; } /** diff --git a/src/rules/noUnusedExpressionRule.ts b/src/rules/noUnusedExpressionRule.ts index 287398c81e1..4fa5285e7e3 100644 --- a/src/rules/noUnusedExpressionRule.ts +++ b/src/rules/noUnusedExpressionRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -33,6 +33,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -69,7 +70,7 @@ export class NoUnusedExpressionWalker extends Lint.RuleWalker { if (checkPreviousSiblings) { const siblings: ts.Node[] = []; - ts.forEachChild(node.parent, child => { siblings.push(child); }); + ts.forEachChild(node.parent, (child) => { siblings.push(child); }); return siblings.slice(0, siblings.indexOf(node)).every((n) => NoUnusedExpressionWalker.isDirective(n, false)); } else { return true; diff --git a/src/rules/noUnusedNewRule.ts b/src/rules/noUnusedNewRule.ts index 87dc6a7daa6..283e3ac57bd 100644 --- a/src/rules/noUnusedNewRule.ts +++ b/src/rules/noUnusedNewRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; import { NoUnusedExpressionWalker } from "./noUnusedExpressionRule"; export class Rule extends Lint.Rules.AbstractRule { @@ -34,6 +34,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noUnusedVariableRule.ts b/src/rules/noUnusedVariableRule.ts index 4ee93abccee..29520650736 100644 --- a/src/rules/noUnusedVariableRule.ts +++ b/src/rules/noUnusedVariableRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_REACT = "react"; const OPTION_CHECK_PARAMETERS = "check-parameters"; @@ -31,6 +31,7 @@ export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { ruleName: "no-unused-variable", + deprecationMessage: "Use the tsc compiler options --noUnusedParameters and --noUnusedLocals instead.", description: "Disallows unused imports, variables, functions and private class members.", optionsDescription: Lint.Utils.dedent` Three optional arguments may be optionally provided: @@ -63,6 +64,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "react"]', '[true, {"ignore-pattern": "^_"}]'], type: "functionality", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ @@ -72,8 +74,9 @@ export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_TYPE_PARAM = "parameter"; public static FAILURE_TYPE_PROP = "property"; public static FAILURE_TYPE_VAR = "variable"; - - public static FAILURE_STRING_FACTORY = (type: string, name: string) => `Unused ${type}: '${name}'`; + public static FAILURE_STRING_FACTORY = (type: string, name: string) => { + return `Unused ${type}: '${name}'`; + } public apply(sourceFile: ts.SourceFile, languageService: ts.LanguageService): Lint.RuleFailure[] { return this.applyWithWalker(new NoUnusedVariablesWalker(sourceFile, this.getOptions(), languageService)); @@ -219,7 +222,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker { if (importClause.namedBindings != null) { if (importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) { let imports = node.importClause.namedBindings as ts.NamedImports; - usedNamedImports = imports.elements.map(e => this.isUsed(e.name.text, e.name.getStart())); + usedNamedImports = imports.elements.map((e) => this.isUsed(e.name.text, e.name.getStart())); } // Avoid deleting the whole statement if there's an import * inside if (importClause.namedBindings.kind === ts.SyntaxKind.NamespaceImport) { @@ -228,7 +231,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker { } // Delete the entire import statement if named and default imports all unused - if (!usesDefaultImport && usedNamedImports.every(e => !e)) { + if (!usesDefaultImport && usedNamedImports.every((e) => !e)) { this.fail(Rule.FAILURE_TYPE_IMPORT, node.getText(), node.getStart(), this.deleteImportStatement(node)); super.visitImportDeclaration(node); return; @@ -245,7 +248,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker { if (importClause.namedBindings != null && importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) { // Delete the entire named imports if all unused, including curly braces. - if (usedNamedImports.every(e => !e)) { + if (usedNamedImports.every((e) => !e)) { const start = importClause.name != null ? importClause.name.getEnd() : importClause.namedBindings.getStart(); this.fail(Rule.FAILURE_TYPE_IMPORT, importClause.namedBindings.getText(), importClause.namedBindings.getStart(), [ this.deleteText(start, importClause.namedBindings.getEnd() - start), @@ -356,7 +359,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker { node.modifiers, ts.SyntaxKind.PublicKeyword, ts.SyntaxKind.PrivateKeyword, - ts.SyntaxKind.ProtectedKeyword + ts.SyntaxKind.ProtectedKeyword, ); if (!isSingleVariable && isPropertyParameter) { @@ -441,7 +444,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker { private fail(type: string, name: string, position: number, replacements?: Lint.Replacement[]) { let fix: Lint.Fix; if (replacements && replacements.length) { - fix = new Lint.Fix("no-unused-variable", replacements); + fix = new Lint.Fix(Rule.metadata.ruleName, replacements); } this.possibleFailures.push(this.createFailure(position, name.length, Rule.FAILURE_STRING_FACTORY(type, name), fix)); } diff --git a/src/rules/noUseBeforeDeclareRule.ts b/src/rules/noUseBeforeDeclareRule.ts index c51250d0948..7eaa15de404 100644 --- a/src/rules/noUseBeforeDeclareRule.ts +++ b/src/rules/noUseBeforeDeclareRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -31,6 +31,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noVarKeywordRule.ts b/src/rules/noVarKeywordRule.ts index 2c51ec52756..d022c85cf96 100644 --- a/src/rules/noVarKeywordRule.ts +++ b/src/rules/noVarKeywordRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,6 +29,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/noVarRequiresRule.ts b/src/rules/noVarRequiresRule.ts index e6498d03773..ac5ada9913a 100644 --- a/src/rules/noVarRequiresRule.ts +++ b/src/rules/noVarRequiresRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -31,6 +31,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/objectLiteralKeyQuotesRule.ts b/src/rules/objectLiteralKeyQuotesRule.ts index 75d4452db23..413581f298b 100644 --- a/src/rules/objectLiteralKeyQuotesRule.ts +++ b/src/rules/objectLiteralKeyQuotesRule.ts @@ -1,5 +1,22 @@ -import * as Lint from "../lint"; +/** + * @license + * Copyright 2016 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"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -28,22 +45,30 @@ export class Rule extends Lint.Rules.AbstractRule { * \`"always"\`: Property names should always be quoted. (This is the default.) * \`"as-needed"\`: Only property names which require quotes may be quoted (e.g. those with spaces in them). + * \`"consistent"\`: Property names should either all be quoted or unquoted. + * \`"consistent-as-needed"\`: If any property name requires quotes, then all properties must be quoted. Otherwise, no + property names may be quoted. For ES6, computed property names (\`{[name]: value}\`) and methods (\`{foo() {}}\`) never need to be quoted.`, options: { type: "string", - enum: ["always", "as-needed"], - // TODO: eslint also supports "consistent", "consistent-as-needed" modes. + enum: ["always", "as-needed", "consistent", "consistent-as-needed"], // TODO: eslint supports "keywords", "unnecessary" and "numbers" options. }, optionExamples: ["[true, \"as-needed\"]", "[true, \"always\"]"], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ - public static UNNEEDED_QUOTES = (name: string) => `Unnecessarily quoted property '${name}' found.`; - public static UNQUOTED_PROPERTY = (name: string) => `Unquoted property '${name}' found.`; + public static INCONSISTENT_PROPERTY = `All property names in this object literal must be consistently quoted or unquoted.`; + public static UNNEEDED_QUOTES = (name: string) => { + return `Unnecessarily quoted property '${name}' found.`; + } + public static UNQUOTED_PROPERTY = (name: string) => { + return `Unquoted property '${name}' found.`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { const objectLiteralKeyQuotesWalker = new ObjectLiteralKeyQuotesWalker(sourceFile, this.getOptions()); @@ -52,14 +77,22 @@ export class Rule extends Lint.Rules.AbstractRule { } // This is simplistic. See https://mothereff.in/js-properties for the gorey details. -const IDENTIFIER_NAME_REGEX = /^(?:[\$A-Z_a-z])*$/; - +const IDENTIFIER_NAME_REGEX = /^(?:[\$A-Z_a-z])+$/; const NUMBER_REGEX = /^[0-9]+$/; - -type QuotesMode = "always" | "as-needed"; +type QuotesMode = "always" | "as-needed" | "consistent" | "consistent-as-needed"; + +interface IObjectLiteralState { + // potential failures for properties that have quotes but don't need them + quotesNotNeededProperties: Lint.RuleFailure[]; + // potential failures for properties that don't have quotes + unquotedProperties: Lint.RuleFailure[]; + // whether or not any of the properties require quotes + hasQuotesNeededProperty: boolean; +} class ObjectLiteralKeyQuotesWalker extends Lint.RuleWalker { private mode: QuotesMode; + private currentState: IObjectLiteralState; constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) { super(sourceFile, options); @@ -69,27 +102,59 @@ class ObjectLiteralKeyQuotesWalker extends Lint.RuleWalker { public visitPropertyAssignment(node: ts.PropertyAssignment) { const name = node.name; - if (this.mode === "always") { - if (name.kind !== ts.SyntaxKind.StringLiteral && - name.kind !== ts.SyntaxKind.ComputedPropertyName) { - this.addFailure(this.createFailure(name.getStart(), name.getWidth(), - Rule.UNQUOTED_PROPERTY(name.getText()))); - } - } else if (this.mode === "as-needed") { - if (name.kind === ts.SyntaxKind.StringLiteral) { - // Check if the quoting is necessary. - const stringNode = name as ts.StringLiteral; - const property = stringNode.text; - - const isIdentifier = IDENTIFIER_NAME_REGEX.test(property); - const isNumber = NUMBER_REGEX.test(property); - if (isIdentifier || (isNumber && Number(property).toString() === property)) { - this.addFailure(this.createFailure(stringNode.getStart(), stringNode.getWidth(), - Rule.UNNEEDED_QUOTES(property))); - } + if (name.kind !== ts.SyntaxKind.StringLiteral && + name.kind !== ts.SyntaxKind.ComputedPropertyName) { + + const errorText = Rule.UNQUOTED_PROPERTY(name.getText()); + this.currentState.unquotedProperties.push(this.createFailure(name.getStart(), name.getWidth(), errorText)); + } + if (name.kind === ts.SyntaxKind.StringLiteral) { + // Check if the quoting is necessary. + const stringNode = name as ts.StringLiteral; + const property = stringNode.text; + + const isIdentifier = IDENTIFIER_NAME_REGEX.test(property); + const isNumber = NUMBER_REGEX.test(property); + if (isIdentifier || (isNumber && Number(property).toString() === property)) { + const errorText = Rule.UNNEEDED_QUOTES(property); + const failure = this.createFailure(stringNode.getStart(), stringNode.getWidth(), errorText); + this.currentState.quotesNotNeededProperties.push(failure); + } else { + this.currentState.hasQuotesNeededProperty = true; } } super.visitPropertyAssignment(node); } + + public visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { + let state: IObjectLiteralState = { + hasQuotesNeededProperty: false, + quotesNotNeededProperties: [], + unquotedProperties: [], + }; + // a nested object literal should store its parent state to restore when finished + let previousState = this.currentState; + this.currentState = state; + + super.visitObjectLiteralExpression(node); + + if (this.mode === "always" || (this.mode === "consistent-as-needed" && state.hasQuotesNeededProperty)) { + for (const failure of state.unquotedProperties) { + this.addFailure(failure); + } + } else if (this.mode === "as-needed" || (this.mode === "consistent-as-needed" && !state.hasQuotesNeededProperty)) { + for (const failure of state.quotesNotNeededProperties) { + this.addFailure(failure); + } + } else if (this.mode === "consistent") { + const hasQuotedProperties = state.hasQuotesNeededProperty || state.quotesNotNeededProperties.length > 0; + const hasUnquotedProperties = state.unquotedProperties.length > 0; + if (hasQuotedProperties && hasUnquotedProperties) { + this.addFailure(this.createFailure(node.getStart(), 1, Rule.INCONSISTENT_PROPERTY)); + } + } + + this.currentState = previousState; + } } diff --git a/src/rules/objectLiteralShorthandRule.ts b/src/rules/objectLiteralShorthandRule.ts index d1eca695246..aefc93181a8 100644 --- a/src/rules/objectLiteralShorthandRule.ts +++ b/src/rules/objectLiteralShorthandRule.ts @@ -1,14 +1,16 @@ -import * as Lint from "../lint"; import * as ts from "typescript"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { ruleName: "object-literal-shorthand", description: "Enforces use of ES6 object literal shorthand when possible.", + optionsDescription: "Not configurable.", options: null, optionExamples: ["true"], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/objectLiteralSortKeysRule.ts b/src/rules/objectLiteralSortKeysRule.ts index ccebcbe8167..78dc7d96efa 100644 --- a/src/rules/objectLiteralSortKeysRule.ts +++ b/src/rules/objectLiteralSortKeysRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -29,10 +29,13 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING_FACTORY = (name: string) => `The key '${name}' is not sorted alphabetically`; + public static FAILURE_STRING_FACTORY = (name: string) => { + return `The key '${name}' is not sorted alphabetically`; + } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new ObjectLiteralSortKeysWalker(sourceFile, this.getOptions())); @@ -42,6 +45,7 @@ export class Rule extends Lint.Rules.AbstractRule { class ObjectLiteralSortKeysWalker extends Lint.RuleWalker { // stacks are used to maintain state while recursing through nested object literals private lastSortedKeyStack: string[] = []; + private multilineFlagStack: boolean[] = []; private sortedStateStack: boolean[] = []; public visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { @@ -49,18 +53,21 @@ class ObjectLiteralSortKeysWalker extends Lint.RuleWalker { this.lastSortedKeyStack.push(""); // sorted state is always initially true this.sortedStateStack.push(true); + this.multilineFlagStack.push(this.isMultilineListNode(node)); super.visitObjectLiteralExpression(node); + this.multilineFlagStack.pop(); this.lastSortedKeyStack.pop(); this.sortedStateStack.pop(); } public visitPropertyAssignment(node: ts.PropertyAssignment) { const sortedState = this.sortedStateStack[this.sortedStateStack.length - 1]; + const isMultiline = this.multilineFlagStack[this.multilineFlagStack.length - 1]; // skip remainder of object literal scan if a previous key was found // in an unsorted position. This ensures only one error is thrown at - // a time and keeps error output clean. - if (sortedState) { + // a time and keeps error output clean. Skip also single line objects. + if (sortedState && isMultiline) { const lastSortedKey = this.lastSortedKeyStack[this.lastSortedKeyStack.length - 1]; const keyNode = node.name; if (isIdentifierOrStringLiteral(keyNode)) { @@ -76,6 +83,12 @@ class ObjectLiteralSortKeysWalker extends Lint.RuleWalker { } super.visitPropertyAssignment(node); } + + private isMultilineListNode(node: ts.ObjectLiteralExpression) { + const startLineOfNode = this.getSourceFile().getLineAndCharacterOfPosition(node.getStart()).line; + const endLineOfNode = this.getSourceFile().getLineAndCharacterOfPosition(node.getEnd()).line; + return endLineOfNode !== startLineOfNode; + } } function isIdentifierOrStringLiteral(node: ts.Node): node is (ts.Identifier | ts.StringLiteral) { diff --git a/src/rules/oneLineRule.ts b/src/rules/oneLineRule.ts index e7bcfc0ef2e..bad0235d9d4 100644 --- a/src/rules/oneLineRule.ts +++ b/src/rules/oneLineRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_BRACE = "check-open-brace"; const OPTION_CATCH = "check-catch"; @@ -49,6 +49,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "check-catch", "check-finally", "check-else"]'], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -195,7 +196,7 @@ class OneLineWalker extends Lint.RuleWalker { public visitModuleDeclaration(node: ts.ModuleDeclaration) { const nameNode = node.name; const body = node.body; - if (body.kind === ts.SyntaxKind.ModuleBlock) { + if (body != null && body.kind === ts.SyntaxKind.ModuleBlock) { const openBraceToken = body.getChildAt(0); this.handleOpeningBrace(nameNode, openBraceToken); } diff --git a/src/rules/oneVariablePerDeclarationRule.ts b/src/rules/oneVariablePerDeclarationRule.ts index 3a79c213f24..f8c056ba4e9 100644 --- a/src/rules/oneVariablePerDeclarationRule.ts +++ b/src/rules/oneVariablePerDeclarationRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_IGNORE_FOR_LOOP = "ignore-for-loop"; @@ -41,6 +41,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["true", `[true, "${OPTION_IGNORE_FOR_LOOP}"]`], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/onlyArrowFunctionsRule.ts b/src/rules/onlyArrowFunctionsRule.ts index f29b191ece7..ad7734e071b 100644 --- a/src/rules/onlyArrowFunctionsRule.ts +++ b/src/rules/onlyArrowFunctionsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ALLOW_DECLARATIONS = "allow-declarations"; @@ -43,6 +43,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["true", `[true, "${OPTION_ALLOW_DECLARATIONS}"]`], type: "typescript", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -55,16 +56,31 @@ export class Rule extends Lint.Rules.AbstractRule { class OnlyArrowFunctionsWalker extends Lint.RuleWalker { public visitFunctionDeclaration(node: ts.FunctionDeclaration) { - if (!node.asteriskToken && !this.hasOption(OPTION_ALLOW_DECLARATIONS)) { - this.addFailure(this.createFailure(node.getStart(), "function".length, Rule.FAILURE_STRING)); + if (!this.hasOption(OPTION_ALLOW_DECLARATIONS)) { + this.failUnlessExempt(node); } super.visitFunctionDeclaration(node); } public visitFunctionExpression(node: ts.FunctionExpression) { - if (!node.asteriskToken) { + this.failUnlessExempt(node); + super.visitFunctionExpression(node); + } + + private failUnlessExempt(node: ts.FunctionLikeDeclaration) { + if (!functionIsExempt(node)) { this.addFailure(this.createFailure(node.getStart(), "function".length, Rule.FAILURE_STRING)); } - super.visitFunctionExpression(node); } } + +/** Generator functions and functions explicitly declaring `this` are allowed. */ +function functionIsExempt(node: ts.FunctionLikeDeclaration) { + return node.asteriskToken || hasThisParameter(node); +} + +function hasThisParameter(node: ts.FunctionLikeDeclaration) { + const first = node.parameters[0]; + return first && first.name.kind === ts.SyntaxKind.Identifier && + (first.name as ts.Identifier).originalKeywordKind === ts.SyntaxKind.ThisKeyword; +} diff --git a/src/rules/orderedImportsRule.ts b/src/rules/orderedImportsRule.ts index d90e636fa1e..a78e4fc26e2 100644 --- a/src/rules/orderedImportsRule.ts +++ b/src/rules/orderedImportsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -27,7 +27,7 @@ export class Rule extends Lint.Rules.AbstractRule { descriptionDetails: Lint.Utils.dedent` Enforce a consistent ordering for ES6 imports: - Named imports must be alphabetized (i.e. "import {A, B, C} from "foo";") - - The exact ordering can be controled by the named-imports-order option. + - The exact ordering can be controlled by the named-imports-order option. - "longName as name" imports are ordered by "longName". - Import sources must be alphabetized within groups, i.e.: import * as foo from "a"; @@ -42,6 +42,7 @@ export class Rule extends Lint.Rules.AbstractRule { * \`"case-insensitive'\`: Correct order is \`"Bar"\`, \`"baz"\`, \`"Foo"\`. (This is the default.) * \`"lowercase-first"\`: Correct order is \`"baz"\`, \`"Bar"\`, \`"Foo"\`. * \`"lowercase-last"\`: Correct order is \`"Bar"\`, \`"Foo"\`, \`"baz"\`. + * \`"any"\`: Allow any order. You may set the \`"named-imports-order"\` option to control the ordering of named imports (the \`{A, B, C}\` in \`import {A, B, C} from "foo"\`). @@ -51,6 +52,7 @@ export class Rule extends Lint.Rules.AbstractRule { * \`"case-insensitive'\`: Correct order is \`{A, b, C}\`. (This is the default.) * \`"lowercase-first"\`: Correct order is \`{b, A, C}\`. * \`"lowercase-last"\`: Correct order is \`{A, C, b}\`. + * \`"any"\`: Allow any order. `, options: { @@ -58,11 +60,11 @@ export class Rule extends Lint.Rules.AbstractRule { properties: { "import-sources-order": { type: "string", - enum: ["case-insensitive", "lowercase-first", "lowercase-last"], + enum: ["case-insensitive", "lowercase-first", "lowercase-last", "any"], }, "named-imports-order": { type: "string", - enum: ["case-insensitive", "lowercase-first", "lowercase-last"], + enum: ["case-insensitive", "lowercase-first", "lowercase-last", "any"], }, }, additionalProperties: false, @@ -72,6 +74,7 @@ export class Rule extends Lint.Rules.AbstractRule { '[true, {"import-sources-order": "lowercase-last", "named-imports-order": "lowercase-first"}]', ], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -86,7 +89,7 @@ export class Rule extends Lint.Rules.AbstractRule { // Convert aBcD --> AbCd function flipCase(x: string): string { - return x.split("").map(char => { + return x.split("").map((char) => { if (char >= "a" && char <= "z") { return char.toUpperCase(); } else if (char >= "A" && char <= "Z") { @@ -107,17 +110,49 @@ function findUnsortedPair(xs: ts.Node[], transform: (x: string) => string): [ts. return null; } +function compare(a: string, b: string) { + const isLow = (value: string) => { + return [".", "/"].some((x) => value[0] === x); + }; + if (isLow(a) && !isLow(b)) { + return 1; + } else if (!isLow(a) && isLow(b)) { + return -1; + } else if (a > b) { + return 1; + } else if (a < b) { + return -1; + } + return 0; +} + +function removeQuotes(value: string) { + // strip out quotes + if (value && value.length > 1 && (value[0] === "'" || value[0] === "\"")) { + value = value.substr(1, value.length - 2); + } + return value; +} + +function sortByKey(xs: T[], getSortKey: (x: T) => string): T[] { + return xs.slice().sort((a, b) => { + return compare(getSortKey(a), getSortKey(b)); + }); +} + // Transformations to apply to produce the desired ordering of imports. // The imports must be lexicographically sorted after applying the transform. const TRANSFORMS: {[ordering: string]: (x: string) => string} = { + "any": () => "", "case-insensitive": (x: string) => x.toLowerCase(), "lowercase-first": flipCase, "lowercase-last": (x: string) => x, }; class OrderedImportsWalker extends Lint.RuleWalker { - // This gets reset after every blank line. - private lastImportSource: string = null; + private currentImportsBlock: ImportsBlock = 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.Fix; private importSourcesOrderTransform: (x: string) => string = null; private namedImportsOrderTransform: (x: string) => string = null; @@ -133,13 +168,17 @@ class OrderedImportsWalker extends Lint.RuleWalker { // e.g. "import Foo from "./foo";" public visitImportDeclaration(node: ts.ImportDeclaration) { - const source = this.importSourcesOrderTransform(node.moduleSpecifier.getText()); + let source = node.moduleSpecifier.getText(); + source = removeQuotes(source); + source = this.importSourcesOrderTransform(source); + const previousSource = this.currentImportsBlock.getLastImportSource(); + this.currentImportsBlock.addImportDeclaration(node, source); - if (this.lastImportSource && source < this.lastImportSource) { - this.addFailure(this.createFailure(node.getStart(), node.getWidth(), - Rule.IMPORT_SOURCES_UNORDERED)); + if (previousSource && compare(source, previousSource) === -1) { + this.lastFix = new Lint.Fix(Rule.metadata.ruleName, []); + const ruleFailure = this.createFailure(node.getStart(), node.getWidth(), Rule.IMPORT_SOURCES_UNORDERED, this.lastFix); + this.addFailure(ruleFailure); } - this.lastImportSource = source; super.visitImportDeclaration(node); } @@ -152,25 +191,135 @@ class OrderedImportsWalker extends Lint.RuleWalker { const pair = findUnsortedPair(imports, this.namedImportsOrderTransform); if (pair !== null) { const [a, b] = pair; - this.addFailure( - this.createFailure( - a.getStart(), - b.getEnd() - a.getStart(), - Rule.NAMED_IMPORTS_UNORDERED)); + const sortedDeclarations = sortByKey(imports, (x) => this.namedImportsOrderTransform(x.getText())).map((x) => x.getText()); + // replace in reverse order to preserve earlier offsets + for (let i = imports.length - 1; i >= 0; i--) { + const start = imports[i].getStart(); + const length = imports[i].getText().length; + + // replace the named imports one at a time to preserve whitespace + this.currentImportsBlock.replaceNamedImports(start, length, sortedDeclarations[i]); + } + + this.lastFix = new Lint.Fix(Rule.metadata.ruleName, []); + const ruleFailure = this.createFailure( + a.getStart(), + b.getEnd() - a.getStart(), + Rule.NAMED_IMPORTS_UNORDERED, + this.lastFix); + this.addFailure(ruleFailure); } super.visitNamedImports(node); } - // Check for a blank line, in which case we should reset the import ordering. + // keep reading the block of import declarations until the block ends, then replace the entire block + // this allows the reorder of named imports to work well with reordering lines public visitNode(node: ts.Node) { const prefixLength = node.getStart() - node.getFullStart(); const prefix = node.getFullText().slice(0, prefixLength); + const hasBlankLine = prefix.indexOf("\n\n") >= 0 || prefix.indexOf("\r\n\r\n") >= 0; + const notImportDeclaration = node.parent != null + && node.parent.kind === ts.SyntaxKind.SourceFile + && node.kind !== ts.SyntaxKind.ImportDeclaration; - if (prefix.indexOf("\n\n") >= 0 || - prefix.indexOf("\r\n\r\n") >= 0) { - this.lastImportSource = null; + if (hasBlankLine || notImportDeclaration) { + // end of block + if (this.lastFix != null) { + const replacement = this.currentImportsBlock.getReplacement(); + if (replacement != null) { + this.lastFix.replacements.push(replacement); + } + this.lastFix = null; + } + this.currentImportsBlock = new ImportsBlock(); } super.visitNode(node); } } + +interface ImportDeclaration { + node: ts.ImportDeclaration; + nodeEndOffset: number; // end position of node within source file + nodeStartOffset: number; // start position of node within source file + text: string; // initialized with original import text; modified if the named imports are reordered + sourcePath: string; +} + +class ImportsBlock { + private importDeclarations: ImportDeclaration[] = []; + + public addImportDeclaration(node: ts.ImportDeclaration, sourcePath: string) { + const start = this.getStartOffset(node); + const end = this.getEndOffset(node); + const text = node.getSourceFile().text.substring(start, end); + + if (start > node.getStart() || end === 0) { + // skip block if any statements don't end with a newline to simplify implementation + this.importDeclarations = []; + return; + } + + this.importDeclarations.push({ + node, + nodeEndOffset: end, + nodeStartOffset: start, + sourcePath, + text, + }); + } + + // replaces the named imports on the most recent import declaration + public replaceNamedImports(fileOffset: number, length: number, replacement: string) { + const importDeclaration = this.getLastImportDeclaration(); + if (importDeclaration == null) { + // nothing to replace. This can happen if the block is skipped + return; + } + + const start = fileOffset - importDeclaration.nodeStartOffset; + if (start < 0 || start + length > importDeclaration.node.getEnd()) { + throw "Unexpected named import position"; + } + + const initialText = importDeclaration.text; + importDeclaration.text = initialText.substring(0, start) + replacement + initialText.substring(start + length); + } + + public getLastImportSource() { + if (this.importDeclarations.length === 0) { + return null; + } + return this.getLastImportDeclaration().sourcePath; + } + + // creates a Lint.Replacement object with ordering fixes for the entire block + public getReplacement() { + if (this.importDeclarations.length === 0) { + return null; + } + const sortedDeclarations = sortByKey(this.importDeclarations.slice(), (x) => x.sourcePath); + const fixedText = sortedDeclarations.map((x) => x.text).join(""); + const start = this.importDeclarations[0].nodeStartOffset; + const end = this.getLastImportDeclaration().nodeEndOffset; + return new Lint.Replacement(start, end - start, fixedText); + } + + // gets the offset immediately after the end of the previous declaration to include comment above + private getStartOffset(node: ts.ImportDeclaration) { + if (this.importDeclarations.length === 0) { + return node.getStart(); + } + return this.getLastImportDeclaration().nodeEndOffset; + } + + // gets the offset of the end of the import's line, including newline, to include comment to the right + private getEndOffset(node: ts.ImportDeclaration) { + let endLineOffset = node.getSourceFile().text.indexOf("\n", node.end) + 1; + return endLineOffset; + } + + private getLastImportDeclaration() { + return this.importDeclarations[this.importDeclarations.length - 1]; + } +} diff --git a/src/rules/preferForOfRule.ts b/src/rules/preferForOfRule.ts index 5fc05b4bfd8..b7096391d6e 100644 --- a/src/rules/preferForOfRule.ts +++ b/src/rules/preferForOfRule.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import * as Lint from "../lint"; import * as ts from "typescript"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -28,94 +28,167 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "typescript", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ public static FAILURE_STRING = "Expected a 'for-of' loop instead of a 'for' loop with this simple iteration"; - public apply(sourceFile: ts.SourceFile, languageService: ts.LanguageService): Lint.RuleFailure[] { - return this.applyWithWalker(new PreferForOfWalker(sourceFile, this.getOptions(), languageService)); + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + const languageService = Lint.createLanguageService(sourceFile.fileName, sourceFile.getFullText()); + return this.applyWithWalker(new PreferForOfWalker(sourceFile, this.getOptions())); } } +interface IIncrementorState { + arrayToken: ts.LeftHandSideExpression; + endIncrementPos: number; + onlyArrayAccess: boolean; +} + class PreferForOfWalker extends Lint.RuleWalker { - constructor(sourceFile: ts.SourceFile, options: Lint.IOptions, private languageService: ts.LanguageService) { + // a map of incrementors and whether or not they are only used to index into an array reference in the for loop + private incrementorMap: { [name: string]: IIncrementorState }; + + constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) { super(sourceFile, options); + this.incrementorMap = {}; } public visitForStatement(node: ts.ForStatement) { - const arrayAccessNode = this.locateArrayNodeInForLoop(node); - - if (arrayAccessNode !== undefined) { - // Skip arrays thats just loop over a hard coded number - // If we are accessing the length of the array, then we are likely looping over it's values - if (arrayAccessNode.kind === ts.SyntaxKind.PropertyAccessExpression && arrayAccessNode.getLastToken().getText() === "length") { - let incrementorVariable = node.incrementor.getFirstToken(); - if (/\+|-/g.test(incrementorVariable.getText())) { - // If it's formatted as `++i` instead, we need to get the OTHER token - incrementorVariable = node.incrementor.getLastToken(); - } - const arrayToken = arrayAccessNode.getChildAt(0); - const loopSyntaxText = node.statement.getText(); - // Find all usages of the incrementor variable - const fileName = this.getSourceFile().fileName; - const highlights = this.languageService.getDocumentHighlights(fileName, incrementorVariable.getStart(), [fileName]); - - if (highlights && highlights.length > 0) { - // There are *usually* three usages when setting up the for loop, - // so remove those from the count to get the count inside the loop block - const incrementorCount = highlights[0].highlightSpans.length - 3; - - // Find `array[i]`-like usages by building up a regex - const arrayTokenForRegex = arrayToken.getText().replace(".", "\\."); - const incrementorForRegex = incrementorVariable.getText().replace(".", "\\."); - const regex = new RegExp(`${arrayTokenForRegex}\\[\\s*${incrementorForRegex}\\s*\\]`, "g"); - const accessMatches = loopSyntaxText.match(regex); - const matchCount = (accessMatches || []).length; - - // If there are more usages of the array item being access than the incrementor variable - // being used, then this loop could be replaced with a for-of loop instead. - // This means that the incrementor variable is not used on its own anywhere and is ONLY - // used to access the array item. - if (matchCount >= incrementorCount) { - const failure = this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING); - this.addFailure(failure); + const arrayNodeInfo = this.getForLoopHeaderInfo(node); + let indexVariableName: string; + if (arrayNodeInfo != null) { + const { indexVariable, arrayToken } = arrayNodeInfo; + indexVariableName = indexVariable.getText(); + + // store `for` loop state + this.incrementorMap[indexVariableName] = { + arrayToken, + endIncrementPos: node.incrementor.end, + onlyArrayAccess: true, + }; + } + + super.visitForStatement(node); + + if (indexVariableName != null) { + const incrementorState = this.incrementorMap[indexVariableName]; + if (incrementorState.onlyArrayAccess) { + // Find `array[i]`-like usages by building up a regex + const length = incrementorState.endIncrementPos - node.getStart() + 1; + const failure = this.createFailure(node.getStart(), length, Rule.FAILURE_STRING); + this.addFailure(failure); + } + + // remove current `for` loop state + delete this.incrementorMap[indexVariableName]; + } + } + + public visitIdentifier(node: ts.Identifier) { + const incrementorState = this.incrementorMap[node.text]; + + // check if the identifier is an iterator and is currently in the `for` loop body + if (incrementorState != null && incrementorState.arrayToken != null && incrementorState.endIncrementPos < node.getStart()) { + // mark `onlyArrayAccess` false if iterator is used on anything except the array in the `for` loop header + if (node.parent.kind !== ts.SyntaxKind.ElementAccessExpression + || incrementorState.arrayToken.getText() !== ( node.parent).expression.getText()) { + + incrementorState.onlyArrayAccess = false; + } + } + super.visitIdentifier(node); + } + + // returns the iterator and array of a `for` loop if the `for` loop is basic. Otherwise, `null` + private getForLoopHeaderInfo(forLoop: ts.ForStatement) { + let indexVariableName: string; + let indexVariable: ts.Identifier; + + // assign `indexVariableName` if initializer is simple and starts at 0 + if (forLoop.initializer != null && forLoop.initializer.kind === ts.SyntaxKind.VariableDeclarationList) { + const syntaxList = forLoop.initializer.getChildAt(1); + if (syntaxList.kind === ts.SyntaxKind.SyntaxList && syntaxList.getChildCount() === 1) { + const assignment = syntaxList.getChildAt(0); + if (assignment.kind === ts.SyntaxKind.VariableDeclaration) { + const value = assignment.getChildAt(2).getText(); + if (value === "0") { + indexVariable = assignment.getChildAt(0); + indexVariableName = indexVariable.getText(); } } } } - super.visitForStatement(node); + // ensure `for` condition + if (indexVariableName == null + || forLoop.condition == null + || forLoop.condition.kind !== ts.SyntaxKind.BinaryExpression + || forLoop.condition.getChildAt(0).getText() !== indexVariableName + || forLoop.condition.getChildAt(1).getText() !== "<") { + + return null; + } + + if (!this.isIncremented(forLoop.incrementor, indexVariableName)) { + return null; + } + + // ensure that the condition checks a `length` property + const conditionRight = forLoop.condition.getChildAt(2); + if (conditionRight.kind === ts.SyntaxKind.PropertyAccessExpression) { + const propertyAccess = conditionRight; + if (propertyAccess.name.getText() === "length") { + return { indexVariable, arrayToken: propertyAccess.expression }; + } + } + + return null; } - private locateArrayNodeInForLoop(forLoop: ts.ForStatement): ts.Node { - // Some oddly formatted (yet still valid!) `for` loops might not have children in the condition - // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for - if (forLoop.condition !== undefined) { - let arrayAccessNode = forLoop.condition.getChildAt(2); - // If We haven't found it, maybe it's not a standard for loop, try looking in the initializer for the array - // Something like `for(var t=0, len=arr.length; t < len; t++)` - if (arrayAccessNode.kind !== ts.SyntaxKind.PropertyAccessExpression && forLoop.initializer !== undefined) { - for (let initNode of forLoop.initializer.getChildren()) { - // look in `var t=0, len=arr.length;` - if (initNode.kind === ts.SyntaxKind.SyntaxList) { - for (let initVar of initNode.getChildren()) { - // look in `t=0, len=arr.length;` - if (initVar.kind === ts.SyntaxKind.VariableDeclaration) { - for (let initVarPart of initVar.getChildren()) { - // look in `len=arr.length` - if (initVarPart.kind === ts.SyntaxKind.PropertyAccessExpression) { - arrayAccessNode = initVarPart; - } - } - } - } + private isIncremented(node: ts.Node, indexVariableName: string) { + if (node == null) { + return false; + } + + // ensure variable is incremented + if (node.kind === ts.SyntaxKind.PrefixUnaryExpression) { + const incrementor = node; + if (incrementor.operator === ts.SyntaxKind.PlusPlusToken && incrementor.operand.getText() === indexVariableName) { + // x++ + return true; + } + } else if (node.kind === ts.SyntaxKind.PostfixUnaryExpression) { + const incrementor = node; + if (incrementor.operator === ts.SyntaxKind.PlusPlusToken && incrementor.operand.getText() === indexVariableName) { + // ++x + return true; + } + } else if (node.kind === ts.SyntaxKind.BinaryExpression) { + const binaryExpression = node; + if (binaryExpression.operatorToken.getText() === "+=" + && binaryExpression.left.getText() === indexVariableName + && binaryExpression.right.getText() === "1") { + // x += 1 + return true; + } + if (binaryExpression.operatorToken.getText() === "=" + && binaryExpression.left.getText() === indexVariableName) { + const addExpression = binaryExpression.right; + if (addExpression.operatorToken.getText() === "+") { + if (addExpression.right.getText() === indexVariableName && addExpression.left.getText() === "1") { + // x = 1 + x + return true; + } else if (addExpression.left.getText() === indexVariableName && addExpression.right.getText() === "1") { + // x = x + 1 + return true; } } } - return arrayAccessNode; } else { - return undefined; + return false; } + return false; } } diff --git a/src/rules/quotemarkRule.ts b/src/rules/quotemarkRule.ts index aabfd9eaf32..ebfb7bda6f3 100644 --- a/src/rules/quotemarkRule.ts +++ b/src/rules/quotemarkRule.ts @@ -17,11 +17,11 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; enum QuoteMark { SINGLE_QUOTES, - DOUBLE_QUOTES + DOUBLE_QUOTES, } export class Rule extends Lint.Rules.AbstractRule { @@ -49,6 +49,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "single", "avoid-escape"]', '[true, "single", "jsx-double"]'], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/radixRule.ts b/src/rules/radixRule.ts index 5bfb33b9c49..e35521fc226 100644 --- a/src/rules/radixRule.ts +++ b/src/rules/radixRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -32,6 +32,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/restrictPlusOperandsRule.ts b/src/rules/restrictPlusOperandsRule.ts index 996fbe5c9b9..ec16c412894 100644 --- a/src/rules/restrictPlusOperandsRule.ts +++ b/src/rules/restrictPlusOperandsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.TypedRule { /* tslint:disable:object-literal-sort-keys */ @@ -28,12 +28,15 @@ export class Rule extends Lint.Rules.TypedRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, requiresTypeInfo: true, }; /* tslint:enable:object-literal-sort-keys */ public static MISMATCHED_TYPES_FAILURE = "Types of values used in '+' operation must match"; - public static UNSUPPORTED_TYPE_FAILURE_FACTORY = (type: string) => `cannot add type ${type}`; + public static UNSUPPORTED_TYPE_FAILURE_FACTORY = (type: string) => { + return `cannot add type ${type}`; + } public applyWithProgram(sourceFile: ts.SourceFile, langSvc: ts.LanguageService): Lint.RuleFailure[] { return this.applyWithWalker(new RestrictPlusOperandsWalker(sourceFile, this.getOptions(), langSvc.getProgram())); diff --git a/src/rules/semicolonRule.ts b/src/rules/semicolonRule.ts index 6ae0d810303..b9be0599be4 100644 --- a/src/rules/semicolonRule.ts +++ b/src/rules/semicolonRule.ts @@ -17,10 +17,11 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ALWAYS = "always"; const OPTION_NEVER = "never"; +const OPTION_IGNORE_BOUND_CLASS_METHODS = "ignore-bound-class-methods"; const OPTION_IGNORE_INTERFACES = "ignore-interfaces"; export class Rule extends Lint.Rules.AbstractRule { @@ -35,7 +36,8 @@ export class Rule extends Lint.Rules.AbstractRule { * \`"${OPTION_NEVER}"\` disallows semicolons at the end of every statement except for when they are necessary. The following arguments may be optionaly provided: - * \`"${OPTION_IGNORE_INTERFACES}"\` skips checking semicolons at the end of interface members.`, + * \`"${OPTION_IGNORE_INTERFACES}"\` skips checking semicolons at the end of interface members. + * \`"${OPTION_IGNORE_BOUND_CLASS_METHODS}"\` skips checking semicolons at the end of bound class methods.`, options: { type: "array", items: [{ @@ -51,8 +53,10 @@ export class Rule extends Lint.Rules.AbstractRule { `[true, "${OPTION_ALWAYS}"]`, `[true, "${OPTION_NEVER}"]`, `[true, "${OPTION_ALWAYS}", "${OPTION_IGNORE_INTERFACES}"]`, + `[true, "${OPTION_ALWAYS}", "${OPTION_IGNORE_BOUND_CLASS_METHODS}"]`, ], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -117,8 +121,13 @@ class SemicolonWalker extends Lint.RuleWalker { public visitPropertyDeclaration(node: ts.PropertyDeclaration) { const initializer = node.initializer; - /* ALWAYS === "enabled" for this rule. */ - if (this.hasOption(OPTION_NEVER) || !(initializer && initializer.kind === ts.SyntaxKind.ArrowFunction)) { + + // check if this is a multi-line arrow function (`[^]` in the regex matches all characters including CR & LF) + if (initializer && initializer.kind === ts.SyntaxKind.ArrowFunction && /\{[^]*\n/.test(node.getText())) { + if (!this.hasOption(OPTION_IGNORE_BOUND_CLASS_METHODS)) { + this.checkSemicolonAt(node, "never"); + } + } else { this.checkSemicolonAt(node); } super.visitPropertyDeclaration(node); @@ -152,13 +161,14 @@ class SemicolonWalker extends Lint.RuleWalker { super.visitTypeAliasDeclaration(node); } - private checkSemicolonAt(node: ts.Node) { + private checkSemicolonAt(node: ts.Node, override?: "never") { const sourceFile = this.getSourceFile(); const children = node.getChildren(sourceFile); const hasSemicolon = children.some((child) => child.kind === ts.SyntaxKind.SemicolonToken); const position = node.getStart(sourceFile) + node.getWidth(sourceFile); + const never = override === "never" || this.hasOption(OPTION_NEVER); // Backwards compatible with plain {"semicolon": true} - const always = this.hasOption(OPTION_ALWAYS) || (this.getOptions() && this.getOptions().length === 0); + const always = !never && (this.hasOption(OPTION_ALWAYS) || (this.getOptions() && this.getOptions().length === 0)); if (always && !hasSemicolon) { const failureStart = Math.min(position, this.getLimit()); @@ -166,7 +176,7 @@ class SemicolonWalker extends Lint.RuleWalker { this.appendText(failureStart, ";"), ]); this.addFailure(this.createFailure(failureStart, 0, Rule.FAILURE_STRING_MISSING, fix)); - } else if (this.hasOption(OPTION_NEVER) && hasSemicolon) { + } else if (never && hasSemicolon) { const scanner = ts.createScanner(ts.ScriptTarget.ES5, false, ts.LanguageVariant.Standard, sourceFile.text); scanner.setTextPos(position); diff --git a/src/rules/switchDefaultRule.ts b/src/rules/switchDefaultRule.ts index a9c3e6b4279..0d8524c9c61 100644 --- a/src/rules/switchDefaultRule.ts +++ b/src/rules/switchDefaultRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -28,6 +28,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/trailingCommaRule.ts b/src/rules/trailingCommaRule.ts index f6ef978a691..845cf4be0f7 100644 --- a/src/rules/trailingCommaRule.ts +++ b/src/rules/trailingCommaRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -53,6 +53,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, {"multiline": "always", "singleline": "never"}]'], type: "maintainability", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ @@ -65,7 +66,7 @@ export class Rule extends Lint.Rules.AbstractRule { } class TrailingCommaWalker extends Lint.RuleWalker { - private static SYNTAX_LIST_WRAPPER_TOKENS: [ts.SyntaxKind, ts.SyntaxKind][] = [ + private static SYNTAX_LIST_WRAPPER_TOKENS: Array<[ts.SyntaxKind, ts.SyntaxKind]> = [ [ts.SyntaxKind.OpenBraceToken, ts.SyntaxKind.CloseBraceToken], [ts.SyntaxKind.OpenBracketToken, ts.SyntaxKind.CloseBracketToken], [ts.SyntaxKind.OpenParenToken, ts.SyntaxKind.CloseParenToken], @@ -188,8 +189,8 @@ class TrailingCommaWalker extends Lint.RuleWalker { // as opposed to optionals alongside it. So instead of children[i + 1] having // [ PropertySignature, Semicolon, PropertySignature, Semicolon ], the AST is // [ PropertySignature, PropertySignature], where the Semicolons are under PropertySignature - const hasSemicolon = grandChildren.some(grandChild => { - return grandChild.getChildren().some(ggc => ggc.kind === ts.SyntaxKind.SemicolonToken); + const hasSemicolon = grandChildren.some((grandChild) => { + return grandChild.getChildren().some((ggc) => ggc.kind === ts.SyntaxKind.SemicolonToken); }); if (!hasSemicolon) { diff --git a/src/rules/tripleEqualsRule.ts b/src/rules/tripleEqualsRule.ts index 87c4fbdfc00..24b04cd9622 100644 --- a/src/rules/tripleEqualsRule.ts +++ b/src/rules/tripleEqualsRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_ALLOW_NULL_CHECK = "allow-null-check"; const OPTION_ALLOW_UNDEFINED_CHECK = "allow-undefined-check"; @@ -47,6 +47,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ["true", '[true, "allow-null-check"]', '[true, "allow-undefined-check"]'], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/typedefRule.ts b/src/rules/typedefRule.ts index 8155c0eec6f..7e0f5b7dce0 100644 --- a/src/rules/typedefRule.ts +++ b/src/rules/typedefRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -53,6 +53,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "call-signature", "parameter", "member-variable-declaration"]'], type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/typedefWhitespaceRule.ts b/src/rules/typedefWhitespaceRule.ts index 53e2aae6651..c7cbb094262 100644 --- a/src/rules/typedefWhitespaceRule.ts +++ b/src/rules/typedefWhitespaceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; /* tslint:disable:object-literal-sort-keys */ const SPACE_OPTIONS = { @@ -30,7 +30,7 @@ const SPACE_OBJECT = { properties: { "call-signature": SPACE_OPTIONS, "index-signature": SPACE_OPTIONS, - parameter: SPACE_OPTIONS, + "parameter": SPACE_OPTIONS, "property-declaration": SPACE_OPTIONS, "variable-declaration": SPACE_OPTIONS, }, @@ -79,6 +79,7 @@ export class Rule extends Lint.Rules.AbstractRule { ]`, ], type: "typescript", + typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ @@ -89,9 +90,7 @@ export class Rule extends Lint.Rules.AbstractRule { class TypedefWhitespaceWalker extends Lint.RuleWalker { private static getColonPosition(node: ts.Node) { - const colon = node.getChildren().filter((child) => - child.kind === ts.SyntaxKind.ColonToken - )[0]; + const colon = node.getChildren().filter((child) => child.kind === ts.SyntaxKind.ColonToken)[0]; return colon == null ? -1 : colon.getStart(); } @@ -240,7 +239,7 @@ class TypedefWhitespaceWalker extends Lint.RuleWalker { hasLeadingWhitespace, hasSeveralLeadingWhitespaces, colonPosition - 1, - message + message, ); } } @@ -282,7 +281,7 @@ class TypedefWhitespaceWalker extends Lint.RuleWalker { hasTrailingWhitespace, hasSeveralTrailingWhitespaces, colonPosition + 1, - message + message, ); } } diff --git a/src/rules/useIsnanRule.ts b/src/rules/useIsnanRule.ts index 5e37d0daf62..651b30f4265 100644 --- a/src/rules/useIsnanRule.ts +++ b/src/rules/useIsnanRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ @@ -31,6 +31,7 @@ export class Rule extends Lint.Rules.AbstractRule { options: null, optionExamples: ["true"], type: "functionality", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/useStrictRule.ts b/src/rules/useStrictRule.ts deleted file mode 100644 index d7aa8335c74..00000000000 --- a/src/rules/useStrictRule.ts +++ /dev/null @@ -1,121 +0,0 @@ -/** - * @license - * Copyright 2013 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"; - -import * as Lint from "../lint"; - -export class Rule extends Lint.Rules.AbstractRule { - /* tslint:disable:object-literal-sort-keys */ - public static metadata: Lint.IRuleMetadata = { - ruleName: "use-strict", - description: "Requires using ECMAScript 5's strict mode.", - optionsDescription: Lint.Utils.dedent` - Two arguments may be optionally provided: - - * \`check-module\` checks that all top-level modules are using strict mode. - * \`check-function\` checks that all top-level functions are using strict mode.`, - options: { - type: "array", - items: { - type: "string", - enum: ["check-module", "check-function"], - }, - minLength: 0, - maxLength: 2, - }, - optionExamples: ['[true, "check-module"]'], - type: "functionality", - }; - /* tslint:enable:object-literal-sort-keys */ - - public static FAILURE_STRING = "missing 'use strict'"; - - public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - const useStrictWalker = new UseStrictWalker(sourceFile, this.getOptions()); - return this.applyWithWalker(useStrictWalker); - } -} - -class UseStrictWalker extends Lint.ScopeAwareRuleWalker<{}> { - private static OPTION_CHECK_FUNCTION = "check-function"; - private static OPTION_CHECK_MODULE = "check-module"; - - private static USE_STRICT_STRING = "use strict"; - - public createScope(): {} { - return {}; - } - - public visitModuleDeclaration(node: ts.ModuleDeclaration) { - if (!Lint.hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword) - && this.hasOption(UseStrictWalker.OPTION_CHECK_MODULE) - && node.body != null - && node.body.kind === ts.SyntaxKind.ModuleBlock) { - let firstModuleDeclaration = getFirstInModuleDeclarationsChain(node); - let hasOnlyModuleDeclarationParents = firstModuleDeclaration.parent.kind === ts.SyntaxKind.SourceFile; - - if (hasOnlyModuleDeclarationParents) { - this.handleBlock(firstModuleDeclaration, node.body); - } - } - - super.visitModuleDeclaration(node); - } - - public visitFunctionDeclaration(node: ts.FunctionDeclaration) { - // current depth is 2: global scope and the scope created by this function - if (this.getCurrentDepth() === 2 && - this.hasOption(UseStrictWalker.OPTION_CHECK_FUNCTION) && - node.body != null) { - this.handleBlock(node, node.body); - } - - super.visitFunctionDeclaration(node); - } - - private handleBlock(node: ts.Declaration, block: ts.Block | ts.ModuleBlock) { - let isFailure = true; - - if (block.statements != null && block.statements.length > 0) { - const firstStatement = block.statements[0]; - - if (firstStatement.kind === ts.SyntaxKind.ExpressionStatement) { - const firstChild = firstStatement.getChildAt(0); - - if (firstChild.kind === ts.SyntaxKind.StringLiteral - && ( firstChild).text === UseStrictWalker.USE_STRICT_STRING) { - isFailure = false; - } - } - } - - if (isFailure) { - this.addFailure(this.createFailure(node.getStart(), node.getFirstToken().getWidth(), Rule.FAILURE_STRING)); - } - } -} - -function getFirstInModuleDeclarationsChain(node: ts.ModuleDeclaration): ts.ModuleDeclaration { - let current = node; - - while (current.parent.kind === ts.SyntaxKind.ModuleDeclaration) { - current = current.parent; - } - - return current; -} diff --git a/src/rules/variableNameRule.ts b/src/rules/variableNameRule.ts index 76699ec737f..77165f54efa 100644 --- a/src/rules/variableNameRule.ts +++ b/src/rules/variableNameRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const BANNED_KEYWORDS = ["any", "Number", "number", "String", "string", "Boolean", "boolean", "Undefined", "undefined"]; @@ -58,6 +58,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "ban-keywords", "check-format", "allow-leading-underscore"]'], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/rules/whitespaceRule.ts b/src/rules/whitespaceRule.ts index 06bb678a10e..3e9bc272042 100644 --- a/src/rules/whitespaceRule.ts +++ b/src/rules/whitespaceRule.ts @@ -17,7 +17,7 @@ import * as ts from "typescript"; -import * as Lint from "../lint"; +import * as Lint from "../index"; const OPTION_BRANCH = "check-branch"; const OPTION_DECL = "check-decl"; @@ -55,6 +55,7 @@ export class Rule extends Lint.Rules.AbstractRule { }, optionExamples: ['[true, "check-branch", "check-operator", "check-typecast"]'], type: "style", + typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/test.ts b/src/test.ts index 8a9d3b665bb..214b68c2f78 100644 --- a/src/test.ts +++ b/src/test.ts @@ -23,9 +23,9 @@ import * as path from "path"; import * as ts from "typescript"; import {Fix} from "./language/rule/rule"; +import * as Linter from "./linter"; import {LintError} from "./test/lintError"; import * as parse from "./test/parse"; -import * as Linter from "./tslint"; const MARKUP_FILE_EXTENSION = ".lint"; const FIXES_FILE_EXTENSION = ".fix"; @@ -40,13 +40,13 @@ export interface TestResult { fixesFromMarkup: string; markupFromLinter: string; markupFromMarkup: string; - } + }, }; } export function runTest(testDirectory: string, rulesDirectory?: string | string[]): TestResult { const filesToLint = glob.sync(path.join(testDirectory, `**/*${MARKUP_FILE_EXTENSION}`)); - const tslintConfig = Linter.findConfiguration(path.join(testDirectory, "tslint.json"), null); + const tslintConfig = Linter.findConfiguration(path.join(testDirectory, "tslint.json"), null).results; const tsConfig = path.join(testDirectory, "tsconfig.json"); let compilerOptions: ts.CompilerOptions = {}; if (fs.existsSync(tsConfig)) { @@ -72,8 +72,7 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ getCanonicalFileName: (filename: string) => filename, getCurrentDirectory: () => "", getDefaultLibFileName: () => ts.getDefaultLibFileName(compilerOptions), - // TODO: include this field when compiling with TS 2.0 - // getDirectories: (path: string) => [], + getDirectories: (_path: string) => [], getNewLine: () => "\n", getSourceFile(filenameToGet: string) { if (filenameToGet === this.getDefaultLibFileName()) { @@ -97,13 +96,14 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ } const lintOptions = { - configuration: tslintConfig, + fix: false, formatter: "prose", formattersDirectory: "", rulesDirectory, }; - const linter = new Linter(fileBasename, fileTextWithoutMarkup, lintOptions, program); - const failures = linter.lint().failures; + const linter = new Linter(lintOptions, program); + linter.lint(fileBasename, fileTextWithoutMarkup, tslintConfig); + const failures = linter.getResult().failures; const errorsFromLinter: LintError[] = failures.map((failure) => { const startLineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const endLineAndCharacter = failure.getEndPosition().getLineAndCharacter(); @@ -129,7 +129,7 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ const stat = fs.statSync(fixedFile); if (stat.isFile()) { fixedFileText = fs.readFileSync(fixedFile, "utf8"); - const fixes = failures.filter(f => f.hasFix()).map(f => f.getFix()); + const fixes = failures.filter((f) => f.hasFix()).map((f) => f.getFix()); newFileText = Fix.applyAll(fileTextWithoutMarkup, fixes); } } catch (e) { diff --git a/src/test/lintError.ts b/src/test/lintError.ts index 6b04e7b080a..5f90a4b3a81 100644 --- a/src/test/lintError.ts +++ b/src/test/lintError.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Error } from "../error"; + export interface PositionInFile { line: number; col: number; @@ -40,5 +42,5 @@ export function errorComparator(err1: LintError, err2: LintError) { } export function lintSyntaxError(message: string) { - return new Error(`Lint File Syntax Error: ${message}`); + return new Error(`Lint File Syntax Error: ${message}`) as Error; } diff --git a/src/test/parse.ts b/src/test/parse.ts index 24366ecbc58..d0f8c8d2abc 100644 --- a/src/test/parse.ts +++ b/src/test/parse.ts @@ -24,7 +24,7 @@ import { parseLine, printLine, } from "./lines"; -import {LintError, errorComparator, lintSyntaxError} from "./lintError"; +import {errorComparator, LintError, lintSyntaxError} from "./lintError"; /** * Takes the full text of a .lint file and returns the contents of the file @@ -83,7 +83,7 @@ export function parseErrorsFromMarkup(text: string): LintError[] { for (let nextLineNo = lineNo + 1; ; ++nextLineNo) { if (!isValidErrorMarkupContinuation(errorLinesForCodeLines, nextLineNo)) { throw lintSyntaxError( - `Error mark starting at ${errorStartPos.line}:${errorStartPos.col} does not end correctly.` + `Error mark starting at ${errorStartPos.line}:${errorStartPos.col} does not end correctly.`, ); } else { const nextErrorLine = errorLinesForCodeLines[nextLineNo].shift(); @@ -122,7 +122,7 @@ export function createMarkupFromErrors(code: string, lintErrors: LintError[]) { errorLinesForCodeText[startPos.line].push(new EndErrorLine( startPos.col, endPos.col, - message + message, )); } else { // multiline error diff --git a/src/tsconfig.json b/src/tsconfig.json index f22a846b63a..82843d7dc6f 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -1,160 +1,13 @@ { - "version": "1.6.2", + "version": "2.0.10", "compilerOptions": { "module": "commonjs", "noImplicitAny": true, + "noUnusedParameters": true, + "noUnusedLocals": true, "declaration": true, "sourceMap": false, "target": "es5", "outDir": "../lib" - }, - "atom": { - "rewriteTsconfig": false - }, - "filesGlob": [ - "../custom-typings/**/*.d.ts", - "../typings/**/*.d.ts", - "./*.ts", - "./configs/**/*.ts", - "./formatters/**/*.ts", - "./language/**/*.ts", - "./rules/**/*.ts", - "./test/**/*.ts" - ], - "files": [ - "../custom-typings/resolve.d.ts", - "../typings/colors/colors.d.ts", - "../typings/diff/diff.d.ts", - "../typings/findup-sync/findup-sync.d.ts", - "../typings/glob/glob.d.ts", - "../typings/js-yaml/js-yaml.d.ts", - "../typings/minimatch/minimatch.d.ts", - "../typings/node/node.d.ts", - "../typings/optimist/optimist.d.ts", - "../typings/underscore.string/underscore.string.d.ts", - "../typings/underscore/underscore.d.ts", - "configuration.ts", - "enableDisableRules.ts", - "formatterLoader.ts", - "formatters.ts", - "lint.ts", - "ruleLoader.ts", - "rules.ts", - "test.ts", - "tslint-cli.ts", - "tslint.ts", - "tslintMulti.ts", - "utils.ts", - "configs/latest.ts", - "configs/recommended.ts", - "formatters/applyFixesFormatter.ts", - "formatters/checkstyleFormatter.ts", - "formatters/fileslistFormatter.ts", - "formatters/index.ts", - "formatters/jsonFormatter.ts", - "formatters/msbuildFormatter.ts", - "formatters/pmdFormatter.ts", - "formatters/proseFormatter.ts", - "formatters/stylishFormatter.ts", - "formatters/verboseFormatter.ts", - "formatters/vsoFormatter.ts", - "language/formatter/abstractFormatter.ts", - "language/formatter/formatter.ts", - "language/languageServiceHost.ts", - "language/rule/abstractRule.ts", - "language/rule/rule.ts", - "language/rule/typedRule.ts", - "language/utils.ts", - "language/walker/blockScopeAwareRuleWalker.ts", - "language/walker/index.ts", - "language/walker/programAwareRuleWalker.ts", - "language/walker/ruleWalker.ts", - "language/walker/scopeAwareRuleWalker.ts", - "language/walker/skippableTokenAwareRuleWalker.ts", - "language/walker/syntaxWalker.ts", - "rules/adjacentOverloadSignaturesRule.ts", - "rules/alignRule.ts", - "rules/arrayTypeRule.ts", - "rules/arrowParensRule.ts", - "rules/banRule.ts", - "rules/classNameRule.ts", - "rules/commentFormatRule.ts", - "rules/curlyRule.ts", - "rules/cyclomaticComplexityRule.ts", - "rules/eoflineRule.ts", - "rules/fileHeaderRule.ts", - "rules/forinRule.ts", - "rules/indentRule.ts", - "rules/interfaceNameRule.ts", - "rules/jsdocFormatRule.ts", - "rules/labelPositionRule.ts", - "rules/labelUndefinedRule.ts", - "rules/linebreakStyleRule.ts", - "rules/maxFileLineCountRule.ts", - "rules/maxLineLengthRule.ts", - "rules/memberAccessRule.ts", - "rules/memberOrderingRule.ts", - "rules/newParensRule.ts", - "rules/noAngleBracketTypeAssertionRule.ts", - "rules/noAnyRule.ts", - "rules/noArgRule.ts", - "rules/noBitwiseRule.ts", - "rules/noConditionalAssignmentRule.ts", - "rules/noConsecutiveBlankLinesRule.ts", - "rules/noConsoleRule.ts", - "rules/noConstructorVarsRule.ts", - "rules/noConstructRule.ts", - "rules/noDebuggerRule.ts", - "rules/noDefaultExportRule.ts", - "rules/noDuplicateKeyRule.ts", - "rules/noDuplicateVariableRule.ts", - "rules/noEmptyRule.ts", - "rules/noEvalRule.ts", - "rules/noForInArrayRule.ts", - "rules/noInferrableTypesRule.ts", - "rules/noInternalModuleRule.ts", - "rules/noInvalidThisRule.ts", - "rules/noMergeableNamespaceRule.ts", - "rules/noNamespaceRule.ts", - "rules/noNullKeywordRule.ts", - "rules/noReferenceRule.ts", - "rules/noRequireImportsRule.ts", - "rules/noShadowedVariableRule.ts", - "rules/noStringLiteralRule.ts", - "rules/noSwitchCaseFallThroughRule.ts", - "rules/noTrailingWhitespaceRule.ts", - "rules/noUnreachableRule.ts", - "rules/noUnsafeFinallyRule.ts", - "rules/noUnusedExpressionRule.ts", - "rules/noUnusedNewRule.ts", - "rules/noUnusedVariableRule.ts", - "rules/noUseBeforeDeclareRule.ts", - "rules/noVarKeywordRule.ts", - "rules/noVarRequiresRule.ts", - "rules/objectLiteralKeyQuotesRule.ts", - "rules/objectLiteralShorthandRule.ts", - "rules/objectLiteralSortKeysRule.ts", - "rules/oneLineRule.ts", - "rules/oneVariablePerDeclarationRule.ts", - "rules/onlyArrowFunctionsRule.ts", - "rules/orderedImportsRule.ts", - "rules/preferForOfRule.ts", - "rules/quotemarkRule.ts", - "rules/radixRule.ts", - "rules/restrictPlusOperandsRule.ts", - "rules/semicolonRule.ts", - "rules/switchDefaultRule.ts", - "rules/trailingCommaRule.ts", - "rules/tripleEqualsRule.ts", - "rules/typedefRule.ts", - "rules/typedefWhitespaceRule.ts", - "rules/useIsnanRule.ts", - "rules/useStrictRule.ts", - "rules/variableNameRule.ts", - "rules/whitespaceRule.ts", - "test/lines.ts", - "test/lintError.ts", - "test/parse.ts", - "test/utils.ts" - ] -} \ No newline at end of file + } +} diff --git a/src/tslint-cli.ts b/src/tslint-cli.ts index f358dc672f3..c8f2dc3e9a6 100644 --- a/src/tslint-cli.ts +++ b/src/tslint-cli.ts @@ -26,8 +26,10 @@ import { DEFAULT_CONFIG, findConfiguration, } from "./configuration"; -import {consoleTestResultHandler, runTest} from "./test"; -import * as Linter from "./tslintMulti"; +import { FatalError } from "./error"; +import * as Linter from "./linter"; +import { consoleTestResultHandler, runTest } from "./test"; +import { updateNotifierCheck } from "./updateNotifier"; let processed = optimist .usage("Usage: $0 [options] file ...") @@ -42,53 +44,58 @@ let processed = optimist } }) .options({ - c: { + "c": { alias: "config", describe: "configuration file", }, - e: { + "e": { alias: "exclude", describe: "exclude globs from path expansion", + type: "string", }, - force: { + "fix": { + describe: "fixes linting errors for select rules (this may overwrite linted files)", + type: "boolean", + }, + "force": { describe: "return status code 0 even if there are lint errors", type: "boolean", }, - h: { + "h": { alias: "help", describe: "display detailed help", }, - i: { + "i": { alias: "init", describe: "generate a tslint.json config file in the current working directory", }, - o: { + "o": { alias: "out", describe: "output file", }, - project: { + "project": { describe: "tsconfig.json file", }, - r: { + "r": { alias: "rules-dir", describe: "rules directory", }, - s: { + "s": { alias: "formatters-dir", describe: "formatters directory", }, - t: { + "t": { alias: "format", default: "prose", describe: "output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist)", }, - test: { + "test": { describe: "test that tslint produces the correct output for the specified directory", }, "type-check": { describe: "enable type checking when linting a project", }, - v: { + "v": { alias: "version", describe: "current version", }, @@ -152,6 +159,9 @@ tslint accepts the following commandline options: This option can be supplied multiple times if you need multiple globs to indicate which files to exclude. + --fix: + Fixes linting errors for select rules. This may overwrite linted files. + --force: Return status code 0 even if there are any lint errors. Useful while running as npm script. @@ -184,7 +194,7 @@ tslint accepts the following commandline options: formatters are prose (human readable), json (machine readable) and verbose. prose is the default if this option is not used. Other built-in options include pmd, msbuild, checkstyle, and vso. - Additonal formatters can be added and used if the --formatters-dir + Additional formatters can be added and used if the --formatters-dir option is set. --test: @@ -220,6 +230,7 @@ const possibleConfigAbsolutePath = argv.c != null ? path.resolve(argv.c) : null; const processFiles = (files: string[], program?: ts.Program) => { const linter = new Linter({ + fix: argv.fix, formatter: argv.t, formattersDirectory: argv.s || "", rulesDirectory: argv.r || "", @@ -248,8 +259,8 @@ const processFiles = (files: string[], program?: ts.Program) => { } const contents = fs.readFileSync(file, "utf8"); - const configuration = findConfiguration(possibleConfigAbsolutePath, file); - linter.lint(file, contents, configuration); + const configLoad = findConfiguration(possibleConfigAbsolutePath, file); + linter.lint(file, contents, configLoad.results); } const lintResult = linter.getResult(); @@ -259,6 +270,11 @@ const processFiles = (files: string[], program?: ts.Program) => { process.exit(argv.force ? 0 : 2); } }); + + if (lintResult.format === "prose") { + // Check to see if there are any updates available + updateNotifierCheck(); + } }; // if both files and tsconfig are present, use files @@ -296,7 +312,28 @@ if (argv.project != null) { } } +const trimSingleQuotes = (str: string) => str.replace(/^'|'$/g, ""); + +let ignorePatterns: string[] = []; +if (argv.e) { + const excludeArguments: string[] = Array.isArray(argv.e) ? argv.e : [argv.e]; + + ignorePatterns = excludeArguments.map(trimSingleQuotes); +} + files = files - .map((file: string) => glob.sync(file, { ignore: argv.e, nodir: true })) - .reduce((a: string[], b: string[]) => a.concat(b)); -processFiles(files, program); + // remove single quotes which break matching on Windows when glob is passed in single quotes + .map(trimSingleQuotes) + .map((file: string) => glob.sync(file, { ignore: ignorePatterns, nodir: true })) + .reduce((a: string[], b: string[]) => a.concat(b)); + +try { + processFiles(files, program); +} catch (error) { + if (error.name === FatalError.NAME) { + console.error(error.message); + process.exit(1); + } + // rethrow unhandled error + throw error; +} diff --git a/src/tslint.ts b/src/tslint.ts deleted file mode 100644 index 075eb51bc75..00000000000 --- a/src/tslint.ts +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @license - * Copyright 2013 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"; - -import { - DEFAULT_CONFIG, - findConfiguration, - findConfigurationPath, - getRulesDirectories, - loadConfigurationFromPath, -} from "./configuration"; -import { ILinterOptions, ILinterOptionsRaw, LintResult } from "./lint"; -import * as MultiLinter from "./tslintMulti"; -import { arrayify } from "./utils"; - -/** - * Linter that can lint exactly one file. - */ -class Linter { - public static VERSION = MultiLinter.VERSION; - - public static findConfiguration = findConfiguration; - public static findConfigurationPath = findConfigurationPath; - public static getRulesDirectories = getRulesDirectories; - public static loadConfigurationFromPath = loadConfigurationFromPath; - - private options: ILinterOptions; - - /** - * Creates a TypeScript program object from a tsconfig.json file path and optional project directory. - */ - public static createProgram(configFile: string, projectDirectory?: string): ts.Program { - return MultiLinter.createProgram(configFile, projectDirectory); - } - - /** - * Returns a list of source file names from a TypeScript program. This includes all referenced - * files and excludes declaration (".d.ts") files. - */ - public static getFileNames(program: ts.Program): string[] { - return MultiLinter.getFileNames(program); - } - - constructor(private fileName: string, private source: string, options: ILinterOptionsRaw, private program?: ts.Program) { - this.options = this.computeFullOptions(options); - } - - public lint(): LintResult { - const multiLinter: MultiLinter = new MultiLinter(this.options, this.program); - multiLinter.lint(this.fileName, this.source, this.options.configuration); - return multiLinter.getResult(); - } - - private computeFullOptions(options: ILinterOptionsRaw = {}): ILinterOptions { - if (typeof options !== "object") { - throw new Error("Unknown Linter options type: " + typeof options); - } - - let { configuration, formatter, formattersDirectory, rulesDirectory } = options; - - return { - configuration: configuration || DEFAULT_CONFIG, - formatter: formatter || "prose", - formattersDirectory, - rulesDirectory: arrayify(rulesDirectory).concat(arrayify(configuration.rulesDirectory)), - }; - } -} - -// tslint:disable-next-line:no-namespace -namespace Linter {} - -export = Linter; diff --git a/src/updateNotifier.ts b/src/updateNotifier.ts new file mode 100644 index 00000000000..c6ee143192e --- /dev/null +++ b/src/updateNotifier.ts @@ -0,0 +1,40 @@ +/** + * @license + * Copyright 2016 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. + */ + +// tslint:disable-next-line:no-var-requires +const updateNotifier = require("update-notifier"); +// tslint:disable-next-line:no-var-requires + +export function updateNotifierCheck(): void { + try { + const pkg = require("../package.json"); + // Check every 3 days for a new version + const cacheTime: number = 1000 * 60 * 60 * 24 * 3; + const changeLogUrl: string = "https://github.com/palantir/tslint/blob/master/CHANGELOG.md"; + const notifier = updateNotifier({ + pkg, + updateCheckInterval: cacheTime, + }); + + if (notifier.notify && notifier.update) { + let message: string = `TSLint update available v${notifier.update.current} → v${notifier.update.latest} \n See ${changeLogUrl}`; + notifier.notify({ message }); + } + } catch (error) { + // ignore error + } +}; diff --git a/src/utils.ts b/src/utils.ts index a288c59199f..7279b2a7396 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -15,6 +15,9 @@ * limitations under the License. */ +/** + * Enforces the invariant that the input is an array. + */ export function arrayify(arg: T | T[]): T[] { if (Array.isArray(arg)) { return arg; @@ -25,6 +28,9 @@ export function arrayify(arg: T | T[]): T[] { } } +/** + * Enforces the invariant that the input is an object. + */ export function objectify(arg: any): any { if (typeof arg === "object" && arg != null) { return arg; @@ -49,7 +55,7 @@ export function dedent(strings: TemplateStringsArray, ...values: string[]) { } // find the smallest indent, we don't want to remove all leading whitespace - const indent = Math.min(...match.map(el => el.length)); + const indent = Math.min(...match.map((el) => el.length)); const regexp = new RegExp("^[ \\t]{" + indent + "}", "gm"); fullString = indent > 0 ? fullString.replace(regexp, "") : fullString; return fullString; @@ -66,7 +72,7 @@ export function stripComments(content: string): string { * Fourth matches line comments */ const regexp: RegExp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; - let result = content.replace(regexp, (match, m1, m2, m3, m4) => { + let result = content.replace(regexp, (match, _m1, _m2, m3, m4) => { // Only one of m1, m2, m3, m4 matches if (m3) { // A block comment. Replace with nothing diff --git a/test/check-bin.sh b/test/check-bin.sh deleted file mode 100755 index 7b87e33a548..00000000000 --- a/test/check-bin.sh +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2014 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. - -num_failures=0 - -expectOut () { - actual=$1 - expect=$2 - msg=$3 - - nodeV=`node -v` - - # if Node 0.10.*, node will sometimes exit with status 8 when an error is thrown - if [[ $expect != $actual || $nodeV == v0.10.* && $expect == 1 && $actual == 8 ]] ; then - echo "$msg: expected $expect got $actual" - num_failures=$(expr $num_failures + 1) - fi -} - -echo "Checking tslint binary" -# make sure calling tslint with no args exits correctly. -./bin/tslint -expectOut $? 1 "tslint with no args did not exit correctly" - -# make sure calling tslint with a good file exits correctly. -./bin/tslint src/configuration.ts -expectOut $? 0 "tslint with a good file did not exit correctly" - -# make sure calling tslint without the -f flag exits correctly -./bin/tslint src/configuration.ts src/formatterLoader.ts -expectOut $? 0 "tslint with valid arguments did not exit correctly" - -# make sure calling tslint with the -f flag exits correctly -./bin/tslint src/configuration.ts -f src/formatterLoader.ts -expectOut $? 1 "tslint with -f flag did not exit correctly" - -# make sure calling tslint with a CLI custom rules directory that doesn't exist fails -# (redirect stderr because it's confusing to see a stack trace during the build) -./bin/tslint -c ./test/config/tslint-custom-rules.json -r ./someRandomDir src/tslint.ts -expectOut $? 1 "tslint with -r pointing to a nonexistent directory did not fail" - -# make sure calling tslint with a CLI custom rules directory that does exist finds the errors it should -./bin/tslint -c ./test/config/tslint-custom-rules.json -r ./test/files/custom-rules src/tslint.ts -expectOut $? 2 "tslint with with -r pointing to custom rules did not find lint failures" - -# make sure calling tslint with a rulesDirectory in a config file works -./bin/tslint -c ./test/config/tslint-custom-rules-with-dir.json src/tslint.ts -expectOut $? 2 "tslint with with JSON pointing to custom rules did not find lint failures" - -# make sure calling tslint with an array as rulesDirectory in a config file works -./bin/tslint -c ./test/config/tslint-custom-rules-with-two-dirs.json src/tslint.ts -expectOut $? 2 "tslint with with JSON pointing to two custom rules did not find lint failures from second directory" - -# make sure --force option makes TSLint return a status code of 0 when there are lint errors -./bin/tslint -c ./test/config/tslint-custom-rules.json -r ./test/files/custom-rules --force src/tslint.ts -expectOut $? 0 "tslint with with -r pointing to custom rules did not find lint failures" - -# make sure path to config without a preceding "./" works on the CLI -./bin/tslint -c test/config/tslint-almost-empty.json src/tslint.ts -expectOut $? 0 "-c relative path without ./ did not work" - -# make sure calling tslint with a config file which extends a package relative to the config file works -./bin/tslint -c test/config/tslint-extends-package-no-mod.json src/tslint.ts -expectOut $? 0 "tslint (with config file extending relative package) did not work" - -# make sure tslint --init generates a file -cd ./bin -if [ -f tslint.json ]; then - rm tslint.json -fi - -./tslint --init -if [ ! -f tslint.json ]; then - echo "--init failed, tslint.json not created" - num_failures=$(expr $num_failures + 1) -fi -expectOut $? 0 "tslint with --init flag did not exit correctly" - -# should fail since tslint.json already exists -./tslint --init -expectOut $? 1 "tslint with --init flag did not exit correctly when tslint.json already exists" - -rm tslint.json -cd .. - -# ensure --test command works correctly -./bin/tslint --test test/rules/no-eval -expectOut $? 0 "tslint --test did not exit correctly for a passing test" - -./bin/tslint --test test/files/incorrect-rule-test -expectOut $? 1 "tslint --test did not exit correctly for a failing test" - -# ensure --test command works correctly with custom rules -./bin/tslint --test test/files/custom-rule-rule-test -expectOut $? 0 "tslint --test did not exit correctly for a passing test with custom rules" - -./bin/tslint -r test/files/custom-rules-2 --test test/files/custom-rule-cli-rule-test -expectOut $? 0 "tslint --test did not exit correctly for a passing test with custom rules from the CLI" - -# ensure --test command works correctly with fixes -./bin/tslint --test test/files/fixes-test -expectOut $? 0 "tslint --test did not exit correctly for a passing test with fixes" - -./bin/tslint --test test/files/incorrect-fixes-test -expectOut $? 1 "tslint --test did not exit correctly for a failing test with fixes" - -# make sure tslint exits correctly when tsconfig is specified but no files are given -./bin/tslint -c test/files/tsconfig-test/tslint.json --project test/files/tsconfig-test/tsconfig.json -expectOut $? 0 "tslint with tsconfig did not exit correctly" - -# make sure tslint only lints files given if tsconfig is also specified -./bin/tslint -c test/files/tsconfig-test/tslint.json --project test/files/tsconfig-test/tsconfig.json test/files/tsconfig-test/other.test.ts -expectOut $? 2 "tslint with tsconfig and files did not find lint failures from given files" - -if [ $num_failures != 0 ]; then - echo "Failed $num_failures tests" - exit 1 -else - echo "Done!" - exit 0 -fi diff --git a/test/config/tslint-almost-empty.json b/test/config/tslint-almost-empty.json index 5f229f5ea27..74f5ff48f51 100644 --- a/test/config/tslint-almost-empty.json +++ b/test/config/tslint-almost-empty.json @@ -1 +1 @@ -{ "rules": {} } +{ "jsRules": {}, "rules": {} } diff --git a/test/config/tslint-custom-rules-with-dir.json b/test/config/tslint-custom-rules-with-dir.json index abe7c97a534..8c4ae31b1e5 100644 --- a/test/config/tslint-custom-rules-with-dir.json +++ b/test/config/tslint-custom-rules-with-dir.json @@ -1,5 +1,8 @@ { "rulesDirectory": "../files/custom-rules/", + "jsRules": { + "always-fail": true + }, "rules": { "always-fail": true } diff --git a/test/config/tslint-custom-rules-with-two-dirs.json b/test/config/tslint-custom-rules-with-two-dirs.json index f02d738225e..a43cf3db773 100644 --- a/test/config/tslint-custom-rules-with-two-dirs.json +++ b/test/config/tslint-custom-rules-with-two-dirs.json @@ -1,7 +1,13 @@ { "rulesDirectory": ["../files/custom-rules-2", "../files/custom-rules/"], + "jsRules": { + "always-fail": true, + "no-fail": true, + "rule-two": true + }, "rules": { "always-fail": true, - "no-fail": true + "no-fail": true, + "rule-two": true } } diff --git a/test/config/tslint-custom-rules.json b/test/config/tslint-custom-rules.json index c6568e1ad90..250eafcd974 100644 --- a/test/config/tslint-custom-rules.json +++ b/test/config/tslint-custom-rules.json @@ -1,4 +1,7 @@ { + "jsRules": { + "always-fail": true + }, "rules": { "always-fail": true } diff --git a/test/config/tslint-extends-builtin.json b/test/config/tslint-extends-builtin.json index 6219cf987a0..4daad33a5c8 100644 --- a/test/config/tslint-extends-builtin.json +++ b/test/config/tslint-extends-builtin.json @@ -1,5 +1,8 @@ { "extends": "tslint:latest", + "jsRules": { + "no-eval": false + }, "rules": { "no-eval": false } diff --git a/test/config/tslint-extends-package-array.json b/test/config/tslint-extends-package-array.json index 2cd7ee1a31b..e52fb098a1d 100644 --- a/test/config/tslint-extends-package-array.json +++ b/test/config/tslint-extends-package-array.json @@ -3,6 +3,9 @@ "tslint-test-custom-rules", "./tslint-custom-rules-with-two-dirs.json" ], + "jsRules": { + "always-fail": false + }, "rules": { "always-fail": false } diff --git a/test/config/tslint-extends-package-two-levels.json b/test/config/tslint-extends-package-two-levels.json index a61c1cb9d2d..2e2a12b63ac 100644 --- a/test/config/tslint-extends-package-two-levels.json +++ b/test/config/tslint-extends-package-two-levels.json @@ -1,6 +1,9 @@ { "extends": "tslint-test-config/tslint.json", "rulesDirectory": "../files/custom-rules", + "jsRules": { + "always-fail": false + }, "rules": { "always-fail": false } diff --git a/test/config/tslint-extends-package.json b/test/config/tslint-extends-package.json index 445ed231aca..ed5eced16c4 100644 --- a/test/config/tslint-extends-package.json +++ b/test/config/tslint-extends-package.json @@ -1,5 +1,9 @@ { "extends": "tslint-test-custom-rules", + "jsRules": { + "rule-two": true, + "rule-three": false + }, "rules": { "rule-two": true, "rule-three": false diff --git a/test/config/tslint-extends-relative.json b/test/config/tslint-extends-relative.json index 006b647d0eb..c53505e38af 100644 --- a/test/config/tslint-extends-relative.json +++ b/test/config/tslint-extends-relative.json @@ -1,5 +1,8 @@ { "extends": "./tslint-custom-rules-with-two-dirs.json", + "jsRules": { + "always-fail": false + }, "rules": { "always-fail": false } diff --git a/test/config/tslint-invalid.json b/test/config/tslint-invalid.json new file mode 100644 index 00000000000..765e0c1d55e --- /dev/null +++ b/test/config/tslint-invalid.json @@ -0,0 +1,2 @@ +{ + \ No newline at end of file diff --git a/test/config/tslint-with-bom.json b/test/config/tslint-with-bom.json index 767e6c5b7e9..2153257c887 100644 --- a/test/config/tslint-with-bom.json +++ b/test/config/tslint-with-bom.json @@ -1 +1 @@ -{ "rules": { } } \ No newline at end of file +{ "jsRules": { }, "rules": { } } \ No newline at end of file diff --git a/test/config/tslint-with-comments.json b/test/config/tslint-with-comments.json index 0990b5256da..ef12ab77da1 100644 --- a/test/config/tslint-with-comments.json +++ b/test/config/tslint-with-comments.json @@ -1,4 +1,13 @@ { + // a nice comment + "jsRules": { + /* + "rule-one": true, + */ + "rule-two": true, + "rule-three": "//not a comment", + "rule-four": "/*also not a comment*/" + }, // a nice comment "rules": { /* diff --git a/test/config/tslint-with-jsrules.json b/test/config/tslint-with-jsrules.json new file mode 100644 index 00000000000..dc4f5463b1c --- /dev/null +++ b/test/config/tslint-with-jsrules.json @@ -0,0 +1,5 @@ +{ + "jsRules": { + "rule": true + } +} \ No newline at end of file diff --git a/test/configurationTests.ts b/test/configurationTests.ts index 9e99caf5433..11134abcacb 100644 --- a/test/configurationTests.ts +++ b/test/configurationTests.ts @@ -15,14 +15,15 @@ */ import * as fs from "fs"; -import * as os from "os"; -import * as path from "path"; -import {IConfigurationFile, extendConfigurationFile, loadConfigurationFromPath} from "../src/configuration"; +import { extendConfigurationFile, IConfigurationFile, loadConfigurationFromPath } from "../src/configuration"; +import { createTempFile } from "./utils"; describe("Configuration", () => { it("extendConfigurationFile", () => { const EMPTY_CONFIG: IConfigurationFile = { + jsRules: {}, + linterOptions: {}, rules: {}, rulesDirectory: [], }; @@ -30,58 +31,88 @@ describe("Configuration", () => { assert.deepEqual(extendConfigurationFile({}, {}), EMPTY_CONFIG); assert.deepEqual(extendConfigurationFile({}, EMPTY_CONFIG), EMPTY_CONFIG); assert.deepEqual(extendConfigurationFile(EMPTY_CONFIG, {}), EMPTY_CONFIG); - assert.deepEqual(extendConfigurationFile({}, {rules: {foo: "bar"}, rulesDirectory: "foo"}), { + assert.deepEqual(extendConfigurationFile({}, { + jsRules: { row: "oar" }, + linterOptions: {}, + rules: { foo: "bar" }, + rulesDirectory: "foo", + }), { + jsRules: { row: "oar" }, + linterOptions: {}, rules: {foo: "bar"}, rulesDirectory: ["foo"], }); - assert.deepEqual(extendConfigurationFile({ + const actualConfig = extendConfigurationFile({ + jsRules: { row: "oar" }, + linterOptions: {}, rules: { a: 1, - b: 2, + b: 1, }, rulesDirectory: ["foo", "bar"], }, { + jsRules: { fly: "wings" }, + linterOptions: {}, rules: { - b: 1, + b: 2, c: 3, }, rulesDirectory: "baz", - }), { + }); + /* tslint:disable:object-literal-sort-keys */ + const expectedConfig = { + jsRules: { + row: "oar", + fly: "wings", + }, + linterOptions: {}, rules: { a: 1, b: 2, c: 3, }, rulesDirectory: ["foo", "bar", "baz"], - }); + }; + assert.deepEqual(actualConfig, expectedConfig); }); describe("loadConfigurationFromPath", () => { it("extends with relative path", () => { - let config = loadConfigurationFromPath("./test/config/tslint-extends-relative.json"); + const config = loadConfigurationFromPath("./test/config/tslint-extends-relative.json"); assert.isArray(config.rulesDirectory); - assert.isTrue(config.rules["no-fail"]); - assert.isFalse(config.rules["always-fail"]); + assert.isTrue(config.rules["no-fail"], "did not pick up 'no-fail' in base config"); + assert.isFalse(config.rules["always-fail"], "did not set 'always-fail' in top config"); + assert.isTrue(config.jsRules["no-fail"]); + assert.isFalse(config.jsRules["always-fail"]); }); it("extends with package", () => { - let config = loadConfigurationFromPath("./test/config/tslint-extends-package.json"); + const config = loadConfigurationFromPath("./test/config/tslint-extends-package.json"); assert.isArray(config.rulesDirectory); /* tslint:disable:object-literal-sort-keys */ - assert.deepEqual(config.rules, { + assert.deepEqual(config.jsRules, { "rule-one": true, + "rule-three": false, "rule-two": true, + }); + assert.deepEqual(config.rules, { + "rule-one": true, "rule-three": false, + "rule-two": true, }); /* tslint:enable:object-literal-sort-keys */ }); it("extends with package without customization", () => { - let config = loadConfigurationFromPath("./test/config/tslint-extends-package-no-mod.json"); + const config = loadConfigurationFromPath("./test/config/tslint-extends-package-no-mod.json"); assert.isArray(config.rulesDirectory); + assert.deepEqual(config.jsRules, { + "rule-one": true, + "rule-two": false, + }); assert.deepEqual(config.rules, { "rule-one": true, "rule-two": false, @@ -90,6 +121,8 @@ describe("Configuration", () => { it("extends with builtin", () => { const config = loadConfigurationFromPath("./test/config/tslint-extends-builtin.json"); + assert.isUndefined(config.jsRules["no-var-keyword"]); + assert.isFalse(config.jsRules["no-eval"]); assert.isTrue(config.rules["no-var-keyword"]); assert.isFalse(config.rules["no-eval"]); }); @@ -98,16 +131,7 @@ describe("Configuration", () => { let tmpfile: string; beforeEach(() => { - for (let i = 0; i < 5; i++) { - const attempt = path.join(os.tmpdir(), `tslint.test${Math.round(Date.now() * Math.random())}.json`); - if (!fs.existsSync(tmpfile)) { - tmpfile = attempt; - break; - } - } - if (tmpfile === undefined) { - throw new Error("Couldn't create temp file"); - } + tmpfile = createTempFile("json"); }); afterEach(() => { @@ -133,6 +157,12 @@ describe("Configuration", () => { assert.isTrue(fs.existsSync(config.rulesDirectory[0])); assert.isTrue(fs.existsSync(config.rulesDirectory[1])); /* tslint:disable:object-literal-sort-keys */ + assert.deepEqual(config.jsRules, { + "always-fail": false, + "rule-one": true, + "rule-two": true, + "rule-four": true, + }); assert.deepEqual(config.rules, { "always-fail": false, "rule-one": true, @@ -146,11 +176,17 @@ describe("Configuration", () => { let config = loadConfigurationFromPath("./test/config/tslint-extends-package-array.json"); assert.isArray(config.rulesDirectory); + assert.deepEqual(config.jsRules, { + "always-fail": false, + "no-fail": true, + "rule-one": true, + "rule-two": true, + }); assert.deepEqual(config.rules, { "always-fail": false, "no-fail": true, "rule-one": true, - "rule-two": false, + "rule-two": true, }); }); @@ -158,6 +194,11 @@ describe("Configuration", () => { const config = loadConfigurationFromPath("./test/config/tslint-with-comments.json"); /* tslint:disable:object-literal-sort-keys */ + assert.deepEqual(config.jsRules, { + "rule-two": true, + "rule-three": "//not a comment", + "rule-four": "/*also not a comment*/", + }); assert.deepEqual(config.rules, { "rule-two": true, "rule-three": "//not a comment", @@ -172,6 +213,7 @@ describe("Configuration", () => { it("can load a built-in configuration", () => { const config = loadConfigurationFromPath("tslint:recommended"); + assert.isTrue(config.jsRules["no-eval"]); assert.isTrue(config.rules["no-eval"]); }); diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts new file mode 100644 index 00000000000..2b9288c827b --- /dev/null +++ b/test/executable/executableTests.ts @@ -0,0 +1,304 @@ +/* + * Copyright 2016 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 cp from "child_process"; +import * as fs from "fs"; +import * as os from "os"; +import * as path from "path"; +import { createTempFile, denormalizeWinPath } from "../utils"; + +// when tests are run with mocha from npm scripts CWD points to project root +const EXECUTABLE_DIR = path.resolve(process.cwd(), "test", "executable"); +const EXECUTABLE_PATH = path.resolve(EXECUTABLE_DIR, "npm-like-executable"); +const TEMP_JSON_PATH = path.resolve(EXECUTABLE_DIR, "tslint.json"); + +/* tslint:disable:only-arrow-functions */ +describe("Executable", function() { + this.slow(3000); // the executable is JIT-ed each time it runs; avoid showing slowness warnings + this.timeout(4000); + + describe("Files", () => { + it("exits with code 1 if no arguments passed", (done) => { + execCli([], (err, stdout, stderr) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 1, "error code should be 1"); + + assert.include(stderr, "Missing files", "stderr should contain notification about missing files"); + assert.strictEqual(stdout, "", "shouldn't contain any output in stdout"); + done(); + }); + }); + + it("exits with code 0 if correct file is passed", (done) => { + execCli(["src/configuration.ts"], (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); + }); + + it("exits with code 0 if several files passed without `-f` flag", (done) => { + execCli(["src/configuration.ts", "src/formatterLoader.ts"], (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); + }); + + it("exits with code 1 if removed `-f` flag is passed", (done) => { + execCli(["src/configuration.ts", "-f", "src/formatterLoader.ts"], (err, stdout, stderr) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 1, "error code should be 1"); + + assert.include(stderr, "-f option is no longer available", "stderr should contain notification about removed flag"); + assert.strictEqual(stdout, "", "shouldn't contain any output in stdout"); + done(); + }); + }); + }); + + describe("Configuration file", () => { + it("exits with code 0 if relative path is passed without `./`", (done) => { + execCli(["-c", "test/config/tslint-almost-empty.json", "src/test.ts"], (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); + }); + + it("exits with code 0 if config file that extends relative config file", (done) => { + execCli(["-c", "test/config/tslint-extends-package-no-mod.json", "src/test.ts"], (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); }); + + it("exits with code 1 if config file is invalid", (done) => { + execCli(["-c", "test/config/tslint-invalid.json", "src/test.ts"], (err, stdout, stderr) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 1, "error code should be 1"); + + assert.include(stderr, "Failed to load", "stderr should contain notification about failing to load json"); + assert.strictEqual(stdout, "", "shouldn't contain any output in stdout"); + done(); + }); + }); + }); + + describe("Custom rules", () => { + it("exits with code 1 if nonexisting custom rules directory is passed", (done) => { + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./someRandomDir", "src/test.ts"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 1, "error code should be 1"); + done(); + }); + }); + + it("exits with code 2 if custom rules directory is passed and file contains lint errors", (done) => { + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "src/test.ts"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 2, "error code should be 2"); + done(); + }); + }); + + it("exits with code 2 if custom rules directory is specified in config file and file contains lint errors", (done) => { + execCli(["-c", "./test/config/tslint-custom-rules-with-dir.json", "src/test.ts"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 2, "error code should be 2"); + done(); + }); + }); + }); + + describe("--fix flag", () => { + it("fixes multiple rules without overwriting each other", (done) => { + const tempFile = createTempFile("ts"); + fs.createReadStream("test/files/multiple-fixes-test/multiple-fixes.test.ts").pipe(fs.createWriteStream(tempFile)); + execCli(["-c", "test/files/multiple-fixes-test/tslint.json", tempFile, "--fix"], + (err, stdout) => { + const content = fs.readFileSync(tempFile, "utf8"); + // compare against file name which will be returned by formatter (used in TypeScript) + const denormalizedFileName = denormalizeWinPath(tempFile); + fs.unlinkSync(tempFile); + assert.strictEqual(content, "import * as y from \"a_long_module\";\nimport * as x from \"b\";\n"); + assert.isNull(err, "process should exit without an error"); + assert.strictEqual(stdout, `Fixed 2 error(s) in ${denormalizedFileName}`); + done(); + }); + }); + }); + + describe("--force flag", () => { + it("exits with code 0 if `--force` flag is passed", (done) => { + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "--force", "src/test.ts"], + (err, stdout) => { + assert.isNull(err, "process should exit without an error"); + assert.include(stdout, "failure", "errors should be reported"); + done(); + }); + }); + }); + + describe("--test flag", () => { + it("exits with code 0 if `--test` flag is used", (done) => { + execCli(["--test", "test/rules/no-eval"], (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); + }); + + it("exits with code 1 if `--test` flag is used with incorrect rule", (done) => { + execCli(["--test", "test/files/incorrect-rule-test"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 1, "error code should be 1"); + done(); + }); + }); + + it("exits with code 0 if `--test` flag is used with custom rule", (done) => { + execCli(["--test", "test/files/custom-rule-rule-test"], (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); + }); + + it("exits with code 0 if `--test` and `-r` flags are used with custom rule", (done) => { + execCli(["-r", "test/files/custom-rules-2", "--test", "test/files/custom-rule-rule-test"], (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); + }); + + it("exits with code 0 if `--test` flag is used with fixes", (done) => { + execCli(["--test", "test/files/fixes-test"], (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); + }); + + it("exits with code 1 if `--test` flag is used with incorrect fixes", (done) => { + execCli(["--test", "test/files/incorrect-fixes-test"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 1, "error code should be 1"); + done(); + }); + }); + }); + + describe("tsconfig.json", () => { + it("exits with code 0 if `tsconfig.json` is passed and it specifies files without errors", (done) => { + execCli(["-c", "test/files/tsconfig-test/tslint.json", "--project", "test/files/tsconfig-test/tsconfig.json"], (err) => { + assert.isNull(err, "process should exit without an error"); + done(); + }); + }); + + it("exits with code 2 if both `tsconfig.json` and files arguments are passed and files contain lint errors", (done) => { + execCli(["-c", "test/files/tsconfig-test/tslint.json", "--project", "test/files/tsconfig-test/tsconfig.json", + "test/files/tsconfig-test/other.test.ts"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 2, "error code should be 2"); + done(); + }); + }); + }); + + describe("--init flag", () => { + // remove temp file before calling tslint --init + beforeEach(cleanTempInitFile); + // clean up temp file after tests + afterEach(cleanTempInitFile); + + it("exits with code 0 if `--init` flag is used in folder without tslint.json", (done) => { + + execCli(["--init"], { cwd: EXECUTABLE_DIR }, (err) => { + assert.isNull(err, "process should exit without an error"); + assert.strictEqual(fs.existsSync(TEMP_JSON_PATH), true, "file should be created"); + done(); + }); + }); + + it("exits with code 1 if `--init` flag is used in folder with tslint.json", (done) => { + // make sure that file exists before test + fs.writeFileSync(TEMP_JSON_PATH, "{}"); + + execCli(["--init"], { cwd: EXECUTABLE_DIR }, (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 1, "error code should be 1"); + done(); + }); + + }); + }); + + describe("globs and quotes", () => { + // when glob pattern is passed without quotes in npm script `process.env` will contain: + // on Windows - pattern string without any quotes + // on Linux - list of files that matches glob (may differ from `glob` module results) + + it("exits with code 2 if correctly finds file containing lint errors when glob is in double quotes", (done) => { + // when glob pattern is passed in double quotes in npm script `process.env` will contain: + // on Windows - pattern string without any quotes + // on Linux - pattern string without any quotes (glob is not expanded) + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "src/**/test.ts"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 2, "error code should be 2"); + done(); + }); + }); + + it("exits with code 2 if correctly finds file containing lint errors when glob is in single quotes", (done) => { + // when glob pattern is passed in single quotes in npm script `process.env` will contain: + // on Windows - pattern string wrapped in single quotes + // on Linux - pattern string without any quotes (glob is not expanded) + execCli(["-c", "./test/config/tslint-custom-rules.json", "-r", "./test/files/custom-rules", "'src/**/test.ts'"], (err) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 2, "error code should be 2"); + done(); + }); + }); + + }); +}); + +type ExecFileCallback = (error: any, stdout: string, stderr: string) => void; + +function execCli(args: string[], cb: ExecFileCallback): cp.ChildProcess; +function execCli(args: string[], options: cp.ExecFileOptions, cb: ExecFileCallback): cp.ChildProcess; +function execCli(args: string[], options: cp.ExecFileOptions | ExecFileCallback, cb?: ExecFileCallback): cp.ChildProcess { + let filePath = EXECUTABLE_PATH; + + // Specify extension for Windows executable to avoid ENOENT errors + if (os.platform() === "win32") { + filePath += ".cmd"; + } + + if (isFunction(options)) { + cb = options as ExecFileCallback; + options = {}; + } + + return cp.execFile(filePath, args, options, (error, stdout, stderr) => { + cb(error, stdout.trim(), stderr.trim()); + }); +} + +function isFunction(fn: any): boolean { + return ({}).toString.call(fn) === "[object Function]"; +} + +function cleanTempInitFile(): void { + if (fs.existsSync(TEMP_JSON_PATH)) { + fs.unlinkSync(TEMP_JSON_PATH); + } +} diff --git a/test/executable/npm-like-executable b/test/executable/npm-like-executable new file mode 100755 index 00000000000..bb1ea78083f --- /dev/null +++ b/test/executable/npm-like-executable @@ -0,0 +1,15 @@ +#!/bin/sh +basedir=`dirname "$0"` + +case `uname` in + *CYGWIN*) basedir=`cygpath -w "$basedir"`;; +esac + +if [ -x "$basedir/node" ]; then + "$basedir/node" "$basedir/../../bin/tslint" "$@" + ret=$? +else + node "$basedir/../../bin/tslint" "$@" + ret=$? +fi +exit $ret diff --git a/test/executable/npm-like-executable.cmd b/test/executable/npm-like-executable.cmd new file mode 100644 index 00000000000..f0072bb4523 --- /dev/null +++ b/test/executable/npm-like-executable.cmd @@ -0,0 +1,7 @@ +@IF EXIST "%~dp0\node.exe" ( + "%~dp0\node.exe" "%~dp0\..\..\bin\tslint" %* +) ELSE ( + @SETLOCAL + @SET PATHEXT=%PATHEXT:;.JS;=;% + node "%~dp0\..\..\bin\tslint" %* +) \ No newline at end of file diff --git a/test/external/tslint-test-config-non-relative/tslint.json b/test/external/tslint-test-config-non-relative/tslint.json index fcaed86a61e..5078a1f987d 100644 --- a/test/external/tslint-test-config-non-relative/tslint.json +++ b/test/external/tslint-test-config-non-relative/tslint.json @@ -1,4 +1,7 @@ { + "jsRules": { + "class-name": true + }, "rules": { "class-name": true } diff --git a/test/external/tslint-test-config/tslint.json b/test/external/tslint-test-config/tslint.json index 2cf73c5a02d..2e3cdcef21a 100644 --- a/test/external/tslint-test-config/tslint.json +++ b/test/external/tslint-test-config/tslint.json @@ -1,5 +1,9 @@ { "extends": "tslint-test-custom-rules", + "jsRules": { + "rule-two": true, + "rule-four": true + }, "rules": { "rule-two": true, "rule-four": true diff --git a/test/external/tslint-test-custom-rules/rules/ruleOneRule.js b/test/external/tslint-test-custom-rules/rules/ruleOneRule.js index 1d2ff62d1af..9b8b16e0fb8 100644 --- a/test/external/tslint-test-custom-rules/rules/ruleOneRule.js +++ b/test/external/tslint-test-custom-rules/rules/ruleOneRule.js @@ -3,7 +3,7 @@ var __extends = (this && this.__extends) || function (d, b) { function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; -var Lint = require("tslint/lib/lint"); +var Lint = require("tslint"); var Rule = (function (_super) { __extends(Rule, _super); function Rule() { diff --git a/test/external/tslint-test-custom-rules/rules/ruleThreeRule.js b/test/external/tslint-test-custom-rules/rules/ruleThreeRule.js index 1d2ff62d1af..9b8b16e0fb8 100644 --- a/test/external/tslint-test-custom-rules/rules/ruleThreeRule.js +++ b/test/external/tslint-test-custom-rules/rules/ruleThreeRule.js @@ -3,7 +3,7 @@ var __extends = (this && this.__extends) || function (d, b) { function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; -var Lint = require("tslint/lib/lint"); +var Lint = require("tslint"); var Rule = (function (_super) { __extends(Rule, _super); function Rule() { diff --git a/test/external/tslint-test-custom-rules/rules/ruleTwoRule.js b/test/external/tslint-test-custom-rules/rules/ruleTwoRule.js index 1d2ff62d1af..9b8b16e0fb8 100644 --- a/test/external/tslint-test-custom-rules/rules/ruleTwoRule.js +++ b/test/external/tslint-test-custom-rules/rules/ruleTwoRule.js @@ -3,7 +3,7 @@ var __extends = (this && this.__extends) || function (d, b) { function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; -var Lint = require("tslint/lib/lint"); +var Lint = require("tslint"); var Rule = (function (_super) { __extends(Rule, _super); function Rule() { diff --git a/test/external/tslint-test-custom-rules/tslint.json b/test/external/tslint-test-custom-rules/tslint.json index 0f4be5d3c42..16ddc786809 100644 --- a/test/external/tslint-test-custom-rules/tslint.json +++ b/test/external/tslint-test-custom-rules/tslint.json @@ -1,5 +1,9 @@ { "rulesDirectory": ["./rules"], + "jsRules": { + "rule-one": true, + "rule-two": false + }, "rules": { "rule-one": true, "rule-two": false diff --git a/test/files/custom-rules-2/noFailRule.js b/test/files/custom-rules-2/noFailRule.js index 1d2ff62d1af..9b8b16e0fb8 100644 --- a/test/files/custom-rules-2/noFailRule.js +++ b/test/files/custom-rules-2/noFailRule.js @@ -3,7 +3,7 @@ var __extends = (this && this.__extends) || function (d, b) { function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; -var Lint = require("tslint/lib/lint"); +var Lint = require("tslint"); var Rule = (function (_super) { __extends(Rule, _super); function Rule() { diff --git a/test/files/custom-rules/alwaysFailRule.js b/test/files/custom-rules/alwaysFailRule.js index ee3abbe634d..b6d3d25921c 100644 --- a/test/files/custom-rules/alwaysFailRule.js +++ b/test/files/custom-rules/alwaysFailRule.js @@ -3,7 +3,7 @@ var __extends = (this && this.__extends) || function (d, b) { function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; -var Lint = require("tslint/lib/lint"); +var Lint = require("tslint"); var Rule = (function (_super) { __extends(Rule, _super); function Rule() { diff --git a/test/files/multiple-fixes-test/multiple-fixes.test.ts b/test/files/multiple-fixes-test/multiple-fixes.test.ts new file mode 100644 index 00000000000..83849f1a699 --- /dev/null +++ b/test/files/multiple-fixes-test/multiple-fixes.test.ts @@ -0,0 +1,2 @@ +import * as x from "b" +import * as y from "a_long_module"; diff --git a/test/files/multiple-fixes-test/tslint.json b/test/files/multiple-fixes-test/tslint.json new file mode 100644 index 00000000000..d57be419e19 --- /dev/null +++ b/test/files/multiple-fixes-test/tslint.json @@ -0,0 +1,6 @@ +{ + "rules": { + "ordered-imports": [true], + "semicolon": [true, "always"] + } +} diff --git a/test/formatters/msbuildFormatterTests.ts b/test/formatters/msbuildFormatterTests.ts index 2560f8fb473..ef2fd8f4344 100644 --- a/test/formatters/msbuildFormatterTests.ts +++ b/test/formatters/msbuildFormatterTests.ts @@ -39,9 +39,9 @@ describe("MSBuild Formatter", () => { ]; const expectedResult = - getFailureString(TEST_FILE, 1, 1, "first failure") + - getFailureString(TEST_FILE, 2, 12, "mid failure") + - getFailureString(TEST_FILE, 9, 2, "last failure"); + getFailureString(TEST_FILE, 1, 1, "first failure", "firstName") + + getFailureString(TEST_FILE, 2, 12, "mid failure", "midName") + + getFailureString(TEST_FILE, 9, 2, "last failure", "lastName"); const actualResult = formatter.format(failures); assert.equal(actualResult, expectedResult); @@ -52,7 +52,7 @@ describe("MSBuild Formatter", () => { assert.equal(result, "\n"); }); - function getFailureString(file: string, line: number, character: number, reason: string) { - return `${file}(${line},${character}): warning: ${reason}\n`; + function getFailureString(file: string, line: number, character: number, reason: string, ruleCamelCase: string) { + return `${file}(${line},${character}): warning ${ruleCamelCase}: ${reason}\n`; } }); diff --git a/test/formatters/proseFormatterTests.ts b/test/formatters/proseFormatterTests.ts index ccf8bc18907..0643e58bfdf 100644 --- a/test/formatters/proseFormatterTests.ts +++ b/test/formatters/proseFormatterTests.ts @@ -47,6 +47,28 @@ describe("Prose Formatter", () => { assert.equal(actualResult, expectedResult); }); + it("formats fixes", () => { + const failures = [ + new RuleFailure(sourceFile, 0, 1, "first failure", "first-name"), + ]; + + const mockFix = { getFileName: () => { return "file2"; } } as any; + + const fixes = [ + new RuleFailure(sourceFile, 0, 1, "first failure", "first-name"), + new RuleFailure(sourceFile, 32, 36, "mid failure", "mid-name"), + mockFix, + ]; + + const expectedResult = + `Fixed 2 error(s) in ${TEST_FILE}\n` + + `Fixed 1 error(s) in file2\n\n` + + `${TEST_FILE}${getPositionString(1, 1)}first failure\n`; + + const actualResult = formatter.format(failures, fixes); + assert.equal(actualResult, expectedResult); + }); + it("handles no failures", () => { const result = formatter.format([]); assert.equal(result, ""); diff --git a/test/formatters/stylishFormatterTests.ts b/test/formatters/stylishFormatterTests.ts index efa515fc929..a694ccf3e25 100644 --- a/test/formatters/stylishFormatterTests.ts +++ b/test/formatters/stylishFormatterTests.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import * as colors from "colors"; + import * as ts from "typescript"; import {IFormatter, RuleFailure, TestUtils} from "../lint"; @@ -43,12 +45,12 @@ describe("Stylish Formatter", () => { const maxPositionTuple = `${maxPositionObj.line + 1}:${maxPositionObj.character + 1}`; - const expectedResult = (require("colors").supportsColor) ? + const expectedResult = colors.enabled ? "formatters/stylishFormatter.test.ts" + "\n" + - "\u001b[31m1:1\u001b[39m \u001b[33mfirst-name\u001b[39m first failure" + "\n" + - "\u001b[31m1:3\u001b[39m \u001b[33mescape \u001b[39m &<>'\" should be escaped" + "\n" + - `\u001b[31m${maxPositionTuple}\u001b[39m \u001b[33mlast-name \u001b[39m last failure` + "\n" + - "\u001b[31m1:1\u001b[39m \u001b[33mfull-name \u001b[39m full failure" + "\n" + + "\u001b[31m1:1\u001b[39m \u001b[90mfirst-name\u001b[39m \u001b[33mfirst failure\u001b[39m" + "\n" + + "\u001b[31m1:3\u001b[39m \u001b[90mescape \u001b[39m \u001b[33m&<>'\" should be escaped\u001b[39m" + "\n" + + `\u001b[31m${maxPositionTuple}\u001b[39m \u001b[90mlast-name \u001b[39m \u001b[33mlast failure\u001b[39m` + "\n" + + "\u001b[31m1:1\u001b[39m \u001b[90mfull-name \u001b[39m \u001b[33mfull failure\u001b[39m" + "\n" + "\n" : "formatters/stylishFormatter.test.ts" + "\n" + "1:1 first-name first failure" + "\n" + diff --git a/test/lint.ts b/test/lint.ts index baa9d0fd203..b3336b4473d 100644 --- a/test/lint.ts +++ b/test/lint.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -export * from "../src/lint"; +export * from "../src/index"; import * as TestUtils from "./utils"; diff --git a/test/ruleLoaderTests.ts b/test/ruleLoaderTests.ts index 064cc642f93..21f784254f4 100644 --- a/test/ruleLoaderTests.ts +++ b/test/ruleLoaderTests.ts @@ -1,4 +1,5 @@ -/* +/** + * @license * Copyright 2013 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,54 +23,46 @@ describe("Rule Loader", () => { it("loads core rules", () => { const validConfiguration: {[name: string]: any} = { "class-name": true, - eofline: true, - forin: false, + "eofline": true, + "forin": false, "no-debugger": true, - quotemark: "single", + "quotemark": "single", }; const rules = loadRules(validConfiguration, {}, RULES_DIRECTORY); assert.equal(rules.length, 5); }); - it("throws if an invalid rule is found", () => { + it("ignores invalid rules", () => { const invalidConfiguration: {[name: string]: any} = { - invalidConfig1: true, - invalidConfig2: false, - }; - - assert.throws( - () => loadRules(invalidConfiguration, {}, RULES_DIRECTORY), - /invalidConfig1\ninvalidConfig2/ - ); - }); - - it("doesn't ignore leading or trailing underscores or dashes", () => { - /* tslint:disable:object-literal-sort-keys */ - const invalidConfiguration: {[name: string]: any} = { - _indent: 6, - forin_: true, - "-quotemark": "single", - "eofline-": true, + "class-name": true, + "invalidConfig1": true, + "invalidConfig2": false, }; - /* tslint:enable:object-literal-sort-keys */ - assert.throws( - () => loadRules(invalidConfiguration, {}, RULES_DIRECTORY), - /_indent\nforin_\n-quotemark\neofline-/ - ); + const rules = loadRules(invalidConfiguration, {}, [RULES_DIRECTORY]); + assert.equal(rules.length, 1); }); it("works with rulesDirectory argument as an Array", () => { const validConfiguration: {[name: string]: any} = { "class-name": true, - eofline: true, - forin: false, + "eofline": true, + "forin": false, "no-debugger": true, - quotemark: "single", + "quotemark": "single", }; const rules = loadRules(validConfiguration, {}, [RULES_DIRECTORY]); assert.equal(rules.length, 5); }); + + it("loads js rules", () => { + const validConfiguration: {[name: string]: any} = { + "class-name": true, + }; + + const rules = loadRules(validConfiguration, {}, RULES_DIRECTORY, true); + assert.equal(rules.length, 1); + }); }); diff --git a/test/rules/_integration/react/tslint.json b/test/rules/_integration/react/tslint.json index 4cc8c887f8e..9af967c5098 100644 --- a/test/rules/_integration/react/tslint.json +++ b/test/rules/_integration/react/tslint.json @@ -3,14 +3,13 @@ "curly": true, "eofline": true, "indent": [true, "spaces"], - "max-line-length": true, + "max-line-length": [true, 120], "no-bitwise": true, - "no-unreachable": true, "no-unused-expression": true, "no-unused-variable": true, "no-use-before-declare": true, "quotemark": [true, "double"], - "semicolon": true, + "semicolon": [true, "always"], "whitespace": [true, "check-branch", "check-decl", diff --git a/test/rules/adjacent-overload-signatures/test.ts.lint b/test/rules/adjacent-overload-signatures/test.ts.lint index 7379405b1b8..de6a26b2f28 100644 --- a/test/rules/adjacent-overload-signatures/test.ts.lint +++ b/test/rules/adjacent-overload-signatures/test.ts.lint @@ -32,6 +32,11 @@ interface i5 { } } +interface i6 { + // ensure no false positives for properties/methods available from prototype chain + toString(): string; +} + // bad @@ -78,3 +83,37 @@ interface b5 { ~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] } } + +// Also works in classes, source files, modules, namespaces + +class C { + a(): void; + b(): void; + a(x: number): void; + ~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] +} + +declare function a(): void; +declare function b(): void; +declare function a(x: number): void; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] + +declare module "m" { + export function a(): void; + export function b(): void; + export function a(x: number): void; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] +} + +declare namespace N { + export function a(): void; + export function b(): void; + export function a(x: number): void; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [All 'a' signatures should be adjacent] +} + +class Foo { + public static bar() {} + constructor() {} + public bar() {} +} \ No newline at end of file diff --git a/test/rules/align/arguments/test.js.lint b/test/rules/align/arguments/test.js.lint new file mode 100644 index 00000000000..3ecef0a198f --- /dev/null +++ b/test/rules/align/arguments/test.js.lint @@ -0,0 +1,152 @@ +function invalidParametersAlignment1(a, +b) { + var i = 0; +} + +function invalidParametersAlignment2(a, b, +c) { + var i = 0; +} + +function invalidParametersAlignment3(a, + b, + c) { + var i = 0; +} + +class C1 { + invalidParametersAlignment(a, + b) + { + } +} + +class InvalidAlignmentInConstructor { + constructor(a, + str) + { + } +} + +var invalidParametersAlignment4 = function(xxx, + yyy) { return true; } + +function validParametersAlignment1(a, b) { + var i = 0; +} + +function validParametersAlignment2(a, b, + c) { + var i = 0; +} + +function validParametersAlignment3(a, + b, + c) { + var i = 0; +} + +function validParametersAlignment4( + a, + b, + c) { + var i = 0; +} + +var validParametersAlignment6 = function(xxx, + yyy) { return true; } + +/////// + +function invalidArgumentsAlignment1() +{ + f(10, + 'abcd', 0); + ~~~~~~ [arguments are not aligned] +} + +function invalidArgumentsAlignment2() +{ + f(10, + 'abcd', + 0); + ~ [arguments are not aligned] + +} + +class Foo { + constructor(a, + str) + { + } +} + +var invalidConstructorArgsAlignment = new foo(10, + "abcd"); + ~~~~~~ [arguments are not aligned] + +function validArgumentsAlignment1() +{ + f(101, 'xyz', 'abc'); +} + +function validArgumentsAlignment2() +{ + f(1, + 2, + 3, + 4); +} + +function validArgumentsAlignment3() +{ + f( + 1, + 2, + 3, + 4); +} + +function validArgumentsAlignment3() +{ + f(1, 2, + 3, 4); +} + +//////// + +function invalidStatementsAlignment1() +{ + var i = 0; + var j = 0; + var k = 1; +} + +function invalidStatementsAlignment1() +{ + var i = 0; + { + var j = 0; + var k = 1; + } +} + +function validStatementsAlignment1() +{ + var i = 0; + var j = 0; + var k = 1; +} + +function validStatementsAlignment2() +{ + var i = 0; + { + var j = 0; + var k = 1; + } +} + +function shouldntCrash() { + let f = new Foo; +} diff --git a/test/rules/align/arguments/tslint.json b/test/rules/align/arguments/tslint.json index 642cc953dcf..22ccf5037b3 100644 --- a/test/rules/align/arguments/tslint.json +++ b/test/rules/align/arguments/tslint.json @@ -1,5 +1,8 @@ { "rules": { "align": [true, "arguments"] + }, + "jsRules": { + "align": [true, "arguments"] } } diff --git a/test/rules/align/parameters/test.js.lint b/test/rules/align/parameters/test.js.lint new file mode 100644 index 00000000000..2822562e3b3 --- /dev/null +++ b/test/rules/align/parameters/test.js.lint @@ -0,0 +1,38 @@ +function invalidParametersAlignment1(a, +b) { +~ [parameters are not aligned] + var i = 0; +} + +function invalidParametersAlignment2(a, b, +c) { +~ [parameters are not aligned] + var i = 0; +} + +function invalidParametersAlignment3(a, + b, + ~ [parameters are not aligned] + c) { + var i = 0; +} + +class C1 { + invalidParametersAlignment(a, + b) + ~ [parameters are not aligned] + { + } +} + +class InvalidAlignmentInConstructor { + constructor(a, + str) + ~~~ [parameters are not aligned] + { + } +} + +var invalidParametersAlignment4 = function(xxx, + yyy) { return true; } + ~~~ [parameters are not aligned] diff --git a/test/rules/align/parameters/tslint.json b/test/rules/align/parameters/tslint.json index b9360403062..5c0c0f8c3d6 100644 --- a/test/rules/align/parameters/tslint.json +++ b/test/rules/align/parameters/tslint.json @@ -1,5 +1,8 @@ { "rules": { "align": [true, "parameters"] + }, + "jsRules": { + "align": [true, "parameters"] } } diff --git a/test/rules/align/statements/test.js.lint b/test/rules/align/statements/test.js.lint new file mode 100644 index 00000000000..576e767a2e1 --- /dev/null +++ b/test/rules/align/statements/test.js.lint @@ -0,0 +1,151 @@ +function invalidParametersAlignment1(a, +b) { + var i = 0; +} + +function invalidParametersAlignment2(a, b, +c) { + var i = 0; +} + +function invalidParametersAlignment3(a, + b, + c) { + var i = 0; +} + +class C1 { + invalidParametersAlignment(a, + b) + { + } +} + +class InvalidAlignmentInConstructor { + constructor(a, + str) + { + } +} + +var invalidParametersAlignment4 = function(xxx, + yyy) { return true; } + +function validParametersAlignment1(a, b) { + var i = 0; +} + +function validParametersAlignment2(a, b, + c) { + var i = 0; +} + +function validParametersAlignment3(a, + b, + c) { + var i = 0; +} + +function validParametersAlignment4( + a, + b, + c) { + var i = 0; +} + +var validParametersAlignment6 = function(xxx, + yyy) { return true; } + + +/////// + +function invalidArgumentsAlignment1() +{ + f(10, + 'abcd', 0); +} + +function invalidArgumentsAlignment2() +{ + f(10, + 'abcd', + 0); +} + +class Foo { + constructor(a, + str) + { + } +} + +var invalidConstructorArgsAlignment = new foo(10, + "abcd"); + +function validArgumentsAlignment1() +{ + f(101, 'xyz', 'abc'); +} + +function validArgumentsAlignment2() +{ + f(1, + 2, + 3, + 4); +} + +function validArgumentsAlignment3() +{ + f( + 1, + 2, + 3, + 4); +} + +function validArgumentsAlignment3() +{ + f(1, 2, + 3, 4); +} + +//////// + +function invalidStatementsAlignment1() +{ + var i = 0; + var j = 0; + var k = 1; + ~~~~~~~~~~ [statements are not aligned] +} + +function invalidStatementsAlignment1() +{ + var i = 0; + { + var j = 0; + var k = 1; + ~~~~~~~~~~ [statements are not aligned] + } +} + +function validStatementsAlignment1() +{ + var i = 0; + var j = 0; + var k = 1; +} + +function validStatementsAlignment2() +{ + var i = 0; + { + var j = 0; + var k = 1; + } +} + +function shouldntCrash() { + let f = new Foo; +} diff --git a/test/rules/align/statements/tslint.json b/test/rules/align/statements/tslint.json index 3bd25ec81d8..b03bdca923a 100644 --- a/test/rules/align/statements/tslint.json +++ b/test/rules/align/statements/tslint.json @@ -1,5 +1,8 @@ { "rules": { "align": [true, "statements"] + }, + "jsRules": { + "align": [true, "statements"] } } diff --git a/test/rules/arrow-parens/test.js.lint b/test/rules/arrow-parens/test.js.lint new file mode 100644 index 00000000000..852f9b29d7e --- /dev/null +++ b/test/rules/arrow-parens/test.js.lint @@ -0,0 +1,15 @@ +// valid case +var a = (a) => {}; +var b = (a: number) => {}; +var c = (a, b) => {}; +var f = (...rest) => {}; +var f = a: number => {}; // TSLint don't warn. But syntax is wrong. +class Foo { + a: (a) =>{} +} + +// invalid case +var e = (a => {})(1); + ~ [Parentheses are required around the parameters of an arrow function definition] +var f = a => {}; + ~ [Parentheses are required around the parameters of an arrow function definition] diff --git a/test/rules/arrow-parens/test.ts.fix b/test/rules/arrow-parens/test.ts.fix new file mode 100644 index 00000000000..780c4f61339 --- /dev/null +++ b/test/rules/arrow-parens/test.ts.fix @@ -0,0 +1,27 @@ +// valid case +var a = (a) => {}; +var b = (a: number) => {}; +var c = (a, b) => {}; +var f = (...rest) => {}; +var f = a: number => {}; // TSLint don't warn. But syntax is wrong. +class Foo { + a: (a) =>{} +} +var bar = (method: () => T) => { + method(); +}; +var barbar = (method: (a: any) => T) => { + method(""); +}; +var barbarbar = (method: (a) => T) => { + method(""); +}; +var piyo = (method: () => T) => { + method(); +}; +const validAsync = async (param: any) => {}; +const validAsync = async (param) => {}; + +// invalid case +var e = ((a) => {})(1); +var f = (ab) => {}; diff --git a/test/rules/arrow-parens/test.ts.lint b/test/rules/arrow-parens/test.ts.lint index 2975baae8aa..463decd2270 100644 --- a/test/rules/arrow-parens/test.ts.lint +++ b/test/rules/arrow-parens/test.ts.lint @@ -25,5 +25,5 @@ const validAsync = async (param) => {}; // invalid case var e = (a => {})(1); ~ [Parentheses are required around the parameters of an arrow function definition] -var f = a => {}; - ~ [Parentheses are required around the parameters of an arrow function definition] +var f = ab => {}; + ~~ [Parentheses are required around the parameters of an arrow function definition] diff --git a/test/rules/arrow-parens/tslint.json b/test/rules/arrow-parens/tslint.json index f2bb606a314..bce07ce14c4 100644 --- a/test/rules/arrow-parens/tslint.json +++ b/test/rules/arrow-parens/tslint.json @@ -1,5 +1,8 @@ { "rules": { "arrow-parens": true + }, + "jsRules": { + "arrow-parens": true } } diff --git a/test/rules/ban/test.js.lint b/test/rules/ban/test.js.lint new file mode 100644 index 00000000000..3ac20772ce8 --- /dev/null +++ b/test/rules/ban/test.js.lint @@ -0,0 +1,15 @@ +console.time(); +window.toString(); +~~~~~~~~~~~~~~~ [Calls to 'window.toString' are not allowed.] +console.log(); +document.window.toString(); +~~~~~~~~~~~~~~~~~~~~~~~~ [Calls to 'window.toString' are not allowed.] +reference.randomContainer.window.toString(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Calls to 'window.toString' are not allowed.] +globals.getDocument().window.toString(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Calls to 'window.toString' are not allowed.] +_.keys(obj).forEach(fun); +_.forEach(fun); +~~~~~~~~~ [Calls to '_.forEach' are not allowed.] +_.filter(array); +~~~~~~~~ [Calls to '_.filter' are not allowed. Use the native JavaScript 'myArray.filter' instead.] \ No newline at end of file diff --git a/test/rules/ban/tslint.json b/test/rules/ban/tslint.json index ca4c09b14f7..877d1ae7f3c 100644 --- a/test/rules/ban/tslint.json +++ b/test/rules/ban/tslint.json @@ -10,5 +10,13 @@ ["_", "forEach"], ["_", "filter", "Use the native JavaScript 'myArray.filter' instead."] ] + }, + "jsRules": { + "ban": [ + true, + ["window", "toString"], + ["_", "forEach"], + ["_", "filter", "Use the native JavaScript 'myArray.filter' instead."] + ] } } diff --git a/test/rules/class-name/test.js.lint b/test/rules/class-name/test.js.lint new file mode 100644 index 00000000000..d8333276abd --- /dev/null +++ b/test/rules/class-name/test.js.lint @@ -0,0 +1,17 @@ +class ValidClassName { + +} + +class invalidClassName { + ~~~~~~~~~~~~~~~~ [0] +} + +class Another_Invalid_Class_Name { + ~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] +} + +export default class { + // should not fail +} + +[0]: Class name must be in pascal case diff --git a/test/rules/class-name/tslint.json b/test/rules/class-name/tslint.json index fcaed86a61e..675b68c2947 100644 --- a/test/rules/class-name/tslint.json +++ b/test/rules/class-name/tslint.json @@ -1,5 +1,8 @@ { "rules": { "class-name": true + }, + "jsRules": { + "class-name": true } } diff --git a/test/rules/comment-format/lower/test.js.lint b/test/rules/comment-format/lower/test.js.lint new file mode 100644 index 00000000000..6b0f7e4cfb2 --- /dev/null +++ b/test/rules/comment-format/lower/test.js.lint @@ -0,0 +1,25 @@ +class Clazz { // this comment is correct + /* block comment + * adada + */ + public funcxion() { // This comment has a capital letter starting it + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [lower] + //This comment is on its own line, and starts with a capital _and_ no space + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [lower] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [space] + console.log("test"); //this comment has no space + ~~~~~~~~~~~~~~~~~~~~~~~~~ [space] + } + /// +} + +//#region test +//#endregion + +`${location.protocol}//${location.hostname}` + +//noinspection JSUnusedGlobalSymbols +const unusedVar = 'unneeded value'; + +[lower]: comment must start with lowercase letter +[space]: comment must start with a space diff --git a/test/rules/comment-format/lower/tslint.json b/test/rules/comment-format/lower/tslint.json index b5c3658ef21..6e48863e1c2 100644 --- a/test/rules/comment-format/lower/tslint.json +++ b/test/rules/comment-format/lower/tslint.json @@ -1,5 +1,8 @@ { "rules": { "comment-format": [true, "check-space", "check-lowercase"] + }, + "jsRules": { + "comment-format": [true, "check-space", "check-lowercase"] } } diff --git a/test/rules/completed-docs/all/test.ts.lint b/test/rules/completed-docs/all/test.ts.lint new file mode 100644 index 00000000000..0cdc5889ed6 --- /dev/null +++ b/test/rules/completed-docs/all/test.ts.lint @@ -0,0 +1,59 @@ +class BadClass { +~~~~~~~~~~~~~~~~ [0] + badProperty; + ~~~~~~~~~~~~ [1] + badMethod() { } + ~~~~~~~~~~~~~~~ [2] +} + +/** + * + */ +class EmptyClass { +~~~~~~~~~~~~~~~~~~ [0] + /** + * + */ + emptyProperty; + ~~~~~~~~~~~~~~ [1] + + /** + * + */ + emptyMethod() { } + ~~~~~~~~~~~~~~~~~ [2] +} + +/** + * ... + */ +class GoodClass { + /** + * ... + */ + goodProperty; + + /** + * ... + */ + goodMethod() { } +} + +function BadFunction() { } +~~~~~~~~~~~~~~~~~~~~~~~~~~ [3] + +/** + * + */ +function EmptyFunction() { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [3] + +/** + * ... + */ +function GoodFunction() { } + +[0]: Classes must have documentation. +[1]: Properties must have documentation. +[2]: Methods must have documentation. +[3]: Functions must have documentation. diff --git a/test/rules/completed-docs/all/tslint.json b/test/rules/completed-docs/all/tslint.json new file mode 100644 index 00000000000..8dce9903cd7 --- /dev/null +++ b/test/rules/completed-docs/all/tslint.json @@ -0,0 +1,8 @@ +{ + "linterOptions": { + "typeCheck": true + }, + "rules": { + "completed-docs": true + } +} diff --git a/test/rules/completed-docs/functions/test.ts.lint b/test/rules/completed-docs/functions/test.ts.lint new file mode 100644 index 00000000000..4fbe4304713 --- /dev/null +++ b/test/rules/completed-docs/functions/test.ts.lint @@ -0,0 +1,50 @@ +class BadClass { + badMember; + badFunction() { } +} + +/** + * + */ +class EmptyClass { + /** + * + */ + emptyProperty; + + /** + * + */ + emptyMethod() { } +} + +/** + * ... + */ +class GoodClass { + /** + * ... + */ + goodProperty; + + /** + * ... + */ + goodMethod() { } +} + +function BadFunction() { } +~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +/** + * + */ +function EmptyFunction() { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +/** + * ... + */ +function GoodFunction() { } + +[0]: Functions must have documentation. diff --git a/test/rules/completed-docs/functions/tslint.json b/test/rules/completed-docs/functions/tslint.json new file mode 100644 index 00000000000..47a6dcf43f6 --- /dev/null +++ b/test/rules/completed-docs/functions/tslint.json @@ -0,0 +1,8 @@ +{ + "linterOptions": { + "typeCheck": true + }, + "rules": { + "completed-docs": [true, "functions"] + } +} diff --git a/test/rules/curly/test.js.lint b/test/rules/curly/test.js.lint new file mode 100644 index 00000000000..54a6099cc81 --- /dev/null +++ b/test/rules/curly/test.js.lint @@ -0,0 +1,81 @@ +if (x == 3) { + console.log("x"); +} + +if (y == 4) +{ + console.log("y"); +} + + if (z == 5) // failure + ~~~~~~~~~~~~~~~~~~~~~~ + console.log("z"); +~~~~~~~~~~~~~~~~~~~~~~~~~ [if statements must be braced] + +for (i = 0; i < 1; ++i) { + console.log("i"); +} + +for (j = 0; j < 1; ++j) +{ + console.log("j"); +} + + for (k = 0; k < 1; ++k) // failure + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + console.log("k"); +~~~~~~~~~~~~~~~~~~~~~~~ [for statements must be braced] + +for (k in l) // failure +~~~~~~~~~~~~~~~~~~~~~~~ + console.log("l"); +~~~~~~~~~~~~~~~~~~~~~ [for statements must be braced] + +while (m < 0) { + console.log("q"); +} + +while (n < 0) +{ + console.log("r"); +} + +while (n < 0) // failure +~~~~~~~~~~~~~~~~~~~~~~~~ + console.log("s"); +~~~~~~~~~~~~~~~~~~~~~ [while statements must be braced] + +do { + console.log("m"); +} while (i == 1); + +do +{ + console.log("n"); +} +while (j == 1); + +do // failure +~~~~~~~~~~~~~ + console.log("o"); +~~~~~~~~~~~~~~~~~~~~~ +while (k == 1); +~~~~~~~~~~~~~~~ [do statements must be braced] + +if (true) { + console.log("x"); +} else console.log("y"); // failure + ~~~~~~~~~~~~~~~~~~~~~~ [else statements must be braced] + +if (true) { + console.log("x"); +} else if (true) {console.log("y")}; + +for (let x of [1, 2, 3]) { + console.log(x); +} + +for (let y of [1, 2, 3]) // failure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + console.log(y); +~~~~~~~~~~~~~~~~~~~ [for statements must be braced] diff --git a/test/rules/curly/tslint.json b/test/rules/curly/tslint.json index c0855ef9fd0..26d7c42bf48 100644 --- a/test/rules/curly/tslint.json +++ b/test/rules/curly/tslint.json @@ -1,5 +1,8 @@ { "rules": { "curly": true + }, + "jsRules": { + "curly": true } } diff --git a/test/rules/file-header/bad-shebang/test.js.lint b/test/rules/file-header/bad-shebang/test.js.lint new file mode 100644 index 00000000000..c55e4ad5604 --- /dev/null +++ b/test/rules/file-header/bad-shebang/test.js.lint @@ -0,0 +1,18 @@ +#!/usr/bin/env node + +~nil [missing file header] +/* + * Bad header 3 + */ + +export class A { + x = 1; + + B() { + return 2; + } +} + +/* + * Good header 4 + */ diff --git a/test/rules/file-header/bad-shebang/tslint.json b/test/rules/file-header/bad-shebang/tslint.json index 79f26da8b41..d995363715f 100644 --- a/test/rules/file-header/bad-shebang/tslint.json +++ b/test/rules/file-header/bad-shebang/tslint.json @@ -1,5 +1,8 @@ { "rules": { "file-header": [true, "Good header \\d"] + }, + "jsRules": { + "file-header": [true, "Good header \\d"] } } diff --git a/test/rules/file-header/bad-use-strict/test.js.lint b/test/rules/file-header/bad-use-strict/test.js.lint new file mode 100644 index 00000000000..b46dceac795 --- /dev/null +++ b/test/rules/file-header/bad-use-strict/test.js.lint @@ -0,0 +1,18 @@ +"use strict"; +~nil [missing file header] + +/* + * Bad header 5 + */ + +export class A { + x = 1; + + B() { + return 2; + } +} + +/* + * Good header 6 + */ diff --git a/test/rules/file-header/bad-use-strict/tslint.json b/test/rules/file-header/bad-use-strict/tslint.json index 79f26da8b41..d995363715f 100644 --- a/test/rules/file-header/bad-use-strict/tslint.json +++ b/test/rules/file-header/bad-use-strict/tslint.json @@ -1,5 +1,8 @@ { "rules": { "file-header": [true, "Good header \\d"] + }, + "jsRules": { + "file-header": [true, "Good header \\d"] } } diff --git a/test/rules/file-header/bad/test.js.lint b/test/rules/file-header/bad/test.js.lint new file mode 100644 index 00000000000..f26963fcabf --- /dev/null +++ b/test/rules/file-header/bad/test.js.lint @@ -0,0 +1,16 @@ +/* +~nil [missing file header] + * Bad header 1 + */ + +export class A { + public x = 1; + + public B() { + return 2; + } +} + +/* + * Good header 2 + */ diff --git a/test/rules/file-header/bad/tslint.json b/test/rules/file-header/bad/tslint.json index 79f26da8b41..d995363715f 100644 --- a/test/rules/file-header/bad/tslint.json +++ b/test/rules/file-header/bad/tslint.json @@ -1,5 +1,8 @@ { "rules": { "file-header": [true, "Good header \\d"] + }, + "jsRules": { + "file-header": [true, "Good header \\d"] } } diff --git a/test/rules/file-header/good-shebang/test.js.lint b/test/rules/file-header/good-shebang/test.js.lint new file mode 100644 index 00000000000..7bf31c076c2 --- /dev/null +++ b/test/rules/file-header/good-shebang/test.js.lint @@ -0,0 +1,14 @@ +#!/usr/bin/env node + + +/* + * Good header 2 + */ + +export class A { + x = 1; + + B() { + return 2; + } +} diff --git a/test/rules/file-header/good-shebang/tslint.json b/test/rules/file-header/good-shebang/tslint.json index 79f26da8b41..d995363715f 100644 --- a/test/rules/file-header/good-shebang/tslint.json +++ b/test/rules/file-header/good-shebang/tslint.json @@ -1,5 +1,8 @@ { "rules": { "file-header": [true, "Good header \\d"] + }, + "jsRules": { + "file-header": [true, "Good header \\d"] } } diff --git a/test/rules/file-header/good-use-strict/test.js.lint b/test/rules/file-header/good-use-strict/test.js.lint new file mode 100644 index 00000000000..3e469beb3a1 --- /dev/null +++ b/test/rules/file-header/good-use-strict/test.js.lint @@ -0,0 +1,13 @@ +/* + * Good header 3 + */ + +"use strict"; + +export class A { + x = 1; + + B() { + return 2; + } +} diff --git a/test/rules/file-header/good-use-strict/tslint.json b/test/rules/file-header/good-use-strict/tslint.json index 79f26da8b41..d995363715f 100644 --- a/test/rules/file-header/good-use-strict/tslint.json +++ b/test/rules/file-header/good-use-strict/tslint.json @@ -1,5 +1,8 @@ { "rules": { "file-header": [true, "Good header \\d"] + }, + "jsRules": { + "file-header": [true, "Good header \\d"] } } diff --git a/test/rules/file-header/good/test.js.lint b/test/rules/file-header/good/test.js.lint new file mode 100644 index 00000000000..f480e249138 --- /dev/null +++ b/test/rules/file-header/good/test.js.lint @@ -0,0 +1,12 @@ + +/* + * Good header 1 + */ + +export class A { + x = 1; + + B() { + return 2; + } +} diff --git a/test/rules/file-header/good/tslint.json b/test/rules/file-header/good/tslint.json index 79f26da8b41..d995363715f 100644 --- a/test/rules/file-header/good/tslint.json +++ b/test/rules/file-header/good/tslint.json @@ -1,5 +1,8 @@ { "rules": { "file-header": [true, "Good header \\d"] + }, + "jsRules": { + "file-header": [true, "Good header \\d"] } } diff --git a/test/rules/forin/test.js.lint b/test/rules/forin/test.js.lint new file mode 100644 index 00000000000..a621922b16b --- /dev/null +++ b/test/rules/forin/test.js.lint @@ -0,0 +1,41 @@ +function a() { + for (var i in obj) { + ~~~~~~~~~~~~~~~~~~~~ + console.log("i"); +~~~~~~~~~~~~~~~~~~~~~~~~~ + } +~~~~~ [0] + + for (var j in obj) { + ~~~~~~~~~~~~~~~~~~~~ + if (j === 3) { +~~~~~~~~~~~~~~~~~~~~~~ + console.log("j"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } +~~~~~~~~~ + console.log("j"); +~~~~~~~~~~~~~~~~~~~~~~~~~ + } +~~~~~ [0] + + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + console.log("k"); + } + } + + for (var m in obj) { + if (!obj.hasOwnProperty(m)) { + continue; + } + console.log("m"); + } + + for (var n in obj) { + if (!obj.hasOwnProperty(n)) continue; + console.log("m"); + } +} + +[0]: for (... in ...) statements must be filtered with an if statement diff --git a/test/rules/forin/tslint.json b/test/rules/forin/tslint.json index c7c10b4b899..f42f3151de7 100644 --- a/test/rules/forin/tslint.json +++ b/test/rules/forin/tslint.json @@ -1,5 +1,8 @@ { "rules": { "forin": true + }, + "jsRules": { + "forin": true } } diff --git a/test/rules/indent/spaces/test.js.lint b/test/rules/indent/spaces/test.js.lint new file mode 100644 index 00000000000..f119a9cd0ef --- /dev/null +++ b/test/rules/indent/spaces/test.js.lint @@ -0,0 +1,136 @@ +// valid code + + var func = () => { + console.warn("hi"); + }; + + class TestClass1 { + variable; + + testFunction() { + this.variable = 3; + } + } + + var obj = { + a: 1, + b: 2, + c: 3 + }; + + switch (integerValue) { + case 1: + console.warn("1"); + break; + default: + console.warn("default"); + break; + } + + function loops() { + for (var i = 0; i < 1; ++i) { + console.warn(i); + } + + while (i < 1) { + console.warn(i); + } + + do { + console.warn(i); + } while (i < 1); + + if (i < 1) { + console.warn(i); + } else { + console.warn(i + 1); + } + } + + +// invalid code +// we get a weird scenario here where our ~~ underlines don't quite line up with the line above +// this is because tabs are only one character and thus only one ~ goes beneath them. + +function name() { + var test = 123; +~~ [0] +} + +class TestClass { + variable; +~ [0] + + testFunction() { +~ [0] + this.variable = 3; +~~ [0] + } +~ [0] +} + +var obj = { + a: 1, +~ [0] + b: 2, + c: 3 +}; + +switch (integerValue) { + case 0: +~ [0] + console.warn("1"); +~~ [0] + break; +~~ [0] + case 1: + console.warn("1"); + break; + default: +~ [0] + console.warn("default"); +~~ [0] + break; +~~ [0] +} + +for (var i = 0; i < 1; ++i) { + console.warn("123"); +~ [0] +} + +while (i < 1) { + console.warn("123"); +~ [0] +} + +do { + console.warn("123"); +~ [0] +} while (i < 1); + +if (i < 1) { + console.warn("123"); +~ [0] +} + +var arr = [ + 1, +~ [0] + 2 +]; + +var arr2 = [ + { + a: 1, +~~ [0] + b: 2 + }, +~ [0] + { + a: 3, + b: 4 + } +]; + +[0]: space indentation expected diff --git a/test/rules/indent/spaces/test.ts.lint b/test/rules/indent/spaces/test.ts.lint index 106b76ece18..0ad97bb449c 100644 --- a/test/rules/indent/spaces/test.ts.lint +++ b/test/rules/indent/spaces/test.ts.lint @@ -18,6 +18,16 @@ module TestModule { c: 3 }; + // ignore leading tabs inside template strings + var s1 = ` + multiline` + ` template + string`; + var s2 = ` + multiline ${ "A" } + template ${ "B" + + "C" } + string`; + export enum TestEnum { VALUE1, VALUE2 diff --git a/test/rules/indent/spaces/tslint.json b/test/rules/indent/spaces/tslint.json index 98c8abd97e1..05594054308 100644 --- a/test/rules/indent/spaces/tslint.json +++ b/test/rules/indent/spaces/tslint.json @@ -1,5 +1,8 @@ { "rules": { "indent": [true, "spaces"] + }, + "jsRules": { + "indent": [true, "spaces"] } } diff --git a/test/rules/indent/tabs/test.js.lint b/test/rules/indent/tabs/test.js.lint new file mode 100644 index 00000000000..c06841aad1f --- /dev/null +++ b/test/rules/indent/tabs/test.js.lint @@ -0,0 +1,134 @@ +// valid code + /** + * Some documentation + */ + var func = () => { + console.warn("hi"); + }; + + class TestClass1 { + variable; + + testFunction() { + this.variable = 3; + } + } + + var obj = { + a: 1, + b: 2, + c: 3 + }; + + switch (integerValue) { + case 1: + console.warn("1"); + break; + default: + console.warn("default"); + break; + } + + function loops() { + for (var i = 0; i < 1; ++i) { + console.warn(i); + } + + while (i < 1) { + console.warn(i); + } + + do { + console.warn(i); + } while (i < 1); + + if (i < 1) { + console.warn(i); + } else { + console.warn(i + 1); + } + } + +// invalid code +function name() { + var test = 123; +~~~~~~~~ [0] +} + +class TestClass { + variable; +~~~~ [0] + + testFunction() { +~~~~ [0] + this.variable = 3; +~~~~~~~ [0] + } +~~~~ [0] +} + +var obj = { + a: 1, +~~~~ [0] + b: 2, + c: 3 +}; + +switch (integerValue) { + case 0: + console.warn("1"); + break; + case 1: +~~~~ [0] + console.warn("1"); +~~~~~~~~ [0] + break; +~~~~~~~~ [0] + default: +~~~~ [0] + console.warn("default"); +~~~~~~~~ [0] + break; +~~~~~~~~ [0] +} + +for (var i = 0; i < 1; ++i) { + console.warn("123"); +~~~~ [0] +} + +while (i < 1) { + console.warn("123"); +~~~~ [0] +} + +do { + console.warn("123"); +~~~~ [0] +} while (i < 1); + +if (i < 1) { + console.warn("123"); +~~~~ [0] +} + +var arr = [ + 1, +~~~~ [0] + 2 +]; + +var arr2 = [ + { + a: 1, +~~~~~~~~ [0] + b: 2 + }, +~~~~ [0] + { + a: 3, + b: 4 + } +]; + +[0]: tab indentation expected diff --git a/test/rules/indent/tabs/test.ts.lint b/test/rules/indent/tabs/test.ts.lint index 1ec440ff490..a8b16546010 100644 --- a/test/rules/indent/tabs/test.ts.lint +++ b/test/rules/indent/tabs/test.ts.lint @@ -21,6 +21,16 @@ module TestModule { c: 3 }; + // ignore leading spaces inside template strings + var s1 = ` + multiline` + ` template + string`; + var s2 = ` + multiline ${ "A" } + template ${ "B" + + "C" } + string`; + export enum TestEnum { VALUE1, VALUE2 diff --git a/test/rules/indent/tabs/tslint.json b/test/rules/indent/tabs/tslint.json index 61b62f2a381..8facc3dcf8f 100644 --- a/test/rules/indent/tabs/tslint.json +++ b/test/rules/indent/tabs/tslint.json @@ -1,5 +1,8 @@ { "rules": { "indent": [true, "tabs"] + }, + "jsRules": { + "indent": [true, "tabs"] } } diff --git a/test/rules/jsdoc-format/jsdoc-windows.js.lint b/test/rules/jsdoc-format/jsdoc-windows.js.lint new file mode 100644 index 00000000000..ffe987ccb6c --- /dev/null +++ b/test/rules/jsdoc-format/jsdoc-windows.js.lint @@ -0,0 +1,10 @@ +/** + * MyClass + * + * Does classy things and impresses everyone. Quite a debonair class indeed. + * + * This file has all windows line endings "\r\n" and valid jsdoc. + */ +class MyClass { + +} \ No newline at end of file diff --git a/test/rules/jsdoc-format/jsdoc.js.lint b/test/rules/jsdoc-format/jsdoc.js.lint new file mode 100644 index 00000000000..52444146974 --- /dev/null +++ b/test/rules/jsdoc-format/jsdoc.js.lint @@ -0,0 +1,79 @@ +function makeHeader(pkg: Package) { + return [ + `\t/**`, + `\t * ${pkg.name} v${pkg.version}`, + `\t */` + ].join("\r\n"); +} + +class Clazz { //this is not a block comment + /* block comment + *Not a jsdoc and not subject to the rules lalala + * oh look I'm over here and you can't do anything about me + *and now I'm here, wheeee +I've even got characters where I shouldn't. How fun! * + You can't stop me! */ + public funcxion() { + /** + * This is jsdoc + * and it is correct + * so should be no errors here + * + * not on the above line either + */ + } + + /** + * this is also jsdoc + *and it has a problem on this line +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [format] + */ + + /** + * this jsoc is fine + * up until the last line when it isn't + */ +~~~~~ [asterisks] + + /** + * this jsdoc has characters where it really should +not */ +~~~~~~~ [format] + + /** + * same thing with this +one * +~~~~~~ [format] + */ + + /** + * what else can go wrong? + * oh right this +~~~~~~~~~~~~~~~~~~ [asterisks] + */ + + /**a bad one liner */ + ~~~~~~~~~~~~~~~~~~~~~ [format] + + /** another bad one liner*/ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ [format] + + /** */ + + /** */ + + /** a good one */ + +} + +// Regression test: jsdoc rule shouldn't look inside template strings (https://github.com/palantir/tslint/issues/332) +function makeHeader(pkg: Package) { + return [ + `\t/**`, + `\t * ${pkg.name} v${pkg.version}`, + `\t */` + ].join("\r\n"); +} + +[format]: jsdoc is not formatted correctly on this line +[asterisks]: asterisks in jsdoc must be aligned diff --git a/test/rules/jsdoc-format/tslint.json b/test/rules/jsdoc-format/tslint.json index 02b95774ec7..393ecc64ceb 100644 --- a/test/rules/jsdoc-format/tslint.json +++ b/test/rules/jsdoc-format/tslint.json @@ -1,5 +1,8 @@ { "rules": { "jsdoc-format": true + }, + "jsRules": { + "jsdoc-format": true } } diff --git a/test/rules/label-position/test.js.lint b/test/rules/label-position/test.js.lint new file mode 100644 index 00000000000..cd7c95afd2d --- /dev/null +++ b/test/rules/label-position/test.js.lint @@ -0,0 +1,38 @@ +var t = function() { + lab1: + ~~~~ [unexpected label on statement] + var x = 123; + + lab2: + ~~~~ [unexpected label on statement] + console.log("123"); + + lab3: + for (var i = 0; i < 5; ++i) { + break lab3; + } + + lab4: + do { + break lab4; + } while (i < 10); + + lab5: + while (i < 10) { + lab6: + while (j < 20) { + break lab5; + } + } + + lab7: + switch (i) { + case 0: + break lab7; + } + + lab8: + for (let value of [1]) { + break lab8; + } +}; diff --git a/test/rules/label-position/tslint.json b/test/rules/label-position/tslint.json index 82a6a0582e6..7e1d262f623 100644 --- a/test/rules/label-position/tslint.json +++ b/test/rules/label-position/tslint.json @@ -1,5 +1,8 @@ { "rules": { "label-position": true + }, + "jsRules": { + "label-position": true } } diff --git a/test/rules/label-undefined/test.ts.lint b/test/rules/label-undefined/test.ts.lint deleted file mode 100644 index d9988de8916..00000000000 --- a/test/rules/label-undefined/test.ts.lint +++ /dev/null @@ -1,55 +0,0 @@ -// invalid code - -function f() { - lab3: - for (var i = 0; i < 10; ++i) { - break lab1; - ~~~~~ [undefined label: 'lab1'] - } -} - -var x = function() { - lab4: - while (i < 10) { - continue lab2; - ~~~~~~~~ [undefined label: 'lab2'] - } -}; - -var y = () => { - lab3: - while (i < 10) { - continue lab3; - } - - (function() { - lab2: - switch (j) { - case 1: - break lab3; - ~~~~~ [undefined label: 'lab3'] - } - })(); -}; - -var z = x => { - lab1: - do { - x++; - continue lab4; - ~~~~~~~~ [undefined label: 'lab4'] - } while (x < 10); -}; - -// valid code - -lab5: -for (var i = 0; i < 10; ++i) { - var w = () => { - lab2: - while (i < 10) { - continue lab2; - } - }; - break lab5; -} diff --git a/test/rules/label-undefined/tslint.json b/test/rules/label-undefined/tslint.json deleted file mode 100644 index 74a9a3d5886..00000000000 --- a/test/rules/label-undefined/tslint.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "label-undefined": true - } -} diff --git a/test/rules/linebreak-style/emptyFile/test.js.lint b/test/rules/linebreak-style/emptyFile/test.js.lint new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/rules/linebreak-style/emptyFile/tslint.json b/test/rules/linebreak-style/emptyFile/tslint.json index f82a6f4d1df..8b246326003 100644 --- a/test/rules/linebreak-style/emptyFile/tslint.json +++ b/test/rules/linebreak-style/emptyFile/tslint.json @@ -1,5 +1,8 @@ { "rules": { "linebreak-style": [true, "LF"] + }, + "jsRules": { + "linebreak-style": [true, "LF"] } } diff --git a/test/rules/linebreak-style/failure/CRLF/test.js.lint b/test/rules/linebreak-style/failure/CRLF/test.js.lint new file mode 100644 index 00000000000..7d55d0fe1f9 --- /dev/null +++ b/test/rules/linebreak-style/failure/CRLF/test.js.lint @@ -0,0 +1,8 @@ +// this line uses CRLF +~~~~~~~~~~~~~~~~~~~~~~ [Expected linebreak to be 'LF'] +// this line uses CRLF +~~~~~~~~~~~~~~~~~~~~~~ [Expected linebreak to be 'LF'] +// this line uses CRLF +~~~~~~~~~~~~~~~~~~~~~~ [Expected linebreak to be 'LF'] +// this line uses CRLF +~~~~~~~~~~~~~~~~~~~~~~ [Expected linebreak to be 'LF'] diff --git a/test/rules/linebreak-style/failure/CRLF/tslint.json b/test/rules/linebreak-style/failure/CRLF/tslint.json index f82a6f4d1df..8b246326003 100644 --- a/test/rules/linebreak-style/failure/CRLF/tslint.json +++ b/test/rules/linebreak-style/failure/CRLF/tslint.json @@ -1,5 +1,8 @@ { "rules": { "linebreak-style": [true, "LF"] + }, + "jsRules": { + "linebreak-style": [true, "LF"] } } diff --git a/test/rules/linebreak-style/failure/LF/test.js.lint b/test/rules/linebreak-style/failure/LF/test.js.lint new file mode 100644 index 00000000000..fa51e943c77 --- /dev/null +++ b/test/rules/linebreak-style/failure/LF/test.js.lint @@ -0,0 +1,8 @@ +// this line uses LF +~~~~~~~~~~~~~~~~~~~~ [Expected linebreak to be 'CRLF'] +// this line uses LF +~~~~~~~~~~~~~~~~~~~~ [Expected linebreak to be 'CRLF'] +// this line uses LF +~~~~~~~~~~~~~~~~~~~~ [Expected linebreak to be 'CRLF'] +// this line uses LF +~~~~~~~~~~~~~~~~~~~~ [Expected linebreak to be 'CRLF'] diff --git a/test/rules/linebreak-style/failure/LF/tslint.json b/test/rules/linebreak-style/failure/LF/tslint.json index d959e7a49e4..1c18385ac74 100644 --- a/test/rules/linebreak-style/failure/LF/tslint.json +++ b/test/rules/linebreak-style/failure/LF/tslint.json @@ -1,5 +1,8 @@ { "rules": { "linebreak-style": [true, "CRLF"] + }, + "jsRules": { + "linebreak-style": [true, "CRLF"] } } diff --git a/test/rules/linebreak-style/success/CRLF/test.js.lint b/test/rules/linebreak-style/success/CRLF/test.js.lint new file mode 100644 index 00000000000..4a60171c332 --- /dev/null +++ b/test/rules/linebreak-style/success/CRLF/test.js.lint @@ -0,0 +1,4 @@ +// this line uses CRLF +// this line uses CRLF +// this line uses CRLF +// this line uses CRLF diff --git a/test/rules/linebreak-style/success/CRLF/tslint.json b/test/rules/linebreak-style/success/CRLF/tslint.json index d959e7a49e4..1c18385ac74 100644 --- a/test/rules/linebreak-style/success/CRLF/tslint.json +++ b/test/rules/linebreak-style/success/CRLF/tslint.json @@ -1,5 +1,8 @@ { "rules": { "linebreak-style": [true, "CRLF"] + }, + "jsRules": { + "linebreak-style": [true, "CRLF"] } } diff --git a/test/rules/linebreak-style/success/LF/test.js.lint b/test/rules/linebreak-style/success/LF/test.js.lint new file mode 100644 index 00000000000..1f88a5a75a2 --- /dev/null +++ b/test/rules/linebreak-style/success/LF/test.js.lint @@ -0,0 +1,4 @@ +// this line uses LF +// this line uses LF +// this line uses LF +// this line uses LF diff --git a/test/rules/linebreak-style/success/LF/tslint.json b/test/rules/linebreak-style/success/LF/tslint.json index f82a6f4d1df..8b246326003 100644 --- a/test/rules/linebreak-style/success/LF/tslint.json +++ b/test/rules/linebreak-style/success/LF/tslint.json @@ -1,5 +1,8 @@ { "rules": { "linebreak-style": [true, "LF"] + }, + "jsRules": { + "linebreak-style": [true, "LF"] } } diff --git a/test/rules/max-classes-per-file/one/test.ts.lint b/test/rules/max-classes-per-file/one/test.ts.lint new file mode 100644 index 00000000000..aa012bfc086 --- /dev/null +++ b/test/rules/max-classes-per-file/one/test.ts.lint @@ -0,0 +1,19 @@ +class one { + public foo = "bar"; +} + +class two { +~~~~~~~~~~~ + public banana = "apple"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + public theAbovePropertyMakesSense = false; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +} +~ [A maximum of 1 class per file is allowed] + +let three = class { + ~~~~~~~ + public foo = "bar"; +~~~~~~~~~~~~~~~~~~~~~~~ +} +~ [A maximum of 1 class per file is allowed] \ No newline at end of file diff --git a/test/rules/max-classes-per-file/one/tslint.json b/test/rules/max-classes-per-file/one/tslint.json new file mode 100644 index 00000000000..d4df2d8e491 --- /dev/null +++ b/test/rules/max-classes-per-file/one/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "max-classes-per-file": [true, 1] + } +} diff --git a/test/rules/max-classes-per-file/two/test.ts.lint b/test/rules/max-classes-per-file/two/test.ts.lint new file mode 100644 index 00000000000..3ce15cdd61f --- /dev/null +++ b/test/rules/max-classes-per-file/two/test.ts.lint @@ -0,0 +1,23 @@ +class one { + public foo = "bar"; +} + +class two { + public foo = "bar"; +} + +let three = class { + ~~~~~~~ + public foo = "bar"; +~~~~~~~~~~~~~~~~~~~~~~~ +} +~ [0] + +class four { +~~~~~~~~~~~~ + public foo = "bar"; +~~~~~~~~~~~~~~~~~~~~~~~ +} +~ [0] + +[0]: A maximum of 2 classes per file are allowed \ No newline at end of file diff --git a/test/rules/max-classes-per-file/two/tslint.json b/test/rules/max-classes-per-file/two/tslint.json new file mode 100644 index 00000000000..2064f81ad82 --- /dev/null +++ b/test/rules/max-classes-per-file/two/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "max-classes-per-file": [true, 2] + } +} diff --git a/test/rules/max-file-line-count/default/test.js.lint b/test/rules/max-file-line-count/default/test.js.lint new file mode 100644 index 00000000000..6dfc34a91e3 --- /dev/null +++ b/test/rules/max-file-line-count/default/test.js.lint @@ -0,0 +1,23 @@ +function App() { +~ [This file has 23 lines, which exceeds the maximum of 10 lines allowed. Consider breaking this file up into smaller parts] + class GiveMeANumber { + + /* tslint:disable:no-any */ + num = 10; + /* tslint:enable:no-any */ + + //This is some kind of comment + constructor(){ + this.giveNumber(); + } + + /* + Here is another comment + It's very helpful. + */ + + giveNumber = () =>{ + alert(this.num); + }; + } +} diff --git a/test/rules/max-file-line-count/default/tslint.json b/test/rules/max-file-line-count/default/tslint.json index 0a612cdcda6..f132ca54701 100644 --- a/test/rules/max-file-line-count/default/tslint.json +++ b/test/rules/max-file-line-count/default/tslint.json @@ -1,5 +1,8 @@ { "rules": { "max-file-line-count": [true, 10] + }, + "jsRules": { + "max-file-line-count": [true, 10] } } diff --git a/test/rules/max-file-line-count/disabled/test.js.lint b/test/rules/max-file-line-count/disabled/test.js.lint new file mode 100644 index 00000000000..5a054246d79 --- /dev/null +++ b/test/rules/max-file-line-count/disabled/test.js.lint @@ -0,0 +1,23 @@ +/* tslint:disable:max-file-line-count */ +//This file NEEDS to be very long, so we've disabled this rule here + +function App() { + class GiveMeANumber { + + //THis is a comment about something + num = 10; + + constructor(){ + this.giveNumber(); + } + + /* + Here is another comment + It's very helpful. + */ + + giveNumber = () =>{ + alert(this.num); + }; + } +} diff --git a/test/rules/max-file-line-count/disabled/tslint.json b/test/rules/max-file-line-count/disabled/tslint.json index 0a612cdcda6..f132ca54701 100644 --- a/test/rules/max-file-line-count/disabled/tslint.json +++ b/test/rules/max-file-line-count/disabled/tslint.json @@ -1,5 +1,8 @@ { "rules": { "max-file-line-count": [true, 10] + }, + "jsRules": { + "max-file-line-count": [true, 10] } } diff --git a/test/rules/max-line-length/test.js.lint b/test/rules/max-line-length/test.js.lint new file mode 100644 index 00000000000..f6a4c466bcc --- /dev/null +++ b/test/rules/max-line-length/test.js.lint @@ -0,0 +1,5 @@ +var simpleName = 1; +var complicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedName; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Exceeds maximum line length of 140] + +var complicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicatedNameIsAcomplicat; diff --git a/test/rules/max-line-length/tslint.json b/test/rules/max-line-length/tslint.json index 26a149d34a0..c3b416d0d96 100644 --- a/test/rules/max-line-length/tslint.json +++ b/test/rules/max-line-length/tslint.json @@ -1,5 +1,8 @@ { "rules": { "max-line-length": [true, 140] + }, + "jsRules": { + "max-line-length": [true, 140] } } diff --git a/test/rules/new-parens/test.js.lint b/test/rules/new-parens/test.js.lint new file mode 100644 index 00000000000..733f48ed974 --- /dev/null +++ b/test/rules/new-parens/test.js.lint @@ -0,0 +1,14 @@ +// correct case +var foo = new Date(); + +// incorrect case +var foge = new Date; + ~~~~~~~~ [0] +class Bar {} +var bar = new Bar; + ~~~~~~~ [0] +var fogefoge = new Bar(new Foo); + ~~~~~~~ [0] + +[0]: Parentheses are required when invoking a constructor + diff --git a/test/rules/new-parens/tslint.json b/test/rules/new-parens/tslint.json index 7cd049d2253..6facdcff9ee 100644 --- a/test/rules/new-parens/tslint.json +++ b/test/rules/new-parens/tslint.json @@ -1,5 +1,8 @@ { "rules": { "new-parens": true + }, + "jsRules": { + "new-parens": true } } diff --git a/test/rules/no-arg/test.js.lint b/test/rules/no-arg/test.js.lint new file mode 100644 index 00000000000..6ac3181430d --- /dev/null +++ b/test/rules/no-arg/test.js.lint @@ -0,0 +1,12 @@ +var testVariable = 123; + +function testFunction(): number { + if(arguments.callee.caller === testFunction) { + ~~~~~~~~~ [Access to arguments.callee is forbidden] + console.log("called"); + } + + argument.callee = testFunction; + + return testVariable; +} diff --git a/test/rules/no-arg/tslint.json b/test/rules/no-arg/tslint.json index 139d0955e11..7724bd2a075 100644 --- a/test/rules/no-arg/tslint.json +++ b/test/rules/no-arg/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-arg": true + }, + "jsRules": { + "no-arg": true } } diff --git a/test/rules/no-bitwise/test.js.lint b/test/rules/no-bitwise/test.js.lint new file mode 100644 index 00000000000..f16f3bcc8b2 --- /dev/null +++ b/test/rules/no-bitwise/test.js.lint @@ -0,0 +1,6 @@ +var z = (x || 3) && (y || 4); +var yy = x | 3; + ~~~~~ [Forbidden bitwise operation] +var zz = (z || y) & (x | y); + ~~~~~~~~~~~~~~~~~~ [Forbidden bitwise operation] + ~~~~~ [Forbidden bitwise operation] diff --git a/test/rules/no-bitwise/tslint.json b/test/rules/no-bitwise/tslint.json index 9dfce74f345..9d62bc3da15 100644 --- a/test/rules/no-bitwise/tslint.json +++ b/test/rules/no-bitwise/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-bitwise": true + }, + "jsRules": { + "no-bitwise": true } } diff --git a/test/rules/no-conditional-assignment/test.js.lint b/test/rules/no-conditional-assignment/test.js.lint new file mode 100644 index 00000000000..d74a168ac97 --- /dev/null +++ b/test/rules/no-conditional-assignment/test.js.lint @@ -0,0 +1,50 @@ +// valid cases +if (x == 5) { } +if (x === 5) { } +else if (y <= 23) { } +else if ((z && a) == 7) { } +else { } + +do { } while (x == 2); +do { } while (x !== 2); + +while (x == 2) { } +while (x !== 2) { } + +for (var x = 8; x == 8; ++x) { } +for (var x = 8; x == 8; x = 12) { } +for (;;) { } + +// invalid cases +if (x = 5) { } + ~~~~~ [0] +if (a && (b = 5)) { } + ~~~~~ [0] +else if (x = 2) { } + ~~~~~ [0] + +do { } while (x = 4); + ~~~~~ [0] + +while (x = 4); + ~~~~~ [0] +while ((x = y - 12)); + ~~~~~~~~~~ [0] + +for (var x = 4; x = 8; x++) { } + ~~~~~ [0] +for (; (y == 2) && (x = 3); ) { } + ~~~~~ [0] + +if (x += 2) { } + ~~~~~~ [0] +else if (h || (x <<= 4)) { } + ~~~~~~~ [0] + +do { } while (x ^= 4) { } + ~~~~~~ [0] +while ((a = 5) && ((b == 4) || (c = 3))) + ~~~~~ [0] + ~~~~~ [0] + +[0]: Assignments in conditional expressions are forbidden diff --git a/test/rules/no-conditional-assignment/tslint.json b/test/rules/no-conditional-assignment/tslint.json index 014f7127c44..0304a5f8ff6 100644 --- a/test/rules/no-conditional-assignment/tslint.json +++ b/test/rules/no-conditional-assignment/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-conditional-assignment": true + }, + "jsRules": { + "no-conditional-assignment": true } } diff --git a/test/rules/no-consecutive-blank-lines/test.ts.lint b/test/rules/no-consecutive-blank-lines/default/test.ts.lint similarity index 100% rename from test/rules/no-consecutive-blank-lines/test.ts.lint rename to test/rules/no-consecutive-blank-lines/default/test.ts.lint diff --git a/test/rules/no-consecutive-blank-lines/tslint.json b/test/rules/no-consecutive-blank-lines/default/tslint.json similarity index 50% rename from test/rules/no-consecutive-blank-lines/tslint.json rename to test/rules/no-consecutive-blank-lines/default/tslint.json index 3aa56ee6643..46bc8118965 100644 --- a/test/rules/no-consecutive-blank-lines/tslint.json +++ b/test/rules/no-consecutive-blank-lines/default/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-consecutive-blank-lines": true + }, + "jsRules": { + "no-consecutive-blank-lines": true } } diff --git a/test/rules/no-consecutive-blank-lines/invalid-option/test.ts.lint b/test/rules/no-consecutive-blank-lines/invalid-option/test.ts.lint new file mode 100644 index 00000000000..6bc6eb7fc90 --- /dev/null +++ b/test/rules/no-consecutive-blank-lines/invalid-option/test.ts.lint @@ -0,0 +1,30 @@ +// This rule will always pass since the arguments value in tslint.json is a string, +// while it should be a valid integer and > 1. +// In such a case, the rule is not enabled. + +class Clazz { // comment + + public funcxion() { + + + // also comment + + + + // still allowed since 2 lines only + + + + + + // this one won't be allowed anymore + + console.log("test"); + + } + + +} + + + diff --git a/test/rules/no-consecutive-blank-lines/invalid-option/tslint.json b/test/rules/no-consecutive-blank-lines/invalid-option/tslint.json new file mode 100644 index 00000000000..11f06b692b3 --- /dev/null +++ b/test/rules/no-consecutive-blank-lines/invalid-option/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-consecutive-blank-lines": [true, "three"] + } +} diff --git a/test/rules/no-consecutive-blank-lines/multiple/test.ts.lint b/test/rules/no-consecutive-blank-lines/multiple/test.ts.lint new file mode 100644 index 00000000000..b81bc3c41d7 --- /dev/null +++ b/test/rules/no-consecutive-blank-lines/multiple/test.ts.lint @@ -0,0 +1,40 @@ +// the markup for this test is a little bit weird +// tslint, for the first error below, says it goes from +// [5, 1] to [6, 1], and thus the markup appears to be off (but it's not) + +class Clazz { // comment + + +~nil + +~nil [Exceeds the 2 allowed consecutive blank lines] + + public funcxion() { + + // also comment + + + // still allowed since 2 lines only + + +~nil + +~nil [Exceeds the 2 allowed consecutive blank lines] + + + // this one won't be allowed anymore + + console.log("test"); + + } + + +} + +//Begin whitespace +// The next lines contain only tabs or spaces, they are also considered "blank" lines + + +~ [Exceeds the 2 allowed consecutive blank lines] + + diff --git a/test/rules/no-consecutive-blank-lines/multiple/tslint.json b/test/rules/no-consecutive-blank-lines/multiple/tslint.json new file mode 100644 index 00000000000..b9a168a7960 --- /dev/null +++ b/test/rules/no-consecutive-blank-lines/multiple/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-consecutive-blank-lines": [true, 2] + } +} diff --git a/test/rules/no-consecutive-blank-lines/test.js.lint b/test/rules/no-consecutive-blank-lines/test.js.lint new file mode 100644 index 00000000000..7fa366bb359 --- /dev/null +++ b/test/rules/no-consecutive-blank-lines/test.js.lint @@ -0,0 +1,32 @@ +// the markup for this test is a little bit weird +// tslint, for the first error below, says it goes from +// [5, 1] to [6, 1], and thus the markup appears to be off (but it's not) + + +~nil +class Clazz { // comment +~nil [Consecutive blank lines are forbidden] + + funcxion() { + + // also comment + + +~nil + console.log("test"); +~nil [Consecutive blank lines are forbidden] + + } + + +~nil +} +~nil [Consecutive blank lines are forbidden] + +//Begin whitespace +// The next two lines of "code" contain only tabs or spaces, they are also considered "blank" lines + + +~ [Consecutive blank lines are forbidden] + + diff --git a/test/rules/no-console/test.js.lint b/test/rules/no-console/test.js.lint new file mode 100644 index 00000000000..2ee294b7d6b --- /dev/null +++ b/test/rules/no-console/test.js.lint @@ -0,0 +1,13 @@ +console.time(); +console.log("log"); +~~~~~~~~~~~ [Calls to 'console.log' are not allowed.] +console.dir(object); +~~~~~~~~~~~ [Calls to 'console.dir' are not allowed.] +console.info("info"); +console.trace("trace"); +console.warn("warn"); +~~~~~~~~~~~~ [Calls to 'console.warn' are not allowed.] +console.error("error"); +~~~~~~~~~~~~~ [Calls to 'console.error' are not allowed.] +console.something(); +console.timeEnd(); diff --git a/test/rules/no-console/tslint.json b/test/rules/no-console/tslint.json index 08a0d1815f8..8f639ef177d 100644 --- a/test/rules/no-console/tslint.json +++ b/test/rules/no-console/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-console": [true, "dir", "error", "log", "warn"] + }, + "jsRules": { + "no-console": [true, "dir", "error", "log", "warn"] } } diff --git a/test/rules/no-construct/test.js.lint b/test/rules/no-construct/test.js.lint new file mode 100644 index 00000000000..b11a12570b8 --- /dev/null +++ b/test/rules/no-construct/test.js.lint @@ -0,0 +1,13 @@ +var s1 = "s"; +var s2 = new String("s"); + ~~~~~~~~~~ [0] + +var n1 = 1; +var n2 = new Number(1); + ~~~~~~~~~~~~~ [0] + +var b1 = true; +var b2 = new Boolean (true); + ~~~~~~~~~~~ [0] + +[0]: Forbidden constructor, use a literal or simple function call instead diff --git a/test/rules/no-construct/tslint.json b/test/rules/no-construct/tslint.json index 9d1db2e04c1..561aacc5772 100644 --- a/test/rules/no-construct/tslint.json +++ b/test/rules/no-construct/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-construct": true + }, + "jsRules": { + "no-construct": true } } diff --git a/test/rules/no-constructor-vars/tslint.json b/test/rules/no-constructor-vars/tslint.json deleted file mode 100644 index 6a614c47fcf..00000000000 --- a/test/rules/no-constructor-vars/tslint.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "no-constructor-vars": true - } -} diff --git a/test/rules/no-debugger/test.js.lint b/test/rules/no-debugger/test.js.lint new file mode 100644 index 00000000000..ba9cfd1eee9 --- /dev/null +++ b/test/rules/no-debugger/test.js.lint @@ -0,0 +1,8 @@ +var testVariable = "debugger"; + +function testFunction(): number { + if (testVariable === "debugger") { + debugger; + ~~~~~~~~ [Use of debugger statements is forbidden] + } +} diff --git a/test/rules/no-debugger/tslint.json b/test/rules/no-debugger/tslint.json index 53e3193c563..2e8428b0baf 100644 --- a/test/rules/no-debugger/tslint.json +++ b/test/rules/no-debugger/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-debugger": true + }, + "jsRules": { + "no-debugger": true } } diff --git a/test/rules/no-default-export/test.js.lint b/test/rules/no-default-export/test.js.lint new file mode 100644 index 00000000000..9d99f45be62 --- /dev/null +++ b/test/rules/no-default-export/test.js.lint @@ -0,0 +1,38 @@ +switch (value) { + case 1: break; + default: break; +} + +export { SingleItem }; + +export { FirstItem, SecondItem }; + +export { Item as aliasForItem }; + +export { ItemFromImport } from 'module'; + +export * from './relativeModule'; + + +export const default = 'VALID'; + +export default 'INVALID'; + ~~~~~~~ [0] + +export default { } + ~~~~~~~ [0] + +export default class { } + ~~~~~~~ [0] + +export default class Test1 { } + ~~~~~~~ [0] + +export default function() { } + ~~~~~~~ [0] + +export default function Test2() { } + ~~~~~~~ [0] + +[0]: Use of default exports is forbidden + diff --git a/test/rules/no-default-export/tslint.json b/test/rules/no-default-export/tslint.json index ebed5e9e331..ee746473cbf 100644 --- a/test/rules/no-default-export/tslint.json +++ b/test/rules/no-default-export/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-default-export": true + }, + "jsRules": { + "no-default-export": true } } diff --git a/test/rules/no-duplicate-key/test.ts.lint b/test/rules/no-duplicate-key/test.ts.lint deleted file mode 100644 index 78ce9d297b2..00000000000 --- a/test/rules/no-duplicate-key/test.ts.lint +++ /dev/null @@ -1,46 +0,0 @@ -var a = { - a: 1, - b: 2 -}; - -var x = { - axa: 1, - bd: 2, - c: 3, - axa: 4, - ~~~ [Duplicate key 'axa'] - d: 5, - ba: 3, - bd: 6, - ~~ [Duplicate key 'bd'] - axa: 6 - ~~~ [Duplicate key 'axa'] -}; - -var z = { - c: [1, 2, 3], - d: { - b: "b", - a: 11, - c: [11, 22, 33] - }, - a: 1, - b: "a" -}; - -var interspersed = { - duplicated: 1, - newContext: {}, - duplicated: 2 - ~~~~~~~~~~ [Duplicate key 'duplicated'] -}; - -var n = { - constructor: function () {}, - hasOwnProperty: function () {} -}; - -var foo = { - ["ab" + "cd"]: "efgh", - [x.axa]: "bar" -} diff --git a/test/rules/no-duplicate-key/tslint.json b/test/rules/no-duplicate-key/tslint.json deleted file mode 100644 index 69550402f75..00000000000 --- a/test/rules/no-duplicate-key/tslint.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "no-duplicate-key": true - } -} diff --git a/test/rules/no-duplicate-variable/test.js.lint b/test/rules/no-duplicate-variable/test.js.lint new file mode 100644 index 00000000000..bcc2d2e675d --- /dev/null +++ b/test/rules/no-duplicate-variable/test.js.lint @@ -0,0 +1,155 @@ +var duplicated = 1; + +class Test { + myFunc() { + var notDuplicated = 123, + duplicated = 234, + someFunc = () => { + var notDuplicated = 345; + }; + + var duplicated = null; + ~~~~~~~~~~ [Duplicate variable: 'duplicated'] + } +} + +function test() { + var notDuplicated = 123, + duplicated = 234, + someFunc = () => { + var notDuplicated = 345; + }; + + var duplicated = null; + ~~~~~~~~~~ [Duplicate variable: 'duplicated'] +} + +duplicated = 2; +var duplicated = 3; + ~~~~~~~~~~ [Duplicate variable: 'duplicated'] + +// valid code +export function tmp() { + var path = require("path"); + export class MyType { + path; + } +} + +export function foo() { + export class ClassA { + id: string; + } + + export class ClassB { + id: string; + } +} + +var a = { + foo(): void { + var bar = 1; + }, + baz(): void { + var bar = 1; + } +}; + +class AccessorTest { + get accesor1(): number { + var x = 0; + return x; + } + + get accesor2(): number { + var x = 0; + return x; + } + +} + +class NoDupConstructor { + test; + constructor() { + var test = "test"; + this.test = test; + } +} + +// valid/invalid code +function letTesting() { + var a = 1; + let b = 1; + let d = 1; + if (true) { + let a = 2; + let b = 2; + let c = 2; + var d = 2; + var e = 2; + } + else { + let b = 3; + let c = 3; + let e = 3; + let f = 3; + } + var f = 4; +} + +// failure: two arguments have the same name. +function testArguments1(arg, arg): void { +} + +// failure: local var/let declarations shadow arguments. +function testArguments2(x, y): void { + var x = 1; + let y = 2; +} + +try { + // +} catch (e) { + e.blah(); + // +} + +try { + // +} catch (e) { + e.blah(); + // +} + +function testDestructuring() { + function myFunc() { + return [1, 2]; + } + + var [x, y] = myFunc(); + var [z, z] = myFunc(); // failure + ~ [Duplicate variable: 'z'] + + let [x1, y1] = myFunc(); + let [z1, z1] = myFunc(); // tsc error + + const [x2, y2] = myFunc(); + const [z2, z2] = myFunc(); // tsc error + + let [a1, [b1, c1]] = [1, [2, 3]]; + let [{a1, d1}] = [{a1: 1, d1: 4}]; // tsc error + + var [a2, [b2, c2]] = [1, [2, 3]]; + var [{a2, d2}] = [{a2: 1, d2: 4}]; // failure + ~~ [Duplicate variable: 'a2'] + + function myFunc2([a, b]) { + var a; // not a failure; caught by no-shadowed-variable + return b; + } + + var [x, y3] = myFunc(); // failure + ~ [Duplicate variable: 'x'] + var [x3, ...y] = [1, 2, 3, 4]; // failure + ~ [Duplicate variable: 'y'] +} diff --git a/test/rules/no-duplicate-variable/tslint.json b/test/rules/no-duplicate-variable/tslint.json index 9d9b7a7156a..2d1c2f4571e 100644 --- a/test/rules/no-duplicate-variable/tslint.json +++ b/test/rules/no-duplicate-variable/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-duplicate-variable": true + }, + "jsRules": { + "no-duplicate-variable": true } } diff --git a/test/rules/no-empty/test.js.lint b/test/rules/no-empty/test.js.lint new file mode 100644 index 00000000000..0bbc38c017a --- /dev/null +++ b/test/rules/no-empty/test.js.lint @@ -0,0 +1,42 @@ +if (x === 1) {} + ~~ [block is empty] +if (x === 2) { + ~ + +~nil + +~nil +} +~ [block is empty] + +function testFunction() { + ~ + +~nil +} +~ [block is empty] + +for (var x = 0; x < 1; ++x) { } + ~~~ [block is empty] + +// empty blocks with comments should be legal +for (var y = 0; y < 1; ++y) { + // empty here +} + +class testClass { + constructor(private allowed: any, private alsoAllowed: any) { + } +} + +class testClass2 { + constructor(protected allowed: any) { + } +} + +class testClass3 { + constructor(notAllowed: any) { + ~ + } +~~~~~ [block is empty] +} diff --git a/test/rules/no-empty/test.ts.lint b/test/rules/no-empty/test.ts.lint index 0bbc38c017a..9abc44e9d88 100644 --- a/test/rules/no-empty/test.ts.lint +++ b/test/rules/no-empty/test.ts.lint @@ -40,3 +40,8 @@ class testClass3 { } ~~~~~ [block is empty] } + +class testClass4 { + constructor(readonly allowed: any) { + } +} diff --git a/test/rules/no-empty/tslint.json b/test/rules/no-empty/tslint.json index 282eaa1ffa3..6ba025b538a 100644 --- a/test/rules/no-empty/tslint.json +++ b/test/rules/no-empty/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-empty": true + }, + "jsRules": { + "no-empty": true } } diff --git a/test/rules/no-eval/test.js.lint b/test/rules/no-eval/test.js.lint new file mode 100644 index 00000000000..d7ffe5c856c --- /dev/null +++ b/test/rules/no-eval/test.js.lint @@ -0,0 +1,10 @@ +var testVariable = "eval"; + +function a() { + function b() { + function c() { + eval("console.log('hi');"); + ~~~~ [forbidden eval] + } + } +} diff --git a/test/rules/no-eval/tslint.json b/test/rules/no-eval/tslint.json index 1f0ba96f559..9c5f3af5fef 100644 --- a/test/rules/no-eval/tslint.json +++ b/test/rules/no-eval/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-eval": true + }, + "jsRules": { + "no-eval": true } } diff --git a/test/rules/no-for-in-array/test.js.lint b/test/rules/no-for-in-array/test.js.lint new file mode 100644 index 00000000000..87e5530518d --- /dev/null +++ b/test/rules/no-for-in-array/test.js.lint @@ -0,0 +1,41 @@ +const array = [1, 2, 3, 4]; +const strArray = ['a', 'b', 'c']; +const objArray = [{a: 1}, {a: 2, b: 10}, {a: 3}]; +const o = {}; +const numArray = { + 1: "a", + 2: "b" +}; +const d = new Date(); +const str = "abc"; +const map = new Map([['a', 1], ['b', 2]]); +const set = new Set([1, 2, 3]); + +class C { + a; + f() {} + g() {} +} +c = new C(); + +// valid cases +for (var k in o); +for (var k in d); +for (var k in map); +for (var k in numArray); +for (var k in c); +for (var k in refType); + +// invalid cases +for (var k in array); +~~~~~~~~~~~~~~~~~~~~~ [0] +for (var k in str); +~~~~~~~~~~~~~~~~~~~ [0] +for (var k in objArray); +~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +// Ideally these would also be forbidden: +for (var k in map); +for (var k in set); + +[0]: for-in loops over arrays are forbidden. Use for-of or array.forEach instead. diff --git a/test/rules/no-for-in-array/tslint.json b/test/rules/no-for-in-array/tslint.json index 583d5858c71..655b4b171e0 100644 --- a/test/rules/no-for-in-array/tslint.json +++ b/test/rules/no-for-in-array/tslint.json @@ -2,6 +2,9 @@ "rules": { "no-for-in-array": true }, + "jsRules": { + "no-for-in-array": true + }, "linterOptions": { "typeCheck": true } diff --git a/test/rules/no-invalid-this/enabled/test.js.lint b/test/rules/no-invalid-this/enabled/test.js.lint new file mode 100644 index 00000000000..ea9d9abc13a --- /dev/null +++ b/test/rules/no-invalid-this/enabled/test.js.lint @@ -0,0 +1,60 @@ +function foo(x) { + console.log(this.x); + ~~~~ [the "this" keyword is disallowed outside of a class body] + + this.evilMethod(); + ~~~~ [the "this" keyword is disallowed outside of a class body] +} + +class AClass { + x; + + constructor() { + this.x = 2; + } + + aMethod() { + this.x = 5; + } + + bMethod() { + [3,4].forEach(function(nr){ + console.log(this.x === nr); + ~~~~ [the "this" keyword is disallowed in function bodies inside class methods, use arrow functions instead] + }); + } + + Method() { + [3,4].forEach((nr) => { + console.log(this.x === nr); + }); + } + + cMethod = () => { + [3,4].forEach(function(nr){ + console.log(this.x === nr); + ~~~~ [the "this" keyword is disallowed in function bodies inside class methods, use arrow functions instead] + }); + } + + dMethod() { + [3,4].forEach(badFunction); + function badFunction(nr) { + console.log(this.x === nr); + ~~~~ [the "this" keyword is disallowed in function bodies inside class methods, use arrow functions instead] + } + } + + eMethod() { + [3,4].forEach(badFunction); + let badFunction = nr => console.log(this.x === nr); + } +} + +const AClassExpression = class { + x; + + aMethod() { + this.x = 5; + } +} diff --git a/test/rules/no-invalid-this/enabled/tslint.json b/test/rules/no-invalid-this/enabled/tslint.json index 55c5eee2986..9ecceb14846 100644 --- a/test/rules/no-invalid-this/enabled/tslint.json +++ b/test/rules/no-invalid-this/enabled/tslint.json @@ -4,5 +4,11 @@ true, "check-function-in-method" ] + }, + "jsRules": { + "no-invalid-this": [ + true, + "check-function-in-method" + ] } } diff --git a/test/rules/no-namespace/allow-declarations/test.ts.lint b/test/rules/no-namespace/allow-declarations/test.ts.lint index 8caa74ce5dc..64db872ce3a 100644 --- a/test/rules/no-namespace/allow-declarations/test.ts.lint +++ b/test/rules/no-namespace/allow-declarations/test.ts.lint @@ -1,3 +1,6 @@ declare namespace Foo { + // Allowed because namespaces nested in ambients are implicitly ambient. + namespace Foo { + } } diff --git a/test/rules/no-null-keyword/test.js.lint b/test/rules/no-null-keyword/test.js.lint new file mode 100644 index 00000000000..1cab307c4a1 --- /dev/null +++ b/test/rules/no-null-keyword/test.js.lint @@ -0,0 +1,4 @@ +var x = null; // error + ~~~~ [Use 'undefined' instead of 'null'] +console.log(null, x); // error + ~~~~ [Use 'undefined' instead of 'null'] diff --git a/test/rules/no-null-keyword/test.ts.lint b/test/rules/no-null-keyword/test.ts.lint index 1cab307c4a1..5eb317ac348 100644 --- a/test/rules/no-null-keyword/test.ts.lint +++ b/test/rules/no-null-keyword/test.ts.lint @@ -2,3 +2,8 @@ var x = null; // error ~~~~ [Use 'undefined' instead of 'null'] console.log(null, x); // error ~~~~ [Use 'undefined' instead of 'null'] + +let match(): string | null; +interface foo { + bar: [number, null, string]; +} diff --git a/test/rules/no-null-keyword/tslint.json b/test/rules/no-null-keyword/tslint.json index 1e4bf06a307..5e51d15a6d3 100644 --- a/test/rules/no-null-keyword/tslint.json +++ b/test/rules/no-null-keyword/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-null-keyword": true + }, + "jsRules": { + "no-null-keyword": true } } diff --git a/test/rules/no-constructor-vars/test.ts.lint b/test/rules/no-parameter-properties/test.ts.lint similarity index 100% rename from test/rules/no-constructor-vars/test.ts.lint rename to test/rules/no-parameter-properties/test.ts.lint diff --git a/test/rules/no-parameter-properties/tslint.json b/test/rules/no-parameter-properties/tslint.json new file mode 100644 index 00000000000..c65a294034b --- /dev/null +++ b/test/rules/no-parameter-properties/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-parameter-properties": true + } +} diff --git a/test/rules/no-reference/test.js.lint b/test/rules/no-reference/test.js.lint new file mode 100644 index 00000000000..2740b845ba2 --- /dev/null +++ b/test/rules/no-reference/test.js.lint @@ -0,0 +1,2 @@ +/// +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ is not allowed, use imports] diff --git a/test/rules/no-reference/tslint.json b/test/rules/no-reference/tslint.json index 6a925a49578..392c262938a 100644 --- a/test/rules/no-reference/tslint.json +++ b/test/rules/no-reference/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-reference": true + }, + "jsRules": { + "no-reference": true } } diff --git a/test/rules/no-require-imports/test.js.lint b/test/rules/no-require-imports/test.js.lint new file mode 100644 index 00000000000..b54741ed2b8 --- /dev/null +++ b/test/rules/no-require-imports/test.js.lint @@ -0,0 +1,24 @@ +var lib = require('lib'); // failure + ~~~~~~~~~~~~~~ [no-require] + +let lib2 = require('lib2'); // failure + ~~~~~~~~~~~~~~~ [no-require] + +import {l} from 'lib'; + +var lib3 = load('not_an_import'); + +var lib4 = lib2.subImport; + +var lib5 = require('lib5'), // failure + ~~~~~~~~~~~~~~~ [no-require] + lib6 = require('lib6'), // failure + ~~~~~~~~~~~~~~~ [no-require] + lib7 = 700; + +import lib8 = require('lib8'); // failure + ~~~~~~~~~~~~~~~ [no-require] + +import lib9 = lib2.anotherSubImport; + +[no-require]: require() style import is forbidden diff --git a/test/rules/no-require-imports/tslint.json b/test/rules/no-require-imports/tslint.json index 39bc26f8312..86ac4a05d9a 100644 --- a/test/rules/no-require-imports/tslint.json +++ b/test/rules/no-require-imports/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-require-imports": true + }, + "jsRules": { + "no-require-imports": true } } diff --git a/test/rules/no-shadowed-variable/test.js.lint b/test/rules/no-shadowed-variable/test.js.lint new file mode 100644 index 00000000000..ea5dbdd7673 --- /dev/null +++ b/test/rules/no-shadowed-variable/test.js.lint @@ -0,0 +1,156 @@ +function letTesting() { + var a = 1; + let b = 1; + + if (true) { + let a = 2; // failure + ~ [Shadowed variable: 'a'] + let b = 2; // failure + ~ [Shadowed variable: 'b'] + let c = 2; + var e = 2; + } else { + let b = 3; // failure + ~ [Shadowed variable: 'b'] + let c = 3; + let e = 3; // failure + ~ [Shadowed variable: 'e'] + let f = 3; + } + + var f = 4; +} + +let a = 1; +if (true) { + let a = 2; // failure + ~ [Shadowed variable: 'a'] +} + +var g = 1; +for (var index in [0, 1, 2]) { + var g = 2; // failure + ~ [Shadowed variable: 'g'] +} + +function constTesting() { + var h = 1; + const i = 1; + + if (true) { + const h = 2; // failure + ~ [Shadowed variable: 'h'] + const i = 2; // failure + ~ [Shadowed variable: 'i'] + } +} + +function testArguments(x: number, y: number): void { + var x = 1; // failure + ~ [Shadowed variable: 'x'] + let y = 2; // tsc error + ~ [Shadowed variable: 'y'] +} + +let j = 1; +for (var index in [0, 1, 2]) { // failure + ~~~~~ [Shadowed variable: 'index'] + let j = 2; // failure + ~ [Shadowed variable: 'j'] +} + +function testTryStatement() { + try { + let foo = 1; + throw new Error(); + } catch (e) { + let foo = 2; + var bar = 2; + } finally { + let foo = 3; + let bar = 3; // failure + ~~~ [Shadowed variable: 'bar'] + } +} + +function testWhileStatement() { + let foo = 1; + + while (true) { + let foo = 2; // failure + ~~~ [Shadowed variable: 'foo'] + } +} + +function testDoStatement() { + let foo = 1; + + do { + let foo = 2; // failure + ~~~ [Shadowed variable: 'foo'] + } while (true); +} + +function testDestructuring(x: number) { + var {y, z} = {y: 2, z: 3}; + + function myFunc() { + return [1]; + } + + function innerFunc() { + var [foo] = myFunc(); + var [x] = myFunc(); // failure + ~ [Shadowed variable: 'x'] + let [y] = myFunc(); // failure + ~ [Shadowed variable: 'y'] + const [z] = myFunc(); // failure + ~ [Shadowed variable: 'z'] + } + + function anotherInnerFunc() { + var [{x}] = [{x: 1}]; // failure + ~ [Shadowed variable: 'x'] + let [[y]] = [[2]]; // failure + ~ [Shadowed variable: 'y'] + var [foo, ...bar] = [1, 2, 3, 4]; + var [...z] = [1, 2, 3, 4]; // failure + ~ [Shadowed variable: 'z'] + } +} + +function falsePositive1(bar: (okay1: any) => void) { + let okay1 = 1; +} + +function falsePositive2(okay2: any, done: (okay2: any) => void) { } + +interface FalsePositive3 { + diffuse: (pos: number) => number; + specular: (pos: number) => number; + pos: number; +} + +interface FalsePositive4 { + (parameters: T, runSynchonous: boolean): TResult; + (parameters: T, callback: (error: Error, result: TResult) => void): void; +} + +{ + const simpleBlockVar = 3 +} + +function testSimpleBlockVar() { + const simpleBlockVar = 4 +} + +const external = 1; +interface ExternalIndexSignature1 { + [external: string]: any; +} + +function creatorFunction(constructor, filter) { + const myVariable = 1; + const myParameter = 1; + console.log(myVariable); +} diff --git a/test/rules/no-shadowed-variable/tslint.json b/test/rules/no-shadowed-variable/tslint.json index f9d0b34237a..b286e654896 100644 --- a/test/rules/no-shadowed-variable/tslint.json +++ b/test/rules/no-shadowed-variable/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-shadowed-variable": true + }, + "jsRules": { + "no-shadowed-variable": true } } diff --git a/test/rules/no-string-literal/tslint.json b/test/rules/no-string-literal/tslint.json index ade4197c3d3..ab3e0640502 100644 --- a/test/rules/no-string-literal/tslint.json +++ b/test/rules/no-string-literal/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-string-literal": true + }, + "jsRules": { + "no-string-literal": true } } diff --git a/test/rules/no-switch-case-fall-through/test.js.lint b/test/rules/no-switch-case-fall-through/test.js.lint new file mode 100644 index 00000000000..1dc40e8627b --- /dev/null +++ b/test/rules/no-switch-case-fall-through/test.js.lint @@ -0,0 +1,87 @@ +switch (foo) { + case 1: + bar(); + case 2: + ~~~~ [expected a 'break' before 'case'] + bar(); + bar(); + case 3: + ~~~~ [expected a 'break' before 'case'] + case 4: + default: + ~~~~~~~ [expected a 'break' before 'default'] + break; +} + + +switch (foo) { + case 1: + bar(); + case 2: + ~~~~ [expected a 'break' before 'case'] + bar(); +} + + +switch (foo) { + case 1: + case 2: + default: + ~~~~~~~ [expected a 'break' before 'default'] + bar(); +} + +switch (foo) { + case 1: + switch (bar) { + case "": + default: + ~~~~~~~ [expected a 'break' before 'default'] + break; + } + case 2: + ~~~~ [expected a 'break' before 'case'] +} + +switch (foo) { + case 1: + case 2: + + case 3: + + case 4: + break; + default: + bar(); +} + + +switch (foo) { + case 1: + return; // handle return the same as break + case 2: + case 3: + throw "error"; +} + +switch (foo) { + case 1: + bar(); + /* falls through */ + case 2: + bar(); + /* Testing */ + /* falls through */ + case 3: + break; +} + +// valid +switch (foo) { + case 1: + break; + case 2: + case 3: + break; + default: +} diff --git a/test/rules/no-switch-case-fall-through/tslint.json b/test/rules/no-switch-case-fall-through/tslint.json index 31c7fba4e6e..25ad95f50a3 100644 --- a/test/rules/no-switch-case-fall-through/tslint.json +++ b/test/rules/no-switch-case-fall-through/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-switch-case-fall-through": true + }, + "jsRules": { + "no-switch-case-fall-through": true } } diff --git a/test/rules/no-trailing-whitespace/test.js.lint b/test/rules/no-trailing-whitespace/test.js.lint new file mode 100644 index 00000000000..6ef8b5e18b4 --- /dev/null +++ b/test/rules/no-trailing-whitespace/test.js.lint @@ -0,0 +1,16 @@ +class Clazz { + public funcxion() { + ~~~~ [0] + console.log("test") ; + ~~~~ [0] + } + +~~~~ [0] + +~~~~ [0] + private foobar() { + } +} + ~~~~ [0] + +[0]: trailing whitespace diff --git a/test/rules/no-trailing-whitespace/tslint.json b/test/rules/no-trailing-whitespace/tslint.json index f81bfe73957..b53f885c954 100644 --- a/test/rules/no-trailing-whitespace/tslint.json +++ b/test/rules/no-trailing-whitespace/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-trailing-whitespace": true + }, + "jsRules": { + "no-trailing-whitespace": true } } diff --git a/test/rules/no-unreachable/test.ts.lint b/test/rules/no-unreachable/test.ts.lint deleted file mode 100644 index 15d51b06714..00000000000 --- a/test/rules/no-unreachable/test.ts.lint +++ /dev/null @@ -1,118 +0,0 @@ -// invalid code - -function f1() { - var x = 3; - return; - var y; - ~~~~~~ [unreachable code] - var z; -} - -var f2 = () => { - if (x === 3) { - throw new Error("error"); - "123"; - ~~~~~~ [unreachable code] - } else { - return y; - } - - return 123; -}; - -lab: -for (var i = 0; i < 10; ++i) { - if (i === 3) { - break; - console.log("hi"); - ~~~~~~~~~~~~~~~~~~ [unreachable code] - } else { - continue lab; - i = 4; - ~~~~~~ [unreachable code] - } -} - -// valid code -var f2 = () => { - if (x === 3) { - throw new Error("error"); - } else { - return y; - } - - return 123; -}; - -switch (x) { - case 1: - i = 2; - break; - case 2: - i = 3; - break; - default: - i = 4; - break; -} - -function f4() { - var x = 3; - if (x === 4) return; - else x = 4; - var y = 7; -} - -function f5() { - var x = 3; - if (x === 4) x = 5; - else return; - var y = 7; -} - -function f6() { - hoisted(); - return 0; - - function hoisted() { - return 0; - } -} - -// more invalid code - -function f7() { - hoisted(); - return 0; - - function hoisted() { - return 0; - } - - var y = 7; - ~~~~~~~~~~ [unreachable code] -} - -// more valid code - -function f8() { - try { - return 0; - } catch (e) { - console.log("here"); - } -} - -// valid case - -function f9() { - return 1; - function bar() {} - type Bar = string; -} - -function f10() { - type Bar = string; - return 1; - function bar() {} -} \ No newline at end of file diff --git a/test/rules/no-unreachable/tslint.json b/test/rules/no-unreachable/tslint.json deleted file mode 100644 index 8219288f905..00000000000 --- a/test/rules/no-unreachable/tslint.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "no-unreachable": true - } -} diff --git a/test/rules/no-unsafe-finally/test.js.lint b/test/rules/no-unsafe-finally/test.js.lint new file mode 100644 index 00000000000..394d3729689 --- /dev/null +++ b/test/rules/no-unsafe-finally/test.js.lint @@ -0,0 +1,361 @@ +function() { + try { + } finally { + return; + ~~~~~~~ [no-return-in-finally] + } +} + +function() { + try { + } catch { + } finally { + return 1; + ~~~~~~~~~ [no-return-in-finally] + } +} + +function() { + try { + } catch { + } finally { + { + return 1; + ~~~~~~~~~ [no-return-in-finally] + } + } +} + +function() { + try { + } catch { + } finally { + for (let i = 0; i < 5; ++i) { + if (i % 2 === 0) { + return 1; + ~~~~~~~~~ [no-return-in-finally] + } + } + } +} + +function() { + try { + } catch { + } finally { + let i = 1; + while (i < 5) { + if (i % 2 === 0) { + return i; + ~~~~~~~~~ [no-return-in-finally] + } + + ++i; + } + } +} + +function() { + try { + } catch { + } finally { + let i = 1; + do { + if (i % 2 === 0) { + return i; + ~~~~~~~~~ [no-return-in-finally] + } + + ++i; + } while (i < 5); + } +} + +function() { + try { + if (foo()) { + try { + bar(); + } catch { + } finally { + return 2; + ~~~~~~~~~ [no-return-in-finally] + } + } + } catch { + } finally { + for (const i of [1, 2, 3, 4, 5]) { + if (i % 2 === 0) { + return 1; + ~~~~~~~~~ [no-return-in-finally] + } + } + } +} + +function foo() { + try { + try { + } finally { + return 1; + ~~~~~~~~~ [no-return-in-finally] + } + } catch { + } +} + +function foo() { + try { + } finally { + throw "error"; + ~~~~~~~~~~~~~~ [no-throw-in-finally] + } +} + +function foo() { + for (const i of [1, 2, 3, 4, 5]) { + try { + } finally { + continue; + ~~~~~~~~~ [no-continue-in-finally] + } + } +} + +function foo() { + for (const i of [1, 2, 3, 4, 5]) { + try { + } finally { + break; + ~~~~~~ [no-break-in-finally] + } + } +} + +function foo() { + for (let i = 0; i < 5; ++i) { + try { + } finally { + continue; + ~~~~~~~~~ [no-continue-in-finally] + } + } +} + +function foo() { + do { + try { + } finally { + continue; + ~~~~~~~~~ [no-continue-in-finally] + } + } while (i > 0); +} + +function foo() { + while (i > 0) { + try { + } finally { + continue; + ~~~~~~~~~ [no-continue-in-finally] + } + } +} + +function foo() { + do { + try { + } finally { + break; + ~~~~~~ [no-break-in-finally] + } + } while (i > 0); +} + +function foo() { + while (i > 0) { + try { + } finally { + break; + ~~~~~~ [no-break-in-finally] + } + } +} + +function foo() { + switch (a) { + case 1: + try { + return; + } finally { + break; + ~~~~~~ [no-break-in-finally] + } + break; + default: + try { + } finally { + break; + ~~~~~~ [no-break-in-finally] + } + break; + } +} + +function foo() { + label: + try { + } finally { + break label; + ~~~~~~~~~~~~ [no-break-in-finally] + } +} + +function foo() { + label: + for (let i = 0; i < 4; ++i) { + try { + } finally { + break label; + ~~~~~~~~~~~~ [no-break-in-finally] + } + } +} + +function foo() { + outer: + for (let i = 0; i < 4; ++i) { + try { + } finally { + inner: + for (let j = 0; j < 2; ++j) { + break outer; + ~~~~~~~~~~~~ [no-break-in-finally] + } + } + } +} + +function foo() { + label: + for (let i = 0; i < 4; ++i) { + try { + } finally { + continue label; + ~~~~~~~~~~~~~~~ [no-continue-in-finally] + } + } +} + +function foo() { + outer: + for (let i = 0; i < 4; ++i) { + try { + } finally { + inner: + for (let j = 0; j < 2; ++j) { + continue outer; + ~~~~~~~~~~~~~~~ [no-continue-in-finally] + } + } + } +} + +// valid +function() { + try { + } finally { + (function() { + return 1; + })(); + } +} + +// valid +function() { + try { + foo(); + } finally { + class C { + bar() { + return 1; + } + } + } + + return 1; +} + +// valid +function() { + try { + } catch { + } finally { + for (let i = 0; i < 5; ++i) { + if (i % 2 === 0) { + continue; + } + } + } +} + +// valid +function() { + try { + } catch { + } finally { + for (let i = 0; i < 5; ++i) { + if (i % 2 === 0) { + break; + } + } + } +} + +// valid +function() { + try { + } catch { + } finally { + switch (a) { + case 1: + break; + default: + break; + } + } +} + +//valid +function() { + try { + } finally { + label: + break label; + } +} + +//valid +function() { + try { + } finally { + outer: + for (let i = 0; i < 2; ++i) { + if (i % 2 === 0) { + continue outer; + } + + inner: + for (let j = 0; j < 2; ++j) { + if (j % 2 === 0) { + continue outer; + } + } + } + } +} + +[no-return-in-finally]: return statements in finally blocks are forbidden. +[no-throw-in-finally]: throw statements in finally blocks are forbidden. +[no-break-in-finally]: break statements in finally blocks are forbidden. +[no-continue-in-finally]: continue statements in finally blocks are forbidden. diff --git a/test/rules/no-unsafe-finally/tslint.json b/test/rules/no-unsafe-finally/tslint.json index 0b957d11b67..93e37a38d96 100644 --- a/test/rules/no-unsafe-finally/tslint.json +++ b/test/rules/no-unsafe-finally/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-unsafe-finally": true + }, + "jsRules": { + "no-unsafe-finally": true } } \ No newline at end of file diff --git a/test/rules/no-unused-expression/test.js.lint b/test/rules/no-unused-expression/test.js.lint new file mode 100644 index 00000000000..80e8e7bd054 --- /dev/null +++ b/test/rules/no-unused-expression/test.js.lint @@ -0,0 +1,112 @@ +"use strict"; +'use asm'; +"ngInject"; +''; + +function fun1() { + "use strict"; + 'someOtherDirective'; + return 0; +} + +(function() { "directive"; +'foo' +'directive2' +console.log('foo'); +'notdirective'; +~~~~~~~~~~~~~~~ [0] +})(); + +const a = () => { +'use strict'; "use cool"; "use lint"; var a = 1; "notdirective"; } + ~~~~~~~~~~~~~~~ [0] + +function fun2(a) { + return 0; +} + +function fun3(a, b) { + return 0; +} + +class Foo { + constructor() { + "ngInject"; + var a = 1; + 'notdirective'; + ~~~~~~~~~~~~~~~ [0] + } + + bar() { + 'use strict'; + } + + get baz() { + 'use asm'; + } + + set baz(newValue) { + "use asm"; + } +} + +// valid code: + +var i; +var j = 3; +i = 1 + 2; +j = fun1(); +fun1(); +fun2(2); +fun3(2, fun1()); +i++; +i += 2; +--i; +i <<= 2; +i = fun1() + fun1(); +j = (j === 0 ? 5 : 6); +(j === 0 ? fun1() : fun2(j)); +(a => 5)(4); +var obj = {}; +delete obj.key; +function* g() { + for (let i = 0; i < 100; i++) { + yield i; + } +} + +async function f(foo) { + await foo; + return 0; +} + +new Foo(); + +// invalid code: + +5; +~~ [0] +i; +~~ [0] +3 + 5; +~~~~~~ [0] +fun1() + fun1(); +~~~~~~~~~~~~~~~~ [0] +fun2(i) + fun3(4,7); +~~~~~~~~~~~~~~~~~~~~ [0] +fun1() + 4; +~~~~~~~~~~~ [0] +4 + fun2(j); +~~~~~~~~~~~~ [0] +(j === 0 ? fun1() : 5); +~~~~~~~~~~~~~~~~~~~~~~~ [0] +(j === 0 ? i : fun2(j)); +~~~~~~~~~~~~~~~~~~~~~~~~ [0] +a => fun2(a); +~~~~~~~~~~~~~ [0] +() => {return fun1();}; +~~~~~~~~~~~~~~~~~~~~~~~ [0] +"use strct"; +~~~~~~~~~~~~ [0] + +[0]: expected an assignment or function call diff --git a/test/rules/no-unused-expression/tslint.json b/test/rules/no-unused-expression/tslint.json index 042bc2f9ac4..0a5c968e513 100644 --- a/test/rules/no-unused-expression/tslint.json +++ b/test/rules/no-unused-expression/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-unused-expression": true + }, + "jsRules": { + "no-unused-expression": true } } diff --git a/test/rules/no-unused-new/test.js.lint b/test/rules/no-unused-new/test.js.lint new file mode 100644 index 00000000000..b3b1d987b1a --- /dev/null +++ b/test/rules/no-unused-new/test.js.lint @@ -0,0 +1,99 @@ +"use strict"; +'use asm'; +"ngInject"; +''; + +function fun1() { + "use strict"; + 'someOtherDirective'; + return 0; +} + +(function() { "directive"; +'foo' +'directive2' +console.log('foo'); +'notdirective'; +})(); + +const a = () => { +'use strict'; "use cool"; "use lint"; var a = 1; "notdirective"; } + +function fun2(a) { + return 0; +} + +function fun3(a, b) { + return 0; +} + +class Foo { + constructor() { + "ngInject"; + var a = 1; + 'notdirective'; + } + + bar() { + 'use strict'; + } + + get baz() { + 'use asm'; + } + + set baz(newValue) { + "use asm"; + } +} + +// valid code: + +var i; +var j = 3; +i = 1 + 2; +j = fun1(); +fun1(); +fun2(2); +fun3(2, fun1()); +i++; +i += 2; +--i; +i <<= 2; +i = fun1() + fun1(); +j = (j === 0 ? 5 : 6); +(j === 0 ? fun1() : fun2(j)); +(a => 5)(4); +var obj = {}; +delete obj.key; +function* g() { + for (let i = 0; i < 100; i++) { + yield i; + } +} + +async function f(foo) { + await foo; + return 0; +} + +5; +3 + 5; +fun1() + fun1(); +(j === 0 ? fun1() : 5); +() => {return fun1();}; + +// invalid code: + +new Foo(); +~~~~~~~~~~ [0] +5 + new Foo(); +~~~~~~~~~~~~~~ [0] +new Foo() + new Foo(); +~~~~~~~~~~~~~~~~~~~~~~ [0] +fun1() + new Foo(); +~~~~~~~~~~~~~~~~~~~ [0] +(j === 0 ? new Foo() : 5); +~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +[0]: do not use 'new' for side effects diff --git a/test/rules/no-unused-new/tslint.json b/test/rules/no-unused-new/tslint.json index 478e4e1736f..38f26ae9ebf 100644 --- a/test/rules/no-unused-new/tslint.json +++ b/test/rules/no-unused-new/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-unused-new": true + }, + "jsRules": { + "no-unused-new": true } } diff --git a/test/rules/no-unused-variable/default/false-positives.ts.lint b/test/rules/no-unused-variable/default/false-positives.ts.lint index 30cd304ee5b..bfd2b0ac19d 100644 --- a/test/rules/no-unused-variable/default/false-positives.ts.lint +++ b/test/rules/no-unused-variable/default/false-positives.ts.lint @@ -40,3 +40,13 @@ interface MyDateTimeOpts extends DateTimeOpts { let opts: MyDateTimeOpts; console.log(opts.timezoneOffset - 1); + +import * as myLib from 'myLib'; +export { myLib }; + +import foo from 'foo'; +const bar = {foo}; +myFunc(bar); + +import a from "module"; +export { a }; diff --git a/test/rules/no-unused-variable/default/import.ts.fix b/test/rules/no-unused-variable/default/import.ts.fix index c8de8aeeee8..081f3e24ca0 100644 --- a/test/rules/no-unused-variable/default/import.ts.fix +++ b/test/rules/no-unused-variable/default/import.ts.fix @@ -37,3 +37,7 @@ baz(); namedExport(); import "jquery"; + +import abc = require('abc'); +import def = abc.someVar; +console.log(def); diff --git a/test/rules/no-unused-variable/default/import.ts.lint b/test/rules/no-unused-variable/default/import.ts.lint index a0f019f289b..539dde7c3e1 100644 --- a/test/rules/no-unused-variable/default/import.ts.lint +++ b/test/rules/no-unused-variable/default/import.ts.lint @@ -58,3 +58,7 @@ baz(); namedExport(); import "jquery"; + +import abc = require('abc'); +import def = abc.someVar; +console.log(def); diff --git a/test/rules/no-use-before-declare/test.js.lint b/test/rules/no-use-before-declare/test.js.lint new file mode 100644 index 00000000000..8c51be3ba61 --- /dev/null +++ b/test/rules/no-use-before-declare/test.js.lint @@ -0,0 +1,74 @@ +$.x = 3; +~ [variable '$' used before declaration] +import $ from "$"; +var vara = varb, varb; + ~~~~ [variable 'varb' used before declaration] + +class Test { + constructor() { + this.a = 3; + } + + a; +} + +var i = j; + ~ [variable 'j' used before declaration] + +class ClassA { + prop; + constructor(object) { + this.prop = object.prop; + } +} + +class ClassB { + prop; +} + +var j; + +if (something) { + var defined = 1; +} else { + var defined; +} + +function testUndeclaredImports() { + console.log(foo1); + ~~~~ [variable 'foo1' used before declaration] + console.log(foo2); + ~~~~ [variable 'foo2' used before declaration] + console.log(foo3); + ~~~~ [variable 'foo3' used before declaration] + map([], (x) => x); + ~~~ [variable 'map' used before declaration] +} + +import { default as foo1 } from "lib"; +import foo2 from "lib"; +import _, { map, foldl } from "underscore"; +import * as foo3 from "lib"; +import "lib"; + +export default function () { + // +}; + +export { + undeclaredA, + ~~~~~~~~~~~ [variable 'undeclaredA' used before declaration] + undeclaredB, // tsc error + undeclaredC, // tsc error + testUndeclaredImports +}; + +var undeclaredA = 42; +let { undeclaredB } = { undeclaredB: 43 }; +const [ undeclaredC, [undeclaredD] ] = [ 1, [2] ]; + +// shouldn't crash tslint +function a() { + var b = ({c: dog}) => { dog++; }; + b({ c: 5 }); +} diff --git a/test/rules/no-use-before-declare/tslint.json b/test/rules/no-use-before-declare/tslint.json index 744ae40f6ff..113653e7cd5 100644 --- a/test/rules/no-use-before-declare/tslint.json +++ b/test/rules/no-use-before-declare/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-use-before-declare": true + }, + "jsRules": { + "no-use-before-declare": true } } diff --git a/test/rules/no-var-keyword/test.js.lint b/test/rules/no-var-keyword/test.js.lint new file mode 100644 index 00000000000..cff272ae817 --- /dev/null +++ b/test/rules/no-var-keyword/test.js.lint @@ -0,0 +1,49 @@ +var foo; +~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] + +function tmp(t) { + var x = 3; + ~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] +} + +var i, +~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] + j; + +var [a, b] = [1, 2]; +~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] + +for (var n; false;); + ~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] +for (var n1 in foo); + ~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] +for (var n2 of foo); + ~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] + +export var exportVar0 = 0; + ~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] +export var exportVar1 = 1; + ~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] +export var exportVar2 = 2, + ~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] + exportVar21 = 21; +export /* var tst */ var exportVar3 = 3; + ~~~ [Forbidden 'var' keyword, use 'let' or 'const' instead] + +let bar; +const qux; + +let k, + l; + +let [x, y] = [1, 2]; + +for (n; false;); +for (let n; false;); +for (let name in foo); +for (let name of foo); +for (const name in foo); +for (const name of foo); + +export let exportLet = 1; +export const exportConst = 1; diff --git a/test/rules/no-var-keyword/tslint.json b/test/rules/no-var-keyword/tslint.json index 1de4119c014..de411ff36f9 100644 --- a/test/rules/no-var-keyword/tslint.json +++ b/test/rules/no-var-keyword/tslint.json @@ -1,5 +1,8 @@ { "rules": { "no-var-keyword": true + }, + "jsRules": { + "no-var-keyword": true } } diff --git a/test/rules/object-literal-key-quotes/always/test.js.lint b/test/rules/object-literal-key-quotes/always/test.js.lint new file mode 100644 index 00000000000..1f245022bd5 --- /dev/null +++ b/test/rules/object-literal-key-quotes/always/test.js.lint @@ -0,0 +1,23 @@ +const o = { + 'hello': 123, + goodbye: 234, // failure + ~~~~~~~ [Unquoted property 'goodbye' found.] + "quote": 345, + "needs quote": 789, + "hyphens-need-quotes": null, + [computed]: 456, + 123: "hello", // failure + ~~~ [Unquoted property '123' found.] + 1e4: "something", // failure + ~~~ [Unquoted property '1e4' found.] + .123: "float", // failure + ~~~~ [Unquoted property '.123' found.] + '123': 'numbers do not need quotes', + '010': 'but this one does.', + '.123': 'as does this one', + fn() { return }, + true: 0, // failure + ~~~~ [Unquoted property 'true' found.] + "0x0": 0, + "true": 0, +}; diff --git a/test/rules/object-literal-key-quotes/always/tslint.json b/test/rules/object-literal-key-quotes/always/tslint.json index a7927997726..3d2d57e481d 100644 --- a/test/rules/object-literal-key-quotes/always/tslint.json +++ b/test/rules/object-literal-key-quotes/always/tslint.json @@ -1,5 +1,8 @@ { "rules": { "object-literal-key-quotes": [true, "always"] + }, + "jsRules": { + "object-literal-key-quotes": [true, "always"] } } diff --git a/test/rules/object-literal-key-quotes/as-needed/test.js.lint b/test/rules/object-literal-key-quotes/as-needed/test.js.lint new file mode 100644 index 00000000000..86c24145018 --- /dev/null +++ b/test/rules/object-literal-key-quotes/as-needed/test.js.lint @@ -0,0 +1,23 @@ +const o = { + 'hello': 123, // failure + ~~~~~~~ [Unnecessarily quoted property 'hello' found.] + goodbye: 234, + "quote": 345, // failure + ~~~~~~~ [Unnecessarily quoted property 'quote' found.] + "needs quote": 789, + "hyphens-need-quotes": null, + [computed]: 456, + 123: "hello", + 1e4: "something", + .123: "float", + '123': 'numbers do not need quotes', // failure + ~~~~~ [Unnecessarily quoted property '123' found.] + '010': 'but this one does.', + '.123': 'as does this one', + fn() { return }, + true: 0, + "0x0": 0, + "true": 0, // failure + ~~~~~~ [Unnecessarily quoted property 'true' found.] + '': 'always quote the empty string', +}; diff --git a/test/rules/object-literal-key-quotes/as-needed/test.ts.lint b/test/rules/object-literal-key-quotes/as-needed/test.ts.lint index e6dc627b5d0..86c24145018 100644 --- a/test/rules/object-literal-key-quotes/as-needed/test.ts.lint +++ b/test/rules/object-literal-key-quotes/as-needed/test.ts.lint @@ -19,4 +19,5 @@ const o = { "0x0": 0, "true": 0, // failure ~~~~~~ [Unnecessarily quoted property 'true' found.] + '': 'always quote the empty string', }; diff --git a/test/rules/object-literal-key-quotes/as-needed/tslint.json b/test/rules/object-literal-key-quotes/as-needed/tslint.json index a366a23efb2..58ce23cc490 100644 --- a/test/rules/object-literal-key-quotes/as-needed/tslint.json +++ b/test/rules/object-literal-key-quotes/as-needed/tslint.json @@ -1,5 +1,8 @@ { "rules": { "object-literal-key-quotes": [true, "as-needed"] + }, + "jsRules": { + "object-literal-key-quotes": [true, "as-needed"] } } diff --git a/test/rules/object-literal-key-quotes/consistent-as-needed/test.js.lint b/test/rules/object-literal-key-quotes/consistent-as-needed/test.js.lint new file mode 100644 index 00000000000..c7ff0f38013 --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent-as-needed/test.js.lint @@ -0,0 +1,50 @@ + +const o = { + 'hello': 123, + ~~~~~~~ [Unnecessarily quoted property 'hello' found.] + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const v = { + "hello": 123, + ~~~~~~~ [Unnecessarily quoted property 'hello' found.] + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const s = { + hello: 123, + bye: 45, +}; +const r = { + "hello": 123, + "bye-bye": 45, +}; +const p = { + hello: 123, + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const q = { + hello: 123, + ~~~~~ [Unquoted property 'hello' found.] + "bye-bye": 45, +}; +const t = { + hello: 123, + bye-bye: 45, + nested: { + "bird": 2, + ~~~~~~ [Unnecessarily quoted property 'bird' found.] + egg: 3, + } +}; +const u = { + hello: 123, + bye: 45, + nested: { + "bird": 1, + ~~~~~~ [Unnecessarily quoted property 'bird' found.] + "egg": 2, + ~~~~~ [Unnecessarily quoted property 'egg' found.] + } +}; \ No newline at end of file diff --git a/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint b/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint new file mode 100644 index 00000000000..c7ff0f38013 --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint @@ -0,0 +1,50 @@ + +const o = { + 'hello': 123, + ~~~~~~~ [Unnecessarily quoted property 'hello' found.] + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const v = { + "hello": 123, + ~~~~~~~ [Unnecessarily quoted property 'hello' found.] + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const s = { + hello: 123, + bye: 45, +}; +const r = { + "hello": 123, + "bye-bye": 45, +}; +const p = { + hello: 123, + "bye": 45, + ~~~~~ [Unnecessarily quoted property 'bye' found.] +}; +const q = { + hello: 123, + ~~~~~ [Unquoted property 'hello' found.] + "bye-bye": 45, +}; +const t = { + hello: 123, + bye-bye: 45, + nested: { + "bird": 2, + ~~~~~~ [Unnecessarily quoted property 'bird' found.] + egg: 3, + } +}; +const u = { + hello: 123, + bye: 45, + nested: { + "bird": 1, + ~~~~~~ [Unnecessarily quoted property 'bird' found.] + "egg": 2, + ~~~~~ [Unnecessarily quoted property 'egg' found.] + } +}; \ No newline at end of file diff --git a/test/rules/object-literal-key-quotes/consistent-as-needed/tslint.json b/test/rules/object-literal-key-quotes/consistent-as-needed/tslint.json new file mode 100644 index 00000000000..f597be075cc --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent-as-needed/tslint.json @@ -0,0 +1,8 @@ +{ + "rules": { + "object-literal-key-quotes": [true, "consistent-as-needed"] + }, + "jsRules": { + "object-literal-key-quotes": [true, "consistent-as-needed"] + } +} diff --git a/test/rules/object-literal-key-quotes/consistent/test.js.lint b/test/rules/object-literal-key-quotes/consistent/test.js.lint new file mode 100644 index 00000000000..a2ee53079b5 --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent/test.js.lint @@ -0,0 +1,44 @@ + +const o = { + 'hello': 123, + "bye": 45, +}; +const v = { + "hello": 123, + "bye": 45, +}; +const s = { + hello: 123, + bye: 45, +}; +const r = { + "hello": 123, + "bye-bye": 45, +}; +const p = { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + hello: 123, + "bye": 45, +}; +const q = { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + hello: 123, + "bye-bye": 45, +}; +const t = { + hello: 123, + bye-bye: 45, + nested: { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + "bird": 2, + egg: 3, + } +}; +const u = { + hello: 123, + bye: 45, + nested: { + "bird": 1, + "egg": 2, + } +}; \ No newline at end of file diff --git a/test/rules/object-literal-key-quotes/consistent/test.ts.lint b/test/rules/object-literal-key-quotes/consistent/test.ts.lint new file mode 100644 index 00000000000..a2ee53079b5 --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent/test.ts.lint @@ -0,0 +1,44 @@ + +const o = { + 'hello': 123, + "bye": 45, +}; +const v = { + "hello": 123, + "bye": 45, +}; +const s = { + hello: 123, + bye: 45, +}; +const r = { + "hello": 123, + "bye-bye": 45, +}; +const p = { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + hello: 123, + "bye": 45, +}; +const q = { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + hello: 123, + "bye-bye": 45, +}; +const t = { + hello: 123, + bye-bye: 45, + nested: { + ~ [All property names in this object literal must be consistently quoted or unquoted.] + "bird": 2, + egg: 3, + } +}; +const u = { + hello: 123, + bye: 45, + nested: { + "bird": 1, + "egg": 2, + } +}; \ No newline at end of file diff --git a/test/rules/object-literal-key-quotes/consistent/tslint.json b/test/rules/object-literal-key-quotes/consistent/tslint.json new file mode 100644 index 00000000000..5c9b583e66b --- /dev/null +++ b/test/rules/object-literal-key-quotes/consistent/tslint.json @@ -0,0 +1,8 @@ +{ + "rules": { + "object-literal-key-quotes": [true, "consistent"] + }, + "jsRules": { + "object-literal-key-quotes": [true, "consistent"] + } +} diff --git a/test/rules/object-literal-shorthand/test.js.lint b/test/rules/object-literal-shorthand/test.js.lint new file mode 100644 index 00000000000..91966f41e6b --- /dev/null +++ b/test/rules/object-literal-shorthand/test.js.lint @@ -0,0 +1,46 @@ +const bad = { + w: function() {}, + ~~~~~~~~~~~~~~~~ [method] + x: function *() {}, + ~~~~~~~~~~~~~~~~~~ [method] + [y]: function() {}, + ~~~~~~~~~~~~~~~~~~ [method] + z: z + ~~~~ [property] +}; + +const good = { + w() {}, + *x() {}, + [y]() {}, + z +}; + +const arrows = { + x: (y) => y // this is OK. +}; + +const namedFunctions = { + x: function y() {} // named function expressions are also OK. +}; + +const quotes = { + "foo-bar": function() {}, + ~~~~~~~~~~~~~~~~~~~~~~~~ [method] + "foo-bar"() {} +}; + +const extraCases = { + x, + a: 123, + b: "hello", + c: 'c', + ["a" + "nested"]: { + x: x + ~~~~ [property] + } +}; + + +[property]: Expected property shorthand in object literal. +[method]: Expected method shorthand in object literal. \ No newline at end of file diff --git a/test/rules/object-literal-shorthand/tslint.json b/test/rules/object-literal-shorthand/tslint.json index 3dc26ff61a2..0002634ddd3 100644 --- a/test/rules/object-literal-shorthand/tslint.json +++ b/test/rules/object-literal-shorthand/tslint.json @@ -1,5 +1,8 @@ { "rules": { "object-literal-shorthand": true + }, + "jsRules": { + "object-literal-shorthand": true } } diff --git a/test/rules/object-literal-sort-keys/test.js.lint b/test/rules/object-literal-sort-keys/test.js.lint new file mode 100644 index 00000000000..813815e14dd --- /dev/null +++ b/test/rules/object-literal-sort-keys/test.js.lint @@ -0,0 +1,85 @@ +var passA = { + a: 1, + b: 2 +}; + +var failA = { + b: 1, + a: 2 + ~ [The key 'a' is not sorted alphabetically] +}; + +var passB = { + a: 1, + b: 2, + c: 3, + d: 4 +}; + +var failB = { + c: 3, + a: 1, + ~ [The key 'a' is not sorted alphabetically] + b: 2, + d: 4 +}; + +var passC = { + a: 1, + b: { + aa: 1, + bb: 2 + } +}; + +var failC = { + a: 1, + b: { + bb: 2, + aa: 1 + ~~ [The key 'aa' is not sorted alphabetically] + } +}; + +var passD = { + a: 1, + b: { + aa: 1, + bb: 2 + }, + c: 3 +}; + +var failD = { + a: 1, + c: { + aa: 1, + bb: 2 + }, + b: 3 + ~ [The key 'b' is not sorted alphabetically] +}; + +var passE = {}; + +var passF = { + asdf: [1, 2, 3], + sdfa: {} +}; + +var failF = { + sdfa: {}, + asdf: [1, 2, 3] + ~~~~ [The key 'asdf' is not sorted alphabetically] +}; + +var passG = { + asdfn: function () {}, + sdafn: function () {} +}; + +var failG = { + sdafn: function () {}, + asdfn: function () {} + ~~~~~ [The key 'asdfn' is not sorted alphabetically] +}; diff --git a/test/rules/object-literal-sort-keys/test.ts.lint b/test/rules/object-literal-sort-keys/test.ts.lint index 5e8c9fccb10..5668b48773e 100644 --- a/test/rules/object-literal-sort-keys/test.ts.lint +++ b/test/rules/object-literal-sort-keys/test.ts.lint @@ -144,3 +144,20 @@ var failK = { ~ [The key 'a' is not sorted alphabetically] c: 3 } + +var passL = {z: 1, y: '1', x: [1, 2]}; + +var failL = {x: 1, y: { + b: 1, + a: 2 + ~ [The key 'a' is not sorted alphabetically] +}, z: [1, 2]}; + +var passM = { + x: 1, + y: { + a: 1, + b: 2 + }, + z: {z: 1, y: '1', x: [1, 2]} +}; diff --git a/test/rules/object-literal-sort-keys/tslint.json b/test/rules/object-literal-sort-keys/tslint.json index 280382fe390..66db23de8d1 100644 --- a/test/rules/object-literal-sort-keys/tslint.json +++ b/test/rules/object-literal-sort-keys/tslint.json @@ -1,5 +1,8 @@ { "rules": { "object-literal-sort-keys": true + }, + "jsRules": { + "object-literal-sort-keys": true } } diff --git a/test/rules/one-line/all/test.js.lint b/test/rules/one-line/all/test.js.lint new file mode 100644 index 00000000000..7dc9c65848d --- /dev/null +++ b/test/rules/one-line/all/test.js.lint @@ -0,0 +1,110 @@ +export function Call() +{ +~ [misplaced opening brace] + if (x == 3) + { + ~ [misplaced opening brace] + x = 4; + } + else { + ~~~~ [misplaced 'else'] + x = 5; + } + return "called"; +} + +var object = +{ +~ [misplaced opening brace] + a: 1, + b: 2 +}; + +for(var x= 0; x < 1; ++x) +{ +~ [misplaced opening brace] + ++i; +} + +switch(y) +{ +~ [misplaced opening brace] + case 0: + x--; + break; + default: + x++; + break; +} + +try +{ +~ [misplaced opening brace] + throw new Error("hi"); +} +catch (e) +~~~~~ [misplaced 'catch'] +{ +~ [misplaced opening brace] + throw(e); +} +finally +~~~~~~~ [misplaced 'finally'] +{ +~ [misplaced opening brace] + // do something +} + +try { + foo(); +} +finally +~~~~~~~ [misplaced 'finally'] +{ +~ [misplaced opening brace] + bar(); +} + +try{ + ~ [missing whitespace] + foo(); +} catch(e){ + ~ [missing whitespace] + bar(); +} finally{ + ~ [missing whitespace] + baz(); +} + +while(x < 10){ + ~ [missing whitespace] + x++; +} + +class BarBooBaz +{ +~ [misplaced opening brace] + +} + +class FooBarBaz { +} + +// Valid multiline declarations +export class LongDescriptiveClassName + extends SomeAbstractBaseClass { +} + +function longFunctionNameWithLotsOfParams( + x, + y, + z, + a) { +} + +let geoConfig += { + maximumAge: 3000, + timeout: 5000, + enableHighAccuracy: false +}; diff --git a/test/rules/one-line/all/test.ts.lint b/test/rules/one-line/all/test.ts.lint index 769f784e529..f33ea57e051 100644 --- a/test/rules/one-line/all/test.ts.lint +++ b/test/rules/one-line/all/test.ts.lint @@ -140,3 +140,6 @@ let geoConfig: { timeout: 5000, enableHighAccuracy: false }; + +declare module "*"; +declare module "someLibrary/*"; diff --git a/test/rules/one-line/all/tslint.json b/test/rules/one-line/all/tslint.json index d8a064cc2e5..720acee53ac 100644 --- a/test/rules/one-line/all/tslint.json +++ b/test/rules/one-line/all/tslint.json @@ -1,5 +1,8 @@ { "rules": { "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-finally", "check-whitespace"] + }, + "jsRules": { + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-finally", "check-whitespace"] } } diff --git a/test/rules/one-line/none/test.js.lint b/test/rules/one-line/none/test.js.lint new file mode 100644 index 00000000000..73ddb983470 --- /dev/null +++ b/test/rules/one-line/none/test.js.lint @@ -0,0 +1,92 @@ +export function Call() +{ + if (x == 3) + { + x = 4; + } + else { + x = 5; + } + return "called"; +} + +var object = +{ + a: 1, + b: 2 +}; + +for(var x= 0; x < 1; ++x) +{ + ++i; +} + +switch(y) +{ + case 0: + x--; + break; + default: + x++; + break; +} + +try +{ + throw new Error("hi"); +} +catch (e) +{ + throw(e); +} +finally +{ + // do something +} + +try { + foo(); +} +finally +{ + bar(); +} + +try{ + foo(); +} catch(e){ + bar(); +} finally{ + baz(); +} + +while(x < 10){ + x++; +} + +class BarBooBaz +{ + +} + +class FooBarBaz { +} + +// Valid multiline declarations +export class LongDescriptiveClassName + extends SomeAbstractBaseClass { +} + +function longFunctionNameWithLotsOfParams( + x, + y, + z, + a) { +} + +let geoConfig += { + maximumAge: 3000, + timeout: 5000, + enableHighAccuracy: false +}; diff --git a/test/rules/one-line/none/test.ts.lint b/test/rules/one-line/none/test.ts.lint index 751e45661ff..a6a5ddca080 100644 --- a/test/rules/one-line/none/test.ts.lint +++ b/test/rules/one-line/none/test.ts.lint @@ -119,3 +119,6 @@ let geoConfig: { timeout: 5000, enableHighAccuracy: false }; + +declare module "*"; +declare module "someLibrary/*"; diff --git a/test/rules/one-line/none/tslint.json b/test/rules/one-line/none/tslint.json index ea05ac32938..806765d9003 100644 --- a/test/rules/one-line/none/tslint.json +++ b/test/rules/one-line/none/tslint.json @@ -1,5 +1,8 @@ { "rules": { "one-line": true + }, + "jsRules": { + "one-line": true } } diff --git a/test/rules/one-variable-per-declaration/default/test.js.lint b/test/rules/one-variable-per-declaration/default/test.js.lint new file mode 100644 index 00000000000..155ff047a7c --- /dev/null +++ b/test/rules/one-variable-per-declaration/default/test.js.lint @@ -0,0 +1,40 @@ +// valid cases +var foo1; +var foo2; +var foo3 = 1; + +let foo4; +let foo5; +let foo6 = 1; + +const foo7 = 1; +const foo8 = 1; + +for (var i = 0; i > 1; i++) {} +for (let i = 0; i > 1; i++) {} +for (const i = 0; i > 1;) {} + +// invalid cases +var foo9, foo10; +~~~~~~~~~~~~~~~~ [0] + +var foo13 = 1, foo14 = 1; +~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +let foo15, foo16; +~~~~~~~~~~~~~~~~~ [0] +let foo19 = 1, foo20 = 1; +~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +const foo23 = 1, foo24 = 1; +~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +for (var i = 0, j = 0; i > 1; i++) {} + ~~~~~~~~~~~~~~~~ [0] +for (let i = 0, j = 0; i > 1; i++) {} + ~~~~~~~~~~~~~~~~ [0] +for (const i = 0, j = 0; i > 1;) {} + ~~~~~~~~~~~~~~~~~~ [0] + +[0]: Multiple variable declarations in the same statement are forbidden + diff --git a/test/rules/one-variable-per-declaration/default/tslint.json b/test/rules/one-variable-per-declaration/default/tslint.json index 3d64c8fa578..20d18dce276 100644 --- a/test/rules/one-variable-per-declaration/default/tslint.json +++ b/test/rules/one-variable-per-declaration/default/tslint.json @@ -1,5 +1,8 @@ { "rules": { "one-variable-per-declaration": true + }, + "jsRules": { + "one-variable-per-declaration": true } } diff --git a/test/rules/one-variable-per-declaration/ignore-for-loop/test.js.lint b/test/rules/one-variable-per-declaration/ignore-for-loop/test.js.lint new file mode 100644 index 00000000000..746d2b87f59 --- /dev/null +++ b/test/rules/one-variable-per-declaration/ignore-for-loop/test.js.lint @@ -0,0 +1,25 @@ +// valid cases +for (var i = 0; i > 1; i++) {} +for (let i = 0; i > 1; i++) {} +for (const i = 0; i > 1;) {} +for (var i = 0, j = 0; i > 1; i++) {} +for (let i = 0, j = 0; i > 1; i++) {} +for (const i = 0, j = 0; i > 1;) {} + +// invalid cases +var foo1, foo2; +~~~~~~~~~~~~~~~ [0] + +var foo5 = 1, foo6 = 1; +~~~~~~~~~~~~~~~~~~~~~~~ [0] + +let foo7, foo8; +~~~~~~~~~~~~~~~ [0] +let foo11 = 1, foo12 = 1; +~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +const foo15 = 1, foo16 = 1; +~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + +[0]: Multiple variable declarations in the same statement are forbidden + diff --git a/test/rules/one-variable-per-declaration/ignore-for-loop/tslint.json b/test/rules/one-variable-per-declaration/ignore-for-loop/tslint.json index 657afeded5d..6e2204090d1 100644 --- a/test/rules/one-variable-per-declaration/ignore-for-loop/tslint.json +++ b/test/rules/one-variable-per-declaration/ignore-for-loop/tslint.json @@ -3,5 +3,10 @@ "one-variable-per-declaration": [true, "ignore-for-loop" ] + }, + "jsRules": { + "one-variable-per-declaration": [true, + "ignore-for-loop" + ] } } diff --git a/test/rules/only-arrow-functions/allow-declarations/test.js.lint b/test/rules/only-arrow-functions/allow-declarations/test.js.lint new file mode 100644 index 00000000000..d976870301b --- /dev/null +++ b/test/rules/only-arrow-functions/allow-declarations/test.js.lint @@ -0,0 +1,16 @@ +function foo(a) { + return; +} + +let a = () => {}; +let b = function () {}; + ~~~~~~~~ [0] + +function c() {} + +((func) => func())(function e() {}); + ~~~~~~~~ [0] + +((func) => func())(() => {}); + +[0]: non-arrow functions are forbidden diff --git a/test/rules/only-arrow-functions/allow-declarations/test.ts.lint b/test/rules/only-arrow-functions/allow-declarations/test.ts.lint index 22dbf05bec4..6b0ce7a08a8 100644 --- a/test/rules/only-arrow-functions/allow-declarations/test.ts.lint +++ b/test/rules/only-arrow-functions/allow-declarations/test.ts.lint @@ -20,4 +20,7 @@ function () { function* generator() {} let generator = function*() {} +function hasThisParameter(this) {} +let hasThisParameter = function(this) {} + [0]: non-arrow functions are forbidden diff --git a/test/rules/only-arrow-functions/allow-declarations/tslint.json b/test/rules/only-arrow-functions/allow-declarations/tslint.json index 89262ad4c12..57892e2c824 100644 --- a/test/rules/only-arrow-functions/allow-declarations/tslint.json +++ b/test/rules/only-arrow-functions/allow-declarations/tslint.json @@ -1,5 +1,8 @@ { "rules": { "only-arrow-functions": [true, "allow-declarations"] + }, + "jsRules": { + "only-arrow-functions": [true, "allow-declarations"] } } diff --git a/test/rules/only-arrow-functions/default/test.js.lint b/test/rules/only-arrow-functions/default/test.js.lint new file mode 100644 index 00000000000..c631afef0e8 --- /dev/null +++ b/test/rules/only-arrow-functions/default/test.js.lint @@ -0,0 +1,18 @@ +function foo(a) { +~~~~~~~~ [0] + return; +} + +let a = () => {}; +let b = function () {}; + ~~~~~~~~ [0] + +function c() {} +~~~~~~~~ [0] + +((func) => func())(function e() {}); + ~~~~~~~~ [0] + +((func) => func())(() => {}); + +[0]: non-arrow functions are forbidden diff --git a/test/rules/only-arrow-functions/default/test.ts.lint b/test/rules/only-arrow-functions/default/test.ts.lint index ddacd8e2fc5..bad11677983 100644 --- a/test/rules/only-arrow-functions/default/test.ts.lint +++ b/test/rules/only-arrow-functions/default/test.ts.lint @@ -23,4 +23,7 @@ function () { function* generator() {} let generator = function*() {} +function hasThisParameter(this) {} +let hasThisParameter = function(this) {} + [0]: non-arrow functions are forbidden diff --git a/test/rules/only-arrow-functions/default/tslint.json b/test/rules/only-arrow-functions/default/tslint.json index 2e69b360a49..42da3aeb813 100644 --- a/test/rules/only-arrow-functions/default/tslint.json +++ b/test/rules/only-arrow-functions/default/tslint.json @@ -1,5 +1,8 @@ { "rules": { "only-arrow-functions": true + }, + "jsRules": { + "only-arrow-functions": true } } diff --git a/test/rules/ordered-imports/case-insensitive/test.js.lint b/test/rules/ordered-imports/case-insensitive/test.js.lint new file mode 100644 index 00000000000..2efabb17c31 --- /dev/null +++ b/test/rules/ordered-imports/case-insensitive/test.js.lint @@ -0,0 +1,33 @@ +// Named imports should be alphabetized. +import {A, B} from 'foo'; +import {B, A} from 'foo'; // failure + ~~~~ [ordered-imports] + +// Case is irrelevant for named import ordering. +import {A, b, C} from 'foo'; +import {b, A, C} from 'foo'; // failure + ~~~~ [ordered-imports] + + +// Import sources should be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as foo from 'foo'; +import * as bar from 'bar'; // failure +~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ordered-sources] + +// Case is irrelevant for source import ordering. +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +import {A, B} from 'Foo'; // should not fail + +// Other styles of import statements. +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; +import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] +import "something"; + +[ordered-imports]: Named imports must be alphabetized. +[ordered-sources]: Import sources within a group must be alphabetized. diff --git a/test/rules/ordered-imports/case-insensitive/test.ts.fix b/test/rules/ordered-imports/case-insensitive/test.ts.fix new file mode 100644 index 00000000000..fe75ec2d0f2 --- /dev/null +++ b/test/rules/ordered-imports/case-insensitive/test.ts.fix @@ -0,0 +1,44 @@ +// Named imports should be alphabetized. +import {A, B} from 'foo'; +import {A, B} from 'foo'; // failure + +// Case is irrelevant for named import ordering. +import {A, bz, C} from 'foo'; // failure +import {A, b, C} from 'zfoo'; + +import {g} from "y"; // failure +import { + a as d, + b as c, +} from "z"; + +// Import sources should be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as bar from 'bar'; // failure +import * as foo from 'foo'; + +// ignore quotes +import * as bar from 'bar'; +import * as foo from "foo"; + +import * as bar from "bar"; +import * as foo from 'foo'; + +// Case is irrelevant for source import ordering. +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +import {A, B} from 'Foo'; // should not fail + +// Other styles of import statements. +import someDefault from "module"; +import "something"; +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; + +// do not fix cases where a newline is missing +import * as foo from 'foo'; import * as bar from 'bar'; + +import * as foo from 'foo'; +import * as bar from 'bar'; \ No newline at end of file diff --git a/test/rules/ordered-imports/case-insensitive/test.ts.lint b/test/rules/ordered-imports/case-insensitive/test.ts.lint index bd7ee497234..441d926d90d 100644 --- a/test/rules/ordered-imports/case-insensitive/test.ts.lint +++ b/test/rules/ordered-imports/case-insensitive/test.ts.lint @@ -4,10 +4,19 @@ import {B, A} from 'foo'; // failure ~~~~ [ordered-imports] // Case is irrelevant for named import ordering. -import {A, b, C} from 'foo'; -import {b, A, C} from 'foo'; // failure - ~~~~ [ordered-imports] +import {A, b, C} from 'zfoo'; +import {bz, A, C} from 'foo'; // failure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] + ~~~~~ [Named imports must be alphabetized.] +import { + b as c, + ~~~~~~~ + a as d, +~~~~~~~~~~ [Named imports must be alphabetized.] +} from "z"; +import {g} from "y"; // failure +~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] // Import sources should be alphabetized. import * as bar from 'bar'; @@ -18,6 +27,13 @@ import * as foo from 'foo'; import * as bar from 'bar'; // failure ~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ordered-sources] +// ignore quotes +import * as bar from 'bar'; +import * as foo from "foo"; + +import * as bar from "bar"; +import * as foo from 'foo'; + // Case is irrelevant for source import ordering. import {A, B} from 'Bar'; import {A, B} from 'baz'; @@ -26,7 +42,15 @@ import {A, B} from 'Foo'; // should not fail // Other styles of import statements. import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] import "something"; +// do not fix cases where a newline is missing +import * as foo from 'foo'; import * as bar from 'bar'; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] + +import * as foo from 'foo'; +import * as bar from 'bar'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] [ordered-imports]: Named imports must be alphabetized. -[ordered-sources]: Import sources within a group must be alphabetized. +[ordered-sources]: Import sources within a group must be alphabetized. \ No newline at end of file diff --git a/test/rules/ordered-imports/case-insensitive/tslint.json b/test/rules/ordered-imports/case-insensitive/tslint.json index 714e6c81bc9..ddc15fe9f00 100644 --- a/test/rules/ordered-imports/case-insensitive/tslint.json +++ b/test/rules/ordered-imports/case-insensitive/tslint.json @@ -1,5 +1,8 @@ { "rules": { "ordered-imports": true + }, + "jsRules": { + "ordered-imports": true } } diff --git a/test/rules/ordered-imports/import-sources-any/test.ts.fix b/test/rules/ordered-imports/import-sources-any/test.ts.fix new file mode 100644 index 00000000000..a523be9f420 --- /dev/null +++ b/test/rules/ordered-imports/import-sources-any/test.ts.fix @@ -0,0 +1,26 @@ +// Named imports should be alphabetized. +import {A, B} from 'foo'; +import {A, B} from 'foo'; // failure + +// Case is irrelevant for named import ordering. +import {A, b, C} from 'zfoo'; +import {A, bz, C} from 'foo'; // failure + +// Import sources don't need to be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as foo from 'foo'; +import * as bar from 'bar'; // should not fail + +// Case is irrelevant for source import ordering. +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +import {A, B} from 'Foo'; // should not fail + +// Other styles of import statements. +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; +import someDefault from "module"; +import "something"; + diff --git a/test/rules/ordered-imports/import-sources-any/test.ts.lint b/test/rules/ordered-imports/import-sources-any/test.ts.lint new file mode 100644 index 00000000000..2e6ab32acad --- /dev/null +++ b/test/rules/ordered-imports/import-sources-any/test.ts.lint @@ -0,0 +1,30 @@ +// Named imports should be alphabetized. +import {A, B} from 'foo'; +import {B, A} from 'foo'; // failure + ~~~~ [ordered-imports] + +// Case is irrelevant for named import ordering. +import {A, b, C} from 'zfoo'; +import {bz, A, C} from 'foo'; // failure + ~~~~~ [ordered-imports] + +// Import sources don't need to be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as foo from 'foo'; +import * as bar from 'bar'; // should not fail + +// Case is irrelevant for source import ordering. +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +import {A, B} from 'Foo'; // should not fail + +// Other styles of import statements. +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; +import someDefault from "module"; +import "something"; + +[ordered-imports]: Named imports must be alphabetized. +[ordered-sources]: Import sources within a group must be alphabetized. diff --git a/test/rules/ordered-imports/import-sources-any/tslint.json b/test/rules/ordered-imports/import-sources-any/tslint.json new file mode 100644 index 00000000000..a88bcb08b5d --- /dev/null +++ b/test/rules/ordered-imports/import-sources-any/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "ordered-imports": [true, {"import-sources-order": "any"}] + } +} diff --git a/test/rules/ordered-imports/lowercase-first/test.js.lint b/test/rules/ordered-imports/lowercase-first/test.js.lint new file mode 100644 index 00000000000..eff6e21b639 --- /dev/null +++ b/test/rules/ordered-imports/lowercase-first/test.js.lint @@ -0,0 +1,33 @@ +// Named imports should be alphabetized. +import {A, B} from 'foo'; +import {B, A} from 'foo'; // failure + ~~~~ [ordered-imports] + +// Lowercase comes before uppercase. +import {b, A, C} from 'foo'; +import {A, b, C} from 'foo'; // failure + ~~~~ [ordered-imports] + +// Import sources should be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as foo from 'foo'; +import * as bar from 'bar'; // failure +~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ordered-sources] + +// Lowercase comes before uppercase +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +~~~~~~~~~~~~~~~~~~~~~~~~~ [ordered-sources] +import {A, B} from 'Foo'; + +// Other styles of import statements. +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; +import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] +import "something"; + +[ordered-imports]: Named imports must be alphabetized. +[ordered-sources]: Import sources within a group must be alphabetized. diff --git a/test/rules/ordered-imports/lowercase-first/test.ts.fix b/test/rules/ordered-imports/lowercase-first/test.ts.fix new file mode 100644 index 00000000000..324ec13d968 --- /dev/null +++ b/test/rules/ordered-imports/lowercase-first/test.ts.fix @@ -0,0 +1,26 @@ +// Named imports should be alphabetized. +import {A, B} from 'foo'; +import {A, B} from 'foo'; // failure + +// Lowercase comes before uppercase. +import {bz, A, C} from 'foo'; // failure +import {b, A, C} from 'zfoo'; + +// Import sources should be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as bar from 'bar'; // failure +import * as foo from 'foo'; + +// Lowercase comes before uppercase +import {A, B} from 'baz'; +import {A, B} from 'Bar'; +import {A, B} from 'Foo'; + +// Other styles of import statements. +import someDefault from "module"; +import "something"; +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; + diff --git a/test/rules/ordered-imports/lowercase-first/test.ts.lint b/test/rules/ordered-imports/lowercase-first/test.ts.lint index ef8de7ea134..1ae184b3ba7 100644 --- a/test/rules/ordered-imports/lowercase-first/test.ts.lint +++ b/test/rules/ordered-imports/lowercase-first/test.ts.lint @@ -4,9 +4,10 @@ import {B, A} from 'foo'; // failure ~~~~ [ordered-imports] // Lowercase comes before uppercase. -import {b, A, C} from 'foo'; -import {A, b, C} from 'foo'; // failure - ~~~~ [ordered-imports] +import {A, b, C} from 'zfoo'; + ~~~~ [Named imports must be alphabetized.] +import {bz, A, C} from 'foo'; // failure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] // Import sources should be alphabetized. import * as bar from 'bar'; @@ -26,6 +27,7 @@ import {A, B} from 'Foo'; // Other styles of import statements. import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] import "something"; [ordered-imports]: Named imports must be alphabetized. diff --git a/test/rules/ordered-imports/lowercase-first/tslint.json b/test/rules/ordered-imports/lowercase-first/tslint.json index 62b8787a617..36358521d9a 100644 --- a/test/rules/ordered-imports/lowercase-first/tslint.json +++ b/test/rules/ordered-imports/lowercase-first/tslint.json @@ -1,5 +1,8 @@ { "rules": { "ordered-imports": [true, {"import-sources-order": "lowercase-first", "named-imports-order": "lowercase-first"}] + }, + "jsRules": { + "ordered-imports": [true, {"import-sources-order": "lowercase-first", "named-imports-order": "lowercase-first"}] } } diff --git a/test/rules/ordered-imports/named-imports-any/test.ts.fix b/test/rules/ordered-imports/named-imports-any/test.ts.fix new file mode 100644 index 00000000000..9e4e0e93811 --- /dev/null +++ b/test/rules/ordered-imports/named-imports-any/test.ts.fix @@ -0,0 +1,26 @@ +// Named imports do not need to be alphabetized. +import {A, B} from 'foo'; +import {B, A} from 'foo'; // should not fail + +// Case is irrelevant for named import ordering. +import {bz, A, C} from 'foo'; // should not fail +import {A, b, C} from 'zfoo'; + +// Import sources should be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as bar from 'bar'; // failure +import * as foo from 'foo'; + +// Case is irrelevant for source import ordering. +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +import {A, B} from 'Foo'; // should not fail + +// Other styles of import statements. +import someDefault from "module"; +import "something"; +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; + diff --git a/test/rules/ordered-imports/named-imports-any/test.ts.lint b/test/rules/ordered-imports/named-imports-any/test.ts.lint new file mode 100644 index 00000000000..e6707e9d62d --- /dev/null +++ b/test/rules/ordered-imports/named-imports-any/test.ts.lint @@ -0,0 +1,31 @@ +// Named imports do not need to be alphabetized. +import {A, B} from 'foo'; +import {B, A} from 'foo'; // should not fail + +// Case is irrelevant for named import ordering. +import {A, b, C} from 'zfoo'; +import {bz, A, C} from 'foo'; // should not fail +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] + +// Import sources should be alphabetized. +import * as bar from 'bar'; +import * as foo from 'foo'; + +import * as abc from 'abc'; +import * as foo from 'foo'; +import * as bar from 'bar'; // failure +~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ordered-sources] + +// Case is irrelevant for source import ordering. +import {A, B} from 'Bar'; +import {A, B} from 'baz'; +import {A, B} from 'Foo'; // should not fail + +// Other styles of import statements. +import someDefault, {nameA, nameBReallyLong as anotherName} from "./wherever"; +import someDefault from "module"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Import sources within a group must be alphabetized.] +import "something"; + +[ordered-imports]: Named imports must be alphabetized. +[ordered-sources]: Import sources within a group must be alphabetized. diff --git a/test/rules/ordered-imports/named-imports-any/tslint.json b/test/rules/ordered-imports/named-imports-any/tslint.json new file mode 100644 index 00000000000..89be91b2528 --- /dev/null +++ b/test/rules/ordered-imports/named-imports-any/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "ordered-imports": [true, {"named-imports-order": "any"}] + } +} diff --git a/test/rules/prefer-for-of/test.ts.lint b/test/rules/prefer-for-of/test.ts.lint index 0457f270347..ac67a99dacb 100644 --- a/test/rules/prefer-for-of/test.ts.lint +++ b/test/rules/prefer-for-of/test.ts.lint @@ -1,70 +1,46 @@ function sampleFunc() { - //This loop only uses the iterator to access the array item, so we can recommend a for-of loop here - for (var a = 0; a <= obj.arr.length; a++) { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // This loop only uses the iterator to access the array item, so we can recommend a for-of loop here + for (var a = 0; a < obj.arr.length; a++) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] console.log(obj.arr[a]); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~~~ [0] - //Same as above, but no curly braces - for (var b = 0; b <= obj.arr.length; b++) console.log(obj.arr[b]); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + // Same as above, but no curly braces + for (var b = 0; b < obj.arr.length; b++) console.log(obj.arr[b]); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] - //the index is used by itself, so a normal for loop is allowed here - for (var c = 0; c <= arr.length; c++) { + // the index is used by itself, so a normal for loop is allowed here + for (var c = 0; c < arr.length; c++) { doMath(c); } - //Same as above, but no curly braces - for (var d = 0; d <= arr.length; d++) doMath(d); + // Same as above, but no curly braces + for (var d = 0; d < arr.length; d++) doMath(d); - //the index is used by itself, so a normal for loop is allowed here - for (var e = 0; e <= arr.length; e++) { + // the index is used by itself, so a normal for loop is allowed here + for (var e = 0; e < arr.length; e++) { if(e > 5) { doMath(e); } console.log(arr[e]); } - //This iterates off of a hard-coded number and should be allowed + // This iterates off of a hard-coded number and should be allowed for (var f = 0; f <= 40; f++) { doMath(f); } - //Same as above, but no curly braces + // Same as above, but no curly braces for (var g = 0; g <= 40; g++) doMath(g); - //Loop set up different, but uses the index alone - this is ok - for(var h=0, len=arr.length; h < len; h++) { - doMath(h); - } - - //Same as above, but no curly braces - for(var i=0, len=arr.length; i < len; i++) doMath(i); - - //Loop set up different, but uses the index alone - this is ok - for(var j=0, len=arr.length; j < len; j++){ - if(j > 5) { - doMath(j); - } - console.log(arr[j]); - } + // multiple operations in the initializer + for(var h=0, len=arr.length; h < len; h++) {} - //Loop set up different, only uses the index to access the array - this should fail - for(var k=0, len=arr.length; k < len; k++) { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - console.log(arr[k]); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - } -~~~~~ [0] - - //Same as above, but no curly braces - for(var l=0, len=arr.length; l < len; l++) console.log(arr[l]); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + // Same as above, but no curly braces + for(var i=0, len=arr.length; i < len; i++) arr[i]; - //Odd for loop setups + // Odd for loop setups var m = 0; for (;;) { if (m > 3) break; @@ -79,28 +55,68 @@ function sampleFunc() { var o = 0; for (; o < arr.length; o++) { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ console.log(arr[o]); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~~~ [0] - //Prefix incrementor + // Prefix incrementor for(let p = 0; p < arr.length; ++p) { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] arr[p].whatever(); -~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~~~ [0] - //For in loops ARE allowed + // empty + for(let x = 0; x < arr.length; x++) {} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + + // missing + for(; x < arr.length; x++) {} + for(let x = 0;; x++) {} + for(let x = 0; x < arr.length;) {} + + // mismatch + for(let x = 0; NOTX < arr.length; x++) {} + for(let x = 0; x < arr.length; NOTX++) {} + for(let NOTX = 0; x < arr.length; x++) {} + + // decrement + for(let x = 0; x < arr.length; x--) {} + + // not `<` + for(let x = 0; x <= arr.length; x++) {} + + // wrong starting point + for(let x = 1; x < arr.length; x++) {} + + // not `length` property + for(let x = 0; x < arr.length(); x++) {} + + // alternate incrementor + for(let x = 0; x < arr.length; x+=1) {} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + for(let x = 0; x < arr.length; x=x+1) {} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + for(let x = 0; x < arr.length; x=1+x) {} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0] + + // adds too much + for(let x = 0; x < arr.length; x+=11) {} + for(let x = 0; x < arr.length; x=x+11) {} + + for(let x = 0; x < arr.length; x++) { + x++; + } + + // unexpected condition + for(let x = 0; true; x++) {} + + // For-in loops ARE allowed for (var q in obj) { if (obj.hasOwnProperty(q)) { console.log(q); } } - //For of loops ARE allowed + // For-of loops ARE allowed for (var r of arr) { console.log(r); } diff --git a/test/rules/quotemark/double-avoid-escape/test.js.lint b/test/rules/quotemark/double-avoid-escape/test.js.lint new file mode 100644 index 00000000000..03f86c4826e --- /dev/null +++ b/test/rules/quotemark/double-avoid-escape/test.js.lint @@ -0,0 +1,5 @@ +var single = 'single'; + ~~~~~~~~ [' should be "] + var doublee = "married"; +var singleWithinDouble = "'singleWithinDouble'"; +var doubleWithinSingle = '"doubleWithinSingle"'; diff --git a/test/rules/quotemark/double-avoid-escape/tslint.json b/test/rules/quotemark/double-avoid-escape/tslint.json index 6c0f14e3051..d49fa4a7e1d 100644 --- a/test/rules/quotemark/double-avoid-escape/tslint.json +++ b/test/rules/quotemark/double-avoid-escape/tslint.json @@ -1,5 +1,8 @@ { "rules": { "quotemark": [true, "double", "avoid-escape"] + }, + "jsRules": { + "quotemark": [true, "double", "avoid-escape"] } } diff --git a/test/rules/quotemark/double/test.js.lint b/test/rules/quotemark/double/test.js.lint new file mode 100644 index 00000000000..2efd3df18b3 --- /dev/null +++ b/test/rules/quotemark/double/test.js.lint @@ -0,0 +1,6 @@ +var single = 'single'; + ~~~~~~~~ [' should be "] + var doublee = "married"; +var singleWithinDouble = "'singleWithinDouble'"; +var doubleWithinSingle = '"doubleWithinSingle"'; + ~~~~~~~~~~~~~~~~~~~~~~ [' should be "] diff --git a/test/rules/quotemark/double/tslint.json b/test/rules/quotemark/double/tslint.json index 9318e0d53e4..4e380ea41bb 100644 --- a/test/rules/quotemark/double/tslint.json +++ b/test/rules/quotemark/double/tslint.json @@ -1,5 +1,8 @@ { "rules": { "quotemark": [true, "double"] + }, + "jsRules": { + "quotemark": [true, "double"] } } diff --git a/test/rules/quotemark/single-avoid-escape/test.js.lint b/test/rules/quotemark/single-avoid-escape/test.js.lint new file mode 100644 index 00000000000..52e21fb78a9 --- /dev/null +++ b/test/rules/quotemark/single-avoid-escape/test.js.lint @@ -0,0 +1,5 @@ +var single = 'single'; + var doublee = "married"; + ~~~~~~~~~ [" should be '] +var singleWithinDouble = "'singleWithinDouble'"; +var doubleWithinSingle = '"doubleWithinSingle"'; diff --git a/test/rules/quotemark/single-avoid-escape/tslint.json b/test/rules/quotemark/single-avoid-escape/tslint.json index c360887f9d7..01b36ddb9fb 100644 --- a/test/rules/quotemark/single-avoid-escape/tslint.json +++ b/test/rules/quotemark/single-avoid-escape/tslint.json @@ -1,5 +1,8 @@ { "rules": { "quotemark": [true, "single", "avoid-escape"] + }, + "jsRules": { + "quotemark": [true, "single", "avoid-escape"] } } diff --git a/test/rules/quotemark/single/test.js.lint b/test/rules/quotemark/single/test.js.lint new file mode 100644 index 00000000000..bba732c703b --- /dev/null +++ b/test/rules/quotemark/single/test.js.lint @@ -0,0 +1,6 @@ +var single = 'single'; + var doublee = "married"; + ~~~~~~~~~ [" should be '] +var singleWithinDouble = "'singleWithinDouble'"; + ~~~~~~~~~~~~~~~~~~~~~~ [" should be '] +var doubleWithinSingle = '"doubleWithinSingle"'; diff --git a/test/rules/quotemark/single/tslint.json b/test/rules/quotemark/single/tslint.json index 4a5f880d8ab..b27e2003874 100644 --- a/test/rules/quotemark/single/tslint.json +++ b/test/rules/quotemark/single/tslint.json @@ -1,5 +1,8 @@ { "rules": { "quotemark": [true, "single"] + }, + "jsRules": { + "quotemark": [true, "single"] } } diff --git a/test/rules/radix/test.js.lint b/test/rules/radix/test.js.lint new file mode 100644 index 00000000000..634a0e9620b --- /dev/null +++ b/test/rules/radix/test.js.lint @@ -0,0 +1,4 @@ +var x = parseInt(3, 10) + + parseInt(4); + ~~~~~~~~~~~ [Missing radix parameter] +var y = parseFloat("2.5"); diff --git a/test/rules/radix/tslint.json b/test/rules/radix/tslint.json index 38441411292..c3e2ba00c22 100644 --- a/test/rules/radix/tslint.json +++ b/test/rules/radix/tslint.json @@ -1,5 +1,8 @@ { "rules": { "radix": true + }, + "jsRules": { + "radix": true } } diff --git a/test/rules/restrict-plus-operands/test.js.lint b/test/rules/restrict-plus-operands/test.js.lint new file mode 100644 index 00000000000..e5e92360603 --- /dev/null +++ b/test/rules/restrict-plus-operands/test.js.lint @@ -0,0 +1,51 @@ + +var x = 5; +var y = "10"; +var z = 8.2; +var w = "6.5"; +var pair = { + first: 5, + second: "10" +}; + +// bad +var bad1 = 5 + "10"; + ~~~~~~~~ [Types of values used in '+' operation must match] +var bad2 = [] + 5; + ~~~~~~ [Types of values used in '+' operation must match] +var bad3 = [] + {}; + ~~~~~~~ [Types of values used in '+' operation must match] +var bad4 = [] + []; + ~~~~~~~ [cannot add type undefined[]] +var bad4 = 5 + []; + ~~~~~~ [Types of values used in '+' operation must match] +var bad5 = "5" + {}; + ~~~~~~~~ [Types of values used in '+' operation must match] +var bad6 = 5.5 + "5"; + ~~~~~~~~~ [Types of values used in '+' operation must match] +var bad7 = "5.5" + 5; + ~~~~~~~~~ [Types of values used in '+' operation must match] +var bad8 = x + y; + ~~~~~ [Types of values used in '+' operation must match] +var bad9 = y + x; + ~~~~~ [Types of values used in '+' operation must match] +var bad10 = x + {}; + ~~~~~~ [Types of values used in '+' operation must match] +var bad11 = [] + y; + ~~~~~~ [Types of values used in '+' operation must match] +var bad12 = pair.first + "10"; + ~~~~~~~~~~~~~~~~~ [Types of values used in '+' operation must match] +var bad13 = 5 + pair.second; + ~~~~~~~~~~~~~~~ [Types of values used in '+' operation must match] +var bad14 = pair + pair; + ~~~~~~~~~~~ [cannot add type { first: number; second: string; }] + +// good +var good1 = 5 + 10; +var good2 = "5.5" + "10"; +var good3 = parseFloat("5.5", 10), + 10; +var good4 = x + z; +var good5 = y + w; + +var good6 = pair.first + 10; +var good8 = "5.5" + pair.second; diff --git a/test/rules/restrict-plus-operands/tslint.json b/test/rules/restrict-plus-operands/tslint.json index 5337f453195..555983b2069 100644 --- a/test/rules/restrict-plus-operands/tslint.json +++ b/test/rules/restrict-plus-operands/tslint.json @@ -4,5 +4,8 @@ }, "rules": { "restrict-plus-operands": true + }, + "jsRules": { + "restrict-plus-operands": true } } diff --git a/test/rules/semicolon/always/test.js.lint b/test/rules/semicolon/always/test.js.lint new file mode 100644 index 00000000000..31f9806a350 --- /dev/null +++ b/test/rules/semicolon/always/test.js.lint @@ -0,0 +1,79 @@ +var x = 3 + ~nil [Missing semicolon] +a += b + ~nil [Missing semicolon] + +c = () => { +} + ~nil [Missing semicolon] + +d = function() { } + ~nil [Missing semicolon] + +console.log("i am adam, am i?") + ~nil [Missing semicolon] + +function xyz() { + return + ~nil [Missing semicolon] +} + +switch(xyz) { + case 1: + break + ~nil [Missing semicolon] + case 2: + continue + ~nil [Missing semicolon] +} + +throw new Error("some error") + ~nil [Missing semicolon] + +do { + var a = 4 + ~nil [Missing semicolon] +} while(x == 3) + ~nil [Missing semicolon] + +debugger + ~nil [Missing semicolon] + +function useStrictMissingSemicolon() { + "use strict" + ~nil [Missing semicolon] + return null; +} + +class MyClass { + name + ~nil [Missing semicolon] + index + ~nil [Missing semicolon] + email; + + initializedProperty = 6 + ~nil [Missing semicolon] + public initializedMethodProperty = () => { + return "hi"; + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] +} + +import {Router} from 'aurelia-router'; + +import {Controller} from 'my-lib' + ~nil [Missing semicolon] + +export default LoginPage; +export default LoginPage + ~nil [Missing semicolon] diff --git a/test/rules/semicolon/always/test.ts.fix b/test/rules/semicolon/always/test.ts.fix index 87f1de6d87f..049d84d358f 100644 --- a/test/rules/semicolon/always/test.ts.fix +++ b/test/rules/semicolon/always/test.ts.fix @@ -51,13 +51,25 @@ class MyClass { private email : string; public initializedProperty = 6; - public initializedMethodProperty = () => { return "hi"; } + public initializedMethodProperty = () => { + return "hi"; + } + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; }; } interface ITest { foo?: string; bar: number; baz: boolean; + + readonly raz: number; } import {Router} from 'aurelia-router'; diff --git a/test/rules/semicolon/always/test.ts.lint b/test/rules/semicolon/always/test.ts.lint index 5794f22dbf0..e99a82a7461 100644 --- a/test/rules/semicolon/always/test.ts.lint +++ b/test/rules/semicolon/always/test.ts.lint @@ -71,7 +71,19 @@ class MyClass { public initializedProperty = 6 ~nil [Missing semicolon] - public initializedMethodProperty = () => { return "hi"; } + public initializedMethodProperty = () => { + return "hi"; + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] } interface ITest { @@ -80,6 +92,8 @@ interface ITest { bar: number ~nil [Missing semicolon] baz: boolean; + + readonly raz: number; } import {Router} from 'aurelia-router'; diff --git a/test/rules/semicolon/always/tslint.json b/test/rules/semicolon/always/tslint.json index 3df79679a99..81c96685e08 100644 --- a/test/rules/semicolon/always/tslint.json +++ b/test/rules/semicolon/always/tslint.json @@ -1,5 +1,8 @@ { "rules": { "semicolon": [true, "always"] + }, + "jsRules": { + "semicolon": [true, "always"] } } diff --git a/test/rules/semicolon/enabled/test.ts.fix b/test/rules/semicolon/enabled/test.ts.fix index 87f1de6d87f..ec4315f624d 100644 --- a/test/rules/semicolon/enabled/test.ts.fix +++ b/test/rules/semicolon/enabled/test.ts.fix @@ -4,6 +4,10 @@ a += b; c = () => { }; +f(() => { + return 1; +}); + d = function() { }; console.log("i am adam, am i?"); @@ -51,7 +55,17 @@ class MyClass { private email : string; public initializedProperty = 6; - public initializedMethodProperty = () => { return "hi"; } + public initializedMethodProperty: mytype = () => { + return "hi"; + } + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; }; } interface ITest { diff --git a/test/rules/semicolon/enabled/test.ts.lint b/test/rules/semicolon/enabled/test.ts.lint index 5794f22dbf0..928d3fac49b 100644 --- a/test/rules/semicolon/enabled/test.ts.lint +++ b/test/rules/semicolon/enabled/test.ts.lint @@ -7,6 +7,10 @@ c = () => { } ~nil [Missing semicolon] +f(() => { + return 1; +}); + d = function() { } ~nil [Missing semicolon] @@ -71,7 +75,19 @@ class MyClass { public initializedProperty = 6 ~nil [Missing semicolon] - public initializedMethodProperty = () => { return "hi"; } + public initializedMethodProperty: mytype = () => { + return "hi"; + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] } interface ITest { diff --git a/test/rules/semicolon/ignore-bound-class-methods/test.ts.fix b/test/rules/semicolon/ignore-bound-class-methods/test.ts.fix new file mode 100644 index 00000000000..3123c4670c0 --- /dev/null +++ b/test/rules/semicolon/ignore-bound-class-methods/test.ts.fix @@ -0,0 +1,82 @@ +var x = 3; +a += b; + +c = () => { +}; + +d = function() { }; + +console.log("i am adam, am i?"); + +function xyz() { + return; +} + +switch(xyz) { + case 1: + break; + case 2: + continue; +} + +throw new Error("some error"); + +do { + var a = 4; +} while(x == 3); + +debugger; + +import v = require("i"); +module M { + export var x; + export function f(s: string): string; + export function f(n: number): number; + export function f(x: any) { return x; } +} + +declare module "M" { + function f(): number; + function g(): number; +} + +function useStrictMissingSemicolon() { + "use strict"; + return null; +} + +class MyClass { + public name : string; + private index : number; + private email : string; + + public initializedProperty = 6; + public initializedMethodProperty = () => { + return "hi"; + }; + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; }; +} + +interface ITest { + foo?: string; + bar: number; + baz: boolean; +} + +import {Router} from 'aurelia-router'; + +import {Controller} from 'my-lib'; + +export default LoginPage; +export default LoginPage; +export = Date; +export = Date; +type t = number; +type t = number; diff --git a/test/rules/semicolon/ignore-bound-class-methods/test.ts.lint b/test/rules/semicolon/ignore-bound-class-methods/test.ts.lint new file mode 100644 index 00000000000..f324082c60d --- /dev/null +++ b/test/rules/semicolon/ignore-bound-class-methods/test.ts.lint @@ -0,0 +1,109 @@ +var x = 3 + ~nil [Missing semicolon] +a += b + ~nil [Missing semicolon] + +c = () => { +} + ~nil [Missing semicolon] + +d = function() { } + ~nil [Missing semicolon] + +console.log("i am adam, am i?") + ~nil [Missing semicolon] + +function xyz() { + return + ~nil [Missing semicolon] +} + +switch(xyz) { + case 1: + break + ~nil [Missing semicolon] + case 2: + continue + ~nil [Missing semicolon] +} + +throw new Error("some error") + ~nil [Missing semicolon] + +do { + var a = 4 + ~nil [Missing semicolon] +} while(x == 3) + ~nil [Missing semicolon] + +debugger + ~nil [Missing semicolon] + +import v = require("i") + ~nil [Missing semicolon] +module M { + export var x + ~nil [Missing semicolon] + export function f(s: string): string; + export function f(n: number): number + ~nil [Missing semicolon] + export function f(x: any) { return x; } +} + +declare module "M" { + function f(): number; + function g(): number + ~nil [Missing semicolon] +} + +function useStrictMissingSemicolon() { + "use strict" + ~nil [Missing semicolon] + return null; +} + +class MyClass { + public name : string + ~nil [Missing semicolon] + private index : number + ~nil [Missing semicolon] + private email : string; + + public initializedProperty = 6 + ~nil [Missing semicolon] + public initializedMethodProperty = () => { + return "hi"; + }; + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] +} + +interface ITest { + foo?: string + ~nil [Missing semicolon] + bar: number + ~nil [Missing semicolon] + baz: boolean; +} + +import {Router} from 'aurelia-router'; + +import {Controller} from 'my-lib' + ~nil [Missing semicolon] + +export default LoginPage; +export default LoginPage + ~nil [Missing semicolon] +export = Date; +export = Date + ~nil [Missing semicolon] +type t = number; +type t = number + ~nil [Missing semicolon] diff --git a/test/rules/semicolon/ignore-bound-class-methods/tslint.json b/test/rules/semicolon/ignore-bound-class-methods/tslint.json new file mode 100644 index 00000000000..52bef362d4b --- /dev/null +++ b/test/rules/semicolon/ignore-bound-class-methods/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "semicolon": [true, "always", "ignore-bound-class-methods"] + } +} diff --git a/test/rules/semicolon/ignore-interfaces/test.ts.fix b/test/rules/semicolon/ignore-interfaces/test.ts.fix index 1bb2d36cedf..af3c4fe6bc6 100644 --- a/test/rules/semicolon/ignore-interfaces/test.ts.fix +++ b/test/rules/semicolon/ignore-interfaces/test.ts.fix @@ -51,7 +51,17 @@ class MyClass { private email : string; public initializedProperty = 6; - public initializedMethodProperty = () => { return "hi"; } + public initializedMethodProperty = () => { + return "hi"; + } + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; }; } interface ITest { diff --git a/test/rules/semicolon/ignore-interfaces/test.ts.lint b/test/rules/semicolon/ignore-interfaces/test.ts.lint index e2251344f0c..75259aed020 100644 --- a/test/rules/semicolon/ignore-interfaces/test.ts.lint +++ b/test/rules/semicolon/ignore-interfaces/test.ts.lint @@ -71,7 +71,19 @@ class MyClass { public initializedProperty = 6 ~nil [Missing semicolon] - public initializedMethodProperty = () => { return "hi"; } + public initializedMethodProperty = () => { + return "hi"; + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~nil [Missing semicolon] } interface ITest { diff --git a/test/rules/semicolon/never/test.ts.fix b/test/rules/semicolon/never/test.ts.fix index a6e29364501..b089d624f0c 100644 --- a/test/rules/semicolon/never/test.ts.fix +++ b/test/rules/semicolon/never/test.ts.fix @@ -50,8 +50,17 @@ class MyClass { private index : number private email : string public initializedProperty = 6 - public initializedMethodProperty = () => { return "hi" } + public initializedMethodProperty = () => { + return "hi" + } + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again" + } + + public initializedMethodProperty1Line = () => { return "hi" } + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again" } } interface ITest { diff --git a/test/rules/semicolon/never/test.ts.lint b/test/rules/semicolon/never/test.ts.lint index bb4b4b02450..32fe4a65f6b 100644 --- a/test/rules/semicolon/never/test.ts.lint +++ b/test/rules/semicolon/never/test.ts.lint @@ -70,9 +70,23 @@ class MyClass { ~ [Unnecessary semicolon] private email : string public initializedProperty = 6 - public initializedMethodProperty = () => { return "hi" }; - ~ [Unnecessary semicolon] - + public initializedMethodProperty = () => { + return "hi"; + ~ [Unnecessary semicolon] + }; + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon = () => { + return "hi again"; + ~ [Unnecessary semicolon] + } + + public initializedMethodProperty1Line = () => { return "hi"; }; + ~ [Unnecessary semicolon] + ~ [Unnecessary semicolon] + + public initializedMethodPropertyWithoutSemicolon1Line = () => { return "hi again"; } + ~ [Unnecessary semicolon] } interface ITest { diff --git a/test/rules/switch-default/test.js.lint b/test/rules/switch-default/test.js.lint new file mode 100644 index 00000000000..2f33aba2eb5 --- /dev/null +++ b/test/rules/switch-default/test.js.lint @@ -0,0 +1,74 @@ +switch (foo) { +~~~~~~~~~~~~~~ +case 1: +~~~~~~~ + bar(); +~~~~~~~~~~ + break; +~~~~~~~~~~ +} +~ [Switch statement should include a 'default' case] + +switch (foo) { +~~~~~~~~~~~~~~ +case 1: +~~~~~~~ + bar(); +~~~~~~~~~~ + break; +~~~~~~~~~~ +case 2: +~~~~~~~ + bar(); +~~~~~~~~~~ + break; +~~~~~~~~~~ +case 3: +~~~~~~~ + bar(); +~~~~~~~~~~ + break; +~~~~~~~~~~ +} +~ [Switch statement should include a 'default' case] + +// valid +switch (foo) { +case 1: + bar(); + break; +default: + break; +} + +// valid +switch (foo) { +default: + bar(); + break; +case 1: + bar(); + break; +} + +// valid +switch (foo) { +case 1: + bar(); + break; +default: + break; +case 2: + break; +} + +// valid +baz: +while (true){ + switch(foo) { + case 1: + bar(); + continue baz; + default: + } +} diff --git a/test/rules/switch-default/tslint.json b/test/rules/switch-default/tslint.json index 05e34955935..55854a35889 100644 --- a/test/rules/switch-default/tslint.json +++ b/test/rules/switch-default/tslint.json @@ -1,5 +1,8 @@ { "rules": { "switch-default": true + }, + "jsRules": { + "switch-default": true } } diff --git a/test/rules/trailing-comma/multiline-always/test.js.lint b/test/rules/trailing-comma/multiline-always/test.js.lint new file mode 100644 index 00000000000..ce112b7c9a5 --- /dev/null +++ b/test/rules/trailing-comma/multiline-always/test.js.lint @@ -0,0 +1,138 @@ +var v = [{ + a: 1, + b: 2, + d: 34, + c: (a + b), +},]; + +var x = [{ + a: 1, + b: 2, + d: 34, + c: (a + b) + ~ [Missing trailing comma] +}]; + +var s = { + sA: 6, +}; + +var t = { + tA: 7 + ~ [Missing trailing comma] +} + +var y = { + yA: 42, + yB: 24, +}; + +var z = { + zOne: 2, + zTwo: 1 + ~ [Missing trailing comma] +}; + +var ss = [ + 6, +]; + +var tt = [ + 7 + ~ [Missing trailing comma] +]; + +var yy = [ + 42, + 24, +]; + +var zz = [ + 2, + 1 + ~ [Missing trailing comma] +]; + +var a = [{a: 1, b: 2, d: 34, c: (a + b),},]; + +var b = [{a: 1, b: 2, d: 34, c: (a + b)}]; + +var c = {cA: 42, cB: 24,}; + +var d = {dOne: 2, dTwo: 1}; + +var cc = [42, 24,]; + +var dd = [2, 1]; + +var { + sA, +} = s; + +var { + tA + ~ [Missing trailing comma] +} = t; + +var { + yA, + yB, +} = y; + +var { + zOne, + zTwo + ~ [Missing trailing comma] +} = z; + +var [ + ssA, +] = ss; + +var [ + ttA + ~ [Missing trailing comma] +] = tt; + +var [ + yyA, + yyB, +] = yy; + +var [ + zzOne, + zzTwo + ~ [Missing trailing comma] +] = zz; + +var {cA, cB,} = c; + +var {dOne, dTwo} = d; + +var [ccA, ccB,] = cc; + +var [ddOne, ddTwo] = dd; + +import { + ClassS, +} from "module"; + +import { + ClassT + ~ [Missing trailing comma] +} from "module"; + +import { + ClassV, + ClassX, +} from "module"; + +import { + ClassY, + ClassZ + ~ [Missing trailing comma] +} from "module"; + +import {ClassA, ClassB,} from "module"; + +import {ClassC, ClassD} from "module"; diff --git a/test/rules/trailing-comma/multiline-always/test.ts.fix b/test/rules/trailing-comma/multiline-always/test.ts.fix index cbee7ac25f7..ca1572a3f90 100644 --- a/test/rules/trailing-comma/multiline-always/test.ts.fix +++ b/test/rules/trailing-comma/multiline-always/test.ts.fix @@ -364,7 +364,7 @@ class Test { [ C, C, - ] + ], C, >, >( @@ -474,7 +474,7 @@ interface ITest { [ C, C, - ] + ], C, >, >( diff --git a/test/rules/trailing-comma/multiline-always/test.ts.lint b/test/rules/trailing-comma/multiline-always/test.ts.lint index 64f72d12a5f..3f62655e8ab 100644 --- a/test/rules/trailing-comma/multiline-always/test.ts.lint +++ b/test/rules/trailing-comma/multiline-always/test.ts.lint @@ -390,7 +390,7 @@ class Test { [ C, C, - ] + ], C ~ [Missing trailing comma] > @@ -509,7 +509,7 @@ interface ITest { [ C, C, - ] + ], C ~ [Missing trailing comma] > diff --git a/test/rules/trailing-comma/multiline-always/tslint.json b/test/rules/trailing-comma/multiline-always/tslint.json index b9d77c2ab7c..2f4ac0d2439 100644 --- a/test/rules/trailing-comma/multiline-always/tslint.json +++ b/test/rules/trailing-comma/multiline-always/tslint.json @@ -1,5 +1,8 @@ { "rules": { "trailing-comma": [true, {"multiline": "always"}] + }, + "jsRules": { + "trailing-comma": [true, {"multiline": "always"}] } } diff --git a/test/rules/trailing-comma/multiline-never/test.ts.fix b/test/rules/trailing-comma/multiline-never/test.ts.fix index 4240f80dbc5..1b2e7ef79cb 100644 --- a/test/rules/trailing-comma/multiline-never/test.ts.fix +++ b/test/rules/trailing-comma/multiline-never/test.ts.fix @@ -364,7 +364,7 @@ class Test { [ C, C - ] + ], C > >( @@ -430,7 +430,7 @@ interface ITest { [ C, C - ] + ], C > >( diff --git a/test/rules/trailing-comma/multiline-never/test.ts.lint b/test/rules/trailing-comma/multiline-never/test.ts.lint index 359d6063b36..bc6e2ed78be 100644 --- a/test/rules/trailing-comma/multiline-never/test.ts.lint +++ b/test/rules/trailing-comma/multiline-never/test.ts.lint @@ -390,7 +390,7 @@ class Test { C, C, ~ [Unnecessary trailing comma] - ] + ], C > >( @@ -462,7 +462,7 @@ interface ITest { C, C, ~ [Unnecessary trailing comma] - ] + ], C > >( diff --git a/test/rules/triple-equals/allow-null-check/test.js.lint b/test/rules/triple-equals/allow-null-check/test.js.lint new file mode 100644 index 00000000000..6fddcf97283 --- /dev/null +++ b/test/rules/triple-equals/allow-null-check/test.js.lint @@ -0,0 +1,19 @@ +var testVariable = 123; + +function testFunction() { + if (x === testFunction && y == 4) { + ~~ [== should be ===] + console.log("called"); + } + + var z = (x + 3) != 5; + ~~ [!= should be !==] + return; +} + +// disallow double-equality undefined checks +var x = (y == undefined) ? 1 : 2; + ~~ [== should be ===] + +// allow double-equality null checks +var x = (y == null) ? 1 : 2; diff --git a/test/rules/triple-equals/allow-null-check/tslint.json b/test/rules/triple-equals/allow-null-check/tslint.json index b60bf169ef6..e3ff478bd69 100644 --- a/test/rules/triple-equals/allow-null-check/tslint.json +++ b/test/rules/triple-equals/allow-null-check/tslint.json @@ -1,5 +1,8 @@ { "rules": { "triple-equals": [true, "allow-null-check"] + }, + "jsRules": { + "triple-equals": [true, "allow-null-check"] } } diff --git a/test/rules/triple-equals/allow-undefined-check/test.js.lint b/test/rules/triple-equals/allow-undefined-check/test.js.lint new file mode 100644 index 00000000000..a3e2136f538 --- /dev/null +++ b/test/rules/triple-equals/allow-undefined-check/test.js.lint @@ -0,0 +1,19 @@ +var testVariable = 123; + +function testFunction() { + if (x === testFunction && y == 4) { + ~~ [== should be ===] + console.log("called"); + } + + var z = (x + 3) != 5; + ~~ [!= should be !==] + return; +} + +// allow double-equality undefined checks +var x = (y == undefined) ? 1 : 2; + +// disallow double-equality null checks +var x = (y == null) ? 1 : 2; + ~~ [== should be ===] diff --git a/test/rules/triple-equals/allow-undefined-check/tslint.json b/test/rules/triple-equals/allow-undefined-check/tslint.json index 1ab9dce6344..3bd1a57fb97 100644 --- a/test/rules/triple-equals/allow-undefined-check/tslint.json +++ b/test/rules/triple-equals/allow-undefined-check/tslint.json @@ -1,5 +1,8 @@ { "rules": { "triple-equals": [true, "allow-undefined-check"] + }, + "jsRules": { + "triple-equals": [true, "allow-undefined-check"] } } diff --git a/test/rules/use-isnan/test.js.lint b/test/rules/use-isnan/test.js.lint new file mode 100644 index 00000000000..6999b049d4c --- /dev/null +++ b/test/rules/use-isnan/test.js.lint @@ -0,0 +1,31 @@ + +// no violation for comparing NaN using isNaN +if (isNaN(NaN)) { +} + +// no violation for correctly checking for isNaN +if (isNaN(something)) { } + +// no violation for assignments +let x = 0; +x = NaN; + +// do not use equality operators to compare for NaN +if (foo == NaN) { } + ~~~~~~~~~~ [Found an invalid comparison for NaN: foo == NaN] +if (NaN === foo) { } + ~~~~~~~~~~~ [Found an invalid comparison for NaN: NaN === foo] +if (foo != NaN) { } + ~~~~~~~~~~ [Found an invalid comparison for NaN: foo != NaN] +if (NaN !== foo) { } + ~~~~~~~~~~~ [Found an invalid comparison for NaN: NaN !== foo] + +// do not use any binary operators to compare for NaN +if (foo > NaN) { } + ~~~~~~~~~ [Found an invalid comparison for NaN: foo > NaN] +if (NaN >= foo) { } + ~~~~~~~~~~ [Found an invalid comparison for NaN: NaN >= foo] +if (foo < NaN) { } + ~~~~~~~~~ [Found an invalid comparison for NaN: foo < NaN] +if (NaN <= foo) { } + ~~~~~~~~~~ [Found an invalid comparison for NaN: NaN <= foo] diff --git a/test/rules/use-isnan/tslint.json b/test/rules/use-isnan/tslint.json index 880adde9812..121d0344d4a 100644 --- a/test/rules/use-isnan/tslint.json +++ b/test/rules/use-isnan/tslint.json @@ -1,5 +1,8 @@ { "rules": { "use-isnan": true + }, + "jsRules": { + "use-isnan": true } } diff --git a/test/rules/use-strict/test.ts.lint b/test/rules/use-strict/test.ts.lint deleted file mode 100644 index e80f0664713..00000000000 --- a/test/rules/use-strict/test.ts.lint +++ /dev/null @@ -1,62 +0,0 @@ -declare function foo(): void; - -function testDoubleQuotes() { - // hello - "use strict"; // bye - - var i = 3; -} - -function testSingleQuotes() { - 'use strict'; -} - -function testNoUseStrict() { -~~~~~~~~ [missing 'use strict'] -} - -module TestModule { - // hello - "use strict"; // bye - - var i = 3; -} - -module TestNoUseStrictModule { -~~~~~~ [missing 'use strict'] - // hello - var i = 3; -} - -module TestNoUseStrictModule.Namespaced.AndAgain { -~~~~~~ [missing 'use strict'] - // hello - var i = 3; -} - -function checkDepth() { - "use strict"; - - function innerFunction() { - - } -} - -module TestModuleWithFunction { - "use strict"; - - function hello() { - // there shouldn't be a failure here since it isn't top level - } -} - -declare module foo { - // shouldn't error because of the declare - export class bar { - } -} - -function shouldPassUseStrictRule(): string { - "use strict" - return "This is a test" -} diff --git a/test/rules/use-strict/tslint.json b/test/rules/use-strict/tslint.json deleted file mode 100644 index 3784cf991b7..00000000000 --- a/test/rules/use-strict/tslint.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "use-strict": [true, "check-function", "check-module"] - } -} diff --git a/test/rules/variable-name/allow-leading-trailing-underscore/test.js.lint b/test/rules/variable-name/allow-leading-trailing-underscore/test.js.lint new file mode 100644 index 00000000000..27af373c96e --- /dev/null +++ b/test/rules/variable-name/allow-leading-trailing-underscore/test.js.lint @@ -0,0 +1,45 @@ +var validName1 = "hi"; +var VALIDNAME2 = "there"; +var InvalidName1 = ","; // failure + ~~~~~~~~~~~~ [variable name must be in camelcase or uppercase] +var invalid_name2 = " "; // failure + ~~~~~~~~~~~~~ [variable name must be in camelcase or uppercase] + +class Test { + Invalid_name3 = "how"; // failure + ~~~~~~~~~~~~~ [variable name must be in camelcase or uppercase] + _optionallyValid = "are"; // sometimes a failure +} + +function test() { + () => { + var InVaLiDnAmE4 = "you"; // failure + ~~~~~~~~~~~~ [variable name must be in camelcase or uppercase] + }; +} + +export function functionWithInvalidParamNames (bad_name, AnotherOne) { // 2 failures + ~~~~~~~~ [variable name must be in camelcase or uppercase] + ~~~~~~~~~~ [variable name must be in camelcase or uppercase] + // +} + +let { foo, bar } = { foo: 1, bar: 2 }; +let [ InvalidFoo, invalid_bar, ...invalid_baz ] = [1, 2, 3, 4]; // 3 failures + ~~~~~~~~~~ [variable name must be in camelcase or uppercase] + ~~~~~~~~~~~ [variable name must be in camelcase or uppercase] + ~~~~~~~~~~~ [variable name must be in camelcase or uppercase] + +export function anotherFunctionWithInvalidParamNames ([first_element, SecondElement]) { // 2 failures + ~~~~~~~~~~~~~ [variable name must be in camelcase or uppercase] + ~~~~~~~~~~~~~ [variable name must be in camelcase or uppercase] + // +} + +export function functionWithInvalidSpread(invalid_arg: ...number) { // 1 failure + ~~~~~~~~~~~ [variable name must be in camelcase or uppercase] + // +} + +let optionallyValid_ = "bar"; +let _$httpBackend_ = "leading and trailing"; diff --git a/test/rules/variable-name/allow-leading-trailing-underscore/tslint.json b/test/rules/variable-name/allow-leading-trailing-underscore/tslint.json index c5d657add43..7c86f5c9881 100644 --- a/test/rules/variable-name/allow-leading-trailing-underscore/tslint.json +++ b/test/rules/variable-name/allow-leading-trailing-underscore/tslint.json @@ -1,5 +1,8 @@ { "rules": { "variable-name": [true, "allow-leading-underscore", "allow-trailing-underscore"] + }, + "jsRules": { + "variable-name": [true, "allow-leading-underscore", "allow-trailing-underscore"] } } diff --git a/test/rules/whitespace/all/test.js.lint b/test/rules/whitespace/all/test.js.lint new file mode 100644 index 00000000000..314a6cd2fe8 --- /dev/null +++ b/test/rules/whitespace/all/test.js.lint @@ -0,0 +1,88 @@ + export var ast=AST; + ~ [missing whitespace] + ~ [missing whitespace] + + var y = (x === 10)?1:2; + ~ [missing whitespace] + ~ [missing whitespace] + ~ [missing whitespace] + ~ [missing whitespace] + + var zz = (y===4); + ~ [missing whitespace] + ~ [missing whitespace] + + var z=y; + ~ [missing whitespace] + ~ [missing whitespace] + + var a,b; + ~ [missing whitespace] + + switch(x) { + ~ [missing whitespace] + case 1:break; + ~ [missing whitespace] + default:break; + ~ [missing whitespace] + } + + for(x = 1;x <2; ++x) { + ~ [missing whitespace] + ~ [missing whitespace] + ~ [missing whitespace] + goto:console.log("hi"); + ~ [missing whitespace] + } + + while(i < 1) { + ~ [missing whitespace] + ++i; + } + + var q; + q.forEach(()=>3); + ~ [missing whitespace] + ~ [missing whitespace] + q.forEach(()=>{ + ~ [missing whitespace] + ~ [missing whitespace] + return 3; + }); + +var a; + +a.then(() => { + return 1; +}).if(() => { + return 1; +}); + +var name = "something"; +var test = ` + +
, Bart van der Schoor -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -declare module Chai { - - interface ChaiStatic { - expect: ExpectStatic; - /** - * Provides a way to extend the internals of Chai - */ - use(fn: (chai: any, utils: any) => void): any; - assert: AssertStatic; - config: Config; - } - - export interface ExpectStatic extends AssertionStatic { - } - - export interface AssertStatic extends Assert { - } - - export interface AssertionStatic { - (target: any, message?: string): Assertion; - } - - interface Assertion extends LanguageChains, NumericComparison, TypeComparison { - not: Assertion; - deep: Deep; - a: TypeComparison; - an: TypeComparison; - include: Include; - contain: Include; - ok: Assertion; - true: Assertion; - false: Assertion; - null: Assertion; - undefined: Assertion; - exist: Assertion; - empty: Assertion; - arguments: Assertion; - Arguments: Assertion; - equal: Equal; - equals: Equal; - eq: Equal; - eql: Equal; - eqls: Equal; - property: Property; - ownProperty: OwnProperty; - haveOwnProperty: OwnProperty; - length: Length; - lengthOf: Length; - match(regexp: RegExp|string, message?: string): Assertion; - string(string: string, message?: string): Assertion; - keys: Keys; - key(string: string): Assertion; - throw: Throw; - throws: Throw; - Throw: Throw; - respondTo(method: string, message?: string): Assertion; - itself: Assertion; - satisfy(matcher: Function, message?: string): Assertion; - closeTo(expected: number, delta: number, message?: string): Assertion; - members: Members; - } - - interface LanguageChains { - to: Assertion; - be: Assertion; - been: Assertion; - is: Assertion; - that: Assertion; - which: Assertion; - and: Assertion; - has: Assertion; - have: Assertion; - with: Assertion; - at: Assertion; - of: Assertion; - same: Assertion; - } - - interface NumericComparison { - above: NumberComparer; - gt: NumberComparer; - greaterThan: NumberComparer; - least: NumberComparer; - gte: NumberComparer; - below: NumberComparer; - lt: NumberComparer; - lessThan: NumberComparer; - most: NumberComparer; - lte: NumberComparer; - within(start: number, finish: number, message?: string): Assertion; - } - - interface NumberComparer { - (value: number, message?: string): Assertion; - } - - interface TypeComparison { - (type: string, message?: string): Assertion; - instanceof: InstanceOf; - instanceOf: InstanceOf; - } - - interface InstanceOf { - (constructor: Object, message?: string): Assertion; - } - - interface Deep { - equal: Equal; - include: Include; - property: Property; - } - - interface Equal { - (value: any, message?: string): Assertion; - } - - interface Property { - (name: string, value?: any, message?: string): Assertion; - } - - interface OwnProperty { - (name: string, message?: string): Assertion; - } - - interface Length extends LanguageChains, NumericComparison { - (length: number, message?: string): Assertion; - } - - interface Include { - (value: Object, message?: string): Assertion; - (value: string, message?: string): Assertion; - (value: number, message?: string): Assertion; - keys: Keys; - members: Members; - } - - interface Keys { - (...keys: string[]): Assertion; - (keys: any[]): Assertion; - } - - interface Throw { - (): Assertion; - (expected: string, message?: string): Assertion; - (expected: RegExp, message?: string): Assertion; - (constructor: Error, expected?: string, message?: string): Assertion; - (constructor: Error, expected?: RegExp, message?: string): Assertion; - (constructor: Function, expected?: string, message?: string): Assertion; - (constructor: Function, expected?: RegExp, message?: string): Assertion; - } - - interface Members { - (set: any[], message?: string): Assertion; - } - - export interface Assert { - /** - * @param expression Expression to test for truthiness. - * @param message Message to display on error. - */ - (expression: any, message?: string): void; - - fail(actual?: any, expected?: any, msg?: string, operator?: string): void; - - ok(val: any, msg?: string): void; - notOk(val: any, msg?: string): void; - - equal(act: any, exp: any, msg?: string): void; - notEqual(act: any, exp: any, msg?: string): void; - - strictEqual(act: any, exp: any, msg?: string): void; - notStrictEqual(act: any, exp: any, msg?: string): void; - - deepEqual(act: any, exp: any, msg?: string): void; - notDeepEqual(act: any, exp: any, msg?: string): void; - - isTrue(val: any, msg?: string): void; - isFalse(val: any, msg?: string): void; - - isNull(val: any, msg?: string): void; - isNotNull(val: any, msg?: string): void; - - isUndefined(val: any, msg?: string): void; - isDefined(val: any, msg?: string): void; - - isFunction(val: any, msg?: string): void; - isNotFunction(val: any, msg?: string): void; - - isObject(val: any, msg?: string): void; - isNotObject(val: any, msg?: string): void; - - isArray(val: any, msg?: string): void; - isNotArray(val: any, msg?: string): void; - - isString(val: any, msg?: string): void; - isNotString(val: any, msg?: string): void; - - isNumber(val: any, msg?: string): void; - isNotNumber(val: any, msg?: string): void; - - isBoolean(val: any, msg?: string): void; - isNotBoolean(val: any, msg?: string): void; - - typeOf(val: any, type: string, msg?: string): void; - notTypeOf(val: any, type: string, msg?: string): void; - - instanceOf(val: any, type: Function, msg?: string): void; - notInstanceOf(val: any, type: Function, msg?: string): void; - - include(exp: string, inc: any, msg?: string): void; - include(exp: any[], inc: any, msg?: string): void; - - notInclude(exp: string, inc: any, msg?: string): void; - notInclude(exp: any[], inc: any, msg?: string): void; - - match(exp: any, re: RegExp, msg?: string): void; - notMatch(exp: any, re: RegExp, msg?: string): void; - - property(obj: Object, prop: string, msg?: string): void; - notProperty(obj: Object, prop: string, msg?: string): void; - deepProperty(obj: Object, prop: string, msg?: string): void; - notDeepProperty(obj: Object, prop: string, msg?: string): void; - - propertyVal(obj: Object, prop: string, val: any, msg?: string): void; - propertyNotVal(obj: Object, prop: string, val: any, msg?: string): void; - - deepPropertyVal(obj: Object, prop: string, val: any, msg?: string): void; - deepPropertyNotVal(obj: Object, prop: string, val: any, msg?: string): void; - - lengthOf(exp: any, len: number, msg?: string): void; - //alias frenzy - throw(fn: Function, msg?: string): void; - throw(fn: Function, regExp: RegExp): void; - throw(fn: Function, errType: Function, msg?: string): void; - throw(fn: Function, errType: Function, regExp: RegExp): void; - - throws(fn: Function, msg?: string): void; - throws(fn: Function, regExp: RegExp): void; - throws(fn: Function, errType: Function, msg?: string): void; - throws(fn: Function, errType: Function, regExp: RegExp): void; - - Throw(fn: Function, msg?: string): void; - Throw(fn: Function, regExp: RegExp): void; - Throw(fn: Function, errType: Function, msg?: string): void; - Throw(fn: Function, errType: Function, regExp: RegExp): void; - - doesNotThrow(fn: Function, msg?: string): void; - doesNotThrow(fn: Function, regExp: RegExp): void; - doesNotThrow(fn: Function, errType: Function, msg?: string): void; - doesNotThrow(fn: Function, errType: Function, regExp: RegExp): void; - - operator(val: any, operator: string, val2: any, msg?: string): void; - closeTo(act: number, exp: number, delta: number, msg?: string): void; - - sameMembers(set1: any[], set2: any[], msg?: string): void; - includeMembers(set1: any[], set2: any[], msg?: string): void; - - ifError(val: any, msg?: string): void; - } - - export interface Config { - includeStack: boolean; - } - - export class AssertionError { - constructor(message: string, _props?: any, ssf?: Function); - name: string; - message: string; - showDiff: boolean; - stack: string; - } -} - -declare var chai: Chai.ChaiStatic; - -declare module "chai" { - export = chai; -} diff --git a/test/typings/mocha/mocha.d.ts b/test/typings/mocha/mocha.d.ts deleted file mode 100644 index 63ad66014a2..00000000000 --- a/test/typings/mocha/mocha.d.ts +++ /dev/null @@ -1,166 +0,0 @@ -// Type definitions for mocha 2.0.1 -// Project: http://mochajs.org/ -// Definitions by: Kazi Manzur Rashid , otiai10 , jt000 -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -interface Mocha { - // Setup mocha with the given setting options. - setup(options: MochaSetupOptions): Mocha; - - //Run tests and invoke `fn()` when complete. - run(callback?: () => void): void; - - // Set reporter as function - reporter(reporter: () => void): Mocha; - - // Set reporter, defaults to "dot" - reporter(reporter: string): Mocha; - - // Enable growl support. - growl(): Mocha -} - -interface MochaSetupOptions { - //milliseconds to wait before considering a test slow - slow?: number; - - // timeout in milliseconds - timeout?: number; - - // ui name "bdd", "tdd", "exports" etc - ui?: string; - - //array of accepted globals - globals?: any[]; - - // reporter instance (function or string), defaults to `mocha.reporters.Dot` - reporter?: any; - - // bail on the first test failure - bail?: boolean; - - // ignore global leaks - ignoreLeaks?: boolean; - - // grep string or regexp to filter tests with - grep?: any; -} - -interface MochaDone { - (error?: Error): void; -} - -declare var mocha: Mocha; - -declare var describe: { - (description: string, spec: () => void): void; - only(description: string, spec: () => void): void; - skip(description: string, spec: () => void): void; - timeout(ms: number): void; -} - -// alias for `describe` -declare var context: { - (contextTitle: string, spec: () => void): void; - only(contextTitle: string, spec: () => void): void; - skip(contextTitle: string, spec: () => void): void; - timeout(ms: number): void; -}; - -// alias for `describe` -declare var suite: { - (suiteTitle: string, spec: () => void): void; - only(suiteTitle: string, spec: () => void): void; - skip(suiteTitle: string, spec: () => void): void; - timeout(ms: number): void; -}; - -declare var it: { - (expectation: string, assertion?: () => void): void; - (expectation: string, assertion?: (done: MochaDone) => void): void; - only(expectation: string, assertion?: () => void): void; - only(expectation: string, assertion?: (done: MochaDone) => void): void; - skip(expectation: string, assertion?: () => void): void; - skip(expectation: string, assertion?: (done: MochaDone) => void): void; - timeout(ms: number): void; -}; - -// alias for `it` -declare var test: { - (expectation: string, assertion?: () => void): void; - (expectation: string, assertion?: (done: MochaDone) => void): void; - only(expectation: string, assertion?: () => void): void; - only(expectation: string, assertion?: (done: MochaDone) => void): void; - skip(expectation: string, assertion?: () => void): void; - skip(expectation: string, assertion?: (done: MochaDone) => void): void; - timeout(ms: number): void; -}; - -declare function before(action: () => void): void; - -declare function before(action: (done: MochaDone) => void): void; - -declare function setup(action: () => void): void; - -declare function setup(action: (done: MochaDone) => void): void; - -declare function after(action: () => void): void; - -declare function after(action: (done: MochaDone) => void): void; - -declare function teardown(action: () => void): void; - -declare function teardown(action: (done: MochaDone) => void): void; - -declare function beforeEach(action: () => void): void; - -declare function beforeEach(action: (done: MochaDone) => void): void; - -declare function suiteSetup(action: () => void): void; - -declare function suiteSetup(action: (done: MochaDone) => void): void; - -declare function afterEach(action: () => void): void; - -declare function afterEach(action: (done: MochaDone) => void): void; - -declare function suiteTeardown(action: () => void): void; - -declare function suiteTeardown(action: (done: MochaDone) => void): void; - -declare module "mocha" { - - class Mocha { - constructor(options?: { - grep?: RegExp; - ui?: string; - reporter?: string; - timeout?: number; - bail?: boolean; - }); - - bail(value?: boolean): Mocha; - addFile(file: string): Mocha; - reporter(value: string): Mocha; - ui(value: string): Mocha; - grep(value: string): Mocha; - grep(value: RegExp): Mocha; - invert(): Mocha; - ignoreLeaks(value: boolean): Mocha; - checkLeaks(): Mocha; - growl(): Mocha; - globals(value: string): Mocha; - globals(values: string[]): Mocha; - useColors(value: boolean): Mocha; - useInlineDiffs(value: boolean): Mocha; - timeout(value: number): Mocha; - slow(value: number): Mocha; - enableTimeouts(value: boolean): Mocha; - asyncOnly(value: boolean): Mocha; - noHighlighting(value: boolean): Mocha; - - run(onComplete?: (failures: number) => void): void; - } - - export = Mocha; -} diff --git a/test/utils.ts b/test/utils.ts index f3c80a751ee..7bf981a040c 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -15,6 +15,7 @@ */ import * as fs from "fs"; +import * as os from "os"; import * as path from "path"; import * as ts from "typescript"; @@ -82,3 +83,23 @@ export function assertContainsFailure(haystack: Lint.RuleFailure[], needle: Lint assert(false, "expected " + stringifiedNeedle + " within " + stringifiedHaystack); } } + +export function createTempFile(extension: string) { + let tmpfile: string; + for (let i = 0; i < 5; i++) { + const attempt = path.join(os.tmpdir(), `tslint.test${Math.round(Date.now() * Math.random())}.${extension}`); + if (!fs.existsSync(tmpfile)) { + tmpfile = attempt; + break; + } + } + if (tmpfile === undefined) { + throw new Error("Couldn't create temp file"); + } + return tmpfile; +} + +// converts Windows normalized paths (with backwards slash `\`) to paths used by TypeScript (with forward slash `/`) +export function denormalizeWinPath(path: string): string { + return path.replace(/\\/g, "/"); +} diff --git a/tsd.json b/tsd.json deleted file mode 100644 index f3f35ec623c..00000000000 --- a/tsd.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "version": "v4", - "repo": "borisyankov/DefinitelyTyped", - "ref": "master", - "path": "typings", - "bundle": "typings/tsd.d.ts", - "installed": { - "colors/colors.d.ts": { - "commit": "78ba6e41543e5ababbd1dda19797601be3c1f304" - }, - "diff/diff.d.ts": { - "commit": "78ba6e41543e5ababbd1dda19797601be3c1f304" - }, - "findup-sync/findup-sync.d.ts": { - "commit": "98d3168c2c570352a3a7393788e2ec9fbb08ade6" - }, - "glob/glob.d.ts": { - "commit": "fb2b3b1e068c9ff7d8f9b0851c08d37d96c95c38" - }, - "js-yaml/js-yaml.d.ts": { - "commit": "8ea42cd8bb11863ed6f242d67c502288ebc45a7b" - }, - "minimatch/minimatch.d.ts": { - "commit": "98d3168c2c570352a3a7393788e2ec9fbb08ade6" - }, - "node/node.d.ts": { - "commit": "98d3168c2c570352a3a7393788e2ec9fbb08ade6" - }, - "optimist/optimist.d.ts": { - "commit": "e8f8e7471b8ca92ca417f8c878f64ae4d1067972" - }, - "underscore.string/underscore.string.d.ts": { - "commit": "98d3168c2c570352a3a7393788e2ec9fbb08ade6" - }, - "underscore/underscore.d.ts": { - "commit": "98d3168c2c570352a3a7393788e2ec9fbb08ade6" - } - } -} diff --git a/tslint.json b/tslint.json index 998acb59a2e..c496ae41946 100644 --- a/tslint.json +++ b/tslint.json @@ -2,11 +2,19 @@ "extends": "tslint:latest", "rules": { "interface-name": false, + "max-classes-per-file": false, "max-line-length": [true, 140], "member-ordering": [true, "public-before-private", "static-before-instance", "variables-before-functions" + ], + "no-unused-variable": false, + "variable-name": [true, + "ban-keywords", + "check-format", + "allow-leading-underscore", + "allow-pascal-case" ] } } diff --git a/typings/colors/colors.d.ts b/typings/colors/colors.d.ts deleted file mode 100644 index 5aa28553a39..00000000000 --- a/typings/colors/colors.d.ts +++ /dev/null @@ -1,123 +0,0 @@ -// Type definitions for Colors.js 0.6.0-1 -// Project: https://github.com/Marak/colors.js -// Definitions by: Bart van der Schoor -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -declare module "colors" { - interface Color { - (text: string): string; - - black: Color; - red: Color; - green: Color; - yellow: Color; - blue: Color; - magenta: Color; - cyan: Color; - white: Color; - gray: Color; - grey: Color; - - bgBlack: Color; - bgRed: Color; - bgGreen: Color; - bgYellow: Color; - bgBlue: Color; - bgMagenta: Color; - bgCyan: Color; - bgWhite: Color; - - reset: Color; - bold: Color; - dim: Color; - italic: Color; - underline: Color; - inverse: Color; - hidden: Color; - strikethrough: Color; - - rainbow: Color; - zebra: Color; - america: Color; - trap: Color; - random: Color; - } - - module e { - export function setTheme(theme:any): void; - - export var black: Color; - export var red: Color; - export var green: Color; - export var yellow: Color; - export var blue: Color; - export var magenta: Color; - export var cyan: Color; - export var white: Color; - export var gray: Color; - export var grey: Color; - - export var bgBlack: Color; - export var bgRed: Color; - export var bgGreen: Color; - export var bgYellow: Color; - export var bgBlue: Color; - export var bgMagenta: Color; - export var bgCyan: Color; - export var bgWhite: Color; - - export var reset: Color; - export var bold: Color; - export var dim: Color; - export var italic: Color; - export var underline: Color; - export var inverse: Color; - export var hidden: Color; - export var strikethrough: Color; - - export var rainbow: Color; - export var zebra: Color; - export var america: Color; - export var trap: Color; - export var random: Color; - } - - export = e; -} - -interface String { - black: string; - red: string; - green: string; - yellow: string; - blue: string; - magenta: string; - cyan: string; - white: string; - gray: string; - grey: string; - - bgBlack: string; - bgRed: string; - bgGreen: string; - bgYellow: string; - bgBlue: string; - bgMagenta: string; - bgCyan: string; - bgWhite: string; - - reset: string; - bold: string; - dim: string; - italic: string; - underline: string; - inverse: string; - hidden: string; - strikethrough: string; - - rainbow: string; - zebra: string; - america: string; - trap: string; - random: string; -} diff --git a/typings/diff/diff.d.ts b/typings/diff/diff.d.ts deleted file mode 100644 index f5c2cc48f83..00000000000 --- a/typings/diff/diff.d.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Type definitions for diff -// Project: https://github.com/kpdecker/jsdiff -// Definitions by: vvakame -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -declare module JsDiff { - interface IDiffResult { - value: string; - added?: boolean; - removed?: boolean; - } - - interface IBestPath { - newPos: number; - componenets: IDiffResult[]; - } - - class Diff { - ignoreWhitespace:boolean; - - constructor(ignoreWhitespace?:boolean); - - diff(oldString:string, newString:string):IDiffResult[]; - - pushComponent(components:IDiffResult[], value:string, added:boolean, removed:boolean):void; - - extractCommon(basePath:IBestPath, newString:string, oldString:string, diagonalPath:number):number; - - equals(left:string, right:string):boolean; - - join(left:string, right:string):string; - - tokenize(value:string):any; // return types are string or string[] - } - - function diffChars(oldStr:string, newStr:string):IDiffResult[]; - - function diffWords(oldStr:string, newStr:string):IDiffResult[]; - - function diffWordsWithSpace(oldStr:string, newStr:string):IDiffResult[]; - - function diffJson(oldObj: Object, newObj: Object): IDiffResult[]; - - function diffLines(oldStr:string, newStr:string):IDiffResult[]; - - function diffCss(oldStr:string, newStr:string):IDiffResult[]; - - function createPatch(fileName:string, oldStr:string, newStr:string, oldHeader:string, newHeader:string):string; - - function applyPatch(oldStr:string, uniDiff:string):string; - - function convertChangesToXML(changes:IDiffResult[]):string; - - function convertChangesToDMP(changes:IDiffResult[]):{0: number; 1:string;}[]; -} - -declare module "diff" { - export = JsDiff; -} diff --git a/typings/findup-sync/findup-sync.d.ts b/typings/findup-sync/findup-sync.d.ts deleted file mode 100644 index b7bf674e231..00000000000 --- a/typings/findup-sync/findup-sync.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Type definitions for findup-sync v0.3.0 -// Project: https://github.com/cowboy/node-findup-sync -// Definitions by: Bart van der Schoor , Nathan Brown -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -/// - -declare module 'findup-sync' { - import minimatch = require('minimatch'); - - interface IOptions extends minimatch.IOptions { - cwd?: string; - } - - function mod(pattern: string[] | string, opts?: IOptions): string; - - export = mod; -} diff --git a/typings/glob/glob.d.ts b/typings/glob/glob.d.ts deleted file mode 100644 index 6e971437587..00000000000 --- a/typings/glob/glob.d.ts +++ /dev/null @@ -1,112 +0,0 @@ -// Type definitions for Glob 5.0.10 -// Project: https://github.com/isaacs/node-glob -// Definitions by: vvakame -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -/// -/// - -declare module "glob" { - - import events = require("events"); - import fs = require('fs'); - import minimatch = require("minimatch"); - - function G(pattern: string, cb: (err: Error, matches: string[]) => void): void; - function G(pattern: string, options: G.IOptions, cb: (err: Error, matches: string[]) => void): void; - - module G { - function sync(pattern: string, options?: IOptions): string[]; - - function hasMagic(pattern: string, options?: IOptions): boolean; - - var Glob: IGlobStatic; - var GlobSync: IGlobSyncStatic; - - interface IOptions extends minimatch.IOptions { - cwd?: string; - root?: string; - dot?: boolean; - nomount?: boolean; - mark?: boolean; - nosort?: boolean; - stat?: boolean; - silent?: boolean; - strict?: boolean; - cache?: { [path: string]: any /* boolean | string | string[] */ }; - statCache?: { [path: string]: fs.Stats }; - symlinks?: any; - sync?: boolean; - nounique?: boolean; - nonull?: boolean; - debug?: boolean; - nobrace?: boolean; - noglobstar?: boolean; - noext?: boolean; - nocase?: boolean; - matchBase?: any; - nodir?: boolean; - ignore?: any; /* string | string[] */ - follow?: boolean; - realpath?: boolean; - nonegate?: boolean; - nocomment?: boolean; - - /** Deprecated. */ - globDebug?: boolean; - } - - interface IGlobStatic extends events.EventEmitter { - new (pattern: string, cb?: (err: Error, matches: string[]) => void): IGlob; - new (pattern: string, options: IOptions, cb?: (err: Error, matches: string[]) => void): IGlob; - prototype: IGlob; - } - - interface IGlobSyncStatic { - new (pattern: string, options?: IOptions): IGlobBase - prototype: IGlobBase; - } - - interface IGlobBase { - minimatch: minimatch.IMinimatch; - options: IOptions; - aborted: boolean; - cache: { [path: string]: any /* boolean | string | string[] */ }; - statCache: { [path: string]: fs.Stats }; - symlinks: { [path: string]: boolean }; - realpathCache: { [path: string]: string }; - found: string[]; - } - - interface IGlob extends IGlobBase, events.EventEmitter { - pause(): void; - resume(): void; - abort(): void; - - /** Deprecated. */ - EOF: any; - /** Deprecated. */ - paused: boolean; - /** Deprecated. */ - maxDepth: number; - /** Deprecated. */ - maxLength: number; - /** Deprecated. */ - changedCwd: boolean; - /** Deprecated. */ - cwd: string; - /** Deprecated. */ - root: string; - /** Deprecated. */ - error: any; - /** Deprecated. */ - matches: string[]; - /** Deprecated. */ - log(...args: any[]): void; - /** Deprecated. */ - emitMatch(m: any): void; - } - } - - export = G; -} diff --git a/typings/js-yaml/js-yaml.d.ts b/typings/js-yaml/js-yaml.d.ts deleted file mode 100644 index 0de5a8f6b38..00000000000 --- a/typings/js-yaml/js-yaml.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -// Type definitions for js-yaml 3.0.2 -// Project: https://github.com/nodeca/js-yaml -// Definitions by: Bart van der Schoor -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -declare module jsyaml { - export function safeLoad(str: string, opts?: LoadOptions): any; - export function load(str: string, opts?: LoadOptions): any; - - export function safeLoadAll(str: string, iterator: (doc: any) => void, opts?: LoadOptions): any; - export function loadAll(str: string, iterator: (doc: any) => void, opts?: LoadOptions): any; - - export function safeDump(obj: any, opts?: DumpOptions): string; - export function dump(obj: any, opts?: DumpOptions): string - - export interface LoadOptions { - // string to be used as a file path in error/warning messages. - filename?: string; - // makes the loader to throw errors instead of warnings. - strict?: boolean; - // specifies a schema to use. - schema?: any; - } - - export interface DumpOptions { - // indentation width to use (in spaces). - indent?: number; - // do not throw on invalid types (like function in the safe schema) and skip pairs and single values with such types. - skipInvalid?: boolean; - // specifies level of nesting, when to switch from block to flow style for collections. -1 means block style everwhere - flowLevel?: number; - // Each tag may have own set of styles. - "tag" => "style" map. - styles?: Object; - // specifies a schema to use. - schema?: any; - } - - // only strings, arrays and plain objects: http://www.yaml.org/spec/1.2/spec.html#id2802346 - export var FAILSAFE_SCHEMA: any; - // only strings, arrays and plain objects: http://www.yaml.org/spec/1.2/spec.html#id2802346 - export var JSON_SCHEMA: any; - // same as JSON_SCHEMA: http://www.yaml.org/spec/1.2/spec.html#id2804923 - export var CORE_SCHEMA: any; - // all supported YAML types, without unsafe ones (!!js/undefined, !!js/regexp and !!js/function): http://yaml.org/type/ - export var DEFAULT_SAFE_SCHEMA: any; - // all supported YAML types. - export var DEFAULT_FULL_SCHEMA: any; -} - -declare module 'js-yaml' { - export = jsyaml; -} diff --git a/typings/minimatch/minimatch.d.ts b/typings/minimatch/minimatch.d.ts deleted file mode 100644 index a79c6ff114d..00000000000 --- a/typings/minimatch/minimatch.d.ts +++ /dev/null @@ -1,64 +0,0 @@ -// Type definitions for Minimatch 2.0.8 -// Project: https://github.com/isaacs/minimatch -// Definitions by: vvakame -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -declare module "minimatch" { - - function M(target: string, pattern: string, options?: M.IOptions): boolean; - - module M { - function match(list: string[], pattern: string, options?: IOptions): string[]; - function filter(pattern: string, options?: IOptions): (element: string, indexed: number, array: string[]) => boolean; - function makeRe(pattern: string, options?: IOptions): RegExp; - - var Minimatch: IMinimatchStatic; - - interface IOptions { - debug?: boolean; - nobrace?: boolean; - noglobstar?: boolean; - dot?: boolean; - noext?: boolean; - nocase?: boolean; - nonull?: boolean; - matchBase?: boolean; - nocomment?: boolean; - nonegate?: boolean; - flipNegate?: boolean; - } - - interface IMinimatchStatic { - new (pattern: string, options?: IOptions): IMinimatch; - prototype: IMinimatch; - } - - interface IMinimatch { - pattern: string; - options: IOptions; - /** 2-dimensional array of regexp or string expressions. */ - set: any[][]; // (RegExp | string)[][] - regexp: RegExp; - negate: boolean; - comment: boolean; - empty: boolean; - - makeRe(): RegExp; // regexp or boolean - match(fname: string): boolean; - matchOne(files: string[], pattern: string[], partial: boolean): boolean; - - /** Deprecated. For internal use. */ - debug(): void; - /** Deprecated. For internal use. */ - make(): void; - /** Deprecated. For internal use. */ - parseNegate(): void; - /** Deprecated. For internal use. */ - braceExpand(pattern: string, options: IOptions): void; - /** Deprecated. For internal use. */ - parse(pattern: string, isSub?: boolean): void; - } - } - - export = M; -} diff --git a/typings/node/node.d.ts b/typings/node/node.d.ts deleted file mode 100644 index d7e23cb1e63..00000000000 --- a/typings/node/node.d.ts +++ /dev/null @@ -1,2077 +0,0 @@ -// Type definitions for Node.js v0.12.0 -// Project: http://nodejs.org/ -// Definitions by: Microsoft TypeScript , DefinitelyTyped -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -/************************************************ -* * -* Node.js v0.12.0 API * -* * -************************************************/ - -interface Error { - stack?: string; -} - - -// compat for TypeScript 1.5.3 -// if you use with --target es3 or --target es5 and use below definitions, -// use the lib.es6.d.ts that is bundled with TypeScript 1.5.3. -interface MapConstructor {} -interface WeakMapConstructor {} -interface SetConstructor {} -interface WeakSetConstructor {} - -/************************************************ -* * -* GLOBAL * -* * -************************************************/ -declare var process: NodeJS.Process; -declare var global: NodeJS.Global; - -declare var __filename: string; -declare var __dirname: string; - -declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; -declare function clearTimeout(timeoutId: NodeJS.Timer): void; -declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; -declare function clearInterval(intervalId: NodeJS.Timer): void; -declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; -declare function clearImmediate(immediateId: any): void; - -interface NodeRequireFunction { - (id: string): any; -} - -interface NodeRequire extends NodeRequireFunction { - resolve(id:string): string; - cache: any; - extensions: any; - main: any; -} - -declare var require: NodeRequire; - -interface NodeModule { - exports: any; - require: NodeRequireFunction; - id: string; - filename: string; - loaded: boolean; - parent: any; - children: any[]; -} - -declare var module: NodeModule; - -// Same as module.exports -declare var exports: any; -declare var SlowBuffer: { - new (str: string, encoding?: string): Buffer; - new (size: number): Buffer; - new (size: Uint8Array): Buffer; - new (array: any[]): Buffer; - prototype: Buffer; - isBuffer(obj: any): boolean; - byteLength(string: string, encoding?: string): number; - concat(list: Buffer[], totalLength?: number): Buffer; -}; - - -// Buffer class -interface Buffer extends NodeBuffer {} - -/** - * Raw data is stored in instances of the Buffer class. - * A Buffer is similar to an array of integers but corresponds to a raw memory allocation outside the V8 heap. A Buffer cannot be resized. - * Valid string encodings: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex' - */ -declare var Buffer: { - /** - * Allocates a new buffer containing the given {str}. - * - * @param str String to store in buffer. - * @param encoding encoding to use, optional. Default is 'utf8' - */ - new (str: string, encoding?: string): Buffer; - /** - * Allocates a new buffer of {size} octets. - * - * @param size count of octets to allocate. - */ - new (size: number): Buffer; - /** - * Allocates a new buffer containing the given {array} of octets. - * - * @param array The octets to store. - */ - new (array: Uint8Array): Buffer; - /** - * Allocates a new buffer containing the given {array} of octets. - * - * @param array The octets to store. - */ - new (array: any[]): Buffer; - prototype: Buffer; - /** - * Returns true if {obj} is a Buffer - * - * @param obj object to test. - */ - isBuffer(obj: any): boolean; - /** - * Returns true if {encoding} is a valid encoding argument. - * Valid string encodings in Node 0.12: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex' - * - * @param encoding string to test. - */ - isEncoding(encoding: string): boolean; - /** - * Gives the actual byte length of a string. encoding defaults to 'utf8'. - * This is not the same as String.prototype.length since that returns the number of characters in a string. - * - * @param string string to test. - * @param encoding encoding used to evaluate (defaults to 'utf8') - */ - byteLength(string: string, encoding?: string): number; - /** - * Returns a buffer which is the result of concatenating all the buffers in the list together. - * - * If the list has no items, or if the totalLength is 0, then it returns a zero-length buffer. - * If the list has exactly one item, then the first item of the list is returned. - * If the list has more than one item, then a new Buffer is created. - * - * @param list An array of Buffer objects to concatenate - * @param totalLength Total length of the buffers when concatenated. - * If totalLength is not provided, it is read from the buffers in the list. However, this adds an additional loop to the function, so it is faster to provide the length explicitly. - */ - concat(list: Buffer[], totalLength?: number): Buffer; - /** - * The same as buf1.compare(buf2). - */ - compare(buf1: Buffer, buf2: Buffer): number; -}; - -/************************************************ -* * -* GLOBAL INTERFACES * -* * -************************************************/ -declare module NodeJS { - export interface ErrnoException extends Error { - errno?: number; - code?: string; - path?: string; - syscall?: string; - stack?: string; - } - - export interface EventEmitter { - addListener(event: string, listener: Function): EventEmitter; - on(event: string, listener: Function): EventEmitter; - once(event: string, listener: Function): EventEmitter; - removeListener(event: string, listener: Function): EventEmitter; - removeAllListeners(event?: string): EventEmitter; - setMaxListeners(n: number): void; - listeners(event: string): Function[]; - emit(event: string, ...args: any[]): boolean; - } - - export interface ReadableStream extends EventEmitter { - readable: boolean; - read(size?: number): string|Buffer; - setEncoding(encoding: string): void; - pause(): void; - resume(): void; - pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; - unshift(chunk: string): void; - unshift(chunk: Buffer): void; - wrap(oldStream: ReadableStream): ReadableStream; - } - - export interface WritableStream extends EventEmitter { - writable: boolean; - write(buffer: Buffer|string, cb?: Function): boolean; - write(str: string, encoding?: string, cb?: Function): boolean; - end(): void; - end(buffer: Buffer, cb?: Function): void; - end(str: string, cb?: Function): void; - end(str: string, encoding?: string, cb?: Function): void; - } - - export interface ReadWriteStream extends ReadableStream, WritableStream {} - - export interface Process extends EventEmitter { - stdout: WritableStream; - stderr: WritableStream; - stdin: ReadableStream; - argv: string[]; - execPath: string; - abort(): void; - chdir(directory: string): void; - cwd(): string; - env: any; - exit(code?: number): void; - getgid(): number; - setgid(id: number): void; - setgid(id: string): void; - getuid(): number; - setuid(id: number): void; - setuid(id: string): void; - version: string; - versions: { - http_parser: string; - node: string; - v8: string; - ares: string; - uv: string; - zlib: string; - openssl: string; - }; - config: { - target_defaults: { - cflags: any[]; - default_configuration: string; - defines: string[]; - include_dirs: string[]; - libraries: string[]; - }; - variables: { - clang: number; - host_arch: string; - node_install_npm: boolean; - node_install_waf: boolean; - node_prefix: string; - node_shared_openssl: boolean; - node_shared_v8: boolean; - node_shared_zlib: boolean; - node_use_dtrace: boolean; - node_use_etw: boolean; - node_use_openssl: boolean; - target_arch: string; - v8_no_strict_aliasing: number; - v8_use_snapshot: boolean; - visibility: string; - }; - }; - kill(pid: number, signal?: string): void; - pid: number; - title: string; - arch: string; - platform: string; - memoryUsage(): { rss: number; heapTotal: number; heapUsed: number; }; - nextTick(callback: Function): void; - umask(mask?: number): number; - uptime(): number; - hrtime(time?:number[]): number[]; - - // Worker - send?(message: any, sendHandle?: any): void; - } - - export interface Global { - Array: typeof Array; - ArrayBuffer: typeof ArrayBuffer; - Boolean: typeof Boolean; - Buffer: typeof Buffer; - DataView: typeof DataView; - Date: typeof Date; - Error: typeof Error; - EvalError: typeof EvalError; - Float32Array: typeof Float32Array; - Float64Array: typeof Float64Array; - Function: typeof Function; - GLOBAL: Global; - Infinity: typeof Infinity; - Int16Array: typeof Int16Array; - Int32Array: typeof Int32Array; - Int8Array: typeof Int8Array; - Intl: typeof Intl; - JSON: typeof JSON; - Map: MapConstructor; - Math: typeof Math; - NaN: typeof NaN; - Number: typeof Number; - Object: typeof Object; - Promise: Function; - RangeError: typeof RangeError; - ReferenceError: typeof ReferenceError; - RegExp: typeof RegExp; - Set: SetConstructor; - String: typeof String; - Symbol: Function; - SyntaxError: typeof SyntaxError; - TypeError: typeof TypeError; - URIError: typeof URIError; - Uint16Array: typeof Uint16Array; - Uint32Array: typeof Uint32Array; - Uint8Array: typeof Uint8Array; - Uint8ClampedArray: Function; - WeakMap: WeakMapConstructor; - WeakSet: WeakSetConstructor; - clearImmediate: (immediateId: any) => void; - clearInterval: (intervalId: NodeJS.Timer) => void; - clearTimeout: (timeoutId: NodeJS.Timer) => void; - console: typeof console; - decodeURI: typeof decodeURI; - decodeURIComponent: typeof decodeURIComponent; - encodeURI: typeof encodeURI; - encodeURIComponent: typeof encodeURIComponent; - escape: (str: string) => string; - eval: typeof eval; - global: Global; - isFinite: typeof isFinite; - isNaN: typeof isNaN; - parseFloat: typeof parseFloat; - parseInt: typeof parseInt; - process: Process; - root: Global; - setImmediate: (callback: (...args: any[]) => void, ...args: any[]) => any; - setInterval: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer; - setTimeout: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer; - undefined: typeof undefined; - unescape: (str: string) => string; - gc: () => void; - } - - export interface Timer { - ref() : void; - unref() : void; - } -} - -/** - * @deprecated - */ -interface NodeBuffer { - [index: number]: number; - write(string: string, offset?: number, length?: number, encoding?: string): number; - toString(encoding?: string, start?: number, end?: number): string; - toJSON(): any; - length: number; - equals(otherBuffer: Buffer): boolean; - compare(otherBuffer: Buffer): number; - copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; - slice(start?: number, end?: number): Buffer; - writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number; - readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number; - readIntLE(offset: number, byteLength: number, noAssert?: boolean): number; - readIntBE(offset: number, byteLength: number, noAssert?: boolean): number; - readUInt8(offset: number, noAsset?: boolean): number; - readUInt16LE(offset: number, noAssert?: boolean): number; - readUInt16BE(offset: number, noAssert?: boolean): number; - readUInt32LE(offset: number, noAssert?: boolean): number; - readUInt32BE(offset: number, noAssert?: boolean): number; - readInt8(offset: number, noAssert?: boolean): number; - readInt16LE(offset: number, noAssert?: boolean): number; - readInt16BE(offset: number, noAssert?: boolean): number; - readInt32LE(offset: number, noAssert?: boolean): number; - readInt32BE(offset: number, noAssert?: boolean): number; - readFloatLE(offset: number, noAssert?: boolean): number; - readFloatBE(offset: number, noAssert?: boolean): number; - readDoubleLE(offset: number, noAssert?: boolean): number; - readDoubleBE(offset: number, noAssert?: boolean): number; - writeUInt8(value: number, offset: number, noAssert?: boolean): void; - writeUInt16LE(value: number, offset: number, noAssert?: boolean): void; - writeUInt16BE(value: number, offset: number, noAssert?: boolean): void; - writeUInt32LE(value: number, offset: number, noAssert?: boolean): void; - writeUInt32BE(value: number, offset: number, noAssert?: boolean): void; - writeInt8(value: number, offset: number, noAssert?: boolean): void; - writeInt16LE(value: number, offset: number, noAssert?: boolean): void; - writeInt16BE(value: number, offset: number, noAssert?: boolean): void; - writeInt32LE(value: number, offset: number, noAssert?: boolean): void; - writeInt32BE(value: number, offset: number, noAssert?: boolean): void; - writeFloatLE(value: number, offset: number, noAssert?: boolean): void; - writeFloatBE(value: number, offset: number, noAssert?: boolean): void; - writeDoubleLE(value: number, offset: number, noAssert?: boolean): void; - writeDoubleBE(value: number, offset: number, noAssert?: boolean): void; - fill(value: any, offset?: number, end?: number): void; -} - -/************************************************ -* * -* MODULES * -* * -************************************************/ -declare module "buffer" { - export var INSPECT_MAX_BYTES: number; -} - -declare module "querystring" { - export function stringify(obj: any, sep?: string, eq?: string): string; - export function parse(str: string, sep?: string, eq?: string, options?: { maxKeys?: number; }): any; - export function escape(str: string): string; - export function unescape(str: string): string; -} - -declare module "events" { - export class EventEmitter implements NodeJS.EventEmitter { - static listenerCount(emitter: EventEmitter, event: string): number; - - addListener(event: string, listener: Function): EventEmitter; - on(event: string, listener: Function): EventEmitter; - once(event: string, listener: Function): EventEmitter; - removeListener(event: string, listener: Function): EventEmitter; - removeAllListeners(event?: string): EventEmitter; - setMaxListeners(n: number): void; - listeners(event: string): Function[]; - emit(event: string, ...args: any[]): boolean; - } -} - -declare module "http" { - import * as events from "events"; - import * as net from "net"; - import * as stream from "stream"; - - export interface Server extends events.EventEmitter { - listen(port: number, hostname?: string, backlog?: number, callback?: Function): Server; - listen(port: number, hostname?: string, callback?: Function): Server; - listen(path: string, callback?: Function): Server; - listen(handle: any, listeningListener?: Function): Server; - close(cb?: any): Server; - address(): { port: number; family: string; address: string; }; - maxHeadersCount: number; - } - /** - * @deprecated Use IncomingMessage - */ - export interface ServerRequest extends IncomingMessage { - connection: net.Socket; - } - export interface ServerResponse extends events.EventEmitter, stream.Writable { - // Extended base methods - write(buffer: Buffer): boolean; - write(buffer: Buffer, cb?: Function): boolean; - write(str: string, cb?: Function): boolean; - write(str: string, encoding?: string, cb?: Function): boolean; - write(str: string, encoding?: string, fd?: string): boolean; - - writeContinue(): void; - writeHead(statusCode: number, reasonPhrase?: string, headers?: any): void; - writeHead(statusCode: number, headers?: any): void; - statusCode: number; - statusMessage: string; - setHeader(name: string, value: string): void; - sendDate: boolean; - getHeader(name: string): string; - removeHeader(name: string): void; - write(chunk: any, encoding?: string): any; - addTrailers(headers: any): void; - - // Extended base methods - end(): void; - end(buffer: Buffer, cb?: Function): void; - end(str: string, cb?: Function): void; - end(str: string, encoding?: string, cb?: Function): void; - end(data?: any, encoding?: string): void; - } - export interface ClientRequest extends events.EventEmitter, stream.Writable { - // Extended base methods - write(buffer: Buffer): boolean; - write(buffer: Buffer, cb?: Function): boolean; - write(str: string, cb?: Function): boolean; - write(str: string, encoding?: string, cb?: Function): boolean; - write(str: string, encoding?: string, fd?: string): boolean; - - write(chunk: any, encoding?: string): void; - abort(): void; - setTimeout(timeout: number, callback?: Function): void; - setNoDelay(noDelay?: boolean): void; - setSocketKeepAlive(enable?: boolean, initialDelay?: number): void; - - // Extended base methods - end(): void; - end(buffer: Buffer, cb?: Function): void; - end(str: string, cb?: Function): void; - end(str: string, encoding?: string, cb?: Function): void; - end(data?: any, encoding?: string): void; - } - export interface IncomingMessage extends events.EventEmitter, stream.Readable { - httpVersion: string; - headers: any; - rawHeaders: string[]; - trailers: any; - rawTrailers: any; - setTimeout(msecs: number, callback: Function): NodeJS.Timer; - /** - * Only valid for request obtained from http.Server. - */ - method?: string; - /** - * Only valid for request obtained from http.Server. - */ - url?: string; - /** - * Only valid for response obtained from http.ClientRequest. - */ - statusCode?: number; - /** - * Only valid for response obtained from http.ClientRequest. - */ - statusMessage?: string; - socket: net.Socket; - } - /** - * @deprecated Use IncomingMessage - */ - export interface ClientResponse extends IncomingMessage { } - - export interface AgentOptions { - /** - * Keep sockets around in a pool to be used by other requests in the future. Default = false - */ - keepAlive?: boolean; - /** - * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. - * Only relevant if keepAlive is set to true. - */ - keepAliveMsecs?: number; - /** - * Maximum number of sockets to allow per host. Default for Node 0.10 is 5, default for Node 0.12 is Infinity - */ - maxSockets?: number; - /** - * Maximum number of sockets to leave open in a free state. Only relevant if keepAlive is set to true. Default = 256. - */ - maxFreeSockets?: number; - } - - export class Agent { - maxSockets: number; - sockets: any; - requests: any; - - constructor(opts?: AgentOptions); - - /** - * Destroy any sockets that are currently in use by the agent. - * It is usually not necessary to do this. However, if you are using an agent with KeepAlive enabled, - * then it is best to explicitly shut down the agent when you know that it will no longer be used. Otherwise, - * sockets may hang open for quite a long time before the server terminates them. - */ - destroy(): void; - } - - export var METHODS: string[]; - - export var STATUS_CODES: { - [errorCode: number]: string; - [errorCode: string]: string; - }; - export function createServer(requestListener?: (request: IncomingMessage, response: ServerResponse) =>void ): Server; - export function createClient(port?: number, host?: string): any; - export function request(options: any, callback?: (res: IncomingMessage) => void): ClientRequest; - export function get(options: any, callback?: (res: IncomingMessage) => void): ClientRequest; - export var globalAgent: Agent; -} - -declare module "cluster" { - import * as child from "child_process"; - import * as events from "events"; - - export interface ClusterSettings { - exec?: string; - args?: string[]; - silent?: boolean; - } - - export class Worker extends events.EventEmitter { - id: string; - process: child.ChildProcess; - suicide: boolean; - send(message: any, sendHandle?: any): void; - kill(signal?: string): void; - destroy(signal?: string): void; - disconnect(): void; - } - - export var settings: ClusterSettings; - export var isMaster: boolean; - export var isWorker: boolean; - export function setupMaster(settings?: ClusterSettings): void; - export function fork(env?: any): Worker; - export function disconnect(callback?: Function): void; - export var worker: Worker; - export var workers: Worker[]; - - // Event emitter - export function addListener(event: string, listener: Function): void; - export function on(event: string, listener: Function): any; - export function once(event: string, listener: Function): void; - export function removeListener(event: string, listener: Function): void; - export function removeAllListeners(event?: string): void; - export function setMaxListeners(n: number): void; - export function listeners(event: string): Function[]; - export function emit(event: string, ...args: any[]): boolean; -} - -declare module "zlib" { - import * as stream from "stream"; - export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; } - - export interface Gzip extends stream.Transform { } - export interface Gunzip extends stream.Transform { } - export interface Deflate extends stream.Transform { } - export interface Inflate extends stream.Transform { } - export interface DeflateRaw extends stream.Transform { } - export interface InflateRaw extends stream.Transform { } - export interface Unzip extends stream.Transform { } - - export function createGzip(options?: ZlibOptions): Gzip; - export function createGunzip(options?: ZlibOptions): Gunzip; - export function createDeflate(options?: ZlibOptions): Deflate; - export function createInflate(options?: ZlibOptions): Inflate; - export function createDeflateRaw(options?: ZlibOptions): DeflateRaw; - export function createInflateRaw(options?: ZlibOptions): InflateRaw; - export function createUnzip(options?: ZlibOptions): Unzip; - - export function deflate(buf: Buffer, callback: (error: Error, result: any) =>void ): void; - export function deflateSync(buf: Buffer, options?: ZlibOptions): any; - export function deflateRaw(buf: Buffer, callback: (error: Error, result: any) =>void ): void; - export function deflateRawSync(buf: Buffer, options?: ZlibOptions): any; - export function gzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void; - export function gzipSync(buf: Buffer, options?: ZlibOptions): any; - export function gunzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void; - export function gunzipSync(buf: Buffer, options?: ZlibOptions): any; - export function inflate(buf: Buffer, callback: (error: Error, result: any) =>void ): void; - export function inflateSync(buf: Buffer, options?: ZlibOptions): any; - export function inflateRaw(buf: Buffer, callback: (error: Error, result: any) =>void ): void; - export function inflateRawSync(buf: Buffer, options?: ZlibOptions): any; - export function unzip(buf: Buffer, callback: (error: Error, result: any) =>void ): void; - export function unzipSync(buf: Buffer, options?: ZlibOptions): any; - - // Constants - export var Z_NO_FLUSH: number; - export var Z_PARTIAL_FLUSH: number; - export var Z_SYNC_FLUSH: number; - export var Z_FULL_FLUSH: number; - export var Z_FINISH: number; - export var Z_BLOCK: number; - export var Z_TREES: number; - export var Z_OK: number; - export var Z_STREAM_END: number; - export var Z_NEED_DICT: number; - export var Z_ERRNO: number; - export var Z_STREAM_ERROR: number; - export var Z_DATA_ERROR: number; - export var Z_MEM_ERROR: number; - export var Z_BUF_ERROR: number; - export var Z_VERSION_ERROR: number; - export var Z_NO_COMPRESSION: number; - export var Z_BEST_SPEED: number; - export var Z_BEST_COMPRESSION: number; - export var Z_DEFAULT_COMPRESSION: number; - export var Z_FILTERED: number; - export var Z_HUFFMAN_ONLY: number; - export var Z_RLE: number; - export var Z_FIXED: number; - export var Z_DEFAULT_STRATEGY: number; - export var Z_BINARY: number; - export var Z_TEXT: number; - export var Z_ASCII: number; - export var Z_UNKNOWN: number; - export var Z_DEFLATED: number; - export var Z_NULL: number; -} - -declare module "os" { - export function tmpdir(): string; - export function hostname(): string; - export function type(): string; - export function platform(): string; - export function arch(): string; - export function release(): string; - export function uptime(): number; - export function loadavg(): number[]; - export function totalmem(): number; - export function freemem(): number; - export function cpus(): { model: string; speed: number; times: { user: number; nice: number; sys: number; idle: number; irq: number; }; }[]; - export function networkInterfaces(): any; - export var EOL: string; -} - -declare module "https" { - import * as tls from "tls"; - import * as events from "events"; - import * as http from "http"; - - export interface ServerOptions { - pfx?: any; - key?: any; - passphrase?: string; - cert?: any; - ca?: any; - crl?: any; - ciphers?: string; - honorCipherOrder?: boolean; - requestCert?: boolean; - rejectUnauthorized?: boolean; - NPNProtocols?: any; - SNICallback?: (servername: string) => any; - } - - export interface RequestOptions { - host?: string; - hostname?: string; - port?: number; - path?: string; - method?: string; - headers?: any; - auth?: string; - agent?: any; - pfx?: any; - key?: any; - passphrase?: string; - cert?: any; - ca?: any; - ciphers?: string; - rejectUnauthorized?: boolean; - } - - export interface Agent { - maxSockets: number; - sockets: any; - requests: any; - } - export var Agent: { - new (options?: RequestOptions): Agent; - }; - export interface Server extends tls.Server { } - export function createServer(options: ServerOptions, requestListener?: Function): Server; - export function request(options: RequestOptions, callback?: (res: http.IncomingMessage) =>void ): http.ClientRequest; - export function get(options: RequestOptions, callback?: (res: http.IncomingMessage) =>void ): http.ClientRequest; - export var globalAgent: Agent; -} - -declare module "punycode" { - export function decode(string: string): string; - export function encode(string: string): string; - export function toUnicode(domain: string): string; - export function toASCII(domain: string): string; - export var ucs2: ucs2; - interface ucs2 { - decode(string: string): string; - encode(codePoints: number[]): string; - } - export var version: any; -} - -declare module "repl" { - import * as stream from "stream"; - import * as events from "events"; - - export interface ReplOptions { - prompt?: string; - input?: NodeJS.ReadableStream; - output?: NodeJS.WritableStream; - terminal?: boolean; - eval?: Function; - useColors?: boolean; - useGlobal?: boolean; - ignoreUndefined?: boolean; - writer?: Function; - } - export function start(options: ReplOptions): events.EventEmitter; -} - -declare module "readline" { - import * as events from "events"; - import * as stream from "stream"; - - export interface ReadLine extends events.EventEmitter { - setPrompt(prompt: string): void; - prompt(preserveCursor?: boolean): void; - question(query: string, callback: Function): void; - pause(): void; - resume(): void; - close(): void; - write(data: any, key?: any): void; - } - export interface ReadLineOptions { - input: NodeJS.ReadableStream; - output: NodeJS.WritableStream; - completer?: Function; - terminal?: boolean; - } - export function createInterface(options: ReadLineOptions): ReadLine; -} - -declare module "vm" { - export interface Context { } - export interface Script { - runInThisContext(): void; - runInNewContext(sandbox?: Context): void; - } - export function runInThisContext(code: string, filename?: string): void; - export function runInNewContext(code: string, sandbox?: Context, filename?: string): void; - export function runInContext(code: string, context: Context, filename?: string): void; - export function createContext(initSandbox?: Context): Context; - export function createScript(code: string, filename?: string): Script; -} - -declare module "child_process" { - import * as events from "events"; - import * as stream from "stream"; - - export interface ChildProcess extends events.EventEmitter { - stdin: stream.Writable; - stdout: stream.Readable; - stderr: stream.Readable; - pid: number; - kill(signal?: string): void; - send(message: any, sendHandle?: any): void; - disconnect(): void; - unref(): void; - } - - export function spawn(command: string, args?: string[], options?: { - cwd?: string; - stdio?: any; - custom?: any; - env?: any; - detached?: boolean; - }): ChildProcess; - export function exec(command: string, options: { - cwd?: string; - stdio?: any; - customFds?: any; - env?: any; - encoding?: string; - timeout?: number; - maxBuffer?: number; - killSignal?: string; - }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; - export function exec(command: string, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; - export function execFile(file: string, - callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; - export function execFile(file: string, args?: string[], - callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; - export function execFile(file: string, args?: string[], options?: { - cwd?: string; - stdio?: any; - customFds?: any; - env?: any; - encoding?: string; - timeout?: number; - maxBuffer?: string; - killSignal?: string; - }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess; - export function fork(modulePath: string, args?: string[], options?: { - cwd?: string; - env?: any; - encoding?: string; - }): ChildProcess; - export function execSync(command: string, options?: { - cwd?: string; - input?: string|Buffer; - stdio?: any; - env?: any; - uid?: number; - gid?: number; - timeout?: number; - maxBuffer?: number; - killSignal?: string; - encoding?: string; - }): ChildProcess; - export function execFileSync(command: string, args?: string[], options?: { - cwd?: string; - input?: string|Buffer; - stdio?: any; - env?: any; - uid?: number; - gid?: number; - timeout?: number; - maxBuffer?: number; - killSignal?: string; - encoding?: string; - }): ChildProcess; -} - -declare module "url" { - export interface Url { - href: string; - protocol: string; - auth: string; - hostname: string; - port: string; - host: string; - pathname: string; - search: string; - query: any; // string | Object - slashes: boolean; - hash?: string; - path?: string; - } - - export interface UrlOptions { - protocol?: string; - auth?: string; - hostname?: string; - port?: string; - host?: string; - pathname?: string; - search?: string; - query?: any; - hash?: string; - path?: string; - } - - export function parse(urlStr: string, parseQueryString?: boolean , slashesDenoteHost?: boolean ): Url; - export function format(url: UrlOptions): string; - export function resolve(from: string, to: string): string; -} - -declare module "dns" { - export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) =>void ): string; - export function lookup(domain: string, callback: (err: Error, address: string, family: number) =>void ): string; - export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) =>void ): string[]; - export function resolve(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; - export function resolve4(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; - export function resolve6(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; - export function resolveMx(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; - export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; - export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; - export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; - export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) =>void ): string[]; - export function reverse(ip: string, callback: (err: Error, domains: string[]) =>void ): string[]; -} - -declare module "net" { - import * as stream from "stream"; - - export interface Socket extends stream.Duplex { - // Extended base methods - write(buffer: Buffer): boolean; - write(buffer: Buffer, cb?: Function): boolean; - write(str: string, cb?: Function): boolean; - write(str: string, encoding?: string, cb?: Function): boolean; - write(str: string, encoding?: string, fd?: string): boolean; - - connect(port: number, host?: string, connectionListener?: Function): void; - connect(path: string, connectionListener?: Function): void; - bufferSize: number; - setEncoding(encoding?: string): void; - write(data: any, encoding?: string, callback?: Function): void; - destroy(): void; - pause(): void; - resume(): void; - setTimeout(timeout: number, callback?: Function): void; - setNoDelay(noDelay?: boolean): void; - setKeepAlive(enable?: boolean, initialDelay?: number): void; - address(): { port: number; family: string; address: string; }; - unref(): void; - ref(): void; - - remoteAddress: string; - remoteFamily: string; - remotePort: number; - localAddress: string; - localPort: number; - bytesRead: number; - bytesWritten: number; - - // Extended base methods - end(): void; - end(buffer: Buffer, cb?: Function): void; - end(str: string, cb?: Function): void; - end(str: string, encoding?: string, cb?: Function): void; - end(data?: any, encoding?: string): void; - } - - export var Socket: { - new (options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }): Socket; - }; - - export interface Server extends Socket { - listen(port: number, host?: string, backlog?: number, listeningListener?: Function): Server; - listen(path: string, listeningListener?: Function): Server; - listen(handle: any, listeningListener?: Function): Server; - close(callback?: Function): Server; - address(): { port: number; family: string; address: string; }; - maxConnections: number; - connections: number; - } - export function createServer(connectionListener?: (socket: Socket) =>void ): Server; - export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: Socket) =>void ): Server; - export function connect(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; - export function connect(port: number, host?: string, connectionListener?: Function): Socket; - export function connect(path: string, connectionListener?: Function): Socket; - export function createConnection(options: { allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; - export function createConnection(port: number, host?: string, connectionListener?: Function): Socket; - export function createConnection(path: string, connectionListener?: Function): Socket; - export function isIP(input: string): number; - export function isIPv4(input: string): boolean; - export function isIPv6(input: string): boolean; -} - -declare module "dgram" { - import * as events from "events"; - - interface RemoteInfo { - address: string; - port: number; - size: number; - } - - interface AddressInfo { - address: string; - family: string; - port: number; - } - - export function createSocket(type: string, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; - - interface Socket extends events.EventEmitter { - send(buf: Buffer, offset: number, length: number, port: number, address: string, callback?: (error: Error, bytes: number) => void): void; - bind(port: number, address?: string, callback?: () => void): void; - close(): void; - address(): AddressInfo; - setBroadcast(flag: boolean): void; - setMulticastTTL(ttl: number): void; - setMulticastLoopback(flag: boolean): void; - addMembership(multicastAddress: string, multicastInterface?: string): void; - dropMembership(multicastAddress: string, multicastInterface?: string): void; - } -} - -declare module "fs" { - import * as stream from "stream"; - import * as events from "events"; - - interface Stats { - isFile(): boolean; - isDirectory(): boolean; - isBlockDevice(): boolean; - isCharacterDevice(): boolean; - isSymbolicLink(): boolean; - isFIFO(): boolean; - isSocket(): boolean; - dev: number; - ino: number; - mode: number; - nlink: number; - uid: number; - gid: number; - rdev: number; - size: number; - blksize: number; - blocks: number; - atime: Date; - mtime: Date; - ctime: Date; - birthtime: Date; - } - - interface FSWatcher extends events.EventEmitter { - close(): void; - } - - export interface ReadStream extends stream.Readable { - close(): void; - } - export interface WriteStream extends stream.Writable { - close(): void; - bytesWritten: number; - } - - /** - * Asynchronous rename. - * @param oldPath - * @param newPath - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function rename(oldPath: string, newPath: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - /** - * Synchronous rename - * @param oldPath - * @param newPath - */ - export function renameSync(oldPath: string, newPath: string): void; - export function truncate(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function truncate(path: string, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function truncateSync(path: string, len?: number): void; - export function ftruncate(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function ftruncate(fd: number, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function ftruncateSync(fd: number, len?: number): void; - export function chown(path: string, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function chownSync(path: string, uid: number, gid: number): void; - export function fchown(fd: number, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function fchownSync(fd: number, uid: number, gid: number): void; - export function lchown(path: string, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function lchownSync(path: string, uid: number, gid: number): void; - export function chmod(path: string, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function chmod(path: string, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function chmodSync(path: string, mode: number): void; - export function chmodSync(path: string, mode: string): void; - export function fchmod(fd: number, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function fchmod(fd: number, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function fchmodSync(fd: number, mode: number): void; - export function fchmodSync(fd: number, mode: string): void; - export function lchmod(path: string, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function lchmod(path: string, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function lchmodSync(path: string, mode: number): void; - export function lchmodSync(path: string, mode: string): void; - export function stat(path: string, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; - export function lstat(path: string, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; - export function fstat(fd: number, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; - export function statSync(path: string): Stats; - export function lstatSync(path: string): Stats; - export function fstatSync(fd: number): Stats; - export function link(srcpath: string, dstpath: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function linkSync(srcpath: string, dstpath: string): void; - export function symlink(srcpath: string, dstpath: string, type?: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function symlinkSync(srcpath: string, dstpath: string, type?: string): void; - export function readlink(path: string, callback?: (err: NodeJS.ErrnoException, linkString: string) => any): void; - export function readlinkSync(path: string): string; - export function realpath(path: string, callback?: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void; - export function realpath(path: string, cache: {[path: string]: string}, callback: (err: NodeJS.ErrnoException, resolvedPath: string) =>any): void; - export function realpathSync(path: string, cache?: { [path: string]: string }): string; - /* - * Asynchronous unlink - deletes the file specified in {path} - * - * @param path - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function unlink(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Synchronous unlink - deletes the file specified in {path} - * - * @param path - */ - export function unlinkSync(path: string): void; - /* - * Asynchronous rmdir - removes the directory specified in {path} - * - * @param path - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function rmdir(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Synchronous rmdir - removes the directory specified in {path} - * - * @param path - */ - export function rmdirSync(path: string): void; - /* - * Asynchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdir(path: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Asynchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param mode - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdir(path: string, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Asynchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param mode - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdir(path: string, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Synchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param mode - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdirSync(path: string, mode?: number): void; - /* - * Synchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param mode - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdirSync(path: string, mode?: string): void; - export function readdir(path: string, callback?: (err: NodeJS.ErrnoException, files: string[]) => void): void; - export function readdirSync(path: string): string[]; - export function close(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function closeSync(fd: number): void; - export function open(path: string, flags: string, callback?: (err: NodeJS.ErrnoException, fd: number) => any): void; - export function open(path: string, flags: string, mode: number, callback?: (err: NodeJS.ErrnoException, fd: number) => any): void; - export function open(path: string, flags: string, mode: string, callback?: (err: NodeJS.ErrnoException, fd: number) => any): void; - export function openSync(path: string, flags: string, mode?: number): number; - export function openSync(path: string, flags: string, mode?: string): number; - export function utimes(path: string, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function utimes(path: string, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function utimesSync(path: string, atime: number, mtime: number): void; - export function utimesSync(path: string, atime: Date, mtime: Date): void; - export function futimes(fd: number, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function futimes(fd: number, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function futimesSync(fd: number, atime: number, mtime: number): void; - export function futimesSync(fd: number, atime: Date, mtime: Date): void; - export function fsync(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function fsyncSync(fd: number): void; - export function write(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void; - export function write(fd: number, buffer: Buffer, offset: number, length: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void; - export function write(fd: number, data: any, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void; - export function write(fd: number, data: any, offset: number, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void; - export function write(fd: number, data: any, offset: number, encoding: string, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void; - export function writeSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number; - export function read(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void; - export function readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number; - /* - * Asynchronous readFile - Asynchronously reads the entire contents of a file. - * - * @param fileName - * @param encoding - * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. - */ - export function readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void; - /* - * Asynchronous readFile - Asynchronously reads the entire contents of a file. - * - * @param fileName - * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFile returns a string; otherwise it returns a Buffer. - * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. - */ - export function readFile(filename: string, options: { encoding: string; flag?: string; }, callback: (err: NodeJS.ErrnoException, data: string) => void): void; - /* - * Asynchronous readFile - Asynchronously reads the entire contents of a file. - * - * @param fileName - * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFile returns a string; otherwise it returns a Buffer. - * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. - */ - export function readFile(filename: string, options: { flag?: string; }, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; - /* - * Asynchronous readFile - Asynchronously reads the entire contents of a file. - * - * @param fileName - * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. - */ - export function readFile(filename: string, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; - /* - * Synchronous readFile - Synchronously reads the entire contents of a file. - * - * @param fileName - * @param encoding - */ - export function readFileSync(filename: string, encoding: string): string; - /* - * Synchronous readFile - Synchronously reads the entire contents of a file. - * - * @param fileName - * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFileSync returns a string; otherwise it returns a Buffer. - */ - export function readFileSync(filename: string, options: { encoding: string; flag?: string; }): string; - /* - * Synchronous readFile - Synchronously reads the entire contents of a file. - * - * @param fileName - * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFileSync returns a string; otherwise it returns a Buffer. - */ - export function readFileSync(filename: string, options?: { flag?: string; }): Buffer; - export function writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; - export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; - export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; - export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; - export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; - export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; - export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; - export function appendFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; - export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; - export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; - export function watchFile(filename: string, listener: (curr: Stats, prev: Stats) => void): void; - export function watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: Stats, prev: Stats) => void): void; - export function unwatchFile(filename: string, listener?: (curr: Stats, prev: Stats) => void): void; - export function watch(filename: string, listener?: (event: string, filename: string) => any): FSWatcher; - export function watch(filename: string, options: { persistent?: boolean; }, listener?: (event: string, filename: string) => any): FSWatcher; - export function exists(path: string, callback?: (exists: boolean) => void): void; - export function existsSync(path: string): boolean; - /** Constant for fs.access(). File is visible to the calling process. */ - export var F_OK: number; - /** Constant for fs.access(). File can be read by the calling process. */ - export var R_OK: number; - /** Constant for fs.access(). File can be written by the calling process. */ - export var W_OK: number; - /** Constant for fs.access(). File can be executed by the calling process. */ - export var X_OK: number; - /** Tests a user's permissions for the file specified by path. */ - export function access(path: string, callback: (err: NodeJS.ErrnoException) => void): void; - export function access(path: string, mode: number, callback: (err: NodeJS.ErrnoException) => void): void; - /** Synchronous version of fs.access. This throws if any accessibility checks fail, and does nothing otherwise. */ - export function accessSync(path: string, mode ?: number): void; - export function createReadStream(path: string, options?: { - flags?: string; - encoding?: string; - fd?: string; - mode?: number; - bufferSize?: number; - }): ReadStream; - export function createReadStream(path: string, options?: { - flags?: string; - encoding?: string; - fd?: string; - mode?: string; - bufferSize?: number; - }): ReadStream; - export function createWriteStream(path: string, options?: { - flags?: string; - encoding?: string; - mode?: number; - }): WriteStream; -} - -declare module "path" { - - /** - * A parsed path object generated by path.parse() or consumed by path.format(). - */ - export interface ParsedPath { - /** - * The root of the path such as '/' or 'c:\' - */ - root: string; - /** - * The full directory path such as '/home/user/dir' or 'c:\path\dir' - */ - dir: string; - /** - * The file name including extension (if any) such as 'index.html' - */ - base: string; - /** - * The file extension (if any) such as '.html' - */ - ext: string; - /** - * The file name without extension (if any) such as 'index' - */ - name: string; - } - - /** - * Normalize a string path, reducing '..' and '.' parts. - * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used. - * - * @param p string path to normalize. - */ - export function normalize(p: string): string; - /** - * Join all arguments together and normalize the resulting path. - * Arguments must be strings. In v0.8, non-string arguments were silently ignored. In v0.10 and up, an exception is thrown. - * - * @param paths string paths to join. - */ - export function join(...paths: any[]): string; - /** - * Join all arguments together and normalize the resulting path. - * Arguments must be strings. In v0.8, non-string arguments were silently ignored. In v0.10 and up, an exception is thrown. - * - * @param paths string paths to join. - */ - export function join(...paths: string[]): string; - /** - * The right-most parameter is considered {to}. Other parameters are considered an array of {from}. - * - * Starting from leftmost {from} paramter, resolves {to} to an absolute path. - * - * If {to} isn't already absolute, {from} arguments are prepended in right to left order, until an absolute path is found. If after using all {from} paths still no absolute path is found, the current working directory is used as well. The resulting path is normalized, and trailing slashes are removed unless the path gets resolved to the root directory. - * - * @param pathSegments string paths to join. Non-string arguments are ignored. - */ - export function resolve(...pathSegments: any[]): string; - /** - * Determines whether {path} is an absolute path. An absolute path will always resolve to the same location, regardless of the working directory. - * - * @param path path to test. - */ - export function isAbsolute(path: string): boolean; - /** - * Solve the relative path from {from} to {to}. - * At times we have two absolute paths, and we need to derive the relative path from one to the other. This is actually the reverse transform of path.resolve. - * - * @param from - * @param to - */ - export function relative(from: string, to: string): string; - /** - * Return the directory name of a path. Similar to the Unix dirname command. - * - * @param p the path to evaluate. - */ - export function dirname(p: string): string; - /** - * Return the last portion of a path. Similar to the Unix basename command. - * Often used to extract the file name from a fully qualified path. - * - * @param p the path to evaluate. - * @param ext optionally, an extension to remove from the result. - */ - export function basename(p: string, ext?: string): string; - /** - * Return the extension of the path, from the last '.' to end of string in the last portion of the path. - * If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string - * - * @param p the path to evaluate. - */ - export function extname(p: string): string; - /** - * The platform-specific file separator. '\\' or '/'. - */ - export var sep: string; - /** - * The platform-specific file delimiter. ';' or ':'. - */ - export var delimiter: string; - /** - * Returns an object from a path string - the opposite of format(). - * - * @param pathString path to evaluate. - */ - export function parse(pathString: string): ParsedPath; - /** - * Returns a path string from an object - the opposite of parse(). - * - * @param pathString path to evaluate. - */ - export function format(pathObject: ParsedPath): string; - - export module posix { - export function normalize(p: string): string; - export function join(...paths: any[]): string; - export function resolve(...pathSegments: any[]): string; - export function isAbsolute(p: string): boolean; - export function relative(from: string, to: string): string; - export function dirname(p: string): string; - export function basename(p: string, ext?: string): string; - export function extname(p: string): string; - export var sep: string; - export var delimiter: string; - export function parse(p: string): ParsedPath; - export function format(pP: ParsedPath): string; - } - - export module win32 { - export function normalize(p: string): string; - export function join(...paths: any[]): string; - export function resolve(...pathSegments: any[]): string; - export function isAbsolute(p: string): boolean; - export function relative(from: string, to: string): string; - export function dirname(p: string): string; - export function basename(p: string, ext?: string): string; - export function extname(p: string): string; - export var sep: string; - export var delimiter: string; - export function parse(p: string): ParsedPath; - export function format(pP: ParsedPath): string; - } -} - -declare module "string_decoder" { - export interface NodeStringDecoder { - write(buffer: Buffer): string; - detectIncompleteChar(buffer: Buffer): number; - } - export var StringDecoder: { - new (encoding: string): NodeStringDecoder; - }; -} - -declare module "tls" { - import * as crypto from "crypto"; - import * as net from "net"; - import * as stream from "stream"; - - var CLIENT_RENEG_LIMIT: number; - var CLIENT_RENEG_WINDOW: number; - - export interface TlsOptions { - pfx?: any; //string or buffer - key?: any; //string or buffer - passphrase?: string; - cert?: any; - ca?: any; //string or buffer - crl?: any; //string or string array - ciphers?: string; - honorCipherOrder?: any; - requestCert?: boolean; - rejectUnauthorized?: boolean; - NPNProtocols?: any; //array or Buffer; - SNICallback?: (servername: string) => any; - } - - export interface ConnectionOptions { - host?: string; - port?: number; - socket?: net.Socket; - pfx?: any; //string | Buffer - key?: any; //string | Buffer - passphrase?: string; - cert?: any; //string | Buffer - ca?: any; //Array of string | Buffer - rejectUnauthorized?: boolean; - NPNProtocols?: any; //Array of string | Buffer - servername?: string; - } - - export interface Server extends net.Server { - // Extended base methods - listen(port: number, host?: string, backlog?: number, listeningListener?: Function): Server; - listen(path: string, listeningListener?: Function): Server; - listen(handle: any, listeningListener?: Function): Server; - - listen(port: number, host?: string, callback?: Function): Server; - close(): Server; - address(): { port: number; family: string; address: string; }; - addContext(hostName: string, credentials: { - key: string; - cert: string; - ca: string; - }): void; - maxConnections: number; - connections: number; - } - - export interface ClearTextStream extends stream.Duplex { - authorized: boolean; - authorizationError: Error; - getPeerCertificate(): any; - getCipher: { - name: string; - version: string; - }; - address: { - port: number; - family: string; - address: string; - }; - remoteAddress: string; - remotePort: number; - } - - export interface SecurePair { - encrypted: any; - cleartext: any; - } - - export interface SecureContextOptions { - pfx?: any; //string | buffer - key?: any; //string | buffer - passphrase?: string; - cert?: any; // string | buffer - ca?: any; // string | buffer - crl?: any; // string | string[] - ciphers?: string; - honorCipherOrder?: boolean; - } - - export interface SecureContext { - context: any; - } - - export function createServer(options: TlsOptions, secureConnectionListener?: (cleartextStream: ClearTextStream) =>void ): Server; - export function connect(options: TlsOptions, secureConnectionListener?: () =>void ): ClearTextStream; - export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; - export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () =>void ): ClearTextStream; - export function createSecurePair(credentials?: crypto.Credentials, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair; - export function createSecureContext(details: SecureContextOptions): SecureContext; -} - -declare module "crypto" { - export interface CredentialDetails { - pfx: string; - key: string; - passphrase: string; - cert: string; - ca: any; //string | string array - crl: any; //string | string array - ciphers: string; - } - export interface Credentials { context?: any; } - export function createCredentials(details: CredentialDetails): Credentials; - export function createHash(algorithm: string): Hash; - export function createHmac(algorithm: string, key: string): Hmac; - export function createHmac(algorithm: string, key: Buffer): Hmac; - interface Hash { - update(data: any, input_encoding?: string): Hash; - digest(encoding: 'buffer'): Buffer; - digest(encoding: string): any; - digest(): Buffer; - } - interface Hmac { - update(data: any, input_encoding?: string): Hmac; - digest(encoding: 'buffer'): Buffer; - digest(encoding: string): any; - digest(): Buffer; - } - export function createCipher(algorithm: string, password: any): Cipher; - export function createCipheriv(algorithm: string, key: any, iv: any): Cipher; - interface Cipher { - update(data: Buffer): Buffer; - update(data: string, input_encoding?: string, output_encoding?: string): string; - final(): Buffer; - final(output_encoding: string): string; - setAutoPadding(auto_padding: boolean): void; - } - export function createDecipher(algorithm: string, password: any): Decipher; - export function createDecipheriv(algorithm: string, key: any, iv: any): Decipher; - interface Decipher { - update(data: Buffer): Buffer; - update(data: string, input_encoding?: string, output_encoding?: string): string; - final(): Buffer; - final(output_encoding: string): string; - setAutoPadding(auto_padding: boolean): void; - } - export function createSign(algorithm: string): Signer; - interface Signer extends NodeJS.WritableStream { - update(data: any): void; - sign(private_key: string, output_format: string): string; - } - export function createVerify(algorith: string): Verify; - interface Verify extends NodeJS.WritableStream { - update(data: any): void; - verify(object: string, signature: string, signature_format?: string): boolean; - } - export function createDiffieHellman(prime_length: number): DiffieHellman; - export function createDiffieHellman(prime: number, encoding?: string): DiffieHellman; - interface DiffieHellman { - generateKeys(encoding?: string): string; - computeSecret(other_public_key: string, input_encoding?: string, output_encoding?: string): string; - getPrime(encoding?: string): string; - getGenerator(encoding: string): string; - getPublicKey(encoding?: string): string; - getPrivateKey(encoding?: string): string; - setPublicKey(public_key: string, encoding?: string): void; - setPrivateKey(public_key: string, encoding?: string): void; - } - export function getDiffieHellman(group_name: string): DiffieHellman; - export function pbkdf2(password: string, salt: string, iterations: number, keylen: number, callback: (err: Error, derivedKey: Buffer) => any): void; - export function pbkdf2(password: string, salt: string, iterations: number, keylen: number, digest: string, callback: (err: Error, derivedKey: Buffer) => any): void; - export function pbkdf2Sync(password: string, salt: string, iterations: number, keylen: number) : Buffer; - export function pbkdf2Sync(password: string, salt: string, iterations: number, keylen: number, digest: string) : Buffer; - export function randomBytes(size: number): Buffer; - export function randomBytes(size: number, callback: (err: Error, buf: Buffer) =>void ): void; - export function pseudoRandomBytes(size: number): Buffer; - export function pseudoRandomBytes(size: number, callback: (err: Error, buf: Buffer) =>void ): void; -} - -declare module "stream" { - import * as events from "events"; - - export interface Stream extends events.EventEmitter { - pipe(destination: T, options?: { end?: boolean; }): T; - } - - export interface ReadableOptions { - highWaterMark?: number; - encoding?: string; - objectMode?: boolean; - } - - export class Readable extends events.EventEmitter implements NodeJS.ReadableStream { - readable: boolean; - constructor(opts?: ReadableOptions); - _read(size: number): void; - read(size?: number): any; - setEncoding(encoding: string): void; - pause(): void; - resume(): void; - pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; - unshift(chunk: any): void; - wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; - push(chunk: any, encoding?: string): boolean; - } - - export interface WritableOptions { - highWaterMark?: number; - decodeStrings?: boolean; - } - - export class Writable extends events.EventEmitter implements NodeJS.WritableStream { - writable: boolean; - constructor(opts?: WritableOptions); - _write(chunk: any, encoding: string, callback: Function): void; - write(chunk: any, cb?: Function): boolean; - write(chunk: any, encoding?: string, cb?: Function): boolean; - end(): void; - end(chunk: any, cb?: Function): void; - end(chunk: any, encoding?: string, cb?: Function): void; - } - - export interface DuplexOptions extends ReadableOptions, WritableOptions { - allowHalfOpen?: boolean; - } - - // Note: Duplex extends both Readable and Writable. - export class Duplex extends Readable implements NodeJS.ReadWriteStream { - writable: boolean; - constructor(opts?: DuplexOptions); - _write(chunk: any, encoding: string, callback: Function): void; - write(chunk: any, cb?: Function): boolean; - write(chunk: any, encoding?: string, cb?: Function): boolean; - end(): void; - end(chunk: any, cb?: Function): void; - end(chunk: any, encoding?: string, cb?: Function): void; - } - - export interface TransformOptions extends ReadableOptions, WritableOptions {} - - // Note: Transform lacks the _read and _write methods of Readable/Writable. - export class Transform extends events.EventEmitter implements NodeJS.ReadWriteStream { - readable: boolean; - writable: boolean; - constructor(opts?: TransformOptions); - _transform(chunk: any, encoding: string, callback: Function): void; - _flush(callback: Function): void; - read(size?: number): any; - setEncoding(encoding: string): void; - pause(): void; - resume(): void; - pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; - unshift(chunk: any): void; - wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; - push(chunk: any, encoding?: string): boolean; - write(chunk: any, cb?: Function): boolean; - write(chunk: any, encoding?: string, cb?: Function): boolean; - end(): void; - end(chunk: any, cb?: Function): void; - end(chunk: any, encoding?: string, cb?: Function): void; - } - - export class PassThrough extends Transform {} -} - -declare module "util" { - export interface InspectOptions { - showHidden?: boolean; - depth?: number; - colors?: boolean; - customInspect?: boolean; - } - - export function format(format: any, ...param: any[]): string; - export function debug(string: string): void; - export function error(...param: any[]): void; - export function puts(...param: any[]): void; - export function print(...param: any[]): void; - export function log(string: string): void; - export function inspect(object: any, showHidden?: boolean, depth?: number, color?: boolean): string; - export function inspect(object: any, options: InspectOptions): string; - export function isArray(object: any): boolean; - export function isRegExp(object: any): boolean; - export function isDate(object: any): boolean; - export function isError(object: any): boolean; - export function inherits(constructor: any, superConstructor: any): void; - export function debuglog(key:string): (msg:string,...param: any[])=>void; -} - -declare module "assert" { - function internal (value: any, message?: string): void; - module internal { - export class AssertionError implements Error { - name: string; - message: string; - actual: any; - expected: any; - operator: string; - generatedMessage: boolean; - - constructor(options?: {message?: string; actual?: any; expected?: any; - operator?: string; stackStartFunction?: Function}); - } - - export function fail(actual?: any, expected?: any, message?: string, operator?: string): void; - export function ok(value: any, message?: string): void; - export function equal(actual: any, expected: any, message?: string): void; - export function notEqual(actual: any, expected: any, message?: string): void; - export function deepEqual(actual: any, expected: any, message?: string): void; - export function notDeepEqual(acutal: any, expected: any, message?: string): void; - export function strictEqual(actual: any, expected: any, message?: string): void; - export function notStrictEqual(actual: any, expected: any, message?: string): void; - export var throws: { - (block: Function, message?: string): void; - (block: Function, error: Function, message?: string): void; - (block: Function, error: RegExp, message?: string): void; - (block: Function, error: (err: any) => boolean, message?: string): void; - }; - - export var doesNotThrow: { - (block: Function, message?: string): void; - (block: Function, error: Function, message?: string): void; - (block: Function, error: RegExp, message?: string): void; - (block: Function, error: (err: any) => boolean, message?: string): void; - }; - - export function ifError(value: any): void; - } - - export = internal; -} - -declare module "tty" { - import * as net from "net"; - - export function isatty(fd: number): boolean; - export interface ReadStream extends net.Socket { - isRaw: boolean; - setRawMode(mode: boolean): void; - } - export interface WriteStream extends net.Socket { - columns: number; - rows: number; - } -} - -declare module "domain" { - import * as events from "events"; - - export class Domain extends events.EventEmitter { - run(fn: Function): void; - add(emitter: events.EventEmitter): void; - remove(emitter: events.EventEmitter): void; - bind(cb: (err: Error, data: any) => any): any; - intercept(cb: (data: any) => any): any; - dispose(): void; - - addListener(event: string, listener: Function): Domain; - on(event: string, listener: Function): Domain; - once(event: string, listener: Function): Domain; - removeListener(event: string, listener: Function): Domain; - removeAllListeners(event?: string): Domain; - } - - export function create(): Domain; -} - -declare module "constants" { - export var E2BIG: number; - export var EACCES: number; - export var EADDRINUSE: number; - export var EADDRNOTAVAIL: number; - export var EAFNOSUPPORT: number; - export var EAGAIN: number; - export var EALREADY: number; - export var EBADF: number; - export var EBADMSG: number; - export var EBUSY: number; - export var ECANCELED: number; - export var ECHILD: number; - export var ECONNABORTED: number; - export var ECONNREFUSED: number; - export var ECONNRESET: number; - export var EDEADLK: number; - export var EDESTADDRREQ: number; - export var EDOM: number; - export var EEXIST: number; - export var EFAULT: number; - export var EFBIG: number; - export var EHOSTUNREACH: number; - export var EIDRM: number; - export var EILSEQ: number; - export var EINPROGRESS: number; - export var EINTR: number; - export var EINVAL: number; - export var EIO: number; - export var EISCONN: number; - export var EISDIR: number; - export var ELOOP: number; - export var EMFILE: number; - export var EMLINK: number; - export var EMSGSIZE: number; - export var ENAMETOOLONG: number; - export var ENETDOWN: number; - export var ENETRESET: number; - export var ENETUNREACH: number; - export var ENFILE: number; - export var ENOBUFS: number; - export var ENODATA: number; - export var ENODEV: number; - export var ENOENT: number; - export var ENOEXEC: number; - export var ENOLCK: number; - export var ENOLINK: number; - export var ENOMEM: number; - export var ENOMSG: number; - export var ENOPROTOOPT: number; - export var ENOSPC: number; - export var ENOSR: number; - export var ENOSTR: number; - export var ENOSYS: number; - export var ENOTCONN: number; - export var ENOTDIR: number; - export var ENOTEMPTY: number; - export var ENOTSOCK: number; - export var ENOTSUP: number; - export var ENOTTY: number; - export var ENXIO: number; - export var EOPNOTSUPP: number; - export var EOVERFLOW: number; - export var EPERM: number; - export var EPIPE: number; - export var EPROTO: number; - export var EPROTONOSUPPORT: number; - export var EPROTOTYPE: number; - export var ERANGE: number; - export var EROFS: number; - export var ESPIPE: number; - export var ESRCH: number; - export var ETIME: number; - export var ETIMEDOUT: number; - export var ETXTBSY: number; - export var EWOULDBLOCK: number; - export var EXDEV: number; - export var WSAEINTR: number; - export var WSAEBADF: number; - export var WSAEACCES: number; - export var WSAEFAULT: number; - export var WSAEINVAL: number; - export var WSAEMFILE: number; - export var WSAEWOULDBLOCK: number; - export var WSAEINPROGRESS: number; - export var WSAEALREADY: number; - export var WSAENOTSOCK: number; - export var WSAEDESTADDRREQ: number; - export var WSAEMSGSIZE: number; - export var WSAEPROTOTYPE: number; - export var WSAENOPROTOOPT: number; - export var WSAEPROTONOSUPPORT: number; - export var WSAESOCKTNOSUPPORT: number; - export var WSAEOPNOTSUPP: number; - export var WSAEPFNOSUPPORT: number; - export var WSAEAFNOSUPPORT: number; - export var WSAEADDRINUSE: number; - export var WSAEADDRNOTAVAIL: number; - export var WSAENETDOWN: number; - export var WSAENETUNREACH: number; - export var WSAENETRESET: number; - export var WSAECONNABORTED: number; - export var WSAECONNRESET: number; - export var WSAENOBUFS: number; - export var WSAEISCONN: number; - export var WSAENOTCONN: number; - export var WSAESHUTDOWN: number; - export var WSAETOOMANYREFS: number; - export var WSAETIMEDOUT: number; - export var WSAECONNREFUSED: number; - export var WSAELOOP: number; - export var WSAENAMETOOLONG: number; - export var WSAEHOSTDOWN: number; - export var WSAEHOSTUNREACH: number; - export var WSAENOTEMPTY: number; - export var WSAEPROCLIM: number; - export var WSAEUSERS: number; - export var WSAEDQUOT: number; - export var WSAESTALE: number; - export var WSAEREMOTE: number; - export var WSASYSNOTREADY: number; - export var WSAVERNOTSUPPORTED: number; - export var WSANOTINITIALISED: number; - export var WSAEDISCON: number; - export var WSAENOMORE: number; - export var WSAECANCELLED: number; - export var WSAEINVALIDPROCTABLE: number; - export var WSAEINVALIDPROVIDER: number; - export var WSAEPROVIDERFAILEDINIT: number; - export var WSASYSCALLFAILURE: number; - export var WSASERVICE_NOT_FOUND: number; - export var WSATYPE_NOT_FOUND: number; - export var WSA_E_NO_MORE: number; - export var WSA_E_CANCELLED: number; - export var WSAEREFUSED: number; - export var SIGHUP: number; - export var SIGINT: number; - export var SIGILL: number; - export var SIGABRT: number; - export var SIGFPE: number; - export var SIGKILL: number; - export var SIGSEGV: number; - export var SIGTERM: number; - export var SIGBREAK: number; - export var SIGWINCH: number; - export var SSL_OP_ALL: number; - export var SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: number; - export var SSL_OP_CIPHER_SERVER_PREFERENCE: number; - export var SSL_OP_CISCO_ANYCONNECT: number; - export var SSL_OP_COOKIE_EXCHANGE: number; - export var SSL_OP_CRYPTOPRO_TLSEXT_BUG: number; - export var SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: number; - export var SSL_OP_EPHEMERAL_RSA: number; - export var SSL_OP_LEGACY_SERVER_CONNECT: number; - export var SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: number; - export var SSL_OP_MICROSOFT_SESS_ID_BUG: number; - export var SSL_OP_MSIE_SSLV2_RSA_PADDING: number; - export var SSL_OP_NETSCAPE_CA_DN_BUG: number; - export var SSL_OP_NETSCAPE_CHALLENGE_BUG: number; - export var SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG: number; - export var SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: number; - export var SSL_OP_NO_COMPRESSION: number; - export var SSL_OP_NO_QUERY_MTU: number; - export var SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: number; - export var SSL_OP_NO_SSLv2: number; - export var SSL_OP_NO_SSLv3: number; - export var SSL_OP_NO_TICKET: number; - export var SSL_OP_NO_TLSv1: number; - export var SSL_OP_NO_TLSv1_1: number; - export var SSL_OP_NO_TLSv1_2: number; - export var SSL_OP_PKCS1_CHECK_1: number; - export var SSL_OP_PKCS1_CHECK_2: number; - export var SSL_OP_SINGLE_DH_USE: number; - export var SSL_OP_SINGLE_ECDH_USE: number; - export var SSL_OP_SSLEAY_080_CLIENT_DH_BUG: number; - export var SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG: number; - export var SSL_OP_TLS_BLOCK_PADDING_BUG: number; - export var SSL_OP_TLS_D5_BUG: number; - export var SSL_OP_TLS_ROLLBACK_BUG: number; - export var ENGINE_METHOD_DSA: number; - export var ENGINE_METHOD_DH: number; - export var ENGINE_METHOD_RAND: number; - export var ENGINE_METHOD_ECDH: number; - export var ENGINE_METHOD_ECDSA: number; - export var ENGINE_METHOD_CIPHERS: number; - export var ENGINE_METHOD_DIGESTS: number; - export var ENGINE_METHOD_STORE: number; - export var ENGINE_METHOD_PKEY_METHS: number; - export var ENGINE_METHOD_PKEY_ASN1_METHS: number; - export var ENGINE_METHOD_ALL: number; - export var ENGINE_METHOD_NONE: number; - export var DH_CHECK_P_NOT_SAFE_PRIME: number; - export var DH_CHECK_P_NOT_PRIME: number; - export var DH_UNABLE_TO_CHECK_GENERATOR: number; - export var DH_NOT_SUITABLE_GENERATOR: number; - export var NPN_ENABLED: number; - export var RSA_PKCS1_PADDING: number; - export var RSA_SSLV23_PADDING: number; - export var RSA_NO_PADDING: number; - export var RSA_PKCS1_OAEP_PADDING: number; - export var RSA_X931_PADDING: number; - export var RSA_PKCS1_PSS_PADDING: number; - export var POINT_CONVERSION_COMPRESSED: number; - export var POINT_CONVERSION_UNCOMPRESSED: number; - export var POINT_CONVERSION_HYBRID: number; - export var O_RDONLY: number; - export var O_WRONLY: number; - export var O_RDWR: number; - export var S_IFMT: number; - export var S_IFREG: number; - export var S_IFDIR: number; - export var S_IFCHR: number; - export var S_IFLNK: number; - export var O_CREAT: number; - export var O_EXCL: number; - export var O_TRUNC: number; - export var O_APPEND: number; - export var F_OK: number; - export var R_OK: number; - export var W_OK: number; - export var X_OK: number; - export var UV_UDP_REUSEADDR: number; -} diff --git a/typings/optimist/optimist.d.ts b/typings/optimist/optimist.d.ts deleted file mode 100644 index 12a51be1d6f..00000000000 --- a/typings/optimist/optimist.d.ts +++ /dev/null @@ -1,89 +0,0 @@ -// Type definitions for optimist -// Project: https://github.com/substack/node-optimist -// Definitions by: Carlos Ballesteros Velasco , Christopher Brown -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped - -declare module "optimist" { - - namespace optimist { - interface Opt { - alias?: string | string[]; - default?: any; - demand?: string | number | string[]; - describe?: string; - type?: string; - } - - interface Parser { - /** Implicitly use process.argv array to construct the argv object */ - argv: any; - /** Pass in the process.argv yourself */ - (args: string[]): any; - /** Use .parse() to do the same thing as treating optimist as a function */ - parse(args: string[]): any; - - // The types below follow the order and documentation of https://github.com/substack/node-optimist - - /** Set key names as equivalent such that updates to a key will propagate to aliases and vice-versa. */ - alias(key: string, alias: string | string[]): Parser; - /** Take an object that maps keys to aliases. */ - alias(aliases: {[index: string]: string | string[]}): Parser; - - /** Set argv[key] to value if no option was specified on process.argv */ - default(key: string, value: any): Parser; - /** Take an object that maps keys to default values */ - default(defaults: {[index: string]: any}): Parser; - - /** Show the usage information and exit if key wasn't specified in process.argv */ - demand(key: string): Parser; - /** Demand at least as many non-option arguments, which show up in argv._ */ - demand(key: number): Parser; - /** Demand each element in key */ - demand(key: string[]): Parser; - - /** Describe a key for the generated usage information */ - describe(key: string, desc: string): Parser; - /** Take an object that maps keys to descriptions */ - describe(descriptions: {[index: string]: string}): Parser; - - /** Instead of chaining together, e.g. optimist.alias().demand().default()..., - you can specify keys in opt for each of the chainable methods. */ - options(key: string, opt: Opt): Parser; - /** Take an object that maps keys to opt parameters */ - options(options: {[index: string]: Opt}): Parser; - - /** Set a usage message to show which commands to use. Inside message, - the string $0 will get interpolated to the current script name or node - command for the present script similar to how $0 works in bash or perl. */ - usage(message: string): Parser; - - /** Check that certain conditions are met in the provided arguments. If fn - throws or returns false, show the thrown error, usage information, and exit. - */ - check(fn: (argv: any) => any): Parser; - - /** Interpret key as a boolean. If a non-flag option follows key in process.argv, - that string won't get set as the value of key. If key never shows up as a - flag in process.arguments, argv[key] will be false. */ - boolean(key: string): Parser; - /** Interpret all the elements as booleans. */ - boolean(key: string[]): Parser; - - /** Tell the parser logic not to interpret key as a number or boolean. This can be useful if you need to preserve leading zeros in an input. */ - string(key: string): Parser; - /** Interpret all the elements as strings */ - string(key: string[]): Parser; - - /** Format usage output to wrap at columns many columns. */ - wrap(columns: number): Parser; - - /** Return the generated usage string. */ - help(): string; - /** Print the usage data using fn for printing (defaults to console.error). */ - showHelp(fn?: (message: string) => void): void; - } - } - - var optimist: optimist.Parser; - export = optimist; -} diff --git a/typings/underscore.string/underscore.string.d.ts b/typings/underscore.string/underscore.string.d.ts deleted file mode 100644 index 1b08dcf852d..00000000000 --- a/typings/underscore.string/underscore.string.d.ts +++ /dev/null @@ -1,573 +0,0 @@ -// Type definitions for underscore.string -// Project: https://github.com/epeli/underscore.string -// Definitions by: Ry Racherbaumer -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -/// - -interface UnderscoreStatic { - str: UnderscoreStringStatic; - string: UnderscoreStringStatic; -} - -declare var s : UnderscoreStringStatic; - -interface UnderscoreStringStatic extends UnderscoreStringStaticExports { - /** - * Tests if string contains a substring. - * ('foobar', 'ob') => true - * @param str - * @param needle - */ - include(str: string, needle: string): boolean; - - /** - * Tests if string contains a substring. - * ('foobar', 'ob') => true - * @param str - * @param needle - */ - contains(str: string, needle: string): boolean; - - /** - * Return reversed string. - * ('foobar') => 'raboof' - * @param str - */ - reverse(str: string): string; -} - -/** - * Functions exported for mixing with underscore object. - * - * Usage: - * _.mixin(_.string.exports()); - * interface UnderscoreStatic extends UnderscoreStringStaticExports { } - */ -interface UnderscoreStringStaticExports { - - exports(): UnderscoreStringStaticExports; - - /** - * Determine if a string is 'blank.' - * @param str - */ - isBlank(str: string): boolean; - - /** - * Removes all html tags from string. - * @param str - */ - stripTags(str: string): string; - - /** - * Converts first letter of the string to uppercase. - * ('foo Bar') => 'Foo Bar' - * @param str - */ - capitalize(str: string): string; - - /** - * Chop a string into pieces. - * ('whitespace', 3) => ['whi','tes','pac','e'] - * @param str String to chop - * @param step Size of the pieces - */ - chop(str: string, step: number): any[]; - - /** - * Compress some whitespaces to one. - * (' foo bar ') => 'foo bar' - * @param str - */ - clean(str: string): string; - - /** - * Count occurences of a sub string. - * ('Hello world', 'l') => 3 - * @param str - * @param substr - */ - count(str: string, substr: string): number; - - /** - * Convert string to an array of characters. - * ('Hello') => ['H','e','l','l','o'] - * @param str - */ - chars(str: string): any[]; - - /** - * Returns a copy of the string in which all the case-based characters have had their case swapped. - * ('hELLO') => 'Hello' - * @param str - */ - swapCase(str: string): string; - - /** - * Converts HTML special characters to their entity equivalents. - * ('
Blah blah blah
') => '<div>Blah blah blah</div>' - * @param str - */ - escapeHTML(str: string): string; - - /** - * Converts entity characters to HTML equivalents. - * ('<div>Blah blah blah</div>') => '
Blah blah blah
' - * @param str - */ - unescapeHTML(str: string): string; - - /** - * Escape a string for use in a regular expression. - * @param str - */ - escapeRegExp(str: string): string; - - /** - * Splice a string like an array. - * @param str - * @param i - * @param howmany - * @param substr - */ - splice(str: string, i: number, howmany: number, substr?: string): string; - - /** - * Insert a string at index. - * @param str - * @param i - * @param substr - */ - insert(str: string, i: number, substr: string): string; - - /** - * Joins strings together with given separator. - * (' ', 'foo', 'bar') => 'foo bar' - * @param separator - * @param args - */ - join(separator: string, ...args: string[]): string; - - /** - * Split string by newlines character. - * ('Hello\nWorld') => ['Hello', 'World'] - * @param str - */ - lines(str: string): any[]; - - /** - * Checks if string starts with another string. - * ('image.gif', 'image') => true - * @param str - * @param starts - */ - startsWith(str: string, starts: string): boolean; - - /** - * Checks if string ends with another string. - * ('image.gif', 'gif') => true - * @param value - * @param starts - */ - endsWith(value: string, starts: string): boolean; - - /** - * Returns the successor to passed string. - * ('a') => 'b' - * @param str - */ - succ(str: string): string; - - /** - * Capitalize first letter of every word in the string. - * ('my name is epeli') => 'My Name Is Epeli' - * @param str - */ - titleize(str: string): string; - - /** - * Converts underscored or dasherized string to a camelized one. - * ('-moz-transform') => 'MozTransform' - * @param str - */ - camelize(str: string): string; - - /** - * Converts a camelized or dasherized string into an underscored one. - * ('MozTransform') => 'moz_transform' - * @param str - */ - underscored(str: string): string; - - /** - * Converts a underscored or camelized string into an dasherized one. - * ('MozTransform') => '-moz-transform' - * @param str - */ - dasherize(str: string): string; - - /** - * Converts string to camelized class name. - * ('some_class_name') => 'SomeClassName' - * @param str - */ - classify(str: string): string; - - /** - * Converts an underscored, camelized, or dasherized string into a humanized one. - * Also removes beginning and ending whitespace, and removes the postfix '_id'. - * (' capitalize dash-CamelCase_underscore trim ') => 'Capitalize dash camel case underscore trim' - * @param str - */ - humanize(str: string): string; - - /** - * Trims defined characters from begining and ending of the string. - * Defaults to whitespace characters. - * (' foobar ') => 'foobar' - * ('_-foobar-_', '_-') => 'foobar' - * @param str - * @param characters - */ - trim(str: string, characters?: string): string; - - /** - * Trims defined characters from begining and ending of the string. - * Defaults to whitespace characters. - * (' foobar ') => 'foobar' - * ('_-foobar-_', '_-') => 'foobar' - * @param str - * @param characters - */ - strip(str: string, characters?: string): string; - - /** - * Left trim. Similar to trim, but only for left side. - * @param str - * @param characters - */ - ltrim(str: string, characters?: string): string; - - /** - * Left trim. Similar to trim, but only for left side. - * @param str - * @param characters - */ - lstrip(str: string, characters?: string): string; - - /** - * Right trim. Similar to trim, but only for right side. - * @param str - * @param characters - */ - rtrim(str: string, characters?: string): string; - - /** - * Right trim. Similar to trim, but only for right side. - * @param str - * @param characters - */ - rstrip(str: string, characters?: string): string; - - /** - * Truncate string to specified length. - * ('Hello world').truncate(5) => 'Hello...' - * ('Hello').truncate(10) => 'Hello' - * @param str - * @param length - * @param truncateStr - */ - truncate(str: string, length: number, truncateStr?: string): string; - - /** - * Elegant version of truncate. - * Makes sure the pruned string does not exceed the original length. - * Avoid half-chopped words when truncating. - * ('Hello, cruel world', 15) => 'Hello, cruel...' - * @param str - * @param length - * @param pruneStr - */ - prune(str: string, length: number, pruneStr?: string): string; - - /** - * Split string by delimiter (String or RegExp). - * /\s+/ by default. - * (' I love you ') => ['I','love','you'] - * ('I_love_you', '_') => ['I','love','you'] - * @param str - * @param delimiter - */ - words(str: string): string[]; - - /** - * Split string by delimiter (String or RegExp). - * /\s+/ by default. - * (' I love you ') => ['I','love','you'] - * ('I_love_you', '_') => ['I','love','you'] - * @param str - * @param delimiter - */ - words(str: string, delimiter: string): string[]; - - /** - * Split string by delimiter (String or RegExp). - * /\s+/ by default. - * (' I love you ') => ['I','love','you'] - * ('I_love_you', '_') => ['I','love','you'] - * @param str - * @param delimiter - */ - words(str: string, delimiter: RegExp): string[]; - - /** - * Pads a string with characters until the total string length is equal to the passed length parameter. - * By default, pads on the left with the space char (' '). - * padStr is truncated to a single character if necessary. - * ('1', 8) => ' 1' - * ('1', 8, '0') => '00000001' - * ('1', 8, '0', 'right') => '10000000' - * ('1', 8, '0', 'both') => '00001000' - * ('1', 8, 'bleepblorp', 'both') => 'bbbb1bbb' - * @param str - * @param length - * @param padStr - * @param type - */ - pad(str: string, length: number, padStr?:string, type?: string): string; - - /** - * Left-pad a string. - * Alias for pad(str, length, padStr, 'left') - * ('1', 8, '0') => '00000001' - * @param str - * @param length - * @param padStr - */ - lpad(str: string, length: number, padStr?: string): string; - - /** - * Left-pad a string. - * Alias for pad(str, length, padStr, 'left') - * ('1', 8, '0') => '00000001' - * @param str - * @param length - * @param padStr - */ - rjust(str: string, length: number, padStr?: string): string; - - /** - * Right-pad a string. - * Alias for pad(str, length, padStr, 'right') - * ('1', 8, '0') => '10000000' - * @param str - * @param length - * @param padStr - */ - rpad(str: string, length: number, padStr?: string): string; - - /** - * Right-pad a string. - * Alias for pad(str, length, padStr, 'right') - * ('1', 8, '0') => '10000000' - * @param str - * @param length - * @param padStr - */ - ljust(str: string, length: number, padStr?: string): string; - - /** - * Left/right-pad a string. - * Alias for pad(str, length, padStr, 'both') - * ('1', 8, '0') => '00001000' - * @param str - * @param length - * @param padStr - */ - lrpad(str: string, length: number, padStr?: string): string; - - /** - * Left/right-pad a string. - * Alias for pad(str, length, padStr, 'both') - * ('1', 8, '0') => '00001000' - * @param str - * @param length - * @param padStr - */ - center(str: string, length: number, padStr?: string): string; - - /** - * C like string formatting. - * _.sprintf('%.1f', 1.17) => '1.2' - * @param format - * @param args - */ - sprintf(format: string, ...args: any[]): string; - - /** - * Parse string to number. - * Returns NaN if string can't be parsed to number. - * ('2.556').toNumber() => 3 - * ('2.556').toNumber(1) => 2.6 - * @param str - * @param decimals - */ - toNumber(str: string, decimals?: number): number; - - /** - * Formats the numbers. - * (1000, 2) => '1,000.00' - * (123456789.123, 5, '.', ',') => '123,456,789.12300' - * @param number - * @param dec - * @param dsep - * @param tsep - */ - numberFormat(number: number, dec?: number, dsep?: string, tsep?: string): string; - - /** - * Searches a string from left to right for a pattern. - * Returns a substring consisting of the characters in the string that are to the right of the pattern. - * If no match found, returns entire string. - * ('This_is_a_test_string').strRight('_') => 'is_a_test_string' - * @param str - * @param sep - */ - strRight(str: string, sep: string): string; - - /** - * Searches a string from right to left for a pattern. - * Returns a substring consisting of the characters in the string that are to the right of the pattern. - * If no match found, returns entire string. - * ('This_is_a_test_string').strRightBack('_') => 'string' - * @param str - * @param sep - */ - strRightBack(str: string, sep: string): string; - - /** - * Searches a string from left to right for a pattern. - * Returns a substring consisting of the characters in the string that are to the left of the pattern. - * If no match found, returns entire string. - * ('This_is_a_test_string').strLeft('_') => 'This' - * @param str - * @param sep - */ - strLeft(str: string, sep: string): string; - - /** - * Searches a string from right to left for a pattern. - * Returns a substring consisting of the characters in the string that are to the left of the pattern. - * If no match found, returns entire string. - * ('This_is_a_test_string').strLeftBack('_') => 'This_is_a_test' - * @param str - * @param sep - */ - strLeftBack(str: string, sep: string): string; - - /** - * Join an array into a human readable sentence. - * (['jQuery', 'Mootools', 'Prototype']) => 'jQuery, Mootools and Prototype' - * (['jQuery', 'Mootools', 'Prototype'], ', ', ' unt ') => 'jQuery, Mootools unt Prototype' - * @param array - * @param separator - * @param lastSeparator - * @param serial - */ - toSentence(array: any[], separator?: string, lastSeparator?: string, serial?: boolean): string; - - /** - * The same as toSentence, but uses ', ' as default for lastSeparator. - * @param array - * @param separator - * @param lastSeparator - */ - toSentenceSerial(array: any[], separator?: string, lastSeparator?: string): string; - - /** - * Transform text into a URL slug. Replaces whitespaces, accentuated, and special characters with a dash. - * ('Un éléphant à l'orée du bois') => 'un-elephant-a-loree-du-bois' - * @param str - */ - slugify(str: string): string; - - /** - * Surround a string with another string. - * ('foo', 'ab') => 'abfooab' - * @param str - * @param wrapper - */ - surround(str: string, wrapper: string): string; - - /** - * Quotes a string. - * quoteChar defaults to " - * ('foo') => '"foo"' - * @param str - */ - quote(str: string, quoteChar?: string): string; - - /** - * Quotes a string. - * quoteChar defaults to " - * ('foo') => '"foo"' - * @param str - */ - q(str: string, quoteChar?: string): string; - - /** - * Unquotes a string. - * quoteChar defaults to " - * ('"foo"') => 'foo' - * ("'foo'", "'") => 'foo' - * @param str - */ - unquote(str: string, quoteChar?: string): string; - - /** - * Repeat a string with an optional separator. - * ('foo', 3) => 'foofoofoo' - * ('foo', 3, 'bar') => 'foobarfoobarfoo' - * @param value - * @param count - * @param separator - */ - repeat(value: string, count: number, separator?:string): string; - - /** - * Naturally sort strings like humans would do. - * Caution: this function is charset dependent. - * @param str1 - * @param str2 - */ - naturalCmp(str1: string, str2: string): number; - - /** - * Calculates Levenshtein distance between two strings. - * ('kitten', 'kittah') => 2 - * @param str1 - * @param str2 - */ - levenshtein(str1: string, str2: string): number; - - /** - * Turn strings that can be commonly considered as booleans to real booleans. - * Such as "true", "false", "1" and "0". This function is case insensitive. - * ('true') => true - * ('FALSE') => false - * ('random') => undefined - * ('truthy', ['truthy'], ['falsy']) => true - * ('true only at start', [/^true/]) => true - * @param str - * @param trueValues - * @param falseValues - */ - toBoolean(str: string, trueValues?: any[], falseValues?: any[]): boolean; - -} -declare module 'underscore.string' { - var underscoreString: UnderscoreStringStatic; - export = underscoreString; -} -// TODO interface UnderscoreString extends Underscore diff --git a/typings/underscore/underscore.d.ts b/typings/underscore/underscore.d.ts deleted file mode 100644 index 7dea66a84ac..00000000000 --- a/typings/underscore/underscore.d.ts +++ /dev/null @@ -1,3413 +0,0 @@ -// Type definitions for Underscore 1.7.0 -// Project: http://underscorejs.org/ -// Definitions by: Boris Yankov , Josh Baldwin -// Definitions: https://github.com/borisyankov/DefinitelyTyped - -declare module _ { - /** - * underscore.js _.throttle options. - **/ - interface ThrottleSettings { - - /** - * If you'd like to disable the leading-edge call, pass this as false. - **/ - leading?: boolean; - - /** - * If you'd like to disable the execution on the trailing-edge, pass false. - **/ - trailing?: boolean; - } - - /** - * underscore.js template settings, set templateSettings or pass as an argument - * to 'template()' to override defaults. - **/ - interface TemplateSettings { - /** - * Default value is '/<%([\s\S]+?)%>/g'. - **/ - evaluate?: RegExp; - - /** - * Default value is '/<%=([\s\S]+?)%>/g'. - **/ - interpolate?: RegExp; - - /** - * Default value is '/<%-([\s\S]+?)%>/g'. - **/ - escape?: RegExp; - } - - interface Collection { } - - // Common interface between Arrays and jQuery objects - interface List extends Collection { - [index: number]: T; - length: number; - } - - interface Dictionary extends Collection { - [index: string]: T; - } - - interface ListIterator { - (value: T, index: number, list: List): TResult; - } - - interface ObjectIterator { - (element: T, key: string, list: Dictionary): TResult; - } - - interface MemoIterator { - (prev: TResult, curr: T, index: number, list: List): TResult; - } - - interface MemoObjectIterator { - (prev: TResult, curr: T, key: string, list: Dictionary): TResult; - } -} - -interface UnderscoreStatic { - /** - * Underscore OOP Wrapper, all Underscore functions that take an object - * as the first parameter can be invoked through this function. - * @param key First argument to Underscore object functions. - **/ - (value: Array): Underscore; - (value: T): Underscore; - - /* ************* - * Collections * - ************* */ - - /** - * Iterates over a list of elements, yielding each in turn to an iterator function. The iterator is - * bound to the context object, if one is passed. Each invocation of iterator is called with three - * arguments: (element, index, list). If list is a JavaScript object, iterator's arguments will be - * (value, key, object). Delegates to the native forEach function if it exists. - * @param list Iterates over this list of elements. - * @param iterator Iterator function for each element `list`. - * @param context 'this' object in `iterator`, optional. - **/ - each( - list: _.List, - iterator: _.ListIterator, - context?: any): _.List; - - /** - * @see _.each - * @param object Iterates over properties of this object. - * @param iterator Iterator function for each property on `object`. - * @param context 'this' object in `iterator`, optional. - **/ - each( - object: _.Dictionary, - iterator: _.ObjectIterator, - context?: any): _.Dictionary; - - /** - * @see _.each - **/ - forEach( - list: _.List, - iterator: _.ListIterator, - context?: any): _.List; - - /** - * @see _.each - **/ - forEach( - object: _.Dictionary, - iterator: _.ObjectIterator, - context?: any): _.Dictionary; - - /** - * Produces a new array of values by mapping each value in list through a transformation function - * (iterator). If the native map method exists, it will be used instead. If list is a JavaScript - * object, iterator's arguments will be (value, key, object). - * @param list Maps the elements of this array. - * @param iterator Map iterator function for each element in `list`. - * @param context `this` object in `iterator`, optional. - * @return The mapped array result. - **/ - map( - list: _.List, - iterator: _.ListIterator, - context?: any): TResult[]; - - /** - * @see _.map - * @param object Maps the properties of this object. - * @param iterator Map iterator function for each property on `object`. - * @param context `this` object in `iterator`, optional. - * @return The mapped object result. - **/ - map( - object: _.Dictionary, - iterator: _.ObjectIterator, - context?: any): TResult[]; - - /** - * @see _.map - **/ - collect( - list: _.List, - iterator: _.ListIterator, - context?: any): TResult[]; - - /** - * @see _.map - **/ - collect( - object: _.Dictionary, - iterator: _.ObjectIterator, - context?: any): TResult[]; - - /** - * Also known as inject and foldl, reduce boils down a list of values into a single value. - * Memo is the initial state of the reduction, and each successive step of it should be - * returned by iterator. The iterator is passed four arguments: the memo, then the value - * and index (or key) of the iteration, and finally a reference to the entire list. - * @param list Reduces the elements of this array. - * @param iterator Reduce iterator function for each element in `list`. - * @param memo Initial reduce state. - * @param context `this` object in `iterator`, optional. - * @return Reduced object result. - **/ - reduce( - list: _.Collection, - iterator: _.MemoIterator, - memo?: TResult, - context?: any): TResult; - - reduce( - list: _.Dictionary, - iterator: _.MemoObjectIterator, - memo?: TResult, - context?: any): TResult; - - /** - * @see _.reduce - **/ - inject( - list: _.Collection, - iterator: _.MemoIterator, - memo?: TResult, - context?: any): TResult; - - /** - * @see _.reduce - **/ - foldl( - list: _.Collection, - iterator: _.MemoIterator, - memo?: TResult, - context?: any): TResult; - - /** - * The right-associative version of reduce. Delegates to the JavaScript 1.8 version of - * reduceRight, if it exists. `foldr` is not as useful in JavaScript as it would be in a - * language with lazy evaluation. - * @param list Reduces the elements of this array. - * @param iterator Reduce iterator function for each element in `list`. - * @param memo Initial reduce state. - * @param context `this` object in `iterator`, optional. - * @return Reduced object result. - **/ - reduceRight( - list: _.Collection, - iterator: _.MemoIterator, - memo?: TResult, - context?: any): TResult; - - /** - * @see _.reduceRight - **/ - foldr( - list: _.Collection, - iterator: _.MemoIterator, - memo?: TResult, - context?: any): TResult; - - /** - * Looks through each value in the list, returning the first one that passes a truth - * test (iterator). The function returns as soon as it finds an acceptable element, - * and doesn't traverse the entire list. - * @param list Searches for a value in this list. - * @param iterator Search iterator function for each element in `list`. - * @param context `this` object in `iterator`, optional. - * @return The first acceptable found element in `list`, if nothing is found undefined/null is returned. - **/ - find( - list: _.List, - iterator: _.ListIterator, - context?: any): T; - - /** - * @see _.find - **/ - find( - object: _.Dictionary, - iterator: _.ObjectIterator, - context?: any): T; - - /** - * @see _.find - **/ - detect( - list: _.List, - iterator: _.ListIterator, - context?: any): T; - - /** - * @see _.find - **/ - detect( - object: _.Dictionary, - iterator: _.ObjectIterator, - context?: any): T; - - /** - * Looks through each value in the list, returning the index of the first one that passes a truth - * test (iterator). The function returns as soon as it finds an acceptable element, - * and doesn't traverse the entire list. - * @param list Searches for a value in this list. - * @param iterator Search iterator function for each element in `list`. - * @param context `this` object in `iterator`, optional. - * @return The index of the first acceptable found element in `list`, if nothing is found -1 is returned. - **/ - findIndex( - list: _.List, - iterator: _.ListIterator, - context?: any): number; - - - /** - * Looks through each value in the list, returning an array of all the values that pass a truth - * test (iterator). Delegates to the native filter method, if it exists. - * @param list Filter elements out of this list. - * @param iterator Filter iterator function for each element in `list`. - * @param context `this` object in `iterator`, optional. - * @return The filtered list of elements. - **/ - filter( - list: _.List, - iterator: _.ListIterator, - context?: any): T[]; - - /** - * @see _.filter - **/ - filter( - object: _.Dictionary, - iterator: _.ObjectIterator, - context?: any): T[]; - - /** - * @see _.filter - **/ - select( - list: _.List, - iterator: _.ListIterator, - context?: any): T[]; - - /** - * @see _.filter - **/ - select( - object: _.Dictionary, - iterator: _.ObjectIterator, - context?: any): T[]; - - /** - * Looks through each value in the list, returning an array of all the values that contain all - * of the key-value pairs listed in properties. - * @param list List to match elements again `properties`. - * @param properties The properties to check for on each element within `list`. - * @return The elements within `list` that contain the required `properties`. - **/ - where( - list: _.List, - properties: U): T[]; - - /** - * Looks through the list and returns the first value that matches all of the key-value pairs listed in properties. - * @param list Search through this list's elements for the first object with all `properties`. - * @param properties Properties to look for on the elements within `list`. - * @return The first element in `list` that has all `properties`. - **/ - findWhere( - list: _.List, - properties: U): T; - - /** - * Returns the values in list without the elements that the truth test (iterator) passes. - * The opposite of filter. - * Return all the elements for which a truth test fails. - * @param list Reject elements within this list. - * @param iterator Reject iterator function for each element in `list`. - * @param context `this` object in `iterator`, optional. - * @return The rejected list of elements. - **/ - reject( - list: _.List, - iterator: _.ListIterator, - context?: any): T[]; - - /** - * @see _.reject - **/ - reject( - object: _.Dictionary, - iterator: _.ObjectIterator, - context?: any): T[]; - - /** - * Returns true if all of the values in the list pass the iterator truth test. Delegates to the - * native method every, if present. - * @param list Truth test against all elements within this list. - * @param iterator Trust test iterator function for each element in `list`. - * @param context `this` object in `iterator`, optional. - * @return True if all elements passed the truth test, otherwise false. - **/ - every( - list: _.List, - iterator?: _.ListIterator, - context?: any): boolean; - - /** - * @see _.every - **/ - every( - list: _.Dictionary, - iterator?: _.ObjectIterator, - context?: any): boolean; - - /** - * @see _.every - **/ - all( - list: _.List, - iterator?: _.ListIterator, - context?: any): boolean; - - /** - * @see _.every - **/ - all( - list: _.Dictionary, - iterator?: _.ObjectIterator, - context?: any): boolean; - - /** - * Returns true if any of the values in the list pass the iterator truth test. Short-circuits and - * stops traversing the list if a true element is found. Delegates to the native method some, if present. - * @param list Truth test against all elements within this list. - * @param iterator Trust test iterator function for each element in `list`. - * @param context `this` object in `iterator`, optional. - * @return True if any elements passed the truth test, otherwise false. - **/ - some( - list: _.List, - iterator?: _.ListIterator, - context?: any): boolean; - - /** - * @see _.some - **/ - some( - object: _.Dictionary, - iterator?: _.ObjectIterator, - context?: any): boolean; - - /** - * @see _.some - **/ - any( - list: _.List, - iterator?: _.ListIterator, - context?: any): boolean; - - /** - * @see _.some - **/ - any( - object: _.Dictionary, - iterator?: _.ObjectIterator, - context?: any): boolean; - - /** - * Returns true if the value is present in the list. Uses indexOf internally, - * if list is an Array. - * @param list Checks each element to see if `value` is present. - * @param value The value to check for within `list`. - * @return True if `value` is present in `list`, otherwise false. - **/ - contains( - list: _.List, - value: T): boolean; - - /** - * @see _.contains - **/ - contains( - object: _.Dictionary, - value: T): boolean; - - /** - * @see _.contains - **/ - include( - list: _.Collection, - value: T): boolean; - - /** - * @see _.contains - **/ - include( - object: _.Dictionary, - value: T): boolean; - - /** - * Calls the method named by methodName on each value in the list. Any extra arguments passed to - * invoke will be forwarded on to the method invocation. - * @param list The element's in this list will each have the method `methodName` invoked. - * @param methodName The method's name to call on each element within `list`. - * @param arguments Additional arguments to pass to the method `methodName`. - **/ - invoke( - list: _.List, - methodName: string, - ...arguments: any[]): any; - - /** - * A convenient version of what is perhaps the most common use-case for map: extracting a list of - * property values. - * @param list The list to pluck elements out of that have the property `propertyName`. - * @param propertyName The property to look for on each element within `list`. - * @return The list of elements within `list` that have the property `propertyName`. - **/ - pluck( - list: _.List, - propertyName: string): any[]; - - /** - * Returns the maximum value in list. - * @param list Finds the maximum value in this list. - * @return Maximum value in `list`. - **/ - max(list: _.List): number; - - /** - * Returns the maximum value in list. If iterator is passed, it will be used on each value to generate - * the criterion by which the value is ranked. - * @param list Finds the maximum value in this list. - * @param iterator Compares each element in `list` to find the maximum value. - * @param context `this` object in `iterator`, optional. - * @return The maximum element within `list`. - **/ - max( - list: _.List, - iterator?: _.ListIterator, - context?: any): T; - - /** - * Returns the minimum value in list. - * @param list Finds the minimum value in this list. - * @return Minimum value in `list`. - **/ - min(list: _.List): number; - - /** - * Returns the minimum value in list. If iterator is passed, it will be used on each value to generate - * the criterion by which the value is ranked. - * @param list Finds the minimum value in this list. - * @param iterator Compares each element in `list` to find the minimum value. - * @param context `this` object in `iterator`, optional. - * @return The minimum element within `list`. - **/ - min( - list: _.List, - iterator?: _.ListIterator, - context?: any): T; - - /** - * Returns a sorted copy of list, ranked in ascending order by the results of running each value - * through iterator. Iterator may also be the string name of the property to sort by (eg. length). - * @param list Sorts this list. - * @param iterator Sort iterator for each element within `list`. - * @param context `this` object in `iterator`, optional. - * @return A sorted copy of `list`. - **/ - sortBy( - list: _.List, - iterator?: _.ListIterator, - context?: any): T[]; - - /** - * @see _.sortBy - * @param iterator Sort iterator for each element within `list`. - **/ - sortBy( - list: _.List, - iterator: string, - context?: any): T[]; - - /** - * Splits a collection into sets, grouped by the result of running each value through iterator. - * If iterator is a string instead of a function, groups by the property named by iterator on - * each of the values. - * @param list Groups this list. - * @param iterator Group iterator for each element within `list`, return the key to group the element by. - * @param context `this` object in `iterator`, optional. - * @return An object with the group names as properties where each property contains the grouped elements from `list`. - **/ - groupBy( - list: _.List, - iterator?: _.ListIterator, - context?: any): _.Dictionary; - - /** - * @see _.groupBy - * @param iterator Property on each object to group them by. - **/ - groupBy( - list: _.List, - iterator: string, - context?: any): _.Dictionary; - - /** - * Given a `list`, and an `iterator` function that returns a key for each element in the list (or a property name), - * returns an object with an index of each item. Just like _.groupBy, but for when you know your keys are unique. - **/ - indexBy( - list: _.List, - iterator: _.ListIterator, - context?: any): _.Dictionary; - - /** - * @see _.indexBy - * @param iterator Property on each object to index them by. - **/ - indexBy( - list: _.List, - iterator: string, - context?: any): _.Dictionary; - - /** - * Sorts a list into groups and returns a count for the number of objects in each group. Similar - * to groupBy, but instead of returning a list of values, returns a count for the number of values - * in that group. - * @param list Group elements in this list and then count the number of elements in each group. - * @param iterator Group iterator for each element within `list`, return the key to group the element by. - * @param context `this` object in `iterator`, optional. - * @return An object with the group names as properties where each property contains the number of elements in that group. - **/ - countBy( - list: _.List, - iterator?: _.ListIterator, - context?: any): _.Dictionary; - - /** - * @see _.countBy - * @param iterator Function name - **/ - countBy( - list: _.List, - iterator: string, - context?: any): _.Dictionary; - - /** - * Returns a shuffled copy of the list, using a version of the Fisher-Yates shuffle. - * @param list List to shuffle. - * @return Shuffled copy of `list`. - **/ - shuffle(list: _.Collection): T[]; - - /** - * Produce a random sample from the `list`. Pass a number to return `n` random elements from the list. Otherwise a single random item will be returned. - * @param list List to sample. - * @return Random sample of `n` elements in `list`. - **/ - sample(list: _.Collection, n: number): T[]; - - /** - * @see _.sample - **/ - sample(list: _.Collection): T; - - /** - * Converts the list (anything that can be iterated over), into a real Array. Useful for transmuting - * the arguments object. - * @param list object to transform into an array. - * @return `list` as an array. - **/ - toArray(list: _.Collection): T[]; - - /** - * Return the number of values in the list. - * @param list Count the number of values/elements in this list. - * @return Number of values in `list`. - **/ - size(list: _.Collection): number; - - /** - * Split array into two arrays: - * one whose elements all satisfy predicate and one whose elements all do not satisfy predicate. - * @param array Array to split in two. - * @param iterator Filter iterator function for each element in `array`. - * @param context `this` object in `iterator`, optional. - * @return Array where Array[0] are the elements in `array` that satisfies the predicate, and Array[1] the elements that did not. - **/ - partition( - array: Array, - iterator: _.ListIterator, - context?: any): T[][]; - - /********* - * Arrays * - **********/ - - /** - * Returns the first element of an array. Passing n will return the first n elements of the array. - * @param array Retrieves the first element of this array. - * @return Returns the first element of `array`. - **/ - first(array: _.List): T; - - /** - * @see _.first - * @param n Return more than one element from `array`. - **/ - first( - array: _.List, - n: number): T[]; - - /** - * @see _.first - **/ - head(array: _.List): T; - - /** - * @see _.first - **/ - head( - array: _.List, - n: number): T[]; - - /** - * @see _.first - **/ - take(array: _.List): T; - - /** - * @see _.first - **/ - take( - array: _.List, - n: number): T[]; - - /** - * Returns everything but the last entry of the array. Especially useful on the arguments object. - * Pass n to exclude the last n elements from the result. - * @param array Retrieve all elements except the last `n`. - * @param n Leaves this many elements behind, optional. - * @return Returns everything but the last `n` elements of `array`. - **/ - initial( - array: _.List, - n?: number): T[]; - - /** - * Returns the last element of an array. Passing n will return the last n elements of the array. - * @param array Retrieves the last element of this array. - * @return Returns the last element of `array`. - **/ - last(array: _.List): T; - - /** - * @see _.last - * @param n Return more than one element from `array`. - **/ - last( - array: _.List, - n: number): T[]; - - /** - * Returns the rest of the elements in an array. Pass an index to return the values of the array - * from that index onward. - * @param array The array to retrieve all but the first `index` elements. - * @param n The index to start retrieving elements forward from, optional, default = 1. - * @return Returns the elements of `array` from `index` to the end of `array`. - **/ - rest( - array: _.List, - n?: number): T[]; - - /** - * @see _.rest - **/ - tail( - array: _.List, - n?: number): T[]; - - /** - * @see _.rest - **/ - drop( - array: _.List, - n?: number): T[]; - - /** - * Returns a copy of the array with all falsy values removed. In JavaScript, false, null, 0, "", - * undefined and NaN are all falsy. - * @param array Array to compact. - * @return Copy of `array` without false values. - **/ - compact(array: _.List): T[]; - - /** - * Flattens a nested array (the nesting can be to any depth). If you pass shallow, the array will - * only be flattened a single level. - * @param array The array to flatten. - * @param shallow If true then only flatten one level, optional, default = false. - * @return `array` flattened. - **/ - flatten( - array: _.List, - shallow?: boolean): any[]; - - /** - * Returns a copy of the array with all instances of the values removed. - * @param array The array to remove `values` from. - * @param values The values to remove from `array`. - * @return Copy of `array` without `values`. - **/ - without( - array: _.List, - ...values: T[]): T[]; - - /** - * Computes the union of the passed-in arrays: the list of unique items, in order, that are - * present in one or more of the arrays. - * @param arrays Array of arrays to compute the union of. - * @return The union of elements within `arrays`. - **/ - union(...arrays: _.List[]): T[]; - - /** - * Computes the list of values that are the intersection of all the arrays. Each value in the result - * is present in each of the arrays. - * @param arrays Array of arrays to compute the intersection of. - * @return The intersection of elements within `arrays`. - **/ - intersection(...arrays: _.List[]): T[]; - - /** - * Similar to without, but returns the values from array that are not present in the other arrays. - * @param array Keeps values that are within `others`. - * @param others The values to keep within `array`. - * @return Copy of `array` with only `others` values. - **/ - difference( - array: _.List, - ...others: _.List[]): T[]; - - /** - * Produces a duplicate-free version of the array, using === to test object equality. If you know in - * advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If - * you want to compute unique items based on a transformation, pass an iterator function. - * @param array Array to remove duplicates from. - * @param isSorted True if `array` is already sorted, optional, default = false. - * @param iterator Transform the elements of `array` before comparisons for uniqueness. - * @param context 'this' object in `iterator`, optional. - * @return Copy of `array` where all elements are unique. - **/ - uniq( - array: _.List, - isSorted?: boolean, - iterator?: _.ListIterator, - context?: any): T[]; - - /** - * @see _.uniq - **/ - uniq( - array: _.List, - iterator?: _.ListIterator, - context?: any): T[]; - - /** - * @see _.uniq - **/ - unique( - array: _.List, - iterator?: _.ListIterator, - context?: any): T[]; - - /** - * @see _.uniq - **/ - unique( - array: _.List, - isSorted?: boolean, - iterator?: _.ListIterator, - context?: any): T[]; - - - /** - * Merges together the values of each of the arrays with the values at the corresponding position. - * Useful when you have separate data sources that are coordinated through matching array indexes. - * If you're working with a matrix of nested arrays, zip.apply can transpose the matrix in a similar fashion. - * @param arrays The arrays to merge/zip. - * @return Zipped version of `arrays`. - **/ - zip(...arrays: any[][]): any[][]; - - /** - * @see _.zip - **/ - zip(...arrays: any[]): any[]; - - /** - * Converts arrays into objects. Pass either a single list of [key, value] pairs, or a - * list of keys, and a list of values. - * @param keys Key array. - * @param values Value array. - * @return An object containing the `keys` as properties and `values` as the property values. - **/ - object( - keys: _.List, - values: _.List): TResult; - - /** - * Converts arrays into objects. Pass either a single list of [key, value] pairs, or a - * list of keys, and a list of values. - * @param keyValuePairs Array of [key, value] pairs. - * @return An object containing the `keys` as properties and `values` as the property values. - **/ - object(...keyValuePairs: any[][]): TResult; - - /** - * @see _.object - **/ - object( - list: _.List, - values?: any): TResult; - - /** - * Returns the index at which value can be found in the array, or -1 if value is not present in the array. - * Uses the native indexOf function unless it's missing. If you're working with a large array, and you know - * that the array is already sorted, pass true for isSorted to use a faster binary search ... or, pass a number - * as the third argument in order to look for the first matching value in the array after the given index. - * @param array The array to search for the index of `value`. - * @param value The value to search for within `array`. - * @param isSorted True if the array is already sorted, optional, default = false. - * @return The index of `value` within `array`. - **/ - indexOf( - array: _.List, - value: T, - isSorted?: boolean): number; - - /** - * @see _indexof - **/ - indexOf( - array: _.List, - value: T, - startFrom: number): number; - - /** - * Returns the index of the last occurrence of value in the array, or -1 if value is not present. Uses the - * native lastIndexOf function if possible. Pass fromIndex to start your search at a given index. - * @param array The array to search for the last index of `value`. - * @param value The value to search for within `array`. - * @param from The starting index for the search, optional. - * @return The index of the last occurrence of `value` within `array`. - **/ - lastIndexOf( - array: _.List, - value: T, - from?: number): number; - - /** - * Uses a binary search to determine the index at which the value should be inserted into the list in order - * to maintain the list's sorted order. If an iterator is passed, it will be used to compute the sort ranking - * of each value, including the value you pass. - * @param list The sorted list. - * @param value The value to determine its index within `list`. - * @param iterator Iterator to compute the sort ranking of each value, optional. - * @return The index where `value` should be inserted into `list`. - **/ - sortedIndex( - list: _.List, - value: T, - iterator?: (x: T) => TSort, context?: any): number; - - /** - * A function to create flexibly-numbered lists of integers, handy for each and map loops. start, if omitted, - * defaults to 0; step defaults to 1. Returns a list of integers from start to stop, incremented (or decremented) - * by step, exclusive. - * @param start Start here. - * @param stop Stop here. - * @param step The number to count up by each iteration, optional, default = 1. - * @return Array of numbers from `start` to `stop` with increments of `step`. - **/ - - range( - start: number, - stop: number, - step?: number): number[]; - - /** - * @see _.range - * @param stop Stop here. - * @return Array of numbers from 0 to `stop` with increments of 1. - * @note If start is not specified the implementation will never pull the step (step = arguments[2] || 0) - **/ - range(stop: number): number[]; - - /************* - * Functions * - *************/ - - /** - * Bind a function to an object, meaning that whenever the function is called, the value of this will - * be the object. Optionally, bind arguments to the function to pre-fill them, also known as partial application. - * @param func The function to bind `this` to `object`. - * @param context The `this` pointer whenever `fn` is called. - * @param arguments Additional arguments to pass to `fn` when called. - * @return `fn` with `this` bound to `object`. - **/ - bind( - func: Function, - context: any, - ...arguments: any[]): () => any; - - /** - * Binds a number of methods on the object, specified by methodNames, to be run in the context of that object - * whenever they are invoked. Very handy for binding functions that are going to be used as event handlers, - * which would otherwise be invoked with a fairly useless this. If no methodNames are provided, all of the - * object's function properties will be bound to it. - * @param object The object to bind the methods `methodName` to. - * @param methodNames The methods to bind to `object`, optional and if not provided all of `object`'s - * methods are bound. - **/ - bindAll( - object: any, - ...methodNames: string[]): any; - - /** - * Partially apply a function by filling in any number of its arguments, without changing its dynamic this value. - * A close cousin of bind. You may pass _ in your list of arguments to specify an argument that should not be - * pre-filled, but left open to supply at call-time. - * @param fn Function to partially fill in arguments. - * @param arguments The partial arguments. - * @return `fn` with partially filled in arguments. - **/ - partial( - fn: Function, - ...arguments: any[]): Function; - - /** - * Memoizes a given function by caching the computed result. Useful for speeding up slow-running computations. - * If passed an optional hashFunction, it will be used to compute the hash key for storing the result, based - * on the arguments to the original function. The default hashFunction just uses the first argument to the - * memoized function as the key. - * @param fn Computationally expensive function that will now memoized results. - * @param hashFn Hash function for storing the result of `fn`. - * @return Memoized version of `fn`. - **/ - memoize( - fn: Function, - hashFn?: (...args: any[]) => string): Function; - - /** - * Much like setTimeout, invokes function after wait milliseconds. If you pass the optional arguments, - * they will be forwarded on to the function when it is invoked. - * @param func Function to delay `waitMS` amount of ms. - * @param wait The amount of milliseconds to delay `fn`. - * @arguments Additional arguments to pass to `fn`. - **/ - delay( - func: Function, - wait: number, - ...arguments: any[]): any; - - /** - * @see _delay - **/ - delay( - func: Function, - ...arguments: any[]): any; - - /** - * Defers invoking the function until the current call stack has cleared, similar to using setTimeout - * with a delay of 0. Useful for performing expensive computations or HTML rendering in chunks without - * blocking the UI thread from updating. If you pass the optional arguments, they will be forwarded on - * to the function when it is invoked. - * @param fn The function to defer. - * @param arguments Additional arguments to pass to `fn`. - **/ - defer( - fn: Function, - ...arguments: any[]): void; - - /** - * Creates and returns a new, throttled version of the passed function, that, when invoked repeatedly, - * will only actually call the original function at most once per every wait milliseconds. Useful for - * rate-limiting events that occur faster than you can keep up with. - * By default, throttle will execute the function as soon as you call it for the first time, and, - * if you call it again any number of times during the wait period, as soon as that period is over. - * If you'd like to disable the leading-edge call, pass {leading: false}, and if you'd like to disable - * the execution on the trailing-edge, pass {trailing: false}. - * @param func Function to throttle `waitMS` ms. - * @param wait The number of milliseconds to wait before `fn` can be invoked again. - * @param options Allows for disabling execution of the throttled function on either the leading or trailing edge. - * @return `fn` with a throttle of `wait`. - **/ - throttle( - func: T, - wait: number, - options?: _.ThrottleSettings): T; - - /** - * Creates and returns a new debounced version of the passed function that will postpone its execution - * until after wait milliseconds have elapsed since the last time it was invoked. Useful for implementing - * behavior that should only happen after the input has stopped arriving. For example: rendering a preview - * of a Markdown comment, recalculating a layout after the window has stopped being resized, and so on. - * - * Pass true for the immediate parameter to cause debounce to trigger the function on the leading instead - * of the trailing edge of the wait interval. Useful in circumstances like preventing accidental double - *-clicks on a "submit" button from firing a second time. - * @param fn Function to debounce `waitMS` ms. - * @param wait The number of milliseconds to wait before `fn` can be invoked again. - * @param immediate True if `fn` should be invoked on the leading edge of `waitMS` instead of the trailing edge. - * @return Debounced version of `fn` that waits `wait` ms when invoked. - **/ - debounce( - fn: T, - wait: number, - immediate?: boolean): T; - - /** - * Creates a version of the function that can only be called one time. Repeated calls to the modified - * function will have no effect, returning the value from the original call. Useful for initialization - * functions, instead of having to set a boolean flag and then check it later. - * @param fn Function to only execute once. - * @return Copy of `fn` that can only be invoked once. - **/ - once(fn: T): T; - - /** - * Creates a version of the function that will only be run after first being called count times. Useful - * for grouping asynchronous responses, where you want to be sure that all the async calls have finished, - * before proceeding. - * @param number count Number of times to be called before actually executing. - * @param Function fn The function to defer execution `count` times. - * @return Copy of `fn` that will not execute until it is invoked `count` times. - **/ - after( - count: number, - fn: Function): Function; - - /** - * Creates a version of the function that can be called no more than count times. The result of - * the last function call is memoized and returned when count has been reached. - * @param number count The maxmimum number of times the function can be called. - * @param Function fn The function to limit the number of times it can be called. - * @return Copy of `fn` that can only be called `count` times. - **/ - before( - count: number, - fn: Function): Function; - - /** - * Wraps the first function inside of the wrapper function, passing it as the first argument. This allows - * the wrapper to execute code before and after the function runs, adjust the arguments, and execute it - * conditionally. - * @param fn Function to wrap. - * @param wrapper The function that will wrap `fn`. - * @return Wrapped version of `fn. - **/ - wrap( - fn: Function, - wrapper: (fn: Function, ...args: any[]) => any): Function; - - /** - * Returns a negated version of the pass-in predicate. - * @param Function predicate - * @return boolean - **/ - negate(predicate: Function): boolean; - - /** - * Returns the composition of a list of functions, where each function consumes the return value of the - * function that follows. In math terms, composing the functions f(), g(), and h() produces f(g(h())). - * @param functions List of functions to compose. - * @return Composition of `functions`. - **/ - compose(...functions: Function[]): Function; - - /********** - * Objects * - ***********/ - - /** - * Retrieve all the names of the object's properties. - * @param object Retrieve the key or property names from this object. - * @return List of all the property names on `object`. - **/ - keys(object: any): string[]; - - /** - * Return all of the values of the object's properties. - * @param object Retrieve the values of all the properties on this object. - * @return List of all the values on `object`. - **/ - values(object: any): any[]; - - /** - * Like map, but for objects. Transform the value of each property in turn. - * @param object The object to transform - * @param iteratee The function that transforms property values - * @param context The optional context (value of `this`) to bind to - * @return a new _.Dictionary of property values - */ - mapObject(object: _.Dictionary, iteratee: (val: T, key: string, object: _.Dictionary) => U, context?: any): _.Dictionary; - - /** - * Like map, but for objects. Transform the value of each property in turn. - * @param object The object to transform - * @param iteratee The function that tranforms property values - * @param context The optional context (value of `this`) to bind to - */ - mapObject(object: any, iteratee: (val: any, key: string, object: any) => T, context?: any): _.Dictionary; - - /** - * Like map, but for objects. Retrieves a property from each entry in the object, as if by _.property - * @param object The object to transform - * @param iteratee The property name to retrieve - * @param context The optional context (value of `this`) to bind to - */ - mapObject(object: any, iteratee: string, context?: any): _.Dictionary; - - /** - * Convert an object into a list of [key, value] pairs. - * @param object Convert this object to a list of [key, value] pairs. - * @return List of [key, value] pairs on `object`. - **/ - pairs(object: any): any[][]; - - /** - * Returns a copy of the object where the keys have become the values and the values the keys. - * For this to work, all of your object's values should be unique and string serializable. - * @param object Object to invert key/value pairs. - * @return An inverted key/value paired version of `object`. - **/ - invert(object: any): any; - - /** - * Returns a sorted list of the names of every method in an object - that is to say, - * the name of every function property of the object. - * @param object Object to pluck all function property names from. - * @return List of all the function names on `object`. - **/ - functions(object: any): string[]; - - /** - * @see _functions - **/ - methods(object: any): string[]; - - /** - * Copy all of the properties in the source objects over to the destination object, and return - * the destination object. It's in-order, so the last source will override properties of the - * same name in previous arguments. - * @param destination Object to extend all the properties from `sources`. - * @param sources Extends `destination` with all properties from these source objects. - * @return `destination` extended with all the properties from the `sources` objects. - **/ - extend( - destination: any, - ...sources: any[]): any; - - /** - * Like extend, but only copies own properties over to the destination object. (alias: assign) - */ - extendOwn( - destination: any, - ...source: any[]): any; - - /** - * Like extend, but only copies own properties over to the destination object. (alias: extendOwn) - */ - assign( - destination: any, - ...source: any[]): any; - - /** - * Return a copy of the object, filtered to only have values for the whitelisted keys - * (or array of valid keys). - * @param object Object to strip unwanted key/value pairs. - * @keys The key/value pairs to keep on `object`. - * @return Copy of `object` with only the `keys` properties. - **/ - pick( - object: any, - ...keys: any[]): any; - - /** - * @see _.pick - **/ - pick( - object: any, - fn: (value: any, key: any, object: any) => any): any; - - /** - * Return a copy of the object, filtered to omit the blacklisted keys (or array of keys). - * @param object Object to strip unwanted key/value pairs. - * @param keys The key/value pairs to remove on `object`. - * @return Copy of `object` without the `keys` properties. - **/ - omit( - object: any, - ...keys: string[]): any; - - /** - * @see _.omit - **/ - omit( - object: any, - keys: string[]): any; - - /** - * @see _.omit - **/ - omit( - object: any, - iteratee: Function): any; - - /** - * Fill in null and undefined properties in object with values from the defaults objects, - * and return the object. As soon as the property is filled, further defaults will have no effect. - * @param object Fill this object with default values. - * @param defaults The default values to add to `object`. - * @return `object` with added `defaults` values. - **/ - defaults( - object: any, - ...defaults: any[]): any; - - /** - * Create a shallow-copied clone of the object. - * Any nested objects or arrays will be copied by reference, not duplicated. - * @param object Object to clone. - * @return Copy of `object`. - **/ - clone(object: T): T; - - /** - * Invokes interceptor with the object, and then returns object. The primary purpose of this method - * is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. - * @param object Argument to `interceptor`. - * @param intercepter The function to modify `object` before continuing the method chain. - * @return Modified `object`. - **/ - tap(object: T, intercepter: Function): T; - - /** - * Does the object contain the given key? Identical to object.hasOwnProperty(key), but uses a safe - * reference to the hasOwnProperty function, in case it's been overridden accidentally. - * @param object Object to check for `key`. - * @param key The key to check for on `object`. - * @return True if `key` is a property on `object`, otherwise false. - **/ - has(object: any, key: string): boolean; - - /** - * Returns a predicate function that will tell you if a passed in object contains all of the key/value properties present in attrs. - * @param attrs Object with key values pair - * @return Predicate function - **/ - matches(attrs: T): _.ListIterator; - - /** - * Returns a function that will itself return the key property of any passed-in object. - * @param key Property of the object. - * @return Function which accept an object an returns the value of key in that object. - **/ - property(key: string): (object: Object) => any; - - /** - * Performs an optimized deep comparison between the two objects, - * to determine if they should be considered equal. - * @param object Compare to `other`. - * @param other Compare to `object`. - * @return True if `object` is equal to `other`. - **/ - isEqual(object: any, other: any): boolean; - - /** - * Returns true if object contains no values. - * @param object Check if this object has no properties or values. - * @return True if `object` is empty. - **/ - isEmpty(object: any): boolean; - - /** - * Returns true if object is a DOM element. - * @param object Check if this object is a DOM element. - * @return True if `object` is a DOM element, otherwise false. - **/ - isElement(object: any): boolean; - - /** - * Returns true if object is an Array. - * @param object Check if this object is an Array. - * @return True if `object` is an Array, otherwise false. - **/ - isArray(object: any): boolean; - - /** - * Returns true if value is an Object. Note that JavaScript arrays and functions are objects, - * while (normal) strings and numbers are not. - * @param object Check if this object is an Object. - * @return True of `object` is an Object, otherwise false. - **/ - isObject(object: any): boolean; - - /** - * Returns true if object is an Arguments object. - * @param object Check if this object is an Arguments object. - * @return True if `object` is an Arguments object, otherwise false. - **/ - isArguments(object: any): boolean; - - /** - * Returns true if object is a Function. - * @param object Check if this object is a Function. - * @return True if `object` is a Function, otherwise false. - **/ - isFunction(object: any): boolean; - - /** - * Returns true if object is a String. - * @param object Check if this object is a String. - * @return True if `object` is a String, otherwise false. - **/ - isString(object: any): boolean; - - /** - * Returns true if object is a Number (including NaN). - * @param object Check if this object is a Number. - * @return True if `object` is a Number, otherwise false. - **/ - isNumber(object: any): boolean; - - /** - * Returns true if object is a finite Number. - * @param object Check if this object is a finite Number. - * @return True if `object` is a finite Number. - **/ - isFinite(object: any): boolean; - - /** - * Returns true if object is either true or false. - * @param object Check if this object is a bool. - * @return True if `object` is a bool, otherwise false. - **/ - isBoolean(object: any): boolean; - - /** - * Returns true if object is a Date. - * @param object Check if this object is a Date. - * @return True if `object` is a Date, otherwise false. - **/ - isDate(object: any): boolean; - - /** - * Returns true if object is a RegExp. - * @param object Check if this object is a RegExp. - * @return True if `object` is a RegExp, otherwise false. - **/ - isRegExp(object: any): boolean; - - /** - * Returns true if object is NaN. - * Note: this is not the same as the native isNaN function, - * which will also return true if the variable is undefined. - * @param object Check if this object is NaN. - * @return True if `object` is NaN, otherwise false. - **/ - isNaN(object: any): boolean; - - /** - * Returns true if the value of object is null. - * @param object Check if this object is null. - * @return True if `object` is null, otherwise false. - **/ - isNull(object: any): boolean; - - /** - * Returns true if value is undefined. - * @param object Check if this object is undefined. - * @return True if `object` is undefined, otherwise false. - **/ - isUndefined(value: any): boolean; - - /* ********* - * Utility * - ********** */ - - /** - * Give control of the "_" variable back to its previous owner. - * Returns a reference to the Underscore object. - * @return Underscore object reference. - **/ - noConflict(): any; - - /** - * Returns the same value that is used as the argument. In math: f(x) = x - * This function looks useless, but is used throughout Underscore as a default iterator. - * @param value Identity of this object. - * @return `value`. - **/ - identity(value: T): T; - - /** - * Creates a function that returns the same value that is used as the argument of _.constant - * @param value Identity of this object. - * @return Function that return value. - **/ - constant(value: T): () => T; - - /** - * Returns undefined irrespective of the arguments passed to it. Useful as the default - * for optional callback arguments. - * Note there is no way to indicate a 'undefined' return, so it is currently typed as void. - * @return undefined - **/ - noop(): void; - - /** - * Invokes the given iterator function n times. - * Each invocation of iterator is called with an index argument - * @param n Number of times to invoke `iterator`. - * @param iterator Function iterator to invoke `n` times. - * @param context `this` object in `iterator`, optional. - **/ - times(n: number, iterator: (n: number) => TResult, context?: any): TResult[]; - - /** - * Returns a random integer between min and max, inclusive. If you only pass one argument, - * it will return a number between 0 and that number. - * @param max The maximum random number. - * @return A random number between 0 and `max`. - **/ - random(max: number): number; - - /** - * @see _.random - * @param min The minimum random number. - * @return A random number between `min` and `max`. - **/ - random(min: number, max: number): number; - - /** - * Allows you to extend Underscore with your own utility functions. Pass a hash of - * {name: function} definitions to have your functions added to the Underscore object, - * as well as the OOP wrapper. - * @param object Mixin object containing key/function pairs to add to the Underscore object. - **/ - mixin(object: any): void; - - /** - * A mostly-internal function to generate callbacks that can be applied to each element - * in a collection, returning the desired result -- either identity, an arbitrary callback, - * a property matcher, or a propetery accessor. - * @param string|Function|Object value The value to iterate over, usually the key. - * @param any context - * @param number argCount - * @return Callback that can be applied to each element in a collection. - **/ - iteratee(value: string): Function; - iteratee(value: Function, context?: any, argCount?: number): Function; - iteratee(value: Object): Function; - - /** - * Generate a globally-unique id for client-side models or DOM elements that need one. - * If prefix is passed, the id will be appended to it. Without prefix, returns an integer. - * @param prefix A prefix string to start the unique ID with. - * @return Unique string ID beginning with `prefix`. - **/ - uniqueId(prefix: string): string; - - /** - * @see _.uniqueId - **/ - uniqueId(): number; - - /** - * Escapes a string for insertion into HTML, replacing &, <, >, ", ', and / characters. - * @param str Raw string to escape. - * @return `str` HTML escaped. - **/ - escape(str: string): string; - - /** - * The opposite of escape, replaces &, <, >, ", and ' with their unescaped counterparts. - * @param str HTML escaped string. - * @return `str` Raw string. - **/ - unescape(str: string): string; - - /** - * If the value of the named property is a function then invoke it; otherwise, return it. - * @param object Object to maybe invoke function `property` on. - * @param property The function by name to invoke on `object`. - * @return The result of invoking the function `property` on `object. - **/ - result(object: any, property: string): any; - - /** - * Compiles JavaScript templates into functions that can be evaluated for rendering. Useful - * for rendering complicated bits of HTML from JSON data sources. Template functions can both - * interpolate variables, using <%= ... %>, as well as execute arbitrary JavaScript code, with - * <% ... %>. If you wish to interpolate a value, and have it be HTML-escaped, use <%- ... %> When - * you evaluate a template function, pass in a data object that has properties corresponding to - * the template's free variables. If you're writing a one-off, you can pass the data object as - * the second parameter to template in order to render immediately instead of returning a template - * function. The settings argument should be a hash containing any _.templateSettings that should - * be overridden. - * @param templateString Underscore HTML template. - * @param data Data to use when compiling `templateString`. - * @param settings Settings to use while compiling. - * @return Returns the compiled Underscore HTML template. - **/ - template(templateString: string, settings?: _.TemplateSettings): (...data: any[]) => string; - - /** - * By default, Underscore uses ERB-style template delimiters, change the - * following template settings to use alternative delimiters. - **/ - templateSettings: _.TemplateSettings; - - /** - * Returns an integer timestamp for the current time, using the fastest method available in the runtime. Useful for implementing timing/animation functions. - **/ - now(): number; - - /* ********** - * Chaining * - *********** */ - - /** - * Returns a wrapped object. Calling methods on this object will continue to return wrapped objects - * until value() is used. - * @param obj Object to chain. - * @return Wrapped `obj`. - **/ - chain(obj: T[]): _Chain; - chain(obj: T): _Chain; -} - -interface Underscore { - - /* ************* - * Collections * - ************* */ - - /** - * Wrapped type `any[]`. - * @see _.each - **/ - each(iterator: _.ListIterator, context?: any): T[]; - - /** - * @see _.each - **/ - each(iterator: _.ObjectIterator, context?: any): T[]; - - /** - * @see _.each - **/ - forEach(iterator: _.ListIterator, context?: any): T[]; - - /** - * @see _.each - **/ - forEach(iterator: _.ObjectIterator, context?: any): T[]; - - /** - * Wrapped type `any[]`. - * @see _.map - **/ - map(iterator: _.ListIterator, context?: any): TResult[]; - - /** - * Wrapped type `any[]`. - * @see _.map - **/ - map(iterator: _.ObjectIterator, context?: any): TResult[]; - - /** - * @see _.map - **/ - collect(iterator: _.ListIterator, context?: any): TResult[]; - - /** - * @see _.map - **/ - collect(iterator: _.ObjectIterator, context?: any): TResult[]; - - /** - * Wrapped type `any[]`. - * @see _.reduce - **/ - reduce(iterator: _.MemoIterator, memo?: TResult, context?: any): TResult; - - /** - * @see _.reduce - **/ - inject(iterator: _.MemoIterator, memo?: TResult, context?: any): TResult; - - /** - * @see _.reduce - **/ - foldl(iterator: _.MemoIterator, memo?: TResult, context?: any): TResult; - - /** - * Wrapped type `any[]`. - * @see _.reduceRight - **/ - reduceRight(iterator: _.MemoIterator, memo?: TResult, context?: any): TResult; - - /** - * @see _.reduceRight - **/ - foldr(iterator: _.MemoIterator, memo?: TResult, context?: any): TResult; - - /** - * Wrapped type `any[]`. - * @see _.find - **/ - find(iterator: _.ListIterator, context?: any): T; - - /** - * @see _.find - **/ - detect(iterator: _.ListIterator, context?: any): T; - - /** - * Wrapped type `any[]`. - * @see _.filter - **/ - filter(iterator: _.ListIterator, context?: any): T[]; - - /** - * @see _.filter - **/ - select(iterator: _.ListIterator, context?: any): T[]; - - /** - * Wrapped type `any[]`. - * @see _.where - **/ - where(properties: U): T[]; - - /** - * Wrapped type `any[]`. - * @see _.findWhere - **/ - findWhere(properties: U): T; - - /** - * Wrapped type `any[]`. - * @see _.reject - **/ - reject(iterator: _.ListIterator, context?: any): T[]; - - /** - * Wrapped type `any[]`. - * @see _.all - **/ - all(iterator?: _.ListIterator, context?: any): boolean; - - /** - * @see _.all - **/ - every(iterator?: _.ListIterator, context?: any): boolean; - - /** - * Wrapped type `any[]`. - * @see _.any - **/ - any(iterator?: _.ListIterator, context?: any): boolean; - - /** - * @see _.any - **/ - some(iterator?: _.ListIterator, context?: any): boolean; - - /** - * Wrapped type `any[]`. - * @see _.contains - **/ - contains(value: T): boolean; - - /** - * Alias for 'contains'. - * @see contains - **/ - include(value: T): boolean; - - /** - * Wrapped type `any[]`. - * @see _.invoke - **/ - invoke(methodName: string, ...arguments: any[]): any; - - /** - * Wrapped type `any[]`. - * @see _.pluck - **/ - pluck(propertyName: string): any[]; - - /** - * Wrapped type `number[]`. - * @see _.max - **/ - max(): number; - - /** - * Wrapped type `any[]`. - * @see _.max - **/ - max(iterator: _.ListIterator, context?: any): T; - - /** - * Wrapped type `any[]`. - * @see _.max - **/ - max(iterator?: _.ListIterator, context?: any): T; - - /** - * Wrapped type `number[]`. - * @see _.min - **/ - min(): number; - - /** - * Wrapped type `any[]`. - * @see _.min - **/ - min(iterator: _.ListIterator, context?: any): T; - - /** - * Wrapped type `any[]`. - * @see _.min - **/ - min(iterator?: _.ListIterator, context?: any): T; - - /** - * Wrapped type `any[]`. - * @see _.sortBy - **/ - sortBy(iterator?: _.ListIterator, context?: any): T[]; - - /** - * Wrapped type `any[]`. - * @see _.sortBy - **/ - sortBy(iterator: string, context?: any): T[]; - - /** - * Wrapped type `any[]`. - * @see _.groupBy - **/ - groupBy(iterator?: _.ListIterator, context?: any): _.Dictionary<_.List>; - - /** - * Wrapped type `any[]`. - * @see _.groupBy - **/ - groupBy(iterator: string, context?: any): _.Dictionary; - - /** - * Wrapped type `any[]`. - * @see _.indexBy - **/ - indexBy(iterator: _.ListIterator, context?: any): _.Dictionary; - - /** - * Wrapped type `any[]`. - * @see _.indexBy - **/ - indexBy(iterator: string, context?: any): _.Dictionary; - - /** - * Wrapped type `any[]`. - * @see _.countBy - **/ - countBy(iterator?: _.ListIterator, context?: any): _.Dictionary; - - /** - * Wrapped type `any[]`. - * @see _.countBy - **/ - countBy(iterator: string, context?: any): _.Dictionary; - - /** - * Wrapped type `any[]`. - * @see _.shuffle - **/ - shuffle(): T[]; - - /** - * Wrapped type `any[]`. - * @see _.sample - **/ - sample(n: number): T[]; - - /** - * @see _.sample - **/ - sample(): T; - - /** - * Wrapped type `any`. - * @see _.toArray - **/ - toArray(): T[]; - - /** - * Wrapped type `any`. - * @see _.size - **/ - size(): number; - - /********* - * Arrays * - **********/ - - /** - * Wrapped type `any[]`. - * @see _.first - **/ - first(): T; - - /** - * Wrapped type `any[]`. - * @see _.first - **/ - first(n: number): T[]; - - /** - * @see _.first - **/ - head(): T; - - /** - * @see _.first - **/ - head(n: number): T[]; - - /** - * @see _.first - **/ - take(): T; - - /** - * @see _.first - **/ - take(n: number): T[]; - - /** - * Wrapped type `any[]`. - * @see _.initial - **/ - initial(n?: number): T[]; - - /** - * Wrapped type `any[]`. - * @see _.last - **/ - last(): T; - - /** - * Wrapped type `any[]`. - * @see _.last - **/ - last(n: number): T[]; - - /** - * Wrapped type `any[]`. - * @see _.rest - **/ - rest(n?: number): T[]; - - /** - * @see _.rest - **/ - tail(n?: number): T[]; - - /** - * @see _.rest - **/ - drop(n?: number): T[]; - - /** - * Wrapped type `any[]`. - * @see _.compact - **/ - compact(): T[]; - - /** - * Wrapped type `any`. - * @see _.flatten - **/ - flatten(shallow?: boolean): any[]; - - /** - * Wrapped type `any[]`. - * @see _.without - **/ - without(...values: T[]): T[]; - - /** - * Wrapped type `any[]`. - * @see _.partition - **/ - partition(iterator: _.ListIterator, context?: any): T[][]; - - /** - * Wrapped type `any[][]`. - * @see _.union - **/ - union(...arrays: _.List[]): T[]; - - /** - * Wrapped type `any[][]`. - * @see _.intersection - **/ - intersection(...arrays: _.List[]): T[]; - - /** - * Wrapped type `any[]`. - * @see _.difference - **/ - difference(...others: _.List[]): T[]; - - /** - * Wrapped type `any[]`. - * @see _.uniq - **/ - uniq(isSorted?: boolean, iterator?: _.ListIterator): T[]; - - /** - * Wrapped type `any[]`. - * @see _.uniq - **/ - uniq(iterator?: _.ListIterator, context?: any): T[]; - - /** - * @see _.uniq - **/ - unique(isSorted?: boolean, iterator?: _.ListIterator): T[]; - - /** - * @see _.uniq - **/ - unique(iterator?: _.ListIterator, context?: any): T[]; - - /** - * Wrapped type `any[][]`. - * @see _.zip - **/ - zip(...arrays: any[][]): any[][]; - - /** - * Wrapped type `any[][]`. - * @see _.object - **/ - object(...keyValuePairs: any[][]): any; - - /** - * @see _.object - **/ - object(values?: any): any; - - /** - * Wrapped type `any[]`. - * @see _.indexOf - **/ - indexOf(value: T, isSorted?: boolean): number; - - /** - * @see _.indexOf - **/ - indexOf(value: T, startFrom: number): number; - - /** - * Wrapped type `any[]`. - * @see _.lastIndexOf - **/ - lastIndexOf(value: T, from?: number): number; - - /** - * Wrapped type `any[]`. - * @see _.sortedIndex - **/ - sortedIndex(value: T, iterator?: (x: T) => any, context?: any): number; - - /** - * Wrapped type `number`. - * @see _.range - **/ - range(stop: number, step?: number): number[]; - - /** - * Wrapped type `number`. - * @see _.range - **/ - range(): number[]; - - /* *********** - * Functions * - ************ */ - - /** - * Wrapped type `Function`. - * @see _.bind - **/ - bind(object: any, ...arguments: any[]): Function; - - /** - * Wrapped type `object`. - * @see _.bindAll - **/ - bindAll(...methodNames: string[]): any; - - /** - * Wrapped type `Function`. - * @see _.partial - **/ - partial(...arguments: any[]): Function; - - /** - * Wrapped type `Function`. - * @see _.memoize - **/ - memoize(hashFn?: (n: any) => string): Function; - - /** - * Wrapped type `Function`. - * @see _.defer - **/ - defer(...arguments: any[]): void; - - /** - * Wrapped type `Function`. - * @see _.delay - **/ - delay(wait: number, ...arguments: any[]): any; - - /** - * @see _.delay - **/ - delay(...arguments: any[]): any; - - /** - * Wrapped type `Function`. - * @see _.throttle - **/ - throttle(wait: number, options?: _.ThrottleSettings): Function; - - /** - * Wrapped type `Function`. - * @see _.debounce - **/ - debounce(wait: number, immediate?: boolean): Function; - - /** - * Wrapped type `Function`. - * @see _.once - **/ - once(): Function; - - /** - * Wrapped type `number`. - * @see _.after - **/ - after(fn: Function): Function; - - /** - * Wrapped type `number`. - * @see _.before - **/ - before(fn: Function): Function; - - /** - * Wrapped type `Function`. - * @see _.wrap - **/ - wrap(wrapper: Function): () => Function; - - /** - * Wrapped type `Function`. - * @see _.negate - **/ - negate(): boolean; - - /** - * Wrapped type `Function[]`. - * @see _.compose - **/ - compose(...functions: Function[]): Function; - - /********* * - * Objects * - ********** */ - - /** - * Wrapped type `object`. - * @see _.keys - **/ - keys(): string[]; - - /** - * Wrapped type `object`. - * @see _.values - **/ - values(): T[]; - - /** - * Wrapped type `object`. - * @see _.pairs - **/ - pairs(): any[][]; - - /** - * Wrapped type `object`. - * @see _.invert - **/ - invert(): any; - - /** - * Wrapped type `object`. - * @see _.functions - **/ - functions(): string[]; - - /** - * @see _.functions - **/ - methods(): string[]; - - /** - * Wrapped type `object`. - * @see _.extend - **/ - extend(...sources: any[]): any; - - /** - * Wrapped type `object`. - * @see _.pick - **/ - pick(...keys: any[]): any; - pick(keys: any[]): any; - pick(fn: (value: any, key: any, object: any) => any): any; - - /** - * Wrapped type `object`. - * @see _.omit - **/ - omit(...keys: string[]): any; - omit(keys: string[]): any; - omit(fn: Function): any; - - /** - * Wrapped type `object`. - * @see _.defaults - **/ - defaults(...defaults: any[]): any; - - /** - * Wrapped type `any[]`. - * @see _.clone - **/ - clone(): T; - - /** - * Wrapped type `object`. - * @see _.tap - **/ - tap(interceptor: (...as: any[]) => any): any; - - /** - * Wrapped type `object`. - * @see _.has - **/ - has(key: string): boolean; - - /** - * Wrapped type `any[]`. - * @see _.matches - **/ - matches(): _.ListIterator; - - /** - * Wrapped type `string`. - * @see _.property - **/ - property(): (object: Object) => any; - - /** - * Wrapped type `object`. - * @see _.isEqual - **/ - isEqual(other: any): boolean; - - /** - * Wrapped type `object`. - * @see _.isEmpty - **/ - isEmpty(): boolean; - - /** - * Wrapped type `object`. - * @see _.isElement - **/ - isElement(): boolean; - - /** - * Wrapped type `object`. - * @see _.isArray - **/ - isArray(): boolean; - - /** - * Wrapped type `object`. - * @see _.isObject - **/ - isObject(): boolean; - - /** - * Wrapped type `object`. - * @see _.isArguments - **/ - isArguments(): boolean; - - /** - * Wrapped type `object`. - * @see _.isFunction - **/ - isFunction(): boolean; - - /** - * Wrapped type `object`. - * @see _.isString - **/ - isString(): boolean; - - /** - * Wrapped type `object`. - * @see _.isNumber - **/ - isNumber(): boolean; - - /** - * Wrapped type `object`. - * @see _.isFinite - **/ - isFinite(): boolean; - - /** - * Wrapped type `object`. - * @see _.isBoolean - **/ - isBoolean(): boolean; - - /** - * Wrapped type `object`. - * @see _.isDate - **/ - isDate(): boolean; - - /** - * Wrapped type `object`. - * @see _.isRegExp - **/ - isRegExp(): boolean; - - /** - * Wrapped type `object`. - * @see _.isNaN - **/ - isNaN(): boolean; - - /** - * Wrapped type `object`. - * @see _.isNull - **/ - isNull(): boolean; - - /** - * Wrapped type `object`. - * @see _.isUndefined - **/ - isUndefined(): boolean; - - /********* * - * Utility * - ********** */ - - /** - * Wrapped type `any`. - * @see _.identity - **/ - identity(): any; - - /** - * Wrapped type `any`. - * @see _.constant - **/ - constant(): () => T; - - /** - * Wrapped type `any`. - * @see _.noop - **/ - noop(): void; - - /** - * Wrapped type `number`. - * @see _.times - **/ - times(iterator: (n: number) => TResult, context?: any): TResult[]; - - /** - * Wrapped type `number`. - * @see _.random - **/ - random(): number; - /** - * Wrapped type `number`. - * @see _.random - **/ - random(max: number): number; - - /** - * Wrapped type `object`. - * @see _.mixin - **/ - mixin(): void; - - /** - * Wrapped type `string|Function|Object`. - * @see _.iteratee - **/ - iteratee(context?: any, argCount?: number): Function; - - /** - * Wrapped type `string`. - * @see _.uniqueId - **/ - uniqueId(): string; - - /** - * Wrapped type `string`. - * @see _.escape - **/ - escape(): string; - - /** - * Wrapped type `string`. - * @see _.unescape - **/ - unescape(): string; - - /** - * Wrapped type `object`. - * @see _.result - **/ - result(property: string): any; - - /** - * Wrapped type `string`. - * @see _.template - **/ - template(settings?: _.TemplateSettings): (...data: any[]) => string; - - /********** * - * Chaining * - *********** */ - - /** - * Wrapped type `any`. - * @see _.chain - **/ - chain(): _Chain; - - /** - * Wrapped type `any`. - * Extracts the value of a wrapped object. - * @return Value of the wrapped object. - **/ - value(): TResult; -} - -interface _Chain { - - /* ************* - * Collections * - ************* */ - - /** - * Wrapped type `any[]`. - * @see _.each - **/ - each(iterator: _.ListIterator, context?: any): _Chain; - - /** - * @see _.each - **/ - each(iterator: _.ObjectIterator, context?: any): _Chain; - - /** - * @see _.each - **/ - forEach(iterator: _.ListIterator, context?: any): _Chain; - - /** - * @see _.each - **/ - forEach(iterator: _.ObjectIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.map - **/ - map(iterator: _.ListIterator, context?: any): _ChainOfArrays; - - /** - * Wrapped type `any[]`. - * @see _.map - **/ - map(iterator: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.map - **/ - map(iterator: _.ObjectIterator, context?: any): _ChainOfArrays; - - /** - * Wrapped type `any[]`. - * @see _.map - **/ - map(iterator: _.ObjectIterator, context?: any): _Chain; - - /** - * @see _.map - **/ - collect(iterator: _.ListIterator, context?: any): _Chain; - - /** - * @see _.map - **/ - collect(iterator: _.ObjectIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.reduce - **/ - reduce(iterator: _.MemoIterator, memo?: TResult, context?: any): _ChainSingle; - - /** - * @see _.reduce - **/ - inject(iterator: _.MemoIterator, memo?: TResult, context?: any): _ChainSingle; - - /** - * @see _.reduce - **/ - foldl(iterator: _.MemoIterator, memo?: TResult, context?: any): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.reduceRight - **/ - reduceRight(iterator: _.MemoIterator, memo?: TResult, context?: any): _ChainSingle; - - /** - * @see _.reduceRight - **/ - foldr(iterator: _.MemoIterator, memo?: TResult, context?: any): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.find - **/ - find(iterator: _.ListIterator, context?: any): _ChainSingle; - - /** - * @see _.find - **/ - detect(iterator: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.filter - **/ - filter(iterator: _.ListIterator, context?: any): _Chain; - - /** - * @see _.filter - **/ - select(iterator: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.where - **/ - where(properties: U): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.findWhere - **/ - findWhere(properties: U): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.reject - **/ - reject(iterator: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.all - **/ - all(iterator?: _.ListIterator, context?: any): _Chain; - - /** - * @see _.all - **/ - every(iterator?: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.any - **/ - any(iterator?: _.ListIterator, context?: any): _Chain; - - /** - * @see _.any - **/ - some(iterator?: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.contains - **/ - contains(value: T): _Chain; - - /** - * Alias for 'contains'. - * @see contains - **/ - include(value: T): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.invoke - **/ - invoke(methodName: string, ...arguments: any[]): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.pluck - **/ - pluck(propertyName: string): _Chain; - - /** - * Wrapped type `number[]`. - * @see _.max - **/ - max(): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.max - **/ - max(iterator: _.ListIterator, context?: any): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.max - **/ - max(iterator?: _.ListIterator, context?: any): _ChainSingle; - - /** - * Wrapped type `number[]`. - * @see _.min - **/ - min(): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.min - **/ - min(iterator: _.ListIterator, context?: any): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.min - **/ - min(iterator?: _.ListIterator, context?: any): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.sortBy - **/ - sortBy(iterator?: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.sortBy - **/ - sortBy(iterator: string, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.groupBy - **/ - groupBy(iterator?: _.ListIterator, context?: any): _ChainOfArrays; - - /** - * Wrapped type `any[]`. - * @see _.groupBy - **/ - groupBy(iterator: string, context?: any): _ChainOfArrays; - - /** - * Wrapped type `any[]`. - * @see _.indexBy - **/ - indexBy(iterator: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.indexBy - **/ - indexBy(iterator: string, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.countBy - **/ - countBy(iterator?: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.countBy - **/ - countBy(iterator: string, context?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.shuffle - **/ - shuffle(): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.sample - **/ - sample(n: number): _Chain; - - /** - * @see _.sample - **/ - sample(): _Chain; - - /** - * Wrapped type `any`. - * @see _.toArray - **/ - toArray(): _Chain; - - /** - * Wrapped type `any`. - * @see _.size - **/ - size(): _Chain; - - /********* - * Arrays * - **********/ - - /** - * Wrapped type `any[]`. - * @see _.first - **/ - first(): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.first - **/ - first(n: number): _Chain; - - /** - * @see _.first - **/ - head(): _Chain; - - /** - * @see _.first - **/ - head(n: number): _Chain; - - /** - * @see _.first - **/ - take(): _Chain; - - /** - * @see _.first - **/ - take(n: number): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.initial - **/ - initial(n?: number): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.last - **/ - last(): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.last - **/ - last(n: number): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.rest - **/ - rest(n?: number): _Chain; - - /** - * @see _.rest - **/ - tail(n?: number): _Chain; - - /** - * @see _.rest - **/ - drop(n?: number): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.compact - **/ - compact(): _Chain; - - /** - * Wrapped type `any`. - * @see _.flatten - **/ - flatten(shallow?: boolean): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.without - **/ - without(...values: T[]): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.partition - **/ - partition(iterator: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[][]`. - * @see _.union - **/ - union(...arrays: _.List[]): _Chain; - - /** - * Wrapped type `any[][]`. - * @see _.intersection - **/ - intersection(...arrays: _.List[]): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.difference - **/ - difference(...others: _.List[]): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.uniq - **/ - uniq(isSorted?: boolean, iterator?: _.ListIterator): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.uniq - **/ - uniq(iterator?: _.ListIterator, context?: any): _Chain; - - /** - * @see _.uniq - **/ - unique(isSorted?: boolean, iterator?: _.ListIterator): _Chain; - - /** - * @see _.uniq - **/ - unique(iterator?: _.ListIterator, context?: any): _Chain; - - /** - * Wrapped type `any[][]`. - * @see _.zip - **/ - zip(...arrays: any[][]): _Chain; - - /** - * Wrapped type `any[][]`. - * @see _.object - **/ - object(...keyValuePairs: any[][]): _Chain; - - /** - * @see _.object - **/ - object(values?: any): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.indexOf - **/ - indexOf(value: T, isSorted?: boolean): _ChainSingle; - - /** - * @see _.indexOf - **/ - indexOf(value: T, startFrom: number): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.lastIndexOf - **/ - lastIndexOf(value: T, from?: number): _ChainSingle; - - /** - * Wrapped type `any[]`. - * @see _.sortedIndex - **/ - sortedIndex(value: T, iterator?: (x: T) => any, context?: any): _Chain; - - /** - * Wrapped type `number`. - * @see _.range - **/ - range(stop: number, step?: number): _Chain; - - /** - * Wrapped type `number`. - * @see _.range - **/ - range(): _Chain; - - /* *********** - * Functions * - ************ */ - - /** - * Wrapped type `Function`. - * @see _.bind - **/ - bind(object: any, ...arguments: any[]): _Chain; - - /** - * Wrapped type `object`. - * @see _.bindAll - **/ - bindAll(...methodNames: string[]): _Chain; - - /** - * Wrapped type `Function`. - * @see _.partial - **/ - partial(...arguments: any[]): _Chain; - - /** - * Wrapped type `Function`. - * @see _.memoize - **/ - memoize(hashFn?: (n: any) => string): _Chain; - - /** - * Wrapped type `Function`. - * @see _.defer - **/ - defer(...arguments: any[]): _Chain; - - /** - * Wrapped type `Function`. - * @see _.delay - **/ - delay(wait: number, ...arguments: any[]): _Chain; - - /** - * @see _.delay - **/ - delay(...arguments: any[]): _Chain; - - /** - * Wrapped type `Function`. - * @see _.throttle - **/ - throttle(wait: number, options?: _.ThrottleSettings): _Chain; - - /** - * Wrapped type `Function`. - * @see _.debounce - **/ - debounce(wait: number, immediate?: boolean): _Chain; - - /** - * Wrapped type `Function`. - * @see _.once - **/ - once(): _Chain; - - /** - * Wrapped type `number`. - * @see _.after - **/ - after(func: Function): _Chain; - - /** - * Wrapped type `number`. - * @see _.before - **/ - before(fn: Function): _Chain; - - /** - * Wrapped type `Function`. - * @see _.wrap - **/ - wrap(wrapper: Function): () => _Chain; - - /** - * Wrapped type `Function`. - * @see _.negate - **/ - negate(): _Chain; - - /** - * Wrapped type `Function[]`. - * @see _.compose - **/ - compose(...functions: Function[]): _Chain; - - /********* * - * Objects * - ********** */ - - /** - * Wrapped type `object`. - * @see _.keys - **/ - keys(): _Chain; - - /** - * Wrapped type `object`. - * @see _.values - **/ - values(): _Chain; - - /** - * Wrapped type `object`. - * @see _.pairs - **/ - pairs(): _Chain; - - /** - * Wrapped type `object`. - * @see _.invert - **/ - invert(): _Chain; - - /** - * Wrapped type `object`. - * @see _.functions - **/ - functions(): _Chain; - - /** - * @see _.functions - **/ - methods(): _Chain; - - /** - * Wrapped type `object`. - * @see _.extend - **/ - extend(...sources: any[]): _Chain; - - /** - * Wrapped type `object`. - * @see _.pick - **/ - pick(...keys: any[]): _Chain; - pick(keys: any[]): _Chain; - pick(fn: (value: any, key: any, object: any) => any): _Chain; - - /** - * Wrapped type `object`. - * @see _.omit - **/ - omit(...keys: string[]): _Chain; - omit(keys: string[]): _Chain; - omit(iteratee: Function): _Chain; - - /** - * Wrapped type `object`. - * @see _.defaults - **/ - defaults(...defaults: any[]): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.clone - **/ - clone(): _Chain; - - /** - * Wrapped type `object`. - * @see _.tap - **/ - tap(interceptor: (...as: any[]) => any): _Chain; - - /** - * Wrapped type `object`. - * @see _.has - **/ - has(key: string): _Chain; - - /** - * Wrapped type `any[]`. - * @see _.matches - **/ - matches(): _Chain; - - /** - * Wrapped type `string`. - * @see _.property - **/ - property(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isEqual - **/ - isEqual(other: any): _Chain; - - /** - * Wrapped type `object`. - * @see _.isEmpty - **/ - isEmpty(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isElement - **/ - isElement(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isArray - **/ - isArray(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isObject - **/ - isObject(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isArguments - **/ - isArguments(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isFunction - **/ - isFunction(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isString - **/ - isString(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isNumber - **/ - isNumber(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isFinite - **/ - isFinite(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isBoolean - **/ - isBoolean(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isDate - **/ - isDate(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isRegExp - **/ - isRegExp(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isNaN - **/ - isNaN(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isNull - **/ - isNull(): _Chain; - - /** - * Wrapped type `object`. - * @see _.isUndefined - **/ - isUndefined(): _Chain; - - /********* * - * Utility * - ********** */ - - /** - * Wrapped type `any`. - * @see _.identity - **/ - identity(): _Chain; - - /** - * Wrapped type `any`. - * @see _.constant - **/ - constant(): _Chain; - - /** - * Wrapped type `any`. - * @see _.noop - **/ - noop(): _Chain; - - /** - * Wrapped type `number`. - * @see _.times - **/ - times(iterator: (n: number) => TResult, context?: any): _Chain; - - /** - * Wrapped type `number`. - * @see _.random - **/ - random(): _Chain; - /** - * Wrapped type `number`. - * @see _.random - **/ - random(max: number): _Chain; - - /** - * Wrapped type `object`. - * @see _.mixin - **/ - mixin(): _Chain; - - /** - * Wrapped type `string|Function|Object`. - * @see _.iteratee - **/ - iteratee(context?: any, argCount?: number): _Chain; - - /** - * Wrapped type `string`. - * @see _.uniqueId - **/ - uniqueId(): _Chain; - - /** - * Wrapped type `string`. - * @see _.escape - **/ - escape(): _Chain; - - /** - * Wrapped type `string`. - * @see _.unescape - **/ - unescape(): _Chain; - - /** - * Wrapped type `object`. - * @see _.result - **/ - result(property: string): _Chain; - - /** - * Wrapped type `string`. - * @see _.template - **/ - template(settings?: _.TemplateSettings): (...data: any[]) => _Chain; - - /************* * - * Array proxy * - ************** */ - - /** - * Returns a new array comprised of the array on which it is called - * joined with the array(s) and/or value(s) provided as arguments. - * @param arr Arrays and/or values to concatenate into a new array. See the discussion below for details. - * @return A new array comprised of the array on which it is called - **/ - concat(...arr: Array): _Chain; - - /** - * Join all elements of an array into a string. - * @param separator Optional. Specifies a string to separate each element of the array. The separator is converted to a string if necessary. If omitted, the array elements are separated with a comma. - * @return The string conversions of all array elements joined into one string. - **/ - join(separator?: any): _ChainSingle; - - /** - * Removes the last element from an array and returns that element. - * @return Returns the popped element. - **/ - pop(): _ChainSingle; - - /** - * Adds one or more elements to the end of an array and returns the new length of the array. - * @param item The elements to add to the end of the array. - * @return The array with the element added to the end. - **/ - push(...item: Array): _Chain; - - /** - * Reverses an array in place. The first array element becomes the last and the last becomes the first. - * @return The reversed array. - **/ - reverse(): _Chain; - - /** - * Removes the first element from an array and returns that element. This method changes the length of the array. - * @return The shifted element. - **/ - shift(): _ChainSingle; - - /** - * Returns a shallow copy of a portion of an array into a new array object. - * @param start Zero-based index at which to begin extraction. - * @param end Optional. Zero-based index at which to end extraction. slice extracts up to but not including end. - * @return A shallow copy of a portion of an array into a new array object. - **/ - slice(start: number, end?: number): _Chain; - - /** - * Sorts the elements of an array in place and returns the array. The sort is not necessarily stable. The default sort order is according to string Unicode code points. - * @param compareFn Optional. Specifies a function that defines the sort order. If omitted, the array is sorted according to each character's Unicode code point value, according to the string conversion of each element. - * @return The sorted array. - **/ - sort(compareFn: (a: T, b: T) => boolean): _Chain; - - /** - * Changes the content of an array by removing existing elements and/or adding new elements. - * @param index Index at which to start changing the array. If greater than the length of the array, actual starting index will be set to the length of the array. If negative, will begin that many elements from the end. - * @param quantity An integer indicating the number of old array elements to remove. If deleteCount is 0, no elements are removed. In this case, you should specify at least one new element. If deleteCount is greater than the number of elements left in the array starting at index, then all of the elements through the end of the array will be deleted. - * @param items The element to add to the array. If you don't specify any elements, splice will only remove elements from the array. - * @return An array containing the deleted elements. If only one element is removed, an array of one element is returned. If no elements are removed, an empty array is returned. - **/ - splice(index: number, quantity: number, ...items: Array): _Chain; - - /** - * A string representing the specified array and its elements. - * @return A string representing the specified array and its elements. - **/ - toString(): _ChainSingle; - - /** - * Adds one or more elements to the beginning of an array and returns the new length of the array. - * @param items The elements to add to the front of the array. - * @return The array with the element added to the beginning. - **/ - unshift(...items: Array): _Chain; - - /********** * - * Chaining * - *********** */ - - /** - * Wrapped type `any`. - * @see _.chain - **/ - chain(): _Chain; - - /** - * Wrapped type `any`. - * @see _.value - **/ - value(): T[]; -} -interface _ChainSingle { - value(): T; -} -interface _ChainOfArrays extends _Chain { - flatten(): _Chain; -} - -declare var _: UnderscoreStatic; - -declare module "underscore" { - export = _; -}