pax_global_header00006660000000000000000000000064132255105330014511gustar00rootroot0000000000000052 comment=235561e411c58ecbd4d96844fae28e998f0ccbda tslint-5.9.1/000077500000000000000000000000001322551053300130425ustar00rootroot00000000000000tslint-5.9.1/.circleci/000077500000000000000000000000001322551053300146755ustar00rootroot00000000000000tslint-5.9.1/.circleci/config.yml000066400000000000000000000041541322551053300166710ustar00rootroot00000000000000version: 2 jobs: build: docker: - image: circleci/node:latest steps: - checkout - restore_cache: key: dependency-cache-{{ checksum "yarn.lock" }} - run: name: Install dependencies command: yarn - save_cache: key: dependency-cache-{{ checksum "yarn.lock" }} paths: - node_modules - run: yarn compile - persist_to_workspace: root: '.' paths: - lib - build - yarn.lock lint: docker: - image: circleci/node:latest steps: - checkout - attach_workspace: at: '.' - restore_cache: key: dependency-cache-{{ checksum "yarn.lock" }} - run: yarn lint test: docker: - image: circleci/node:8 steps: - checkout - attach_workspace: at: '.' - restore_cache: key: dependency-cache-{{ checksum "yarn.lock" }} - run: yarn test test2.1: docker: - image: circleci/node:4 steps: - checkout - attach_workspace: at: '.' - restore_cache: key: dependency-cache-{{ checksum "yarn.lock" }} - run: yarn add typescript@2.1 - run: yarn test test2.4: docker: - image: circleci/node:6 steps: - checkout - attach_workspace: at: '.' - restore_cache: key: dependency-cache-{{ checksum "yarn.lock" }} - run: yarn add typescript@2.4 - run: yarn test testNext: docker: - image: circleci/node:latest steps: - checkout - attach_workspace: at: '.' - restore_cache: key: dependency-cache-{{ checksum "yarn.lock" }} - run: yarn add typescript@next - run: yarn test workflows: version: 2 build_lint_test: jobs: - build - lint: requires: - build - test: requires: - build - test2.1: requires: - build - test2.4: requires: - build - testNext: requires: - build tslint-5.9.1/.editorconfig000066400000000000000000000002621322551053300155170ustar00rootroot00000000000000root = true [*] indent_style = space indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [tslint.json] indent_size = 2 tslint-5.9.1/.gitattributes000066400000000000000000000007121322551053300157350ustar00rootroot00000000000000# lint files can't get an extra \r character before \n, otherwise # they'll make some rule tests fail on windows, due to the lint error # being reported to be 1 character longer *.lint text eol=lf *.fix text eol=lf /test/rules/linebreak-style/**/CRLF/*.lint text eol=crlf /test/rules/linebreak-style/**/LF/*.fix text eol=crlf /test/rules/jsdoc-format/**/jsdoc-windows.ts.lint text eol=crlf /test/rules/object-literal-sort-keys/default/crlf.ts.lint eol=crlf tslint-5.9.1/.github/000077500000000000000000000000001322551053300144025ustar00rootroot00000000000000tslint-5.9.1/.github/ISSUE_TEMPLATE.md000066400000000000000000000005111322551053300171040ustar00rootroot00000000000000### Bug Report - __TSLint version__: - __TypeScript version__: - __Running TSLint via__: (pick one) CLI / Node.js API / VSCode / grunt-tslint / Atom / Visual Studio / etc #### TypeScript code being linted ```ts // code snippet ``` with `tslint.json` configuration: ```json ``` #### Actual behavior #### Expected behavior tslint-5.9.1/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000007331322551053300202060ustar00rootroot00000000000000#### PR checklist - [ ] Addresses an existing issue: #0000 - [ ] New feature, bugfix, or enhancement - [ ] Includes tests - [ ] Documentation update #### Overview of change: #### Is there anything you'd like reviewers to focus on? #### CHANGELOG.md entry: tslint-5.9.1/.gitignore000066400000000000000000000006551322551053300150400ustar00rootroot00000000000000.DS_Store .sass-cache .tscache/ /build/ /docs/site/ /scripts/*.js /scripts/*.js.map /lib/ /test/executable/tslint.json node_modules/ !test/rules/**/node_modules tscommand*.txt npm-debug.log package-lock.json # created by grunt-ts for faster compiling typings/.basedir.ts # vim swap files *.swo *.swp docs/_data/rules.json docs/_data/formatters.json docs/rules/*/index.html docs/formatters/*/index.html /coverage/ /.nyc_output tslint-5.9.1/.npmignore000066400000000000000000000004271322551053300150440ustar00rootroot00000000000000.DS_Store .github .gitmodules .gitattributes .eslintrc.json .npmrc .project .settings .travis.yml .tscache .tslintrc .vscode .nycrc .editorconfig .circleci appveyor.yml circle.yml tslint.json yarn.lock /build/ /docs/ /scripts/ /src/ /test/ tscommand*.txt /coverage/ /.nyc_output tslint-5.9.1/.nycrc000066400000000000000000000003571322551053300141660ustar00rootroot00000000000000{ "include": [ "build/**/*.js" ], "extension": [ ".js" ], "exclude": [ "build/test" ], "reporter": [ "text-summary", "html" ], "sourceMap": true, "all": true }tslint-5.9.1/.vscode/000077500000000000000000000000001322551053300144035ustar00rootroot00000000000000tslint-5.9.1/.vscode/launch.json000066400000000000000000000055001322551053300165500ustar00rootroot00000000000000{ "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", "outputCapture": "std", "sourceMaps": true, "outFiles": ["${workspaceRoot}/build/**/*.js"] }, { "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"], "cwd": "${workspaceRoot}", "preLaunchTask": "tsc", "runtimeExecutable": null, "runtimeArgs": [ "--nolazy" ], "env": { "NODE_ENV": "development" }, "console": "internalConsole", "outputCapture": "std", "sourceMaps": true, "outFiles": ["${workspaceRoot}/build/**/*.js"] }, { "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", "outputCapture": "std", "sourceMaps": true, "outFiles": ["${workspaceRoot}/build/**/*.js"] }, { "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", "outputCapture": "std", "sourceMaps": true, "outFiles": ["${workspaceRoot}/build/**/*/js"] } ] } tslint-5.9.1/.vscode/settings.json000066400000000000000000000016521322551053300171420ustar00rootroot00000000000000{ // Controls the rendering size of tabs in characters. If set to auto, the value will be guessed based on the opened file. "editor.tabSize": 4, // Controls if the editor will insert spaces for tabs. If set to auto, the value will be guessed based on the opened file. "editor.insertSpaces": true, // Controls after how many characters the editor will wrap to the next line. "editor.wordWrap": "wordWrapColumn", "editor.wordWrapColumn": 140, "editor.wrappingIndent": "none", // The folders to exclude when doing a full text search in the workspace. "search.exclude": { ".git": true, ".tscache": true, "bower_components": true, "bin": true, "build": true, "lib": true, "node_modules": true }, // Always use project's provided typescript compiler version "typescript.tsdk": "node_modules/typescript/lib", "files.eol": "\n" } tslint-5.9.1/.vscode/tasks.json000066400000000000000000000004711322551053300164250ustar00rootroot00000000000000{ // 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" }tslint-5.9.1/CHANGELOG.md000066400000000000000000002720131322551053300146600ustar00rootroot00000000000000Change Log === v5.9.1 --- ## :hammer_and_wrench: Bugfixes - [bugfix] Removed extraneous deprecation warning produced when using `tslint:recommended` or `tslint:latest` by disabling `typeof-compare` in these rulesets. (#3639) - [bugfix] Resolve directories as absolute paths when validating custom `rulesDirectory` paths, which fixes usage with tslint-loader. (#3640) v5.9.0 --- ## :warning: Deprecations - [deprecation] Several utility functions from `src/language/utils.ts` have been deprecated (#3476) - [deprecation] Linting non-existent files now outputs a warning. This will be an error in TSLint 6. (#3313) ## Configuration inheritance changes Significant changes have been made to configuration inheritance to address a long-standing UX issue around `defualtSeverity`: #2569. `defaultSeverity` defined in a `tslint.json` file will now override the `defaultSeverity` value defined in any configurations you are extending. This means that any rules specified in the base configurations can now take on a new `defaultSeverity` if you so choose. If you extend multiple configuration files, the `defaultSeverity` defined in the last one wins. In practice, this allows users to, for example, more easily use the built-in TSLint configurations (`tslint:recommended`, `tslint:latest`, `tslint:all`) and treat all errors as warnings instead of errors. For more details, see the relevant PRs: - Override `defaultSeverity` defined in extended configs (#3449) - Inherit defaultSeverity and apply it to preceding base configs (#3530) ## :tada: Features - [feature] Support yaml configuration files (#1598) (#3433) - [new-fixer] [`file-header`](https://palantir.github.io/tslint/rules/file-header/) (#3475) - [new-rule] [`no-dynamic-delete`](https://palantir.github.io/tslint/rules/no-dynamic-delete/) (#3573) - [new-rule] [`prefer-readonly`](https://palantir.github.io/tslint/rules/prefer-readonly/) (#2896) - [new-rule] [`newline-per-chained-call`](https://palantir.github.io/tslint/rules/newline-per-chained-call/) (#3278) - [new-rule-option] `"temporalDeadZone"` for [`no-shadowed-variable`](https://palantir.github.io/tslint/rules/no-shadowed-variable/) to ignore shadowing in the temporal dead zone of classes, parameters, enums and variables declared with `let` or `const` (#3389) - [new-rule-option] `"shorthand-first"` for [`object-literal-sort-key`](https://palantir.github.io/tslint/rules/object-literal-sort-key) (#3607) - [new-rule-option] Add support for an ignore pattern for [`max-line-length`](https://palantir.github.io/tslint/rules/max-line-length/) (#3099) ## :hammer_and_wrench: Bugfixes & enhancements - [bugfix] Update commander.js dependency to prevent users from transitively installing a buggy 2.12.0 release (#3510) - [bugfix] `--project` excludes all files of external dependencies (#3320) - [bugfix] Show errors when `tsconfig.json` is invalid (#3410) - [bugfix] [`no-implicit-dependencies`](https://palantir.github.io/tslint/rules/no-implicit-dependencies/) don't crash on malformed package.json (#3373) - [bugfix] [`strict-type-predicates`](https://palantir.github.io/tslint/rules/strict-type-predicates/) allows comparing typeof result with non-literals (#3542) - [bugfix] [`no-redundant-jsdoc`](https://palantir.github.io/tslint/rules/no-redundant-jsdoc/) fixed crash on unhandled tag (#3414) - [bugfix] [`object-literal-sort-keys`](https://palantir.github.io/tslint/rules/object-literal-sort-keys/) fixed regression that effectively disabled the rule with `\r\n` line breaks (#3427) - [bugfix] [`curly`](https://palantir.github.io/tslint/rules/curly/) fixer now correctly handles comments (#3473) - [bugfix] [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/) fixed false-positive with namespaced types (#3487) - [bugfix] Removed potentailly dangerous fixer for [`no-any`](https://palantir.github.io/tslint/rules/no-any/) (#3486) - [bugfix] [`no-unnecessary-type-assertion`](https://palantir.github.io/tslint/rules/no-unnecessary-type-assertion/) fixed false negatives for types with numeric keys (#3468) - [bugfix] [`callable-types`](https://palantir.github.io/tslint/rules/callable-types/) adds parentheses when fixing a type literal inside an array type (#3440) - [bugfix] [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/) allows spreading an `any` value into an object (#3439) - [bugfix] no unnecessary whitespace before argument in callback functions fixed with [`arrow-parens`](https://palantir.github.io/tslint/rules/arrow-parens) fixer (#3618) - [bugfix] [`prefer-const`](https://palantir.github.io/tslint/rules/prefer-const/) false negative with index signature named like a variable (#3385) - [bugfix] [`whitespace`](https://palantir.github.io/tslint/rules/whitespace) rule checks property declarations if `"check-decl"` is enabled (#3546) - [bugfix] Using ternary operator for calling super() now passes [`no-duplicate-super`](https://palantir.github.io/tslint/rules/no-duplicate-super) rule. (#3544) - [bugfix] [`no-shadowed-variable`](https://palantir.github.io/tslint/rules/no-shadowed-variable/) now excludes declaration files and ambient modules (#3387) - [bugfix] [`no-duplicate-imports`](https://palantir.github.io/tslint/rules/no-duplicate-imports) Allow duplicate imports from separate ambient module declarations (#3398) - [bugfix] [`await-promise`](https://palantir.github.io/tslint/rules/await-promise/) correctly recognises classes extending Promise (#3383) - [bugfix] [`prefer-conditional-expression`](https://palantir.github.io/tslint/rules/prefer-conditional-expression/): don't repeat error on nested if statements (#3528) - [bugfix] [`completed-docs`](https://palantir.github.io/tslint/rules/completed-docs/): don't require documentation on methods in object literals (#3532) - [bugfix] [`one-line`](https://palantir.github.io/tslint/rules/one-line/) fixed crash on syntax error in class or interface (#3538) - [bugfix] [`no-redundant-jsdoc`](https://palantir.github.io/tslint/rules/no-redundant-jsdoc/) allow `@template` tag if it has a description (#3415) - [bugfix] Fix condition for deprecation of [`typeof-compare`](https://palantir.github.io/tslint/rules/typeof-compare) (#3429) - [enhancement] Better error message for files not contained in the project (#3313) - [enhancement] `"properties"` option for [`completed-docs`](https://palantir.github.io/tslint/rules/completed-docs/) rule now checks getter and setter accessors. (#3497) - [enhancement]: [`no-magic-numbers`](https://palantir.github.io/tslint/rules/no-magic-numbers) ignores parseInt radix parameter (#3536) - [enhancement] Avoid duplicate I/O when using `--project` option (#3313) - [enhancement] clicking the filename in `stylish`-formatter's output jumps to the first failure in that file. (#3491) - [enhancement] [`ban-comma-operator`](https://palantir.github.io/tslint/rules/ban-comma-operator/) ignores comma operator inside for-loop incrementor (#3485) - [enhancement] [`space-within-parens`](https://palantir.github.io/tslint/rules/space-within-parens/) updated to always allow empty parentheses `()`. (#3513) - [enhancement] Better error message syntax for [`completed-docs`](https://palantir.github.io/tslint/rules/completed-docs/) modifier lists (#3379) - [enhancement] Improve failure message & docs for [`ban-comma-operator`](https://palantir.github.io/tslint/rules/ban-comma-operator/) (#3384) - [enhancement] Output code warnings in yellow instead of red for codeFrame formatter (#3402) - [enhancement] Converted [`completed-docs`](https://palantir.github.io/tslint/rules/completed-docs) rule to use a function instead of a walker (#3466) - [docs] [`ban-comma-operator`](https://palantir.github.io/tslint/rules/ban-comma-operator/): fix metadata, list as "functionality" rule (#3612) - [docs] Enhance [`no-use-before-declare`](https://palantir.github.io/tslint/rules/no-use-before-declare/) documentation to clarify the rule's status (#3520) - [docs] Enhance [`await-promise`](https://palantir.github.io/tslint/rules/await-promise/) options documentation (#3519) - [docs] Add `hasFix` metadata for the [`indent`](https://palantir.github.io/tslint/rules/indent) rule (#3529) - [docs] Clearer rule description for [`no-irregular-whitespace`](https://palantir.github.io/tslint/rules/no-irregular-whitespace) (#3627) Thanks to our contributors! - Klaus Meinhardt - Josh Goldberg - Chris Barr - Nathan Shively-Sanders - Jeremy Morton - Sergey Koshechkin - Daniel Kucal - Eric Smekens - Johannes Choo - Elena Vilchik - Eugene Timokhov - Carlo Bottiglieri - reduckted - Glavin Wiechert - jbsingh - Mateusz Witkowski - HideDev - Bruno Lemos - aervin_ - Roman - Ryan Waskiewicz v5.8.0 --- ## :warning: Deprecations - [deprecation] [`typeof-compare`](https://palantir.github.io/tslint/rules/typeof-compare/) is deprecated because typescript already does that check (#3286) - [deprecation] CLI argument `--type-check` is no longer necessary and will be removed in the next major version (#3322) ## Updates to `tslint:latest` configuration ```diff + "ban-comma-operator": true, + "jsdoc-format": { + options: "check-multiline-start", + }, + "no-duplicate-switch-case": true, + "no-implicit-dependencies": true, + "no-return-await": true, ``` ## :tada: Features - [feature] Added `linterOptions` configuration field to `tslint.json`, which supports a list of `exclude` globs to disable linting for a subset of files (#2409) - [new-rule] [`no-return-await`](https://palantir.github.io/tslint/rules/no-return-await/) (#3233) - [new-rule] [`no-redundant-jsdoc`](https://palantir.github.io/tslint/rules/no-redundant-jsdoc/) (#2754) - [new-rule] [`no-duplicate-switch-case`](https://palantir.github.io/tslint/rules/no-duplicate-switch-case/) (#2937) - [new-rule] [`no-implicit-dependencies`](https://palantir.github.io/tslint/rules/no-implicit-dependencies/) (#3343) - [new-rule] [`no-unnecessary-class`](https://palantir.github.io/tslint/rules/no-unnecessary-class/) (#3119) - [new-rule] [`ban-comma-operator`](https://palantir.github.io/tslint/rules/ban-comma-operator/) (#3250) - [new-fixer] [`one-line`](https://palantir.github.io/tslint/rules/one-line/) (#3200) - [new-fixer] [`curly`](https://palantir.github.io/tslint/rules/curly/) (#3262) - [new-rule-option] [`jsdoc-format`](https://palantir.github.io/tslint/rules/jsdoc-format/) adds option `"check-multiline-start"` to enforce the first line of a multiline JSDoc comment to be empty. (#3181) - [new-rule-option] [`trailing-comma`](https://palantir.github.io/tslint/rules/trailing-comma/) adds option `"esSpecCompliant"` to make it compatible with the ES spec regarding trailing commas after object/array rest and rest parameters. (#3176) - [new-rule-option] `"check-parameter-property"` option for [`member-access`](https://palantir.github.io/tslint/rules/member-access/) rule (#3325) - [new-rule-option] `"strict-bound-class-methods"` option for [`semicolon`](https://palantir.github.io/tslint/rules/semicolon/) rule (#3294) - [new-rule-option] `"grouped-imports"` option for [`ordered-imports`](https://palantir.github.io/tslint/rules/ordered-imports/) rule (#3138) - [new-rule-option] `"ignore-blank-lines"` option for [`no-trailing-whitespace`](https://palantir.github.io/tslint/rules/no-trailing-whitespace/) rule (#3346) - [new-rule-option] `"never"` option for [`object-literal-shorthand`](https://palantir.github.io/tslint/rules/object-literal-shorthand/) disallows shorthand notation (#3268) - [new-rule-option] `"exclude-class-expressions"` option for [`max-classes-per-file`](https://palantir.github.io/tslint/rules/max-classes-per-file/) rule (#3281) - [new-rule-option] [`no-unnecessary-type-assertion`](https://palantir.github.io/tslint/rules/no-unnecessary-type-assertion/) supports a whitelist of types to ignore (#3257) - [new-rule-option] `"module-source-path"` for [`ordered-imports`](https://palantir.github.io/tslint/rules/ordered-imports/) allows sorting imports by trailing end of path (#3178) - [new-formatter] JUnit (#3194) ## :hammer_and_wrench: Bugfixes & enhancements - [bugfix] [`no-empty-interface`](https://palantir.github.io/tslint/rules/no-empty-interface/) allows providing type arguments for extended type (#3260) - [bugfix] Fixed line switches to not disable failures in the next line following the disabled line (#3177) - [bugfix] [`return-undefined`](https://palantir.github.io/tslint/rules/return-undefined/) handles union return types in async functions (#3298) - [bugfix] [`deprecation`](https://palantir.github.io/tslint/rules/deprecation/) checks correct constructor overload (#3203) - [bugfix] [`return-undefined`](https://palantir.github.io/tslint/rules/return-undefined/) declared return type takes precedence over contextual type (#3298) - [bugfix] Correctly mark `inputFilePath` as an optional parameter in `Configuration.findConfiguration()` (#3195) - [bugfix] [`return-undefined`](https://palantir.github.io/tslint/rules/return-undefined/) fixed regressions: once again allows anything if return type is `any` (#3298) - [bugfix] [`only-arrow-functions`](https://palantir.github.io/tslint/rules/only-arrow-functions/) allow function if `this` is used in parameter initializer (#3315) - [bugfix] [`no-conditional-assignment`](https://palantir.github.io/tslint/rules/no-conditional-assignment/): exclude intentional assignments, e.g. inside functions (#2629) - [bugfix] [`no-angle-bracket-type-assertion`](https://palantir.github.io/tslint/rules/no-angle-bracket-type-assertion/) fixer adds parentheses when necessary (#3301) - [bugfix] [`no-angle-bracket-type-assertion`](https://palantir.github.io/tslint/rules/no-angle-bracket-type-assertion/) fixed order when autofixing consecutive assertions (#3301) - [bugfix] `vso` formatter no longer duplicates output for fixed failures (#3348) - [bugfix] [`no-unbound-method`](https://palantir.github.io/tslint/rules/no-unbound-method/): Allow negation of method (#3349) - [bugfix] [`arrow-parens`](https://palantir.github.io/tslint/rules/arrow-parens/) with option `"ban-single-arg-parens"` no longer produces invalid code when fixed (#3247) - [bugfix] Fixed regression where the lookup of `tslint.json` stopped at the current directory. (#3309) - [bugfix] `--test` works correctly with any `compilerOptions.target` (#3296) - [bugfix] `whitepace` handles files with BOM and other irregular whitespace (#3305) - [bugfix] [`callable-types`](https://palantir.github.io/tslint/rules/callable-types/) auto fix produces invalid results (#3342) - [bugfix] [`no-string-literal`](https://palantir.github.io/tslint/rules/no-string-literal/) correctly fix property names with leading underscores (#3184) - [bugfix] [`variable-name`](https://palantir.github.io/tslint/rules/variable-name/) fixed crash on empty variable name (#3292) - [bugfix] [`trailing-comma`](https://palantir.github.io/tslint/rules/trailing-comma/) fixed crash on arrow function without parens (#3246) - [bugfix] Fix [`space-before-function-paren`](https://palantir.github.io/tslint/rules/space-before-function-paren/) for anonymous/arrow generic functions (#3085) - [bugfix] Removed warning printed to console when using the [`no-unused-variable`](https://palantir.github.io/tslint/rules/no-unused-variable/) along with the `noUnusedLocals` and `noUnusedParameters` compiler options (#3227) - [bugfix] [`no-invalid-this`](https://palantir.github.io/tslint/rules/no-invalid-this/) ignores functions with a `this` param (#3267) - [enhancement] Sort failures by line and character for formatters (#3345) - [enhancement] [`import-blacklist`](https://palantir.github.io/tslint/rules/import-blacklist/) also checks exports and dynamic imports (#3258) - [enhancement] [`no-conditional-assignment`](https://palantir.github.io/tslint/rules/no-conditional-assignment/) added check for conditional (ternary) expressions (#2629) - [enhancement] Allow [`completed-docs`](https://palantir.github.io/tslint/rules/completed-docs/) to list doc tags that mark a node as not requiring a documentation body. Tags can also provide a regexp matcher to validate that their contents are docs-valid. (#2415) - [enhancement] [`await-promise`](https://palantir.github.io/tslint/rules/await-promise/) enforces that `for-await-of` is only used with `AsyncIterable` (#3297) - [enhancement] [`one-line`](https://palantir.github.io/tslint/rules/one-line/) checks type alias declarations (#3200) - [enhancement] [`deprecation`](https://palantir.github.io/tslint/rules/deprecation/) checks object destructuring (#3318) - [enhancement] [`no-submodule-imports`](https://palantir.github.io/tslint/rules/no-submodule-imports/) also checks exports (#3258) - [enhancement] [`restrict-plus-operands`](https://palantir.github.io/tslint/rules/restrict-plus-operands/): More specific error message when arguments include strings (#3220) - [enhancement] [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/) checks more expressions, for example destructuring, `yield`, property initializer (#3196) - [enhancement] [`object-literal-sort-keys`](https://palantir.github.io/tslint/rules/object-literal-sort-keys/): allow grouping of object properties via additional blank lines when using alphabetical ordering. (#3191) - [enhancement] Migrated CLI from using `colors` module to `chalk` module (#3171) - [enhancement] [`no-unused-variable`](https://palantir.github.io/tslint/rules/no-unused-variable/) applies the ignorePattern to imports (#3187) Thanks to our contributors! - Klaus Meinhardt - Charles Samborski - Donald Pipowitch - Josh Goldberg - mmkal - Erik - Csaba Miklos - Dominik Moritz - Khalid Saifullah - Lukas Spieß - Merott Movahedi - Bowen Ni - ksvitkovsky - Hutson Betts - Caleb Eggensperger - Brent Erickson - Trivikram - Brandon Furtwangler - Pavel Zet - aervin_ - Holger Jeromin - Danny Guo - Jeremy Morton - Cyril Gandon - Andy Hanson - yadan v5.7.0 --- ## :tada: New rules, options, and fixers - [new-rule] [`no-parameter-reassignment`](https://palantir.github.io/tslint/rules/no-parameter-reassignment/) (#3045) - [new-rule-option]: [`object-literal-sort-keys`](https://palantir.github.io/tslint/rules/object-literal-sort-keys/): Add `match-declaration-order` option (#2829) - [new-rule-option] `check-type-operator` for [`whitespace`](https://palantir.github.io/tslint/rules/whitespace/) rule (#3083) - [new-rule-option] [`whitespace`](https://palantir.github.io/tslint/rules/whitespace/): Add `check-rest-spread` option (#3089) ## :hammer_and_wrench: Bugfixes & enhancements - [api] `AbstractRule#applyWithFunction` allows additional parameter that is passed through to `walkFn` (#3140) - [api] `AbstractRule#applyWithFunction` has better type checking for its type parameter (#2660) - [bugfix] [`member-access`](https://palantir.github.io/tslint/rules/member-access/) autofix now correcly inserts `public` keyword after decorators (#3162) - [bugfix] [`prefer-const`](https://palantir.github.io/tslint/rules/prefer-const/) correctly handle `catch` without binding parameter introduced in `typescript@2.5.1` (#3151) - [bugfix] [`no-invalid-template-strings`](https://palantir.github.io/tslint/rules/no-invalid-template-strings/) allows backslash-prefixed template expressions (#3116) - [bugfix] [`deprecation`](https://palantir.github.io/tslint/rules/deprecation/) no longer shows errors on imports and exports (#3141) - [bugfix] [`deprecation`](https://palantir.github.io/tslint/rules/deprecation/): fix false positive when calling a function or method where another overload is deprecated (#2883) - [bugfix] [`whitespace`](https://palantir.github.io/tslint/rules/whitespace/): fixed `"check-separator"` for trivial `for` cases. (#3132) - [bugfix] [`prefer-object-spread`](https://palantir.github.io/tslint/rules/prefer-object-spread/) prevent spreading `this` as it is not allowed by the compiler (#3126) - [bugfix] `msbuild` formatter uses backslashes in paths on Windows (#3145) - [bugfix] [`no-namespace`](https://palantir.github.io/tslint/rules/no-namespace/) ignores global augmentation (#3161) - [enhancement] remove superfluous empty lines on tslint output. (#3121) - [enhancement] [`no-submodule-imports`](https://palantir.github.io/tslint/rules/no-submodule-imports/) allows whitelisting of submodules like `@angular/core/testing` (#3129) - [enhancement] custom lint rules will be resolved using node's path resolution to allow for loaders like `ts-node` (#3108) - [enhancement] [`quotemark`](https://palantir.github.io/tslint/rules/quotemark/) no longer requires `"single"` or `"double"` to be the first option. The rule defaults to `"double"` if none is specified. (#3114) - [enhancement] [`no-unused-variable`](https://palantir.github.io/tslint/rules/no-unused-variable/) autofix removes trailing comments of imports (#3156) - [enhancement] [`no-unnecessary-type-assertion`](https://palantir.github.io/tslint/rules/no-unnecessary-type-assertion/) allows certain necessary assertions to prevent type widening (#3120) Thanks to our contributors! - Paul Gschwendtner - Andy Hanson - ksvitkovsky - Santi Albo - aervin - Junle Li - Joscha Feth - WiseBird - Caleb Eggensperger - WGroenestein - Bowen Ni v5.6.0 --- ## :tada: New rules, options, and fixers - [new-rule] [`no-duplicate-imports`](https://palantir.github.io/tslint/rules/no-duplicate-imports/) (#3075) - [new-rule] [`no-submodule-imports`](https://palantir.github.io/tslint/rules/no-submodule-imports/) (#3091) - [new-rule] [`space-within-parens`](https://palantir.github.io/tslint/rules/space-within-parens/) (#2959) - [new-fixer] [`member-access`](https://palantir.github.io/tslint/rules/member-access/) (#2969) - [new-fixer] [`no-null-keyword`](https://palantir.github.io/tslint/rules/no-null-keyword/): fix `x == null` to `x == undefined` (#2802) - [new-rule-option] [`no-shadowed-variable`](https://palantir.github.io/tslint/rules/no-shadowed-variable/) let's you optionally ignore certain kinds of declarations (#3030) - [new-rule-option] [`prefer-conditional-expression`](https://palantir.github.io/tslint/rules/prefer-conditional-expression/) adds `check-else-if` (#2963) ## :hammer_and_wrench: Bugfixes & enhancements - [bugfix] [`array-type`](https://palantir.github.io/tslint/rules/array-type/): consider `this` to be simple type (#2982) - [bugfix] [`await-promise`](https://palantir.github.io/tslint/rules/await-promise/) accepts not only union types but also intersection types with Promise-like types (#2987) - [bugfix] [`callable-types`](https://palantir.github.io/tslint/rules/callable-types/): don't remove export modifier of interfaces (#2962) - [bugfix] [`completed-docs`](https://palantir.github.io/tslint/rules/completed-docs/): Only checks variables at the file-level. (#2950) - [bugfix] [`completed-docs`](https://palantir.github.io/tslint/rules/completed-docs/): Uses correct visibility of variables. (#2950) - [bugfix] [`no-floating-promises`](https://palantir.github.io/tslint/rules/no-floating-promises/): recognize rejection handler passed as second argument to `promise.then()` (#3048) - [bugfix] [`no-shadowed-variable`](https://palantir.github.io/tslint/rules/no-shadowed-variable/) don't warn for shadowed type parameter on static class members (#3030) - [bugfix] [`no-shadowed-variable`](https://palantir.github.io/tslint/rules/no-shadowed-variable/) fixed false positive with key name in index signature (#3030) - [bugfix] [`no-shadowed-variable`](https://palantir.github.io/tslint/rules/no-shadowed-variable/) fixed false positive with parameter inside function decorator (#3030) - [bugfix] [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/): allow truthyness and falsyness checks (#3008) - [bugfix] [`no-unused-variable`](https://palantir.github.io/tslint/rules/no-unused-variable/) fixed crash when using destructuring (#3058) - [bugfix] [`one-line`](https://palantir.github.io/tslint/rules/one-line/) correctly handles multiline type parameters (#3004) - [bugfix] [`prefer-for-of`](https://palantir.github.io/tslint/rules/prefer-for-of/) fixed false positives when array is modified, e.g. `arr[i]++` (#3044) - [bugfix] [`prefer-object-spread`](https://palantir.github.io/tslint/rules/prefer-object-spread/) adds parens when fixing arrow function return (#3026) - [bugfix] [`prefer-object-spread`](https://palantir.github.io/tslint/rules/prefer-object-spread/) permit functions as first argument to Object.assign (#3098) - [bugfix] [`space-before-function-paren`](https://palantir.github.io/tslint/rules/space-before-function-paren/) Handle default exports of functions without names like anonymous functions (fixes #3040) (#3053) - [bugfix] Fixed an issue where, at runtime, the module `./test/parse` could not be located due after consumers had run `yarn clean` (#3072) - [enhancement] [`no-null-keyword`](https://palantir.github.io/tslint/rules/no-null-keyword/) allows strict comparison (#2802) - [enhancement] [`no-switch-case-fall-through`](https://palantir.github.io/tslint/rules/no-switch-case-fall-through/) matches `// falls through` comments case insensitive and allows trailing text (#2983) - [enhancement] [`ordered-imports`](https://palantir.github.io/tslint/rules/ordered-imports/): support importEqualsDeclaration (#3102) - [enhancement] Added NaN and (+/-)Infinity as numbers to [`no-inferrable-types`](https://palantir.github.io/tslint/rules/no-inferrable-types/) (#2885) - [enhancement] Improved CLI error message when no filenames are specified (#3066) - [rule-change] [`prefer-conditional-expression`](https://palantir.github.io/tslint/rules/prefer-conditional-expression/): ignore `if-else-if` by default. Use the new `"check-else-if"` option to check nested if statements (#2963) Thanks to our contributors! - Klaus Meinhardt - Julian Verdurmen - Alexandre Alonso - Josh Goldberg - ksvitkovsky - Daisuke Yokomoto - Andrii Dieiev - Florent Suc - Jason Killian - Amin Pakseresht - reduckted - vilicvane - Russell Briggs - Andy Hanson - Leo Liang - Dan Homola - BehindTheMath - David Golightly - aervin - Daniel Kucal - Ika - Chris Barr v5.5.0 --- __Editor's note__: This release features an important bugfix for overlapping fixes when using `--project` and `--fix` (#2864). ## :tada: New rules and options - [new-rule-option] [`completed-docs`](https://palantir.github.io/tslint/rules/completed-docs/): Add `enum-members` option (#2911) - [new-rule] [`no-this-assignment`](https://palantir.github.io/tslint/rules/no-this-assignment/) (#2931) ## :hammer_and_wrench: Bugfixes & enhancements - [bugfix] [`encoding`](https://palantir.github.io/tslint/rules/encoding/) closes files correctly (#2958) - [bugfix] [`whitespace`](https://palantir.github.io/tslint/rules/whitespace/) fix whitespace `"check-module"` to properly lint and fix errors (#2401) (#2825) - [bugfix]: [`whitespace`](https://palantir.github.io/tslint/rules/whitespace/): now correctly handles dynamic imports introduced in typescript@2.4.0 (#2924) - [bugfix] [`switch-final-break`](https://palantir.github.io/tslint/rules/switch-final-break/): don't fail if break jumps to a label outside of the switch (#2914) - [bugfix] [`no-shadowed-variable`](https://palantir.github.io/tslint/rules/no-shadowed-variable/): exempt `this` parameter (#2598) - [bugfix] [`prefer-for-of`](https://palantir.github.io/tslint/rules/prefer-for-of/) correctly handles variable scopes and other unrelated identifiers (#2984) - [bugfix] Don't leave blank lines when [`no-unused-variable`](https://palantir.github.io/tslint/rules/no-unused-variable/) autofix removes whole import (#2901) - [cli] restore `-v` option (#2926) - [enhancement] Print stack trace of exceptions (#2890) - [enhancement] Added allow-empty-catch option to [`no-empty`](https://palantir.github.io/tslint/rules/no-empty/) (#2886) - [enhancement] [`prefer-const`](https://palantir.github.io/tslint/rules/prefer-const/): handle destructuring in for-of loop initializer as if `{"destructuring": "all"}` was specified (#2904) - [enhancement] [`no-shadowed-variable`](https://palantir.github.io/tslint/rules/no-shadowed-variable/): added checks for other shadowing declarations, e.g. interfaces, classes, type parameters, imports, etc. (#2598) - [rule-change] [`no-shadowed-variable`](https://palantir.github.io/tslint/rules/no-shadowed-variable/) no longer fails for declarations in the same scope, e.g. `var foo; var foo;`. Use the rule [`no-duplicate-variable`](https://palantir.github.io/tslint/rules/no-duplicate-variable/) to find such errors. (#2598) Thanks to our contributors! - Klaus Meinhardt - Josh Goldberg - Petr Kosikhin - Pablo Núñez - Benny Neugebauer - Radon Rosborough - reduckted - Chris Barr - Julian Verdurmen v5.4.3 --- ## :hammer_and_wrench: Bugfixes - [bugfix] Fixed regression with empty `--out` file (#2867) - [bugfix] [`unified-signatures`](https://palantir.github.io/tslint/rules/unified-signatures/): Don't suggest to unify rest parameters. (#2874) - [bugfix] [`binary-expression-operand-order`](https://palantir.github.io/tslint/rules/binary-expression-operand-order/): Allow if both sides of the binary expression are literals. (#2873) - [bugfix] Restore compatibility with typescript@2.1 and 2.2 for [`whitespace`](https://palantir.github.io/tslint/rules/whitespace/), [`space-before-function-paren`](https://palantir.github.io/tslint/rules/space-before-function-paren/) and [`deprecation`](https://palantir.github.io/tslint/rules/deprecation/) (#2893) - [docs] [`no-string-literal`](https://palantir.github.io/tslint/rules/no-string-literal/): Fix documentation (#2875) v5.4.2 --- ## :hammer_and_wrench: Bugfixes - [bugfix] Restored support for multiple `--exclude` options in the CLI (#2855) - [bugfix] Restored support for `--version` CLI option (#2857) v5.4.1 --- ## :hammer_and_wrench: Bugfixes - [bugfix] Fixed regression in `--exclude` CLI option when using `--project` (#2852) v5.4.0 --- ## :star: Non-breaking API changes - `--type-check` only checks for errors before linting is no longer required to enable rules that use the type checker. You only need to supply `--project` now. ## :tada: New rules, options, and fixers - [new-rule] [`switch-final-break`](https://palantir.github.io/tslint/rules/switch-final-break/) (#2804) - [new-rule] [`use-default-type-parameter`](https://palantir.github.io/tslint/rules/use-default-type-parameter/) (#2253) - [new-rule] [`binary-expression-operand-order`](https://palantir.github.io/tslint/rules/binary-expression-operand-order/) (#2805) - [new-rule-option] [`ban`](https://palantir.github.io/tslint/rules/ban/) new options format: allows to specify an optional explanation message for function bans, banning nested methods and using a wildcard for object of a method ban (#2547) - [new-rule-option] [`no-duplicate-variable`](https://palantir.github.io/tslint/rules/no-duplicate-variable/) adds `check-parameters` option to check if variable has the same name as a parameter (#2597) - [new-rule-option] [`curly`](https://palantir.github.io/tslint/rules/curly/): "as-needed" option (#2842) - [new-rule-option] [`no-unbound-method`](https://palantir.github.io/tslint/rules/no-unbound-method/) add option `"ignore-static"` (#2751) - [new-rule-option] [`strict-boolean-expressions`](https://palantir.github.io/tslint/rules/strict-boolean-expressions/) adds `allow-boolean-or-undefined` (#2820) - [new-fixer] [`object-literal-shorthand`](https://palantir.github.io/tslint/rules/object-literal-shorthand/) can fix longhand methods (#2558) ## :hammer_and_wrench: Bugfixes & enhancements - [bugfix] [`prefer-object-spread`](https://palantir.github.io/tslint/rules/prefer-object-spread/) allows constructor, function and method calls and more as first argument to `Object.assign` (#2828) - [bugfix] [`no-unbound-method`](https://palantir.github.io/tslint/rules/no-unbound-method/) walker skips past the parent if it is a cast or parenthesized expression (#2838) - [bugfix] [`object-literal-shorthand`](https://palantir.github.io/tslint/rules/object-literal-shorthand/): fixed suggestion for generator functions (#2558) - [bugfix] Fixed issue with case sensitivity of [`no-unused-variable`](https://palantir.github.io/tslint/rules/no-unused-variable/) rule on Windows (#2819) - [bugfix] don't crash `tslint --project` if `allowJs` is set in tsconfig.json (#2823) - [bugfix] [`align`](https://palantir.github.io/tslint/rules/align/) with option `"members"`: check members of class expressions; don't check semicolons in classes (#2668) - [bugfix] [`no-inferred-empty-object-type`](https://palantir.github.io/tslint/rules/no-inferred-empty-object-type/): fix stack overflow (#2762) - [bugfix] [`semicolon`](https://palantir.github.io/tslint/rules/semicolon/): don't warn about unnecesary semicolon when it is actually needed, e.g. when followed by type assertion or template string (#2655) - [bugfix] [`space-before-function-paren`](https://palantir.github.io/tslint/rules/space-before-function-paren/): Ignore async arrow function with no parentheses (#2833) - [bugfix]: [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/): Don't fail on `continue label;` (#2830) - [bugfix] [`no-unbound-method`](https://palantir.github.io/tslint/rules/no-unbound-method/): Allow unbound method to be used as a condition (#2834) - [bugfix] [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/): Allow to switch on a value of type `any` (#2836) - [bugfix] [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/): Don't mark `declare global {}` as an unsafe any. (#2839) - [bugfix] [`indent`](https://palantir.github.io/tslint/rules/indent/) now checks indentation of expressions inside template strings (#2826) - [enhancement] `--project` (or `-p`) enables rules that require the type checker. `--type-check` only checks for errors before linting is no longer required (#2773) - [enhancement] [`deprecation`](https://palantir.github.io/tslint/rules/deprecation/): error message includes deprecation text if available (#2748) - [enhancement] [`cyclomatic-complexity`](https://palantir.github.io/tslint/rules/cyclomatic-complexity/): Don't count empty switch case(#2743) - [enhancement] [`strict-boolean-expressions`](https://palantir.github.io/tslint/rules/strict-boolean-expressions/): Allow `any`, and `true` and `false` literal types (#2758) - [enhancement] [`no-floating-promises`](https://palantir.github.io/tslint/rules/no-floating-promises/): Allow 'promise.catch()' (#2774) - [enhancement] [`comment-format`](https://palantir.github.io/tslint/rules/comment-format/) no longer excludes comments with triple slash from linting except `/// ` (#2616) - [enhancement] [`prefer-object-spread`](https://palantir.github.io/tslint/rules/prefer-object-spread/): lint more locations where return value is used. (#2828) - [enhancement] [`semicolon`](https://palantir.github.io/tslint/rules/semicolon/): option `"never"` is now spec compliant (#2655) - [enhancement] [`object-literal-shorthand`](https://palantir.github.io/tslint/rules/object-literal-shorthand/) handles async functions correctly (#2558) - [enhancement] `--test` CLI option: allow passing path to tslint.json (#2784) - [enhancement] Use commander instead of optimist for CLI arguments (#2689) - [enhancement] [`strict-type-predicates`](https://palantir.github.io/tslint/rules/strict-type-predicates/): warn if strictNullChecks is not enabled (#2786) Thanks to our contributors! - Klaus Meinhardt - Manuel Lopez - Andy Hanson - Piotr Tomiak v5.3.2 --- - [bugfix] Fixes `not a directory` error (#2813) v5.3.0 --- ## This change may require a change to tslint.json - [enhancement] [`prefer-switch`](https://palantir.github.io/tslint/rules/prefer-switch/): Change default `min-cases` to 3. (#2669) ## :tada: Features & enhancements - [new-cli-option] cli: Add `outputAbsolutePaths` option (#2667) - [new-rule] [`prefer-object-spread`](https://palantir.github.io/tslint/rules/prefer-object-spread/) (#2624) - [new-rule] [`encoding`](https://palantir.github.io/tslint/rules/encoding/) (#2368) - [new-rule] [`prefer-conditional-expression`](https://palantir.github.io/tslint/rules/prefer-conditional-expression/) (#2363) - [new-rule-option] [`indent`](https://palantir.github.io/tslint/rules/indent/) support indent size (#2723) - [new-rule-option] [`object-literal-sort-keys`](https://palantir.github.io/tslint/rules/object-literal-sort-keys/) adds `ignore-case` (#2592) - [new-rule-option] [`quotemark`](https://palantir.github.io/tslint/rules/quotemark/): Add `avoid-template` option (#2766) - [new-rule-option] [`await-promise`](https://palantir.github.io/tslint/rules/await-promise): What's considered a "Promise" is now configurable. (#2661) - [new-fixer] [`indent`](https://palantir.github.io/tslint/rules/indent/) (#2723) - [new-fixer] [`typedef-whitespace`](https://palantir.github.io/tslint/rules/typedef-whitespace/) (#2718) - [enhancement] better error messages in [`variable-name`](https://palantir.github.io/tslint/rules/variable-name/) (#2672) - [enhancement] [`typedef`](https://palantir.github.io/tslint/rules/typedef/): Use name or parameters for error location (#2460) - [enhancement] [`object-literal-sort-keys`](https://palantir.github.io/tslint/rules/object-literal-sort-keys/): check shorthand properties (#2592) - [enhancement] [`space-before-function-paren`](https://palantir.github.io/tslint/rules/space-before-function-paren/): Handle `get`/`set` accessor (#2700) - [enhancement] [`typedef-whitespace`](https://palantir.github.io/tslint/rules/typedef-whitespace/) added checks for arrow function, call and construct signature (#2718) - [enhancement] [`no-object-literal-type-assertion`](https://palantir.github.io/tslint/rules/no-object-literal-type-assertion/): Allow cast to `any` (#2671) - [enhancement] cli: `-p` option handles directories (#2756) - [develop] testing rules with type information is enabled when a `tsconfig.json` is found next to `tslint.json` (#2769) - [configuration] deprecate mixed case tslint.json (#2713) - [bugfix] [`return-undefined`](https://palantir.github.io/tslint/rules/return-undefined/): Treat a return type `void | undefined` same as `void` (#2731) - [bugfix] [`no-unnecessary-initializer`](https://palantir.github.io/tslint/rules/no-unnecessary-initializer/): Handle `BindingElement` anywhere, not just in a `VariableDeclaration`. (#2707) - [bugfix] [`jsdoc-format`](https://palantir.github.io/tslint/rules/jsdoc-format/): correctly handle alignment in files with BOM (#2619) - [bugfix] [`jsdoc-format`](https://palantir.github.io/tslint/rules/jsdoc-format/): don't treat empty comments (`/**/`) as jsdoc (#2619) - [bugfix] [`typedef-whitespace`](https://palantir.github.io/tslint/rules/typedef-whitespace/) don't warn for leading whitespace if token is preceded by line break (#2718) - [bugfix] Make "completed-docs" rule respect "public" privacy (or lack thereof) (#2749) - [bugfix] [`jsdoc-format`](https://palantir.github.io/tslint/rules/jsdoc-format/): fixed error position if line ends with `\r\n` (#2619) - [bugfix] [`prefer-switch`](https://palantir.github.io/tslint/rules/prefer-switch/): add missing checks for some expressions (#2686) - [bugfix] [`prefer-template`](https://palantir.github.io/tslint/rules/prefer-template/): Allow `"a" + "b" + "c"`. (#2741) - [bugfix] [`prefer-const`](https://palantir.github.io/tslint/rules/prefer-const/): fix false positive with variable declared outside of for-of or for-in (#2760) - [bugfix] `--project`: fix file matching with relative path to `tsconfig.json` (#2688) - [bugfix] [`no-default-export`](https://palantir.github.io/tslint/rules/no-default-export/): correctly handle `export default abstract class {...}` (#2630) - [bugfix] [`no-mergeable-namespace`](https://palantir.github.io/tslint/rules/no-mergeable-namespace/): display correct line in error message (#2656) - [bugfix] [`object-literal-sort-keys`](https://palantir.github.io/tslint/rules/object-literal-sort-keys/): handle object spread correctly (#2592) - [bugfix] Consistently output absolute/relative paths (#2667) - [bugfix] [`await-promise`](https://palantir.github.io/tslint/rules/await-promise): Consider types derived from a Promise in union types too. (#2661) - [bugfix] [`no-unsafe-any`](https://palantir.github.io/tslint/rules/no-unsafe-any/): Fix bug where number literal in type position was flagged as an unsafe `any`. (#2712) - [api] Deprecate `Lint.Utils.objectify` (#2764) Thanks to our contributors! - Andy Hanson - Klaus Meinhardt - Martin Probst - Filipe Silva - walkerburgin - René Scheibe v5.2.0 --- - [rule-change] [`no-console`](https://palantir.github.io/tslint/rules/no-console/) bans all console methods when no methods are specified (#2610) - [new-rule] [`no-object-literal-type-assertion`](https://palantir.github.io/tslint/rules/no-object-literal-type-assertion/) (#2580) - [new-rule] [`no-irregular-whitespace`](https://palantir.github.io/tslint/rules/no-irregular-whitespace/) (#2487) - [new-rule] [`prefer-switch`](https://palantir.github.io/tslint/rules/prefer-switch/) (#2331) - [new-rule] [`number-literal-format`](https://palantir.github.io/tslint/rules/number-literal-format/) (#2526) - [new-rule] [`deprecation`](https://palantir.github.io/tslint/rules/deprecation/) (#2395) - [new-rule] [`no-unnecessary-type-assertion`](https://palantir.github.io/tslint/rules/no-unnecessary-type-assertion/) (#2519) - [new-fixer] [`interface-over-type-literal`](https://palantir.github.io/tslint/rules/interface-over-type-literal/) (#2617) - [new-fixer] [`callable-types`](https://palantir.github.io/tslint/rules/callable-types/) (#2552) - [new-fixer] [`no-string-literal`](https://palantir.github.io/tslint/rules/no-string-literal/) (#2495) - [new-fixer] [`no-internal-module`](https://palantir.github.io/tslint/rules/no-internal-module/) (#2517) - [new-rule-option] [`align`](https://palantir.github.io/tslint/rules/align/) rule added `members` option, which checks alignment of methods and properties of classes, objects, interfaces, type literals and object destructuring (#2387) - [new-rule-option] [`align`](https://palantir.github.io/tslint/rules/align/) rule added `elements` option, which checks alignment of elements in array literals, array destructuring and tuple types (#2387) - [new-rule-option] [`trailing-comma`](https://palantir.github.io/tslint/rules/trailing-comma/) adds more granular options to specify trailing commas for arrays, objects, functions, type literals, imports, and exports (#2538) - [api] Deprecate `ScopeAwareRuleWalker` and `BlockScopeAwareRuleWalker`. (#2561) - [develop] added support for [error templates in rule tests](https://palantir.github.io/tslint/develop/testing-rules/) (#2481) - [bugfix] Fixes "Severity for rule not found" error (#2516) - [bugfix] [`no-unused-expression`](https://palantir.github.io/tslint/rules/no-unused-expression/): allow `void(0)` in addition to `void 0` and `void` in expression and statement position (#2645) - [bugfix] [`align`](https://palantir.github.io/tslint/rules/align/): fix false positive for files with BOM (#2642) - [bugfix] [`return-undefined`](https://palantir.github.io/tslint/rules/return-undefined/): Handle contextual types with ambiguous signatures; allow `any`; and handle async functions. (#2576) - [bugfix] [`semicolon`](https://palantir.github.io/tslint/rules/semicolon/): don't mark semicolon as unnecessary when the next statement is on the same line (#2591) - [bugfix] [`no-internal-module`](https://palantir.github.io/tslint/rules/no-internal-module/): no more false positives for global augmentation (#2517) - [bugfix] [`no-unnecessary-qualifier`](https://palantir.github.io/tslint/rules/no-unnecessary-qualifier/): no longer breaks when walking a function that references `arguments` (#2555) - [bugfix] [`prefer-const`](https://palantir.github.io/tslint/rules/prefer-const/) no longer shows warnings on ambient declarations (#2391) - [bugfix] [`callable-types`](https://palantir.github.io/tslint/rules/callable-types/): suggest correct fix for interfaces with type arguments (#2552) - [bugfix] [`quotemark`](https://palantir.github.io/tslint/rules/quotemark/): fix regression with jsx attributes (#2605) - [bugfix] [`adjacent-overload-signatures`](https://palantir.github.io/tslint/rules/adjacent-overload-signatures/) handles functions ending in semicolon (#2412) - [bugfix] [`object-literal-key-quotes`](https://palantir.github.io/tslint/rules/object-literal-key-quotes/): correctly stringify numbers when fixing (#2515) - [bugfix] [`object-literal-key-quotes`](https://palantir.github.io/tslint/rules/object-literal-key-quotes/): does no longer require quotes for property names containing digits (#2515) - [enhancement] Failures in extended config files now indicate which file (#2588) - [enhancement] [`align`](https://palantir.github.io/tslint/rules/align/): Don't report 'statements are not aligned' for empty statements (#2653) - [enhancement] [`class-name`](https://palantir.github.io/tslint/rules/class-name/) now also checks class expressions (#2553) - [enhancement] `optionExamples`: Allow to use an options array directly instead of a string representation. (#2527) - [enhancement] `rulesDirectory` can now be resolved with Nodes resolve logic, if the directory contains an `index.js` (#2163) (#2358) - [enhancement] [`no-unused-expression`](https://palantir.github.io/tslint/rules/no-unused-expression/): narrow error location for comma separated expressions and conditional expressions (#2645) - [enhancement] [`no-string-literal`](https://palantir.github.io/tslint/rules/no-string-literal/) now handles escaped strings (#2495) - [enhancement] [`no-unnecessary-callback-wrapper`](https://palantir.github.io/tslint/rules/no-unnecessary-callback-wrapper/): Allow `x => x(x)` (#2524) - [enhancement] [`no-var-keyword`](https://palantir.github.io/tslint/rules/no-var-keyword/): Allow global var declarations (#2513) Thanks to our contributors! - Andy Hanson - Alex Eagle - Donald Pipowitch - Klaus Meinhardt - Gord P - Andy - Quentin - Mitchell Wills - Vito - CSchulz - Josh Goldberg - Brian Olore - Manuel Lopez - James Clark v5.1.0 --- - [new-rule] `no-invalid-template-strings` (#2332) - [new-rule] `no-sparse-arrays` (#2407) - [new-rule-option] `no-void-expression`: adds `ignore-arrow-function-shorthand` (#2445) - [api] `tslint:all` configuration (#2417) - [bugfix] In tslint:recommended move `no-reference-import` from `jsRules` to `rules` (#2441) - [bugfix] `no-unnecessary-callback-wrapper`: only check if callback is identifier, allow all other expressions (#2510) - [bugfix] `member-access`: Skip index signature, it can not have an access modifier (#2437) - [bugfix] `restrict-plus-operands` fixes regression where every assignment and comparison was checked (#2454) - [bugfix] `no-unnecessary-callback-wrapper`: allow async wrapper function (#2510) - [bugfix] `prefer-for-of`: No error if `delete` is used (#2458) - [bugfix] `radix`: don't warn for missing radix on method calls (#2352) - [bugfix] `no-use-before-declare`: Handle symbol with empty declarations list. (#2436) - [bugfix] `strict-type-predicates`: Check for construct signatures in `isFunction`. (#2479) - [enhancement] `strict-boolean-expressions`: When `--strictNullChecks` is turned off, `allow-null-union` and `allow-undefined-union` turn off "always truthy" errors. (#2373) - [enhancement] `radix`: added check for global.parseInt and window.parseInt (#2352) - [enhancement] `arrow-return-shorthand`: Improve failure message when return expression is an object literal (#2466) Thanks to our contributors! - Andy Hanson - bumbleblym - Klaus Meinhardt - Jonas Kello - Minko Gechev - Donald Pipowitch v5.0.0 --- ## :fire: Breaking changes - Minimum version of TypeScript version is now 2.1.0 (#2425) - The severity level of rules are now configurable and defaults to severity "error". This affects the output of formatters: - [formatter] `msbuild` was outputting all failures as "warning". - [formatter] `pmd` was outputting all failures as priority 1. Now, it uses _priority 3_ for "error" (default) and _priority 4_ for "warning" - [formatter] `json` changed the `fix` property to now contain either one replacement or an array of replacements (#2403) - `tslint:recommended` configuration updated with `tslint:latest` rules & options (#2424) - Removed `no-unused-new` rule, with logic moved into `no-unused-expression` (#2269) - `no-trailing-whitespace` now checks template strings by default. Use the new options `ignore-template-strings` to restore the old behavior. (#2359) ### API breaks for custom rules - Removed method `skip` from `RuleWalker` (#2313) - Removed all use of the TypeScript Language Service, use only Program APIs instead (#2235) - This means that some rules that previously worked without the type checker _now require it_. This includes: - `no-unused-variable` - `no-use-before-declare` - This breaks custom rule compilation. If your rule was not using the `ts.LanguageService` APIs, the migration is quite simple: ```diff - public applyWithProgram(srcFile: ts.SourceFile, langSvc: ts.LanguageService): Lint.RuleFailure[] { - return this.applyWithWalker(new Walker(srcFile, this.getOptions(), langSvc.getProgram())); + public applyWithProgram(srcFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] { + return this.applyWithWalker(new Walker(srcFile, this.getOptions(), program)); ``` - N.B. If you are refactoring your custom rules, consider [these performance tips for writing custom rules](https://palantir.github.io/tslint/develop/custom-rules/performance.html). - Removed `createFix`. Replacements should be passed directly into addFailure. (#2403) - Removed deprecated `scanAllTokens` and `skippableTokenAwareRuleWalker` (#2370) ## :tada: Notable features & enhancements - [feature] The severity level of rules are now individually configurable. Default severity can also be configured. (#629, #345) - Valid values for `severity`: `default` | `error | warn | warning | none | off` - Valid values for `defaultSeverity`: `error | warn | warning | none | off` - Old style: ```json { "extends": "tslint:latest", "rules": { "callable-types": true, "max-line-length": [true, 140] } } ``` - New style (in this example, `callable-types` outputs errors and `max-line-length` outputs warnings): ```json { "extends": "tslint:latest", "defaultSeverity": "error", "rules": { "callable-types": true, "max-line-length": { "options": 140, "severity": "warning" } } } ``` - [new-rule] `prefer-template` (#2243) - [new-rule] `return-undefined` (#2251) - [new-rule] `no-reference-import` (#2273) - [new-rule] `no-unnecessary-callback-wrapper` (#2249) - [new-fixer] `linebreak-style` (#2394) - [new-fixer] `eofline` (#2393) ## Full list of changes - [api] Added class `OptionallyTypedRule`, which allows rule authors to write a rule that applies when typing is either enabled or disabled (#2300) - [bugfix] `prefer-function-over-method` now ignores abstract methods (#2307) - [bugfix] `arrow-parens` with option `ban-single-arg-parens` now correctly handles functions with return type annotation (#2265) - [bugfix] `prefer-function-over-method` exclude overload signatures (#2315) - [bugfix] `use-isnan` now applies only to comparison operators (#2317) - [bugfix] `file-header-rule` now handles single-line comments correctly (#2320) - [bugfix] `newline-before-return`: fix handling of blank lines between comments (#2321) - [bugfix] `trailing-comma` No longer enforce trailing commas in type parameters and tuple types (#2236) - [bugfix] `align` don't fix if it would remove code (#2379) - [bugfix] `unified-signatures` now recognizes rest parameters (#2342) - [bugfix] `no-inferrable-types` don't warn for inferrable type on readonly property (#2312) - [bugfix] `trailing-comma` no longer crashes on new without parentheses (e.g. `new Foo`) (#2389) - [bugfix] `semicolon` Ignore comments when checking for unnecessary semicolon (#2240) - [bugfix] `semicolon` Don't report unnecessary semicolon when followed by regex literal (#2240) - [bugfix] CLI: exit with 0 on type check errors when `--force` is specified (#2322) - [bugfix] CLI: `--test` now correctly strips single quotes from patterns on windows (#2322) - [bugfix] `prefer-const` only fix initialized variables (#2219) - [bugfix] `prefer-const` correctly handle variables shadowed by parameters and catched exceptions (#2219) - [bugfix] `prefer-const` don't warn if one variable in a for loop initializer can not be const (#2219) - [bugfix] `prefer-const` handle more cases in destructuring (#2219) - [bugfix] `no-unused-expression` allow comma separated assignments (#2269) - [chore] removed update-notifier dependency (#2262) - [development] allow rule tests to specify version requirement for typescript (#2323) - [enhancement] `ignore-properties` option of `no-inferrable-types` now also ignores parameter properties (#2312) - [enhancement] `unified-signatures` now displays line number of the overload to unify if there are more than 2 overloads (#2270) - [enhancement] `trailing-comma` New checks for CallSignature and NamedExports (#2236) - [enhancement] `semicolon` New check for export statements, function overloads and shorthand module declaration (#2240) - [enhancement] `semicolon` Report unnecessary semicolons in classes and in statement position (for option "always" too) (#2240) - [enhancement] `semicolon` check for semicolon after method overload (#2240) - [enhancement] `array-type` now consider `object`, `undefined` and `never` as simple types, allowing `object`, `undefined[]` and `never[]` (#1843)(#2353) - [enhancement] `align` check statement alignment for all blocks (#2379) - [enhancement] `align`check parameter alignment for all signatures (#2379) - [enhancement] `--test` can handle multiple paths at once (#2322) - [enhancement] `only-arrow-functions` allow functions that use `this` in the body (#2229) - [enhancement] CLI: print error when `--type-check` is used without `--project` (#2322) - [enhancement] CLI: don't print stack trace on type check error (#2322) - [enhancement] CLI: added `-p` as shorthand for `--project` to be consistent with `tsc` (#2322) - [enhancement] `prefer-const` show warnings for `var` (#2219) - [enhancement] `quotemark` fixer unescapes original quotemark (e.g. `'\''` -> `"'"`) (#2359) - [enhancement] `no-unused-expression` allow indirect eval `(0, eval)("");` (#2269) - [enhancement] `no-unused-expression` checking for unused new can now use option `allow-fast-null-checks` (#2269) - [enhancement] `no-unused-expression` find unused comma separated expressions in all locations of the code (#2269) - [enhancement] `no-unused-expression` find unused expressions inside void expression (#2269) - [new-config-option] Adds `defaultSeverity` with options `error`, `warning`, and `off`. (#2416) - [new-formatter] TAP formatter (#2325) - [new-rule-option] `no-unused-expression` adds option `allow-tagged-template` to allow tagged templates for side effects (#2269) - [new-rule-option] `no-unused-expression` adds option `allow-new` to allow `new` without using the new object (#2269) - [new-rule-option] `member-access` adds `no-public` option (#2247) - [new-rule-option] `curly` added option `ignore-same-line` (#2334) - [new-rule-option] `{destructuring: "all"}` to only warn if all variables in a destructuring can be const (#2219) - [new-rule-option] added `ignore-template-strings` to `no-trailing-whitespace` (#2359) - [rule-update] `array-type` now consider `undefined` and `never` as simple types, allowing `undefined[]` and `never[]` (#1843) Thanks to our contributors! - Brian Olore - Andy Hanson - @andy-ms - Chris Barr - Klaus Meinhardt - @bumbleblym - Josh Goldberg - James Clark - @vilic - Aleksandr Filatov - Matt Banz - Karol Janyst - Mike Deverell - Alexander James Phillips - Irfan Hudda v4.5.1 --- - [enhancement] Updated recommended rules to include `ban-types` and `no-duplicate-super` (#2271) - [bugfix] `object-literal-key-quotes` handle negative number property name (#2273) v4.5.0 --- - [new-rule] `no-import-side-effect` (#2155) - [new-rule] `match-default-export-name` (#2117) - [new-rule] `no-non-null-assertion` (#2221) - [new-rule] `ban-types` (#2175) - [new-rule] `no-duplicate-super` (#2038) - [new-rule] `newline-before-return` (#2173) - [new-rule-option] `completed-docs` adds options for location, type, and privacy. Also adds interfaces, enums, types (#2095) - [new-rule-option] `no-inferrable-types` adds option `ignore-properties` (#2178) - [new-rule-option] `typedef` adds options `object-destructuring` and `array-destructuring` options (#2146) - [new-rule-option] `member-ordering` adds option `alphabetize` (#2101) - [new-rule-option] `no-trailing-whitespace` adds option `ignore-jsdoc` (#2177) - [new-rule-option] `no-trailing-whitespace` adds option `ignore-comments` option (#2153) - [new-fixer] `no-inferrable-types` automatically remove inferrable type annotations (#2178) - [new-fixer] `no-any` (#2165) - [new-fixer] `noConsecutiveBlankLines` (#2201) - [new-fixer] `object-literal-shorthand` (#2165) - [bugfix] `no-switch-case-fallthrough` handle break, throw, continue and return nested in block, if-else and switch (#2218) - [bugfix] `no-switch-case-fallthrough` allow empty case clauses before default clause (#2218) - [bugfix] `no-mergeable-namespace` ignore property types that can't be merged (#2105) - [bugfix] `object-literal-key-quotes` no need to quote a float if its .toString() is the same. (#2144) - [bugfix] `no-consecutive-blank-lines` Correctly apply fixes at EOF (#2239) - [bugfix]: Fixes installation issue with node 7.5 (#2212) - [bugfix]: `quotemark` now handles escaped chars (#2224) - [enhancement] Don't exit when a rule requires type checking but type checking is not enabled (#2188) - [enhancement] `no-switch-case-fallthrough` allow single line comment `// falls through` (#2218) - [enhancement] `no-unbound-method` allows property access and binary expressions (#2143) - [api] Introduce `AbstractWalker` for performance (#2093) - see [performance] (https://palantir.github.io/tslint/develop/custom-rules/performance.html) and [migration] (https://palantir.github.io/tslint/develop/custom-rules/migration.html) docs Thanks to our contributors! - Andy Hanson - Stefan Reichel - Shlomi Assaf - Josh Goldberg - Minko Gechev - Irfan Hudda - Klaus Meinhardt - Martin Probst - Naoto Usuyama - Caleb Eggensperger - Arturs Vonda - Joscha Feth - Moritz - Alexander Rusakov - Alex Ryan - Andy - Yuichi Nukiyama v4.4.2 --- * [bugfix] `whitespace` rule caused false positive on EOF (#2131) * [bugfix] WebStorm fails because `json` formatter parameter has extra space (#2132) v4.4.1 --- * [bugfix] errant space in recommended ruleset (couldn't find `no-misused-new`) v4.4.0 --- * [new-rule] `arrow-return-shorthand` (#1972) * [new-rule] `no-unbound-method` (#2089) * [new-rule] `no-boolean-literal-compare` (#2013) * [new-rule] `no-unsafe-any` (#2047) * [new-rule] `no-unnecessary-qualifier` (#2008) * [new-rule] `no-unnecessary-initializer` (#2106) * [new-rule] `await-promise` (#2102) * [new-rule] `no-floating-promises` (#1632) * [new-rule] `strict-type-predicates` (#2046) * [new-rule] `no-misused-new` (#1963) * [new-rule] `prefer-method-signature` (#2028) * [new-rule] `prefer-function-over-method` (#2037) * [new-rule-option] `allow-fast-null-checks` added to `no-unused-expression` (#1638) * [new-rule-option] `comment-format-rule` adds `ignore-words` and `ignore-pattern` options (#1757) * [new-rule-option] `whitespace` adds `check-preblock` option (#2002) * [new-rule-option] `strict-boolean-expressions` adds `allow-null-union`, `allow-undefined-union`, `allow-string`, and `allow-number` and (#2033) * [new-fixer] `align` (#2097) * [new-fixer] `no-trailing-whitespace` (#2060) * [bugfix] `no-magic-numbers` false positive on default parameter values (#2004) * [bugfix] `no-empty-interface` allow empty interface with 2 or more parents (#2070) * [bugfix] `no-trailing-whitespace` fixed for comments and EOF (#2060) * [bugfix] `no-empty` no longer fails for private or protected constructor (#1976) * [bugfix] `tslint:disable`/`tslint-enable` now handles multiple rules and fixes what code is enabled/disabled (#2061) * [bugfix] `no-inferrable-types` now validates property declarations (#2081) * [bugfix] `unified-signatures` false positive (#2016) * [bugfix] `whitespace` finds all whitespace errors in JsxExpressions and TemplateExpressions (#2036) * [bugfix] `comment-format` no more false positives in JsxText (#2036) * [enhancement] `--test` option now accepts glob (#2079) Thanks to our contributors! * Alexander Rusakov * Andrii Dieiev * @andy-ms * Andy Hanson * Josh Goldberg * Kei Son * Klaus Meinhardt * Krati Ahuja * Martin Probst * Mohsen Azimi * Romke van der Meulen * cameron-mcateer v4.3.1 --- * [bugfix] Fix back-compat break. Allow formattersDirectory === null (#1997) v4.3.0 --- * **Enabled additional rules in `tslint:latest` configuration** (#1981) * [new-rule] `space-before-function-paren` (#1897) * [new-rule] `typeof-compare` (#1927) * [new-rule] `import-spacing` (#1935) * [new-rule] `unified-signatures` (#1944) * [new-fixer] `object-literal-key-quotes` (#1953) * [new-fixer] `no-angle-bracket-type-assertion` (#1979) * [bugfix] `adjacent-overload-signature` now handles static/computed function names (#1831) * [bugfix] `file-header` now handles files with only comments (#1913) * [bugfix] `no-consecutive-blank-lines` now allows blank lines in template strings (#1886) * [bugfix] `object-literal-key-quotes` no longer throws exception when using rest operator (#1916) * [bugfix] `restrict-plus-operands` no longer shows false positive in ternary operation (#1925) * [bugfix] `prefer-for-of` now handles nested `for` loops with reused iterator (#1926) * [bugfix] Exit gracefully when `tsconfig.json` passed as `--project` argument doens't have files (#1933) * [bugfix] `object-literal-key-quotes` now handles shorthand and spread properties (#1945) * [bugfix] `arrow-parens` Allow binding patterns `([x, y]) => ...` and `({x, y}) => ...` to have parens (#1958) * [bugfix] `semicolon` fixer now handles comma separator in interfaces and indicates failure when commas are using in interfaces (#1856) * [bugfix] `only-arrow-functions` option `allow-named-functions` now allows function declarations (#1961) * [bugfix] `prefer-for-of` no longer shows false positive when array is in parentheses (#1986) * [bugfix] `prefer-const` now works for TypeScript versions < 2.1.0 (#1989) * [enhancement] `member-access` narrow location of error (#1964) Thanks to our contributors! * Andrii Dieiev * @andy-ms * Andy Hanson * Josh Goldberg * Klaus Meinhardt * Linda_pp * Mohsen Azimi * Victor Grigoriu * Yuichi Nukiyama * cameron-mcateer v4.2.0 --- * [new-rule] `no-string-throw` (#1878) * [new-rule] `no-empty-interface` (#1889) * [new-rule] `interface-over-type-literal` (#1890) * [new-rule] `callable-types` (#1891) * [new-rule] `no-void-expression` (#1903) * [new-rule-option] `ban-single-arg-parens` added to `arrow-parens` (#1893) * [bugfix] `prefer-const` handles destructuring arrays (#1894), destructuring objects (#1906), and forward references (#1908) * [bugfix] Don't error for misplaced braces for 'else' in `one-line` rule (#1866) * [bugfix] `no-shadowed-variable` now identifies shadowed `for` iterator (#1816) * [bugfix] `object-literal-key-quotes` now includes function names (#1874) * [bugfix] error when EOF comes after `disable-next-line` comment (#1902) Thanks to our contributors! * Andrew Scott * @andy-ms * Andy Hanson * James Booth * Klaus Meinhardt * Vladimir Matveev v4.1.1 --- * [bugfix] `typedef` rule was showing false positive for `catch` clause (#1887) v4.1.0 --- * [new-rule] `prefer-const` (#1801) * [new-rule] `strict-boolean-expressions` (#1820) * [new-rule] `no-magic-numbers` (#1799) * [new-rule] `import-blacklist` (#1841) * [new-rule] `promise-functions-async` (#1779) * [new-rule] `no-inferred-empty-object-type`: a type must be specified when using a generic class/function/etc (#1821) * [new-rule-option] `allow-named-functions` added to `only-arrow-functions` (#1857) * [new-fixer] `prefer-const` (#1801) * [new-fixer] `quotemark` (#1790) * [new-formatter] `code-frame` formatter shows you the error in context (#1819) * [enhancement] `no-internal-module` failures highlight less text (#1781) * [enhancement] Avoid auto-fixing errors that would result in compilation errors for rules that use type-check (#1608) * [rule-change] `only-arrow-functions` will allow functions with a `this` parameter (#1597) * [bugfix] `no-use-before-declare` false positive on named import (#1620) * [bugfix] `prefer-for-of` was showing false positive when the element is assigned (#1813) * [bugfix] The command line argument `type-check` was swallowing the next argument (#1783) * [bugfix] `tslint:disable-line` was re-enabling `tslint:disable` (#1634) * [bugfix] `adjacent-overload-signatures` did not work for constructors (#1800) * [bugfix] `checkstyle` formatter was reporting errors under one file (#1811) * [bugfix] `trailing-comma` was applied to parameter lists (#1775) * [api] CLI logic moved into API friendly class (#1688) Thanks to our contributors! * Alex Eagle * Andrii Dieiev * Andy Hanson * Art Chaidarun * Donald Pipowitch * Feisal Ahmad * Josh Goldberg * Klaus Meinhardt * Maciej Sypień * Mohsen Azimi * Ryan Lester * Simon Schick * Subhash Sharma * Timothy Slatcher * Yaroslav Admin * Yuichi Nukiyama * tdsmithATabc * @wmrowan 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-imports` rule option `import-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) v3.15.0 --- * Stable release containing changes from the last dev release (v3.15.0-dev.0) v3.15.0-dev.0 --- * [enhancement] Rules can automatically fix errors (#1423) * [enhancement] Better error messages for invalid source files (#1480) * [new-rule] `adjacent-overload-signatures` rule (#1426) * [new-rule] `file-header` rule (#1441) * [new-rule] `object-literal-shorthand` rule (#1488) * [new-rule-option] `allow-declarations` option for `only-arrow-functions` rule (#1452) * [new-rule-option] `import-sources-order` option for `ordered-imports` rule (#1466) * [bugfix] `arrow-parens` rule handles async and generics (#1446, #1479) * [bugfix] `comment-format` rule ignores tslint control comments (#1473) * [bugfix] Fix `no-shadowed-variable` rule false positives (#1482) Thanks to our contributors! * @apacala * @danvk * @DovydasNavickas * @glen-84 * @IllusionMH * @JoshuaKGoldberg * @markwongsk * @rakatyal * @rhysd * @ScottSWu * @YuichiNukiyama v3.14.0 --- * Stable release containing changes from the last dev releases (v3.14.0-dev.0, v3.14.0-dev.1) v3.14.0-dev.1 --- * [new-rule] `arrow-parens` rule (#777) * [new-rule] `max-file-line-count` rule (#1360) * [new-rule] `no-unsafe-finally` rule (#1349) * [new-rule] `no-for-in-array` rule (#1380) * [new-rule] `object-literal-key-quotes` rule (#1364) * [enhancement] Better `ban` rule failure messages (#1385) * [enhancement] New stylish formatter (#1406) Thanks to our contributors! * @chrismbarr * @danvk * @gjuchault * @lowkay * @ScottSWu * @YuichiNukiyama v3.14.0-dev.0 --- * [enhancement] Add optional type information to rules (#1323) Thanks to our contributors! * @ScottSWu v3.13.0 --- * Stable release containing changes from the last dev release (v3.13.0-dev.0) v3.13.0-dev.0 --- * [new-rule] `ordered-imports` rule (#1325) * [enhancement] MPEG transport stream files are ignored by the CLI (#1357) Thanks to our contributors! * @chrismbarr * @corydeppen * @danvk * @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) v3.12.0-dev.1 --- * [bugfix] Fix null reference bug in typedef rule (#1345) v3.12.0 --- * Stable release containing changes from the last dev release (v3.12.0-dev.0) v3.12.0-dev.0 --- * [new-rule] `only-arrow-functions` rule (#1318) * [new-rule] `no-unused-new` rule (#1316) * [new-rule-option] `arrow-call-signature` option for `typedef` rule (#1284) * [enhancement] Metadata for every rule (#1311) * [enhancement] `typedef` rule is more flexible about the location of typedefs for arrow functions (#1176) * [enhancement] Failure messages are clearer and more consistent for many rules (#1303, #1307, #1309) * [bugfix] `no-consecutive-blank-lines` now handles lines with only whitespace correctly (#1249) * [bugfix] Correctly load `.json` config files that have a BOM (#1338) Thanks to our contributors! * @allannienhuis * @arnaudvalle * @bencoveney * @chrismbarr * @corydeppen * @HamletDRC * @JoshuaKGoldberg * @timbrown81 * @tomduncalf * @YuichiNukiyama v3.11.0 --- * Stable release containing changes from the last dev release (v3.11.0-dev.0) v3.11.0-dev.0 --- * [new-rule] `linebreak-style` rule (#123) * [new-rule] `no-mergeable-namespace` rule (#843) * [enhancement] Add built-in configurations (#1261) * [enhancement] New vso formatter (#1281) * [new-rule-option] `ignore-interfaces` option for `semicolon` rule (#1233) * [bugfix] `no-default-export` rule handles more default export cases (#1241) Thanks to our contributors! * @cgwrench * @HamletDRC * @lijunle * @paldepind * @patsissons * @schmuli * @YuichiNukiyama v3.10.2 --- * Stable release containing changes from the last dev release (v3.10.0-dev.2) v3.10.0-dev.2 --- * [bugfix] `member-ordering` rule doesn't crash on methods in class expressions (#1252) * [bugfix] `ban` rule handles chained methods appropriately (#1234) Thanks to our contributors! * @marines v3.10.1 --- * Stable release containing changes from the last dev release (v3.10.0-dev.1) v3.10.0-dev.1 --- * [bugfix] `member-ordering` rule doesn't crash on methods in object literals (#1243) v3.10.0 --- * Stable release containing changes from the last dev release (v3.10.0-dev.0) v3.10.0-dev.0 --- * [new-rule] `new-parens` rule (#1177) * [new-rule] `no-default-export` rule (#1182) * [new-rule-option] `order: ...` option for `member-ordering` rule (#1208) * [new-rule-option] "ignore-for-loop" option for `one-variable-per-declaration` rule (#1204) * [enhancement] "no-this-in-function-in-method" option renamed to "check-function-in-method" (#1203) * [bugfix] `semicolon` rule checks export statements (#1155) Thanks to our contributors! * @chrismbarr * @HamletDRC * @larshp * @patsissons * @YuichiNukiyama v3.9.0 --- * Stable release containing changes from the last dev release (v3.9.0-dev.0) v3.9.0-dev.0 --- * [new-rule] `no-namespace` rule (#1133) * [new-rule] `one-variable-per-declaration` rule (#525) * [new-rule-option] "ignore-params" option for `no-inferrable-types` rule (#1190) * [new-rule-option] "no-this-in-function-in-method" option for `no-invalid-this` rule (#1179) * [enhancement] Single line enable/disable comments (#144) * [enhancement] Resolve `extends` packages relative to location of configuration file (#1171) * [enhancement] `Linter` class will throw an error if configuration is of an invalid type (#1167) * [bugfix] `use-isnan` allows assaignments to `NaN` (#1054) * [bugfix] `no-unreachable` handles allows hoisted type aliases (#564) * [bugfix] `member-ordering` rule now checks constructors (#1158) * [bugfix] `--test` CLI command works correctly with specifiying custom rules (#1195) Thanks to our contributors! * @abierbaum * @HamletDRC * @inthemill * @janslow * @JoshuaKGoldberg * @mprobst * @patsissions * @YuichiNukiyama v3.8.1 --- * Stable release containing changes from the last dev release (v3.8.0-dev.1) v3.8.0-dev.1 --- * [bugfix] Allow JS directives at the start of constructors, getters, and setters (#1159) * [bugfix] Remove accidentally included performance profiles from published NPM artifact (#1160) v3.8.0 --- * Stable release containing changes from the last dev release (v3.8.0-dev.0) v3.8.0-dev.0 --- * [new-rule] `no-invalid-this` rule (#1105) * [new-rule] `use-isnan` rule (#1054) * [new-rule] `no-reference` rule (#1139) * [new-rule-option] "allow-pascal-case" option for `variable-name` rule (#1079) * [enhancement] Comments now allowed in `tslint.json` files (#1129) * [enhancement] Smarter `trailing-comma` behavior (#1122) * [enhancement] `semicolon` rule more lenient with arrow-function class members (#1076) * [enhancement] Allow enabling/disabling rules with `//` comments (#1134) * [enhancement] New checkstyle formatter (#250) * [enhancement] Clearer message for `no-var-keyword` rule (#1124) * [bugfix] Loaded configurations are not cached (#1128) * [bugfix] Allow JS directives at the start of class methods (#1144) Thanks to our contributors! * @AndyMoreland * @chrismbarr * @HamletDRC * @JoshuaKGoldberg * @sshev * @unional v3.7.4 --- * Stable release containing changes from the last dev release (v3.7.0-dev.5) v3.7.0-dev.5 --- * [bugfix] Allow JS directives in namespaces (#1115) v3.7.3 --- * Stable release containing changes from the last dev release (v3.7.0-dev.4) v3.7.0-dev.4 --- * [bugfix] Downgrade `findup-sync` dependency (#1108) v3.7.2 --- * Stable release containing changes from the last dev release (v3.7.0-dev.3) v3.7.0-dev.3 --- * [bugfix] `findConfigurationPath` always returns an absolute path (#1093) * [bugfix] Update `findup-sync` dependency (#1080) * [bugfix] `declare global` no longer triggers `no-internal-module` rule (#1069) * [bugfix] Valid JS directives no longer trigger `no-unused-expression` rule (#1050) v3.7.1 --- * Stable release containing changes from the last dev release v3.7.0-dev.2 --- * [bugfix] Improve handling of paths provided via the -c CLI option (#1083) v3.7.0 --- * Stable release containing changes from the last dev release v3.7.0-dev.1 --- * [enhancement] `extends` field for `tslint.json` files (#997) * [enhancement] `--force` CLI option (#1059) * [enhancement] Improve how `Linter` class handles configurations with a `rulesDirectory` field (#1035) * [new-rule] `no-angle-bracket-type-assertion` rule (#639) * [new-rule-option] "allow-undefined-check" option for `triple-equals` rule (#602) * [new-rule-option] "always-prefix" and "never-prefix" option for `interface-name` rule (#512) Thanks to our contributors! * @Arnavion * @chrismbarr * @ChrisPearce * @JoshuaKGoldberg * @patsissonso * @sasidhar * @unional * @vvakame v3.6.0 --- * Stable release containing changes from the last dev release v3.6.0-dev.1 --- * [enhancement] Add `--exclude` CLI option (#915) * [bugfix] Fix `no-shadowed-variable` rule handling of standalone blocks (#1021) * [deprecation] Configuration through `package.json` files (#1020) * [API] Export additional configuration methods from top-level "tslint" module (#1009) Thanks to our contributors! * @blakeembrey * @hamhut1066 * @meowtec v3.5.0 --- * Stable release containing changes from the last dev release v3.5.0-dev.1 --- * [new-rule-option] "ignore-pattern" option for `no-unused-variable` rule (#314) * [bugfix] Fix occassional crash in `no-string-literal` rule (#906) * [enhancement] Tweak behavior of `member-ordering` rule with regards to arrow function types in interfaces (#226) Thanks to our contributors! * @arusakov * @Pajn v3.4.0 --- * Stable release containing changes from the last two dev releases v3.4.0-dev.2 --- * [new-rule-option] "arrow-parameter" option for `typedef` rule (#333) * [new-rule-option] "never" option for `semicolon` rule (#363) * [new-rule-option] "onespace" setting for `typedef-whitespace` rule (#888) * [new-rule-option] `typedef-whitespace` rule can now check spacing on right side of typdef colon (#888) * [enhancement] `member-ordering` rule treats arrow functions as methods (#226) * [bugfix] Handle spaces before typedefs correctly in `typedef-whitespace` rule (#955) * [bugfix] `label-position` rule now allows labels on `for-of` loops (#959) Thanks to our contributors! * @b0r3as * @ChaseMoskal * @Pajn * @pe8ter * @tomduncalf v3.4.0-dev.1 --- * [enhancement] Revamped testing system (#620) * Writing tests for rules is now much simpler with a linter DSL. See exisitng tests in `test/rules/**/*.ts.lint` for examples. * [enhancement] New msbuild formatter (#947) * [bugfix] Fix handling of multiline literals in `trailing-comma` rule (#856) * [bugfix] `one-line` rule correctly checks space between `catch` and opening brace (#925) * [bugfix] `one-line` rule correctly checks multiline variable declarations (#935) * [new-rule-option] New option `check-finally` for `one-line` rule (#925) * __BREAKING CHANGES__ * [bugfix] Report error when a rule in the config file is not found (#598) Thanks to our contributors! * @mmv * @pe8ter v3.3.0 --- * [bugfix] Tweak TSLint build so TSLint works with typescript@next (#926) v3.3.0-dev.1 --- * [bugfix] Correctly handle more than one custom rules directory (#928) v3.2.2 --- * Stable release containing changes from the last dev release v3.2.2-dev.1 --- * [enhancement] Throw an error if a path to a directory of custom rules is invalid (#910) * [new-rule-option] "jsx-single" and "jsx-double" options for `quotemark` rule (#673) * [bugfix] Handle paths to directories of custom rules more accurately * [bugfix] `no-unused-expression` rule handles `await` statements correctly (#887) v3.2.1 --- * Stable release containing changes from the last dev release v3.2.1-dev.1 --- * [enhancement] automatically generate a `tslint.json` file with new `--init` CLI command (#717) * [bugfix] `no-var-keyword` rule detects the use of `var` in all types of `for` loops (#855) v3.2.0 --- * Stable release containing changes from last two dev releases v3.2.0-dev.2 --- * [bugfix] formatters are now exported correctly to work with TS 1.8 (#863) v3.2.0-dev.1 --- * [bugfix] fixed bug in how custom rules directories are registered (#844) * [enhancement] better support for globs in CLI (#827) * [new-rule] `no-null-keyword` rule (#722) v3.1.1 --- * Bump TypeScript peer dependency to `>= 1.7.3` due to `const enum` incompatibility (#832) v3.1.0 --- * [bugfix] build with TS v1.7.3 to fix null pointer exception (#832) * [bugfix] fixed false positive in `no-require-imports` rule (#816) v3.1.0-dev.1 --- * [bugfix] fixed `no-shadowed-variable` false positives when handling destructuring in function params (#727) * [enhancement] `rulesDirectory` in `tslint.json` now supports multiple file paths (#795) v3.0.0 --- * [bugfix] `member-access` rule now handles object literals and get/set accessors properly (#801) * New rule options: `check-accessor` and `check-constructor` * All the changes from the following releases, including some **breaking changes**: * `3.0.0-dev.3` * `3.0.0-dev.2` * `3.0.0-dev.1` * `2.6.0-dev.2` * `2.6.0-dev.1` v3.0.0-dev.3 --- * TypeScript is now a peerDependency (#791) * [bugfix] `no-unused-variable` rule with `react` option works with self-closing JSX tags (#776) * [bugfix] `use-strict` bugfix (#544) v3.0.0-dev.2 --- * [new-rule-option] "react" option for `no-unused-variable` rule (#698, #725) * [bugfix] Fix how `Linter` is exported from "tslint" module (#760) * [bugfix] `no-use-before-declare` rule doesn't crash on uncompilable code (#763) v3.0.0-dev.1 --- * **BREAKING CHANGES** * Rearchitect TSLint to use external modules instead of merged namespaces (#726) * Dependencies need to be handled differently now by custom rules and formatters * See the [PR](https://github.com/palantir/tslint/pull/726) for full details about this change * `no-trailing-comma` rule removed, it is replaced by the `trailing-comma` rule (#687) * Rename `sort-object-literal-keys` rule to `object-literal-sort-keys` (#304, #537) * `Lint.abstract()` has been removed (#700) * [new-rule] `trailing-comma` rule (#557, #687) * [new-rule-option] "ban-keywords" option for `variable-name` rule (#735, #748) * [bugfix] `typedef` rule now handles `for-of` loops correctly (#743) * [bugfix] Handle tslint.json utf-8 files which have a BOM correctly (#90) v2.6.0-dev.2 --- * Upgrade TypeScript compiler to `v1.7.0-dev.20151003` * [bugfix] `no-unused-expression` rule now handles yield expressions properly (#706) v2.6.0-dev.1 --- * Upgrade TypeScript compiler to `v1.7.0-dev.20150924` v2.5.1 --- * [new-rule] no-inferrable-types rule (#676) * [new-rule-option] "avoid-escape" option for quotemark rule (#543) * [bugfix] type declaration for tslint external module #686 * [enhancement] `AbstractRule` and `AbstractFormatter` are now abstract classes (#631) * Note: `Lint.abstract()` is now deprecated v2.5.0 --- * Use TypeScript compiler `v1.6.2` * [bugfixes] #637, #642, #650, #652 * [bugfixes] fix various false positives in `no-unused-variable` rule (#570, #613, #663) * Update project setup for latest VSCode (#662) v2.5.0-beta --- * Use TypeScript compiler `v1.6.0-beta` * [bugfix] Fix `no-internal-module` false positives on nested namespaces (#600) * [docs] Add documentation for `sort-object-literal-keys` rule v2.5.0-dev.5 --- * Upgrade TypeScript compiler to `v1.7.0-dev.20150828` * [bugfix] Handle .tsx files appropriately (#597, #558) v2.5.0-dev.4 --- * Upgrade TypeScript compiler to `v1.6.0-dev.20150825` v2.5.0-dev.3 --- * Upgrade TypeScript compiler to `v1.6.0-dev.20150821` v2.5.0-dev.2 --- * Upgrade TypeScript compiler to `v1.6.0-dev.20150811` * [bug] fix `whitespace` false positive in JSX elements (#559) v2.5.0-dev.1 --- * Upgrade TypeScript compiler to `v1.6.0-dev.20150805` * [enhancement] Support `.tsx` syntax (#490) v2.4.5 --- * [bugfix] fix false positives on `no-shadowed-variable` rule (#500) * [enhancement] add `allow-trailing-underscore` option to `variable-name` rule v2.4.4 --- * [bugfix] remove "typescript" block from package.json (#606) v2.4.3 --- * [new-rule] `no-conditional-assignment` (#507) * [new-rule] `member-access` (#552) * [new-rule] `no-internal-module` (#513) * [bugfix] small fixes to `sample.tslint.json` (#545) * [bugfix] fix README docs for quotemark and indent (#523) * [enhancement] update `findup-sync` and `underscore.string` dependencies * [enhancement] add `"typescript"` field to `package.json` (#560) * [enhancement] small improvements to CLI help text * [enhancement] expose raw failures array in the JS API (#477) v2.4.2 --- * [bug] remove npm-shrinkwrap.json from the published package v2.4.0 --- * Upgraded Typescript compiler to 1.5.3 * [bugs] #332, #493, #509, #483 * [bug] fix error message in `no-var-keyword` rule * [enhancement] CI tests are now run on node v0.12 in addition to v0.10 * **BREAKING** * `-f` option removed from CLI v2.3.1-beta --- * [bugs] #137 #434 #451 #456 * [new-rule] `no-require-imports` disallows `require()` style imports * [new-rule] `no-shadowed-variable` moves over shadowed variable checking from `no-duplicate-variable` into its own rule * **BREAKING** * `no-duplicate-variable` now only checks for duplicates within the same block scope; enable `no-shadowed-variable` to get duplicate-variable checking across block scopes * [enhancement] `no-duplicate-variable`, `no-shadowed-variable`, and `no-use-before-declare` now support ES6 destructuring * [enhancement] tslint CLI now uses a default configuration if no config file is found v2.3.0-beta --- * [bugs] #401 #367 #324 #352 * [new-rule] `no-var-keyword` disallows `var` in favor of `let` and `const` * [new-rule] `sort-object-literal-keys` forces object-literal keys to be sorted alphabetically * Add support for ES6 destructuring and module syntax (affects `variable-name`, `no-use-before-declare`, `whitespace` and `no-unused-variable`) * Add support for ES6 for-of and spread operator syntax * Use tsconfig.json & JSCS in the build system v2.2.0-beta --- * Upgraded Typescript compiler to 1.5.0-beta * **BREAKING CHANGES** * due to changes to the typescript compiler API, old custom rules may no longer work and may need to be rewritten * the JSON formatter's line and character positions are now back to being 0-indexed instead of 1-indexed * [bugs] #328 #334 #319 #351 #365 #254 * [bug] fixes for tslint behavior around template strings (fixes #357, #349, #332, and more) * [new-rule] `align` rule now enforces vertical alignment on parameters, arguments, and statements * [new-rule] `switch-default` enforces a `default` case in `switch` statements * [feature] `no-duplicate-variable` rule now additionally checks if function parameters have been shadowed * Additional fixes to existing rules to work as before with the typescript 1.5 compiler v2.1.1 --- * [bugs] #292 #293 #295 #301 #302 * Some internal refactoring * Added Windows CI testing (appveyor) v2.1.0 --- * Fix crash on Windows v2.0.1 --- * Upgraded Typescript compiler to 1.4 * **BREAKING CHANGES** * typedef rule options were modified: * index-signature removed as no longer necessary * property-signature renamed to property-declaration * variable-declarator renamed to variable-declaration * member-variable-declarator renamed to member-variable-declaration * typedef-whitespace rule options were modified: * catch-clause was removed as invalid * further options were added, see readme for more details * due to changes to the typescript compiler API, old custom rules may no longer work and may need to be rewritten * the JSON formatter's line and character positions are now 1-indexed instead of 0-indexed v1.2.0 --- * [bug] #245 v1.0.1 --- * [bug] #238 v1.0.0 --- * upgrade TypeScript compiler to 1.3 * **BREAKING CHANGES** * all error messages now start with a lower-case character and do not end with a period * all rule options are consistent in nomenclature. The `typedef` and `typedef-whitespace` rules now take in hyphenated options * `unused-variables` rule cannot find unused private variables defined in the constructor due to a bug in 1.3 compiler * `indent` rule has changed to only check for tabs or spaces and not enforce indentation levels v0.4.12 --- * multiple files with -f on cli * config file search starts with input file v0.4.11 --- * [bugs] #136, #163 * internal refactors v0.4.10 --- * [bugs] #138, #145, #146, #148 v0.4.9 --- * [new-rule] `no-any` disallows all uses of `any` * [bug] `/* tslint:disable */` now disables semicolon rule as well * [bug] delete operator no longer results in a false positive for `no-unused-expression` v0.4.8 --- * [new-rule] `no-var-requires` disallows require statements not part of an import statement * [new-rule] `typedef` rule also checks for member variables * [bug] `no-unused-variable` no longer triggers false positives for class members labeled only `static` * [bug] `no-unused-expression` no longer triggers false positives for `"use strict";` expressions * [bug] `use-strict` works correctly on function declarations * [bug] config file is now discoverable from other drives on Windows v0.4.7 --- * [new-rule] added `no-unused-expression` rule which disallows unused expression statements * [feature] the `check-operator` option for the `whitespace` rule now checks whitespace around the => token * [bug] `no-use-before-declare-rule` no longer triggers false positives for member variables of classes used before the class is declared * [bug] semicolon at end of file no longer triggers false positives for `whitespace` rule * [bug] hoisted functions no longer cause false positives for the `no-unreachable` rule * [bug] the rule loader no longer transforms/ignores the leading and trailing underscores and dashes of rule names in the config file * [bug] `export import` statements no longer false positives for `no-unused-variable-rule` * [docs] added documentation for creating custom rules and formatters * [docs] added sample `tslint.json` file, under `docs/sample.tslint.json` v0.4.6 --- * [build] migrated build to use `grunt-ts` instead of `grunt-typescript` * [feature] `package.json` now contains a `tslintConfig` paramater to allow users to specify the location of the configuration file there * [feature] tslint now searches for the configuration file in the user's home directory if not found in the current path * [bug] unbraced conditionals no longer cause false positives for the `no-unreachable` rule v0.4.5 --- * [feature] `no-unused-variable` no longer checks parameters by defualt. Parameters are now only checked if the `check-parameters` option is set. * [bug] `no-unused-variable` parameter check no longer fails on variable argument parameters (like ...args) and on cases where the parameters are broken up by newlines. v0.4.4 --- * [bug] `no-unused-variable` validates function parameters and constructor methods * [bug] `no-empty` and `no-trailing-comma` rules handle empty objects v0.4.3 --- * [new-rule] `no-unused-variable` * [new-rule] `no-trailing-comma` * [new-rule] `no-use-before-declare` * [feature] support `--version` in CLI * [feature] expose rule names to custom formatters * [feature] add `verbose` formatter * [bug] `no-empty` allows constructors with member declaration parameters * [bug] CLI supports `--help` * [bug] `max-line-length` allows CRLF endings tslint-5.9.1/LICENSE000066400000000000000000000261351322551053300140560ustar00rootroot00000000000000 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: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) 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 (d) 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 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 "{}" 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 file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. 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. 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-5.9.1/README.md000066400000000000000000000121171322551053300143230ustar00rootroot00000000000000[![NPM version](https://badge.fury.io/js/tslint.svg)](http://badge.fury.io/js/tslint) [![Downloads](http://img.shields.io/npm/dm/tslint.svg)](https://npmjs.org/package/tslint) [![Circle CI](https://circleci.com/gh/palantir/tslint.svg?style=svg)](https://circleci.com/gh/palantir/tslint) TSLint ====== TSLint is an extensible static analysis tool that checks [TypeScript](https://github.com/Microsoft/TypeScript) code for readability, maintainability, and functionality errors. It is widely supported across modern editors & build systems and can be customized with your own lint rules, configurations, and formatters. TSLint supports: - an extensive set of core rules - custom lint rules - custom formatters (failure reporters) - inline disabling and enabling of rules with comment flags in source code - configuration presets (`tslint:latest`, `tslint-react`, etc.) and plugin 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 2015](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.WebAnalyzer), [Visual Studio 2017](https://marketplace.visualstudio.com/items?itemName=RichNewman.TypeScriptAnalyzer), [Visual Studio code](https://marketplace.visualstudio.com/items?itemName=eg2.tslint), [WebStorm](https://www.jetbrains.com/webstorm/help/tslint.html) and [more](https://palantir.github.io/tslint/usage/third-party-tools/) Installation & Usage ------------ Please refer to the full installation & usage documentation on the [TSLint website](https://palantir.github.io/tslint/). There, you'll find information about - [configuration](https://palantir.github.io/tslint/usage/configuration/), - [core rules](https://palantir.github.io/tslint/rules/), - [core formatters](https://palantir.github.io/tslint/formatters/), and - [customization of TSLint](https://palantir.github.io/tslint/develop/custom-rules/). - [inline disabling and enabling of rules with comment flags](https://palantir.github.io/tslint/usage/rule-flags/) Custom Rules & Plugins ------------ #### Custom rule sets from Palantir - [tslint-react](https://github.com/palantir/tslint-react) - Lint rules related to React & JSX. - [tslint-blueprint](https://github.com/palantir/tslint-blueprint) - Lint rules to enforce best practices with [blueprintjs libraries](https://github.com/palantir/blueprint) #### Custom rule sets from the community If we don't have all the rules you're looking for, you can either write your own [custom rules](https://palantir.github.io/tslint/develop/custom-rules/) or use rules implementations developed by the community. The repos below are a good source of custom rules: - [ESLint rules for TSLint](https://github.com/buzinas/tslint-eslint-rules) - Improve your TSLint with the missing ESLint Rules - [tslint-microsoft-contrib](https://github.com/Microsoft/tslint-microsoft-contrib) - A set of TSLint rules used on some Microsoft projects - [codelyzer](https://github.com/mgechev/codelyzer) - A set of tslint rules for static code analysis of Angular TypeScript projects - [vrsource-tslint-rules](https://github.com/vrsource/vrsource-tslint-rules) - [tslint-immutable](https://github.com/jonaskello/tslint-immutable) - TSLint rules to disable mutation in TypeScript - [tslint-consistent-codestyle](https://github.com/ajafff/tslint-consistent-codestyle) - TSLint rules to enforce consistent code style in TypeScript - [tslint-sonarts](https://github.com/SonarSource/SonarTS) - Bug-finding rules based on advanced code models to spot hard to find errors in TypeScript - [tslint-clean-code](https://github.com/Glavin001/tslint-clean-code) - A set of TSLint rules inspired by the Clean Code handbook - [rxjs-tslint-rules](https://github.com/cartant/rxjs-tslint-rules) - TSLint rules for RxJS Development ----------- Prerequisites: - `node` v7+ - `yarn` v1.0+ #### Quick Start ```bash git clone git@github.com:palantir/tslint.git --config core.autocrlf=input --config core.eol=lf yarn yarn compile yarn test ``` Creating a new release ---------------------- 1. Bump the version number in `package.json` and `src/linter.ts` 2. Add release notes in `CHANGELOG.md` - Use `./scripts/generate-changelog.js` (after building it with `tsc -p scripts`) to generate the changelog diff. This script expects a [Github.com personal access token](https://github.com/settings/tokens) to exist at `~/github_token.txt` with "repo" permissions. 4. Commit with message `Prepare release ` 5. Push your branch to GitHub and make a PR 6. Once your PR is merged, wait for the tests to pass on CircleCI for develop 7. Create a "Release" on GitHub with the proper tag version and notes from the changelog. - The tag should be identical to the version in `package.json` 8. Run `yarn run publish:local` tslint-5.9.1/appveyor.yml000066400000000000000000000004041322551053300154300ustar00rootroot00000000000000environment: matrix: - nodejs_version: "4.1.2" - nodejs_version: "5.7" - nodejs_version: "6.1" install: - ps: Install-Product node $env:nodejs_version - npm install test_script: - node --version - npm --version - npm run verify build: off tslint-5.9.1/bin/000077500000000000000000000000001322551053300136125ustar00rootroot00000000000000tslint-5.9.1/bin/tslint000077500000000000000000000000631322551053300150540ustar00rootroot00000000000000#!/usr/bin/env node require("../lib/tslint-cli"); tslint-5.9.1/docs/000077500000000000000000000000001322551053300137725ustar00rootroot00000000000000tslint-5.9.1/docs/Gemfile000066400000000000000000000000611322551053300152620ustar00rootroot00000000000000source 'https://rubygems.org' gem 'github-pages' tslint-5.9.1/docs/_config.yml000066400000000000000000000010351322551053300161200ustar00rootroot00000000000000# Site settings title: TSLint email: your-email@domain.com description: > # this means to ignore newlines until "baseurl:" TSLint documentation. A linter for the TypeScript language. baseurl: "/tslint" # the subpath of your site, e.g. /blog/ url: "https://palantir.github.io/" # the base hostname & protocol for your site twitter_username: PalantirTech github_username: palantir/tslint # Build settings markdown: kramdown markdown_ext: md exclude: [vendor] page_gen: - data: rules template: rule name: ruleName dir: rules tslint-5.9.1/docs/_data/000077500000000000000000000000001322551053300150425ustar00rootroot00000000000000tslint-5.9.1/docs/_data/develop_sidebar.json000066400000000000000000000013041322551053300210620ustar00rootroot00000000000000{ "title": "Develop", "url": "/develop", "links": [ { "title": "Custom Rules", "url": "/custom-rules/" }, { "title": "Performance Tips", "url": "/custom-rules/performance-tips.html" }, { "title": "Walker Design", "url": "/custom-rules/walker-design.html" }, { "title": "Custom Formatters", "url": "/custom-formatters/" }, { "title": "Contributing", "url": "/contributing/" }, { "title": "Docs Development", "url": "/docs/" }, { "title": "Testing Rules", "url": "/testing-rules" } ] } tslint-5.9.1/docs/_data/usage_sidebar.json000066400000000000000000000010461322551053300205330ustar00rootroot00000000000000{ "title": "Usage", "url": "/usage", "links": [ { "title": "CLI", "url": "/cli/" }, { "title": "Library", "url": "/library/" }, { "title": "Configuration", "url": "/configuration/" }, { "title": "Rule Flags", "url": "/rule-flags/" }, { "title": "Type Checking", "url": "/type-checking/" }, { "title": "Third-Party Tools", "url": "/third-party-tools/" } ] }tslint-5.9.1/docs/_includes/000077500000000000000000000000001322551053300157375ustar00rootroot00000000000000tslint-5.9.1/docs/_includes/footer.html000066400000000000000000000060071322551053300201260ustar00rootroot00000000000000 tslint-5.9.1/docs/_includes/head.html000066400000000000000000000010231322551053300175220ustar00rootroot00000000000000 {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} tslint-5.9.1/docs/_includes/header.html000066400000000000000000000020461322551053300200570ustar00rootroot00000000000000
{% if page.title == site.title %} {% endif %}
tslint-5.9.1/docs/_includes/peer_dependencies.md000066400000000000000000000007131322551053300217230ustar00rootroot00000000000000##### Peer dependencies The `typescript` package is a peer dependency of TSLint. This allows you to update the compiler independently from the linter. This also means that `tslint` will have to use the same version of `tsc` which is used to actually compile your sources. Although the peer dependency allows installing the latest nightly releases of `typescript@next`, be aware that these might include breaking changes that cause the linter to malfunction.tslint-5.9.1/docs/_includes/rule_list.html000066400000000000000000000017421322551053300206330ustar00rootroot00000000000000tslint-5.9.1/docs/_includes/sidebar.html000066400000000000000000000010061322551053300202330ustar00rootroot00000000000000{% assign baseurl = site.baseurl | append: include.sidebar.url %} tslint-5.9.1/docs/_layouts/000077500000000000000000000000001322551053300156315ustar00rootroot00000000000000tslint-5.9.1/docs/_layouts/default.html000066400000000000000000000003221322551053300201400ustar00rootroot00000000000000 {% include head.html %} {% include header.html %}
{{ content }} {% include footer.html %}
tslint-5.9.1/docs/_layouts/formatter.html000066400000000000000000000004001322551053300205140ustar00rootroot00000000000000--- layout: page --- {{page.description | markdownify}} {% if page.descriptionDetails %} {{page.descriptionDetails | markdownify}} {% endif %} {% if page.sample %}
Sample Output
{{page.sample | xml_escape | markdownify}}
{% endif %} tslint-5.9.1/docs/_layouts/page.html000066400000000000000000000021131322551053300174300ustar00rootroot00000000000000--- layout: default ---
{% unless page.hideTitle %}

{{ page.title }}

{{ page.hideTitle }}

{% endunless %} {{ content }}
{% comment %} There has to be a better way than this... {% endcomment %} {% capture develop_len %}{{site.data.develop_sidebar.url | size}}{% endcapture %} {% assign maybe_develop_url = page.url | remove: site.baseurl | truncate: develop_len,"" %} {% capture usage_len %}{{site.data.usage_sidebar.url | size}}{% endcapture %} {% assign maybe_usage_url = page.url | remove: site.baseurl | truncate: usage_len,"" %} {% if maybe_develop_url == site.data.develop_sidebar.url %} {% include sidebar.html sidebar=site.data.develop_sidebar %} {% elsif maybe_usage_url == site.data.usage_sidebar.url %} {% include sidebar.html sidebar=site.data.usage_sidebar %} {% endif %}
tslint-5.9.1/docs/_layouts/post.html000066400000000000000000000005711322551053300175070ustar00rootroot00000000000000--- layout: default ---

{{ page.title }}

{{ content }}
tslint-5.9.1/docs/_layouts/rule.html000066400000000000000000000022741322551053300174730ustar00rootroot00000000000000--- layout: page --- {{page.description | markdownify}} {% if page.descriptionDetails %} {{page.descriptionDetails | markdownify}} {% endif %} {% if page.rationale %}
Rationale
{{page.rationale | markdownify}} {% endif %} {% if page.typescriptOnly or page.hasFix or page.requiresTypeInfo %}
Notes:
{% if page.typescriptOnly %} TS Only {% endif %} {% if page.hasFix %} Has Fixer {% endif %} {% if page.requiresTypeInfo %} Requires Type Info {% endif %}
{% endif %}

Config

{{page.optionsDescription | markdownify}}
Examples
{% for example in page.optionExamples %}
"{{page.ruleName}}": {{example}}
{% endfor %}
Schema
{{page.optionsJSON}}
tslint-5.9.1/docs/_posts/000077500000000000000000000000001322551053300153015ustar00rootroot00000000000000tslint-5.9.1/docs/_posts/2015-12-10-a-new-tslint-website.md000066400000000000000000000036741322551053300226420ustar00rootroot00000000000000--- layout: post title: "A New TSLint Website" date: 2015-12-10 20:15:21 --- As TSLint has grown in usage and popularity alongside of TypeScript, it also has evolved in terms of functionality and complexity. Today, all sorts of projects and products, from [Angular 2][1] to the [TypeScript compiler itself][2] use TSLint to help keep their code high-quality. Unfortunately, we've done a poor job of scaling the documentation and guides for TSLint as it has grown. For example, the only good way to see the possible rules TSLint can enforce and what they can do is to scroll through the quite-long [TSLint README][3]. Each rule is accompanied by a short description of its functionality, but nowhere does it explain why the rule is actually useful. There's also a short description of the rule's options, but the syntax for specifying these options is often unclear. This website, in its current, very simple form, marks the beginning of a renewed focus on developer and user experience. But it's just the tip of the iceberg in changes to come - other things in progress include: * [A documentation overhaul][4] that will provide more comprehensive and clear documentation on TSLint and will make it easier to navigate that documentation. * [A new `--init` feature][5] in the TSLint CLI that will make it easier to generate a sensible initial `tslint.json` config file. * [An improved contributor experience][6] that will make things easier for those who want to contribute code to TSLint. Feedback is always great, so please comment on any of the above GitHub issues and let us know what you would like to see to make TSLint user experience even better! [1]: https://angular.io/ [2]: https://github.com/Microsoft/TypeScript [3]: https://github.com/palantir/tslint/blob/409aa6e4aa4b63da11fd61e15b26b0100cf1e845/README.md [4]: https://github.com/palantir/tslint/issues/830 [5]: https://github.com/palantir/tslint/pull/871 [6]: https://github.com/palantir/tslint/issues/831 tslint-5.9.1/docs/_posts/2016-03-31-sharable-configurations-rules.md000066400000000000000000000060001322551053300246070ustar00rootroot00000000000000--- layout: post title: "Sharable Configurations and Rules" date: 2016-03-31 15:19:00 --- With the release of [TSLint v3.7.0][0] comes a few new features that will make configuration files (aka [`tslint.json` files][1]) easier to maintain and share. The crux of the changes is a new `extends` field, which when provided indicates that a configuration file augments another configuration file. ### Example ### Let's imagine you've created some custom rules and want to share them with others. You also have a couple of configurations for them you want to share. Here's the layout of our NPM package, which we'll call `shared-tslint-rules`. We have a directory with rules, as well as a few different config files for TSLint. ``` shared-tslint-rules ├── package.json ├── rules │   ├── noAdditionRule.js │   ├── noErrorsRule.js │   └── noExcessiveCommentingRule.js ├── tslint-base.json ├── tslint-config.json └── tslint-crazy-config.js ``` Our starting-point config file just references the directory the custom rules are in but doesn't enable any of them: **tslint-base.json**: ```json { "rulesDirectory": "./rules" } ``` We also want to provide a sane default config for our rules. Notice how it extends our base config, so we don't have to redeclare `rulesDirectory` here: **tslint-config.json**: ```json { "extends": "./tslint-base.json", "rules": { "no-errors": true, "no-addition": false } } ``` Finally, we can even make a crazy config file for fun that gives you back a different config each time you run TSLint. Notice how this is a `.js` file that exports an object: **tslint-crazy-config.js** ```js module.exports = { extends: "./tslint-base.json", rules: { "no-excessive-commenting": [true, {maxComments: Math.random() * 10}] } }; ``` Finally, we have our `package.json` file which references our base config file through its `main` field: **package.json**: ```json { "name": "shared-tslint-rules", "version": "1.0.0", "description": "Some TSLint rules that are great!", "main": "tslint-base.json", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "MIT" } ``` We can publish our package on NPM to let the world use it! --- Now let's say we're a user, and we want to use the custom rules above to lint our code. First, we'll make sure we have the necessary npm packages installed: ``` npm install -g tslint shared-tslint-rules ``` Then, in our `tslint.json` file for our project, we can reference the package of custom rules with `extends`: ``` { "extends": "shared-tslint-rules/tslint-config", "rules": { "no-addition": true } } ``` and that's all we have to do to use the custom rules! We can now run TSLint as we would normally and see any lint errors produced by the custom rules: ``` tslint -c path/to/tslint.json my/files/**/to/lint.ts ``` [0]: https://github.com/palantir/tslint/releases [1]: {{ site.baseurl }}/usage/tslint-json tslint-5.9.1/docs/_posts/2016-11-17-new-for-4.0.md000066400000000000000000000071421322551053300205350ustar00rootroot00000000000000--- 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 tslint-5.9.1/docs/_sass/000077500000000000000000000000001322551053300151025ustar00rootroot00000000000000tslint-5.9.1/docs/_sass/_base.scss000066400000000000000000000066311322551053300170560ustar00rootroot00000000000000/** * Reset some basic elements */ body, h1, h2, h3, h4, h5, h6, p, blockquote, pre, hr, dl, dd, ol, ul, figure { margin: 0; padding: 0; } /** * Set `margin-bottom` to maintain vertical rhythm */ h1, h2, h3, h4, h5, h6, p, blockquote, pre, ul, ol, dl, figure, %vertical-rhythm { margin-bottom: 1rem; } /** * Images */ img { max-width: 100%; vertical-align: middle; } /** * Figures */ figure > img { display: block; } figcaption { font-size: $small-font-size; } /** * Clearfix */ %clearfix { &:after { content: ""; display: table; clear: both; } } /** * Icons */ .icon { > svg { display: inline-block; width: 16px; height: 16px; vertical-align: middle; path { fill: $text-color; } } } /** * Rules & Feature Badges */ .rules-list { list-style: none; margin: 0 !important; //need to override the `main-content ul` selector > li { &:nth-child(odd) { a { background-color: rgba(0, 0, 0, .03); } } a { display: block; border-left: 3px solid transparent; text-decoration: none; padding: .75rem; &:hover { background-color: rgba(0, 0, 0,.075); border-left-color: #159957; } } } } .rule-features { //This is the container for a list of feature badges display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; } .feature { //This is the setup for the a feature badge display: inline-block; margin-right: 2px; padding: 2px 4px; font-weight: 700; line-height: 1; text-align: center; white-space: nowrap; vertical-align: baseline; border: 1px solid transparent; border-radius: .25rem; cursor: help; &:before { //This is the setup for the icon that appears inside the badge display: inline-block; margin-right: 2px; } &.feature-sm { //This class is added to make the feature badge smaller. This is used on the rules list padding: 1px 3px; font-size: 75%; } &.feature-ts-only { //This feature badge is added to rules that are "TypeScript Only" background-color: #FCF8E3; border-color: #FAF2CC; color: #8A6D3B; &:before { content: "\1F4C4"; //"page facing up" icon - http://www.fileformat.info/info/unicode/char/1F4C4/index.htm } } &.feature-fixer { //This feature badge is added to rules that have an auto-fixer background-color: #DFF0D8; border-color: #D0E9C6; color: #3C763D; &:before { content: "\1f527"; //"wrench" icon - http://www.fileformat.info/info/unicode/char/1f527/index.htm } } &.feature-requires-type-info { //This feature badge is added to rules that require type information background-color: #F2DEDE; border-color: #EBCCCC; color: #A94442; &:before { content: "\2139"; //"information source" icon - http://www.fileformat.info/info/unicode/char/2139/index.htm //Surround it with a blue circle border-radius: 50%; background: #0078D7; color: #FFF; width: 1em; } } } tslint-5.9.1/docs/_sass/_cayman.scss000066400000000000000000000163751322551053300174220ustar00rootroot00000000000000$large-breakpoint: 64em; $medium-breakpoint: 36em; @mixin large { @media screen and (min-width: #{$large-breakpoint}) { @content; } } @mixin medium { @media screen and (min-width: #{$medium-breakpoint}) and (max-width: #{$large-breakpoint}) { @content; } } @mixin small { @media screen and (max-width: #{$medium-breakpoint}) { @content; } } * { box-sizing: border-box; } body { padding: 0; margin: 0; font-family: $font-stack; font-size: $base-font-size; line-height: $base-line-height; color: $text-color; } a { color: $link-color; text-decoration: none; &:hover { text-decoration: underline; } &:visited { color: $link-visited-color; } } h1 { font-size: 2.5rem; } h2 { font-size: 2rem; } h3 { font-size: 1.6rem; } h4 { font-size: 1.4rem; } h5 { font-size: 1.2rem; } h6 { font-size: 1rem; } /** * Site header */ $header-content-color: rgba(255, 255, 255, 0.7); $header-hover-color: rgba(255, 255, 255, 0.8); .site-header { border-bottom: 1px solid rgba(white, 0.2); padding: 0 20px; min-height: 56px; @extend %clearfix; } .site-title { font-size: 26px; line-height: 56px; margin-bottom: 0; float: left; &, &:visited { color: $header-content-color; } &:hover { color: $header-hover-color; text-decoration: none; } @include small { display: block; text-align: left; } } .site-nav { float: right; line-height: 56px; .page-link { &, &:visited { color: $header-content-color; } &:hover { color: $header-hover-color; text-decoration: none; } line-height: $base-line-height; // Gaps between nav items, but not on the first one &:not(:first-child) { margin-left: 20px; } @include small { display: block; text-align: left; &:not(:first-child) { margin-left: 0; } } } } .btn { display: inline-block; margin-bottom: 1rem; background-color: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.2); border-style: solid; border-width: 1px; border-radius: 0.3rem; transition: color 0.2s, background-color 0.2s, border-color 0.2s; &, &:visited { color: $header-content-color; } &:hover { color: $header-hover-color; text-decoration: none; background-color: rgba(255, 255, 255, 0.2); border-color: rgba(255, 255, 255, 0.3); } + .btn { margin-left: 1rem; } @include large { padding: 0.75rem 1rem; } @include medium { padding: 0.6rem 0.9rem; font-size: 0.9rem; } @include small { display: block; width: 100%; padding: 0.75rem; font-size: 0.9rem; + .btn { margin-top: 1rem; margin-left: 0; } } } .header { color: #fff; text-align: center; background-color: #159957; background-image: linear-gradient(120deg, #155799, #159957); } .page-header { @include large { padding: 3rem; } @include medium { padding: 2rem; } @include small { padding: 1rem; } } .project-name { margin-top: 0; margin-bottom: 0.1rem; @include large { font-size: 3.25rem; } @include medium { font-size: 2.25rem; } @include small { font-size: 1.75rem; } } .project-tagline { margin-bottom: 2rem; font-weight: normal; opacity: 0.7; @include large { font-size: 1.25rem; } @include medium { font-size: 1.15rem; } @include small { font-size: 1rem; } } .main-content { :first-child { margin-top: 0; } @include large { max-width: 68rem; padding: 2rem 6rem; margin: 0 auto; font-size: 1.1rem; } @include medium { padding: 2rem 4rem; font-size: 1.1rem; } @include small { padding: 2rem 1rem; font-size: 1rem; } img { max-width: 100%; } h1, h2, h3, h4, h5, h6 { margin-top: 2rem; margin-bottom: 1rem; font-weight: normal; color: $heading-color; } p { margin-bottom: 1rem; } code { padding: 2px 4px; font-family: $code-font-stack; font-size: 0.9rem; color: #383e41; background-color: #f3f6fa; border-radius: 0.3rem; } pre { padding: 0.8rem; margin-top: 0; margin-bottom: 1rem; font: 1rem $code-font-stack; color: #567482; word-wrap: normal; background-color: #f3f6fa; border: solid 1px #dce6f0; border-radius: 0.3rem; > code { padding: 0; margin: 0; font-size: 0.9rem; color: #567482; word-break: normal; white-space: pre; background: transparent; border: 0; } } .highlight { margin-bottom: 1rem; pre { margin-bottom: 0; word-break: normal; } } .highlight pre, pre { padding: 0.8rem; overflow: auto; font-size: 0.9rem; line-height: 1.45; border-radius: 0.3rem; -webkit-overflow-scrolling: touch; } pre code, pre tt { display: inline; max-width: initial; padding: 0; margin: 0; overflow: initial; line-height: inherit; word-wrap: normal; background-color: transparent; border: 0; &:before, &:after { content: normal; } } ul, ol { margin-top: 0; margin-left: 30px; margin-bottom: 1rem; ul, ol { margin-bottom: 0; } } blockquote { padding: 0 1rem; margin-left: 0; color: #819198; border-left: 0.3rem solid #dce6f0; > :first-child { margin-top: 0; } > :last-child { margin-bottom: 0; } } table { display: block; width: 100%; overflow: auto; word-break: normal; word-break: keep-all; // For Firefox to horizontally scroll wider tables. -webkit-overflow-scrolling: touch; th { font-weight: bold; } th, td { padding: 0.5rem 1rem; border: 1px solid #e9ebec; } } dl { padding: 0; dt { padding: 0; margin-top: 1rem; font-size: 1rem; font-weight: bold; } dd { padding: 0; margin-bottom: 1rem; } } hr { height: 2px; padding: 0; margin: 1rem 0; background-color: #eff0f1; border: 0; } } .page { @extend %clearfix; width: 100%; } .page-content { width: 80%; padding: 1rem; float: left; } .page-sidebar { width: 20%; padding: 1rem; float: left; .active { font-style: italic; } } .sidebar-title { border-bottom: 1px solid $heading-color; } ul.sidebar-links { list-style: none; margin-left: 0; h6 { margin-bottom: 0.33rem; } } /** * Posts */ ul.post-list { margin-left: 0; list-style: none; > li { margin-bottom: 1rem; } } .post-meta { font-size: $small-font-size; color: #828282; font-style: italic; } .post-link { display: inline-block; color: inherit; } .post-header { margin-bottom: 2rem; } .post-title { letter-spacing: -1px; line-height: 1; } /** * Site footer */ .site-footer { padding-top: 2rem; margin-top: 2rem; border-top: solid 1px #eff0f1; font-size: 0.9rem; } ul.contact-list, ul.social-media-list { list-style: none; margin-left: 0; } .footer-col-wrapper { @extend %clearfix; } .footer-col { float: left; } .footer-col-2 { float: right; @include small { float: left; } } tslint-5.9.1/docs/_sass/_normalize.scss000066400000000000000000000171651322551053300201500ustar00rootroot00000000000000/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ /** * 1. Set default font family to sans-serif. * 2. Prevent iOS text size adjust after orientation change, without disabling * user zoom. */ html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ } /** * Remove default margin. */ body { margin: 0; } /* HTML5 display definitions ========================================================================== */ /** * Correct `block` display not defined for any HTML5 element in IE 8/9. * Correct `block` display not defined for `details` or `summary` in IE 10/11 * and Firefox. * Correct `block` display not defined for `main` in IE 11. */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } /** * 1. Correct `inline-block` display not defined in IE 8/9. * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. */ audio, canvas, progress, video { display: inline-block; /* 1 */ vertical-align: baseline; /* 2 */ } /** * Prevent modern browsers from displaying `audio` without controls. * Remove excess height in iOS 5 devices. */ audio:not([controls]) { display: none; height: 0; } /** * Address `[hidden]` styling not present in IE 8/9/10. * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. */ [hidden], template { display: none; } /* Links ========================================================================== */ /** * Remove the gray background color from active links in IE 10. */ a { background-color: transparent; } /** * Improve readability when focused and also mouse hovered in all browsers. */ a:active, a:hover { outline: 0; } /* Text-level semantics ========================================================================== */ /** * Address styling not present in IE 8/9/10/11, Safari, and Chrome. */ abbr[title] { border-bottom: 1px dotted; } /** * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. */ b, strong { font-weight: bold; } /** * Address styling not present in Safari and Chrome. */ dfn { font-style: italic; } /** * Address variable `h1` font-size and margin within `section` and `article` * contexts in Firefox 4+, Safari, and Chrome. */ h1 { font-size: 2em; margin: 0.67em 0; } /** * Address styling not present in IE 8/9. */ mark { background: #ff0; color: #000; } /** * Address inconsistent and variable font size in all browsers. */ small { font-size: 80%; } /** * Prevent `sub` and `sup` affecting `line-height` in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } /* Embedded content ========================================================================== */ /** * Remove border when inside `a` element in IE 8/9/10. */ img { border: 0; } /** * Correct overflow not hidden in IE 9/10/11. */ svg:not(:root) { overflow: hidden; } /* Grouping content ========================================================================== */ /** * Address margin not present in IE 8/9 and Safari. */ figure { margin: 1em 40px; } /** * Address differences between Firefox and other browsers. */ hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; } /** * Contain overflow in all browsers. */ pre { overflow: auto; } /** * Address odd `em`-unit font size rendering in all browsers. */ code, kbd, pre, samp { font-family: monospace, monospace; font-size: 1em; } /* Forms ========================================================================== */ /** * Known limitation: by default, Chrome and Safari on OS X allow very limited * styling of `select`, unless a `border` property is set. */ /** * 1. Correct color not being inherited. * Known issue: affects color of disabled elements. * 2. Correct font properties not being inherited. * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. */ button, input, optgroup, select, textarea { color: inherit; /* 1 */ font: inherit; /* 2 */ margin: 0; /* 3 */ } /** * Address `overflow` set to `hidden` in IE 8/9/10/11. */ button { overflow: visible; } /** * Address inconsistent `text-transform` inheritance for `button` and `select`. * All other form control elements do not inherit `text-transform` values. * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. * Correct `select` style inheritance in Firefox. */ button, select { text-transform: none; } /** * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` * and `video` controls. * 2. Correct inability to style clickable `input` types in iOS. * 3. Improve usability and consistency of cursor style between image-type * `input` and others. */ button, html input[type="button"], /* 1 */ input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } /** * Re-set default cursor for disabled elements. */ button[disabled], html input[disabled] { cursor: default; } /** * Remove inner padding and border in Firefox 4+. */ button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } /** * Address Firefox 4+ setting `line-height` on `input` using `!important` in * the UA stylesheet. */ input { line-height: normal; } /** * It's recommended that you don't attempt to style these elements. * Firefox's implementation doesn't respect box-sizing, padding, or width. * * 1. Address box sizing set to `content-box` in IE 8/9/10. * 2. Remove excess padding in IE 8/9/10. */ input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** * Fix the cursor style for Chrome's increment/decrement buttons. For certain * `font-size` values of the `input`, it causes the cursor style of the * decrement button to change from `default` to `text`. */ input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { height: auto; } /** * 1. Address `appearance` set to `searchfield` in Safari and Chrome. * 2. Address `box-sizing` set to `border-box` in Safari and Chrome * (include `-moz` to future-proof). */ input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; } /** * Remove inner padding and search cancel button in Safari and Chrome on OS X. * Safari (but not Chrome) clips the cancel button when the search input has * padding (and `textfield` appearance). */ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** * Define consistent border, margin, and padding. */ fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } /** * 1. Correct `color` not being inherited in IE 8/9/10/11. * 2. Remove padding so people aren't caught out if they zero out fieldsets. */ legend { border: 0; /* 1 */ padding: 0; /* 2 */ } /** * Remove default vertical scrollbar in IE 8/9/10/11. */ textarea { overflow: auto; } /** * Don't inherit the `font-weight` (applied by a rule above). * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. */ optgroup { font-weight: bold; } /* Tables ========================================================================== */ /** * Remove most spacing between table cells. */ table { border-collapse: collapse; border-spacing: 0; } td, th { padding: 0; }tslint-5.9.1/docs/_sass/_syntax-highlighting.scss000066400000000000000000000063411322551053300221330ustar00rootroot00000000000000/** * Syntax highlighting styles */ .highlight { background: #fff; @extend %vertical-rhythm; .c { color: #998; font-style: italic } // Comment .err { color: #a61717; background-color: #e3d2d2 } // Error .k { font-weight: bold } // Keyword .o { font-weight: bold } // Operator .cm { color: #998; font-style: italic } // Comment.Multiline .cp { color: #999; font-weight: bold } // Comment.Preproc .c1 { color: #998; font-style: italic } // Comment.Single .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special .gd { color: #000; background-color: #fdd } // Generic.Deleted .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific .ge { font-style: italic } // Generic.Emph .gr { color: #a00 } // Generic.Error .gh { color: #999 } // Generic.Heading .gi { color: #000; background-color: #dfd } // Generic.Inserted .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific .go { color: #888 } // Generic.Output .gp { color: #555 } // Generic.Prompt .gs { font-weight: bold } // Generic.Strong .gu { color: #aaa } // Generic.Subheading .gt { color: #a00 } // Generic.Traceback .kc { font-weight: bold } // Keyword.Constant .kd { font-weight: bold } // Keyword.Declaration .kp { font-weight: bold } // Keyword.Pseudo .kr { font-weight: bold } // Keyword.Reserved .kt { color: #458; font-weight: bold } // Keyword.Type .m { color: #099 } // Literal.Number .s { color: #d14 } // Literal.String .na { color: #008080 } // Name.Attribute .nb { color: #0086B3 } // Name.Builtin .nc { color: #458; font-weight: bold } // Name.Class .no { color: #008080 } // Name.Constant .ni { color: #800080 } // Name.Entity .ne { color: #900; font-weight: bold } // Name.Exception .nf { color: #900; font-weight: bold } // Name.Function .nn { color: #555 } // Name.Namespace .nt { color: #000080 } // Name.Tag .nv { color: #008080 } // Name.Variable .ow { font-weight: bold } // Operator.Word .w { color: #bbb } // Text.Whitespace .mf { color: #099 } // Literal.Number.Float .mh { color: #099 } // Literal.Number.Hex .mi { color: #099 } // Literal.Number.Integer .mo { color: #099 } // Literal.Number.Oct .sb { color: #d14 } // Literal.String.Backtick .sc { color: #d14 } // Literal.String.Char .sd { color: #d14 } // Literal.String.Doc .s2 { color: #d14 } // Literal.String.Double .se { color: #d14 } // Literal.String.Escape .sh { color: #d14 } // Literal.String.Heredoc .si { color: #d14 } // Literal.String.Interpol .sx { color: #d14 } // Literal.String.Other .sr { color: #009926 } // Literal.String.Regex .s1 { color: #d14 } // Literal.String.Single .ss { color: #990073 } // Literal.String.Symbol .bp { color: #999 } // Name.Builtin.Pseudo .vc { color: #008080 } // Name.Variable.Class .vg { color: #008080 } // Name.Variable.Global .vi { color: #008080 } // Name.Variable.Instance .il { color: #099 } // Literal.Number.Integer.Long } tslint-5.9.1/docs/circle.yml000066400000000000000000000002541322551053300157570ustar00rootroot00000000000000machine: ruby: # see available versions here: https://circleci.com/docs/build-image-precise/#ruby version: 2.2.3 test: override: - bundle exec jekyll build tslint-5.9.1/docs/css/000077500000000000000000000000001322551053300145625ustar00rootroot00000000000000tslint-5.9.1/docs/css/main.scss000077500000000000000000000011761322551053300164130ustar00rootroot00000000000000--- # Only the main Sass file needs front matter (the dashes are enough) --- @charset "utf-8"; // Our variables $font-stack: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; $code-font-stack: Consolas, "Liberation Mono", Menlo, Courier, monospace; $base-font-size: 16px; $small-font-size: $base-font-size * 0.875; $base-line-height: 1.5; $heading-color: #159957; $text-color: #606c71; $link-color: #1e6bb8; $link-visited-color: #7d0ce8; // Import partials from `sass_dir` (defaults to `_sass`) @import "normalize", "base", "cayman", "syntax-highlighting" ; tslint-5.9.1/docs/develop/000077500000000000000000000000001322551053300154305ustar00rootroot00000000000000tslint-5.9.1/docs/develop/contributing/000077500000000000000000000000001322551053300201375ustar00rootroot00000000000000tslint-5.9.1/docs/develop/contributing/index.md000066400000000000000000000026101322551053300215670ustar00rootroot00000000000000--- layout: page title: Contributing to TSLint permalink: /develop/contributing/ --- To develop TSLint, clone the repository and install its dependencies: ```bash git clone git@github.com:palantir/tslint.git --config core.autocrlf=input --config core.eol=lf yarn yarn compile yarn test ``` #### Running a specific test You can test a specific test by using the `--test` command line parameter followed by your test directory. For example: ``` // global tslint // point to a dir that has tslint.json and .lint files tslint --test test/rules/semicolon/always // locally built tslint ./bin/tslint --test test/rules/semicolon/always ``` #### Debugging in Visual Studio Code Configuration files to work with Visual Studio Code are included when you check out the source code. These files live in the `.vscode` directory. To run TSLint in the debugger, switch to Debug view and use the dropdown at the top of the Debug pane to select the launch configuration (specified in `.vscode/launch.json`). Press `F5` to debug. You should be able to set breakpoints and debug as usual. The current debug configurations are: - Debug CLI: Used to debug TSLint using command line arguments. Modify the `args` array in `.vscode/launch.json` to add arguments. - Debug Mocha Tests: Runs non-rule tests - Debug Rule Tests: Runs rule tests (under `test/rules`) - Debug Document Generation: Debug the `scripts/buildDocs.ts` script. tslint-5.9.1/docs/develop/custom-formatters/000077500000000000000000000000001322551053300211265ustar00rootroot00000000000000tslint-5.9.1/docs/develop/custom-formatters/index.md000066400000000000000000000016701322551053300225630ustar00rootroot00000000000000--- layout: page title: Custom Formatters permalink: /develop/custom-formatters/ --- Just like [custom rules][0], additional formatters can also be supplied to TSLint via `--formatters-dir` on the CLI or `formattersDirectory` option on the library or `grunt-tslint`. Writing a new formatter is simpler than writing a new rule, as shown in the JSON formatter's code. ```ts import * as ts from "typescript"; import * as Lint from "tslint"; export class Formatter extends Lint.Formatters.AbstractFormatter { public format(failures: Lint.RuleFailure[]): string { var failuresJSON = failures.map((failure: Lint.RuleFailure) => failure.toJson()); return JSON.stringify(failuresJSON); } } ``` Such custom formatters can also be written in Javascript. Additionally, formatter files are always named with the suffix `Formatter`, and referenced from TSLint without its suffix. [0]: {{site.baseurl | append: "/develop/custom-rules"}} tslint-5.9.1/docs/develop/custom-rules/000077500000000000000000000000001322551053300200725ustar00rootroot00000000000000tslint-5.9.1/docs/develop/custom-rules/index.md000066400000000000000000000100531322551053300215220ustar00rootroot00000000000000--- title: Developing TSLint rules layout: page permalink: "/develop/custom-rules/" --- TSLint ships with a set of core rules that can be configured. However, users are also allowed to write their own rules, which allows them to enforce specific behavior not covered by the core of TSLint. TSLint's internal rules are itself written to be pluggable, so adding a new rule is as simple as creating a new rule file named by convention. New rules can be written in either TypeScript or JavaScript; if written in TypeScript, the code must be compiled to JavaScript before invoking TSLint. 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. __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`. Now, let us first write the rule in TypeScript: ```typescript import * as ts from "typescript"; import * as Lint from "tslint"; export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING = "import statement forbidden"; public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new NoImportsWalker(sourceFile, this.getOptions())); } } // The walker takes care of all the work. class NoImportsWalker extends Lint.RuleWalker { public visitImportDeclaration(node: ts.ImportDeclaration) { // create a failure at the current position this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); // call the base version of this visitor to actually parse this node super.visitImportDeclaration(node); } } ``` Given a walker, TypeScript's parser visits the AST using the visitor pattern. So the rule walkers only need to override the appropriate visitor methods to enforce its checks. For reference, the base walker can be found in [syntaxWalker.ts](https://github.com/palantir/tslint/blob/master/src/language/walker/syntaxWalker.ts). To see what your Typescript file or snippet looks like as an AST, visit [astexplorer.net](http://astexplorer.net/) (__note__: current version of TypeScript may not be supported, yet). We still need to hook up this new rule to TSLint. First make sure to compile `noImportsRule.ts`: ```sh tsc 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, 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 fix = new Lint.Replacement(node.getStart(), node.getWidth(), ""); // 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()`). - As of TSLint v5.7.0 you no longer need to compile your custom rules before using them. You need to tell node.js how to load `.ts` files for example by using `ts-node`: ```sh ts-node node_modules/.bin/tslint # or node -r ts-node/register node_modules/.bin/tslint # or NODE_OPTIONS="-r ts-node/register" tslint ``` [0]: {{site.baseurl | append: "/usage/tslint-json/"}} tslint-5.9.1/docs/develop/custom-rules/performance-tips.md000066400000000000000000000162151322551053300236770ustar00rootroot00000000000000--- title: TSLint performance tips layout: page permalink: "/develop/custom-rules/performance-tips" --- As TSLint has matured, we have developed some best practices for making rules run faster. TSLint 5.0 was a particularly significant release that featured many performance enhancements using the below tips (some codebases experienced lint times cut in half). ### Use the TypeChecker only when needed The TypeChecker is a really mighty tool, but that comes with a cost. To create a TypeChecker the Program first has to locate, read, parse and bind all SourceFiles referenced. To avoid that cost, try to avoid the TypeChecker where possible. If you are interested in the JSDoc of a function for example, you *could* ask the TypeChecker. But there's another way: call `.getChildren()` on the FunctionDeclaration and search for nodes of kind `ts.SyntaxKind.JSDocComment`. Those nodes will precede other nodes in the array. ### Avoid walking the AST if possible Some rules work directly on the content of the source file. For example, `max-file-line-count` and `linebreak-style` don't need to walk the AST at all. Other rules define exceptions: `no-consecutive-blank-lines` ignores template strings. To optimize for the best case, this rule can first look for failures in the source. If and only if there are any failures, walk the AST to find the location of all template strings to filter the failures. ### Implement your own walking algorithm Convenience comes with a price. When using `SyntaxWalker` or any subclass thereof like `RuleWalker` you pay the price for the big switch statement in `visitNode` which then calls the appropriate `visitXXX` method for **every** node in the AST, even if you don't use them. Use `AbstractWalker` instead and implement the `walk` method to fit the needs of your rule. It's as simple as this: ```ts class MyWalker extends Lint.AbstractWalker { public walk(sourceFile: ts.SourceFile) { const cb = (node: ts.Node): void => { if (someCondition) { // do stuff } // Wondering why return is used below? Refer to "Make use of tail calls" return ts.forEachChild(node, cb); // recurse deeper }; return ts.forEachChild(sourceFile, cb); // start recursion with children of sourceFile } ``` ### Don't walk the whole AST if possible __The language specification is your friend__: The language spec defines where each statement can occur. For example, if you are interested in `import` statements, you only need to search in `sourceFile.statements` and nested `NamespaceDeclaration`s. __Don't visit AST branches you're not interested in__: For example, `no-null-keyword` creates no failure if the null keyword is part of another type. There are two ways to achieve this: * Recurse into the AST until you find a token of kind NullKeyword and then walk up its parent chain to find out if it is part of a type node. * Stop recursing deeper into that branch as soon as you hit a type node (preferred). ### Avoid frequently creating one-time closures in the hot path ```ts class SomeClass { // this is a simplified version of what SyntaxWalker does under the hood doStuff(node: ts.Node) { // do stuff ... ts.forEachChild(node, (n) => this.doStuff(n)); // ~~~~~~~~~~~~~~~~~~~~~~ [a new closure is created for EVERY node in the AST and remains on the call stack // until processing of all children is done] } } ``` Instead use the same closure for every call like the example above in __Implement your own walking algorithm__. ### Create small specialized functions / methods Instead of stuffing the whole logic in a single closure, consider splitting it up into smaller functions or methods. Each function should handle similar kinds of nodes. Don't worry too much about the function call, since V8 eventually inlines the function if possible. The AST nodes have different properties, therefore they have a different hidden class in V8. A function can only be optimized for a certain amount of different hidden classes. Above that threshold the function will be deoptimized and is never optimized again. ### Supply the optional sourceFile parameter There are serveral methods that have an optional parameter `sourceFile`. Don't omit this parameter if you care for performance. If ommitted, typescript needs to walk up the node's parent chain until it reaches the SourceFile. This *can* be quite costly when done frequently on deeply nested nodes. Some examples: * `node.getStart()` * `node.getWidth()` * `node.getText()` * `node.getChildren()` * `node.getFirstToken()` * `node.getLeadingTriviaWidth()` ### Avoid excessive calls to node.getStart(), node.getWidth() and node.getText() `node.getStart()` scans the source to skip all the leading trivia. Although barely noticeable, this operation is not for free. If you need the start position of a node more than once per function, consider caching it. `node.getWidth()` is most of the time used together with `node.getStart()` to get the node's span. Internally it uses `node.getEnd() - node.getStart()` which effectively doubles the calls to `node.getStart()`. Consider using `node.getEnd()` instead and calculate the width yourself if necessary. `node.getText()` calculates the start of the node and returns a substring until the end of the token. Most of the time this not needed, because this substring is already contained in the node. ```ts declare node: ts.Identifier; node.getText() === node.text; // prefer node.text where available ``` __Bonus points:__ If you know the width of the node (either from the `text` property or because it is a keyword of known width), you can use `node.getEnd() - width` to calculate the node's start. `node.getEnd()` is effectively for free as it only returns the `end` property. This way you avoid the cost of skipping leading trivia. ### Make use of tail calls Tail calls are function or method calls at the end of the control flow of a function. It's only a tail call if the return value of that call is directly returned unchanged. Browsers can optimize this pattern for performance. Further optimization is specced in ES2015 as "Proper Tail Calls". With proper tail calls the browser reuses the stack frame of the current function. When done right this allows for infinite recursion. ```ts function foo() { if (condition) return bar(); // tail call if (someOtherCondition) return foo() + 1; // no tail call, return value is modified return baz(); // tail call } function bas() { if (cond) return someGlobalVariable = bar(); // no tail call, return value is stored in value before it is returned foo(); // no tail call because there is no return } ``` ### Typeguards Typeguard functions are very small by default. These functions will be inlined into the containing function. After inlining you no longer pay the cost of the function call. But beware of the inlining limit. If a function is big enough or already has many inlined functions, V8 will stop inlining other functions. Try to use a discriminated union if possible. A typeguard makes sense if you can save up multiple type assertions. tslint-5.9.1/docs/develop/custom-rules/walker-design.md000066400000000000000000000141111322551053300231460ustar00rootroot00000000000000--- title: Designing rule walkers layout: page permalink: "/develop/custom-rules/walker-design" --- ## Using WalkContext and applyWithFunction If you have a rule with a pretty simple implementation, you don't need to declare a class which extends the `Walker` class. Instead, you can define a callback function that accepts following argument: - `ctx: WalkContext`: An object containing rule information, an object `options: T` containing the parsed rule arguments, the `ts.sourceFile` object, and functions for adding failures Use this callback as an argument to `applyWithFunction`. You can also pass your parsed rule arguments as optional 3rd parameter. Let's look at `no-null-keyword` as an example: ```ts import * as ts from "typescript"; import * as Lint from "tslint"; export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING = "Use 'undefined' instead of 'null'"; public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { // Call `applyWithFunction` with your callback function, `walk`. // This creates a `WalkContext` and passes it in as an argument. // An optional 3rd parameter allows you to pass in a parsed version of `this.ruleArguments`. If used, it is not recommended to // simply pass in `this.getOptions()`, but to parse it into a more useful object instead. return this.applyWithFunction(sourceFile, walk); } } // Here, the options object type is `void` because we don't pass any options in this example. function walk(ctx: Lint.WalkContext) { // Recursively walk the AST starting with root node, `ctx.sourceFile`. // Call the function `cb` (defined below) for each child. return ts.forEachChild(ctx.sourceFile, cb); function cb(node: ts.Node): void { // Stop recursing further into the AST by returning early. Here, we ignore type nodes. if (node.kind >= ts.SyntaxKind.FirstTypeNode && node.kind <= ts.SyntaxKind.LastTypeNode) { return; } // Add failures using the `WalkContext` object. Here, we add a failure if we find the null keyword. if (node.kind === ts.SyntaxKind.NullKeyword) { return ctx.addFailureAtNode(node, Rule.FAILURE_STRING); } // Continue recursion into the AST by calling function `cb` for every child of the current node. return ts.forEachChild(node, cb); } } ``` ## Using AbstractWalker If your rule implementation is a bit more involved than the above example, you can also implement it as a class. Simply extend `AbstractWalker` and implement the `walk` method. ```ts import * as ts from "typescript"; import * as Lint from "tslint"; export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING = "'magic numbers' are not allowed"; public static ALLOWED_NODES = new Set([ ... ]); public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { // We convert the `ruleArguments` into a useful format before passing it to the constructor of AbstractWalker. return this.applyWithWalker(new NoMagicNumbersWalker(sourceFile, this.ruleName, new Set(this.ruleArguments.map(String)))); } } // The type parameter of AbstractWalker corresponds to the third constructor parameter. class NoMagicNumbersWalker extends Lint.AbstractWalker> { public walk(sourceFile: ts.SourceFile) { const cb = (node: ts.Node): void => { // Finds specific node types and do checking. if (node.kind === ts.SyntaxKind.NumericLiteral) { this.checkNumericLiteral(node, (node as ts.NumericLiteral).text); } else if (node.kind === ts.SyntaxKind.PrefixUnaryExpression && (node as ts.PrefixUnaryExpression).operator === ts.SyntaxKind.MinusToken) { this.checkNumericLiteral(node, "-" + ((node as ts.PrefixUnaryExpression).operand as ts.NumericLiteral).text); } else { // Continue rescursion: call function `cb` for all children of the current node. return ts.forEachChild(node, cb); } }; // Start recursion for all children of `sourceFile`. return ts.forEachChild(sourceFile, cb); } private checkNumericLiteral(node: ts.Node, num: string) { // `this.options` is the third constructor parameter from above (the Set we created in `Rule.apply`) if (!Rule.ALLOWED_NODES.has(node.parent!.kind) && !this.options.has(num)) { // Add failures to the Walker. this.addFailureAtNode(node, Rule.FAILURE_STRING); } } } ``` ## Migrating from RuleWalker to AbstractWalker The main difference between `RuleWalker` and `AbstractWalker` is that you need to implement the AST recursion yourself. But why would you want to do that? __Performance!__ `RuleWalker` wants to be "one walker to rule them all" (pun intended). It's easy to use but that convenience makes it slow by default. When implementing the walking yourself, you only need to do as much work as needed. Besides that you *should* convert the `ruleArguments` to a useful format before passing it to `AbstractWalker` as seen above. This table describes the equivalent methods between the two classes: `RuleWalker` | `AbstractWalker` ------------ | -------------- `this.createFailure()` and `this.addFailure()` | `this.addFailureAt()` `this.addFailureFromStartToEnd()` | `this.addFailure()` `this.createReplacement()` | `new Lint.Replacement()` `this.deleteText()` | `Lint.Replacement.deleteText()` `this.deleteFromTo()` | `Lint.Replacement.deleteFromTo()` `this.appendText()` | `Lint.Replacement.appendText()` `this.hasOption()` and `this.getOptions()` | use `this.options` directly `this.getLineAndCharacterOfPosition()` | `ts.getLineAndCharacterOfPosition(this.sourceFile, ...)` `this.getLimit()` | `this.sourceFile.end` `this.getSourceFile()` | is available to be compatible, but prefer `this.sourceFile` `this.getFailures()` | is available to be compatible, but prefer `this.failures` `this.skip()` | just don't use it, it's a noop `this.getRuleName()` | `this.ruleName` tslint-5.9.1/docs/develop/docs/000077500000000000000000000000001322551053300163605ustar00rootroot00000000000000tslint-5.9.1/docs/develop/docs/index.md000066400000000000000000000027151322551053300200160ustar00rootroot00000000000000--- layout: page title: Docs Development permalink: /develop/docs/ --- This docs site is a [Jekyll site][0] hosted on [GitHub pages][1]. 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 `.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 `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. #### Creating News Posts #### To create a new news post, simply add a new markdown file to the `_posts` directory, following the same pattern as existing ones. [0]: http://jekyllrb.com/ [1]: https://pages.github.com/ [2]: https://github.com/palantir/tslint/tree/master/docs [3]: {{site.baseurl}}/rules/ [4]: https://git-scm.com/docs/git-worktree tslint-5.9.1/docs/develop/testing-rules/000077500000000000000000000000001322551053300202355ustar00rootroot00000000000000tslint-5.9.1/docs/develop/testing-rules/index.md000066400000000000000000000171351322551053300216750ustar00rootroot00000000000000--- layout: page title: Testing Rules permalink: /develop/testing-rules/ --- Every TSLint rule has a corresponding directory inside `test/rules/` which contains one or more test cases for the rule. Each test case contains: * A `tslint.json` file which specifies the configuration for TSLint to use * `.ts.lint` test files which contain TypeScript code and a special markup which indicate where lint failures should be found The test system lints the `.ts.lint` files with the settings specified in `tslint.json` and makes sure that failures generated by the TSLint match the failures marked in the `.ts.lint` files. ### Example ### ##### Testing a New Rule ##### Say we're contributing a new rule to TSLint that bans the use of animal variable names and we now need to test it. First we create our configuration file which enables only the rule to be tested: `test/rules/no-animal-variable-names/default/tslint.json`: ``` { "rules": { "no-animal-variable-names": true } } ``` In this case, we placed our configuration inside `no-animal-variable-names/default` to indicate that we're testing the default configuration for our rule. Now let's make the actual test file: `test/rules/no-animal-variable-names/default/test.ts.lint`: ``` const octopus = 5; ~~~~~~~ [Variables named after animals are not allowed!] let giraffe: number, tiger: number; ~~~~~~~ [Variables named after animals are not allowed!] ~~~~~ [Variables named after animals are not allowed!] const tree = 5; const skyscraper = 100; ``` In the above file, `~` characters "underline" where our rule should generate a lint failure and the message that should be produced appears in brackets afterwards. If multiple lint failures occur on the same line of TypeScript code, the markup for them is placed on consecutive lines, as shown in the above example with the line `let giraffe: number, tiger: number;` Notice how we also include lines of code that *shouldn't* generate lint failures. This is important to ensure that the rule isn't creating false-positives. We can now run `yarn compile:test && yarn test:rules` to make sure that our rule produces the output we expect. ##### Testing a New Rule Option ##### Let's look at one more example. Say we've added an `also-no-plants` option to our rule above that disallows variable names that are plants. We should add a test for this new option: `test/rules/no-animal-variable-names/also-no-plants/tslint.json`: ``` { "rules": { "no-animal-variable-names": [true, "also-no-plants"] } } ``` `test/rules/no-animal-variable-names/also-no-plants/test.ts.lint`: ``` const octopus = 5; ~~~~~~~ [no-animal] let giraffe: number, tiger: number; ~~~~~~~ [no-animal] ~~~~~ [no-animal] const tree = 5; ~~~~ [no-plant] const skyscraper = 100; [no-animal]: Variables named after animals are not allowed! [no-plant]: Variables named after plants are not allowed! ``` We've now used a special message shorthand syntax so we don't have to type out the same failure message over and over. Instead of writing out the full lint failure message after each occurance of it, we instead just specify a shortcut name. (Shortcut names can only consist of letters, numbers, underscores, and hyphens.) Then, at the bottom of our test file, we specify what full message each shortcut should expand to. Again, we can run `yarn compile:test && yarn test:rules` to make sure our rule is producing the output we expect. If it isn't we'll see the difference between the output from the rule and the output we marked. You can also use placeholders to format messages. That's useful if the error message contains non-static parts, e.g. variable names. But let's stick to the above example for now. ``` const octopus = 5; ~~~~~~~ [no-animal] let giraffe: number, tiger: number; ~~~~~~~ [no-animal] ~~~~~ [no-animal] const tree = 5; ~~~~ [error % ("plants")] const skyscraper = 100; [error] Variables named after %s are not allowed! [no-animal]: error % ('animals') ``` We created a message template called `error` which has one placeholder `%s`. For a complete list of supported placeholders, please refer to the documentation of node's [util.format()](https://nodejs.org/api/util.html#util_util_format_format_args). To use the template for formatting, you need to use a special syntax: `template_name % ('substitution1' [, "substitution2" [, ...]])`. Substitutions are passed as comma separated list of javascript string literals. The strings need to be wrapped in single or double quotes. Escaping characters works like you would expect in javascript. You may have noticed that the template is used for formatting in two different places. Use it in inline errors to pass another substitution every time. If you use formatting in another message shorthand (like we did for `[no-animal]`), you need to make sure the template is defined before its use. That means swapping the lines of `[error]` and `[no-animal]` will not work. There are no restrictions for the use of `[no-animal]` in inline errors, though. Now let's pretend the rule changed its error message to include the variable name at the end. The following example shows how to substitute multiple placeholders. ``` const octopus = 5; ~~~~~~~ [no-animal % ('octopus')] let giraffe: number, tiger: number; ~~~~~~~ [no-animal % ('giraffe')] ~~~~~ [no-animal % ('tiger')] const tree = 5; ~~~~ [error % ("plants", "tree")] const skyscraper = 100; [error] Variables named after %s are not allowed: '%s' [no-animal]: error % ('animals') ``` ##### Typescript version requirement ##### Sometimes a rule requires a minimum version of the typescript compiler or your test contains syntax that older versions of the typescript parser cannot handle. When testing with multiple versions of typescript - like `tslint` does in CI - those tests will fail. To avoid failing tests, each test file can specify a version requirement for typescript **in the first line**. If you don't specify one, the test will always be executed. Example: ``` [typescript]: >= 2.1.0 ``` The syntax should look familiar, because it is basically the shorthand syntax from the chapter above. It needs to start with `[typescript]:`. The following part can be any [version range](https://github.com/npm/node-semver#ranges). The prerelease suffix will be removed before matching to allow testing with nightly builds. ### Tips & Tricks ### * You can use this system to test rules outside of the TSLint build! Use the `tslint --test path/to/dir` command to test your own custom rules. You can specify one or more paths to `tslint.json` files or directories containing a `tslint.json`. Glob patterns are also supported. Besides the `tslint.json` each directory you pass should contain `*.ts.lint` files. You can try this out on the TSLint rule test cases, for example, `tslint --test path/to/tslint-code/test/rules/quotemark/single`. If you want to test all of your rules at once, you can use it like this: `tslint --test rules/test/**/tslint.json` * To test rules that need type information, you can simply add a `tsconfig.json` with the desired configuration next to `tslint.json`. * Lint failures sometimes span over multiple lines. To handle this case, don't specify a message until the end of the error. For example: ``` for (let key in obj) { ~~~~~~~~~~~~~~~~~~~~~~ console.log(key); ~~~~~~~~~~~~~~~~~~~ } ~ [for-in loops are not allowed] ``` * If for some reason your lint rule generates a failure that has zero width, you can use the `~nil` mark to indicate this. tslint-5.9.1/docs/feed.xml000066400000000000000000000024141322551053300154200ustar00rootroot00000000000000--- layout: null --- {{ site.title | xml_escape }} {{ site.description | xml_escape }} {{ site.url }}{{ site.baseurl }}/ {{ site.time | date_to_rfc822 }} {{ site.time | date_to_rfc822 }} Jekyll v{{ jekyll.version }} {% for post in site.posts limit:10 %} {{ post.title | xml_escape }} {{ post.content | xml_escape }} {{ post.date | date_to_rfc822 }} {{ post.url | prepend: site.baseurl | prepend: site.url }} {{ post.url | prepend: site.baseurl | prepend: site.url }} {% for tag in post.tags %} {{ tag | xml_escape }} {% endfor %} {% for cat in post.categories %} {{ cat | xml_escape }} {% endfor %} {% endfor %} tslint-5.9.1/docs/formatters/000077500000000000000000000000001322551053300161605ustar00rootroot00000000000000tslint-5.9.1/docs/formatters/index.md000066400000000000000000000007421322551053300176140ustar00rootroot00000000000000--- layout: page title: TSLint core formatters permalink: /formatters/ menu: main order: 2 --- Lint _formatters_ allow for transformation of lint results into various forms before outputting to stdout or a file. ### Built-in formatters {% assign formatters = site.data.formatters | sort: "name" %} {% for formatter in formatters %} * [{{formatter.formatterName}}]({{formatter.formatterName}}) - {{formatter.description | markdownify | remove:"

" | remove: "

"}} {% endfor %}tslint-5.9.1/docs/index.md000066400000000000000000000014021322551053300154200ustar00rootroot00000000000000--- title: TSLint layout: default subtitle: An extensible linter for the TypeScript language. --- TSLint is an extensible static analysis tool that checks [TypeScript][0] code for readability, maintainability, and functionality errors. It is widely supported across modern editors & build systems and can be customized with your own lint rules, configurations, and formatters. ## Quick start ```sh # Install the global CLI and its peer dependency yarn global add tslint typescript # Navigate to to your sources folder cd path/to/project # Generate a basic configuration file tslint --init # Lint TypeScript source globs tslint -c tslint.json 'src/**/*.ts' ``` Check out [the full usage guide][1] to learn more. [0]: http://www.typescriptlang.org/ [1]: usage/cli tslint-5.9.1/docs/news/000077500000000000000000000000001322551053300147465ustar00rootroot00000000000000tslint-5.9.1/docs/news/index.html000066400000000000000000000017331322551053300167470ustar00rootroot00000000000000--- layout: page title: News hideTitle: true permalink: /news/ menu: main order: 4 --- {% assign post = site.posts | first %}

{{ post.title }}

{{ post.content }}

{% if site.posts.size <= 1 %} {% else %}

Also Read...

    {% for post in site.posts offset:1 limit:2 %}
  • {{ post.title }}
  • {% endfor %}
{% endif %} tslint-5.9.1/docs/rules/000077500000000000000000000000001322551053300151245ustar00rootroot00000000000000tslint-5.9.1/docs/rules/index.md000066400000000000000000000013511322551053300165550ustar00rootroot00000000000000--- layout: page title: TSLint core rules permalink: /rules/ menu: main order: 2 --- Lint _rules_ encode logic for syntactic & semantic checks of TypeScript source code. ### TypeScript-specific _These rules find errors related to TypeScript features_: {% include rule_list.html ruleType="typescript" %} ### Functionality _These rules catch common errors in JS programming or otherwise confusing constructs that are prone to producing bugs_: {% include rule_list.html ruleType="functionality" %} ### Maintainability _These rules make code maintenance easier_: {% include rule_list.html ruleType="maintainability" %} ### Style _These rules enforce consistent style across your codebase_: {% include rule_list.html ruleType="style" %} tslint-5.9.1/docs/usage/000077500000000000000000000000001322551053300150765ustar00rootroot00000000000000tslint-5.9.1/docs/usage/cli/000077500000000000000000000000001322551053300156455ustar00rootroot00000000000000tslint-5.9.1/docs/usage/cli/index.md000066400000000000000000000134471322551053300173070ustar00rootroot00000000000000--- title: TSLint command-line interface layout: page permalink: /usage/cli/ --- ### Installation __Local__ (in your project's working directory): ```sh npm install tslint typescript --save-dev # or yarn add tslint typescript --dev ``` __Global__: ```sh npm install tslint typescript -g # or yarn global add tslint typescript ``` {% include peer_dependencies.md %} ### CLI Usage Please ensure that the TypeScript source files compile correctly _before_ running the linter. Usage: `tslint [options] [file ...]` Options: ``` -v, --version output the version number -c, --config [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 -i, --init generate a tslint.json config file in the current working directory -o, --out [out] output file --outputAbsolutePaths whether or not outputted file paths are absolute -r, --rules-dir [rules-dir] rules directory -s, --formatters-dir [formatters-dir] formatters directory -t, --format [format] output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist, codeFrame) --test test that tslint produces the correct output for the specified directory -p, --project [project] tsconfig.json file --type-check (deprecated) check for type errors before linting the project -h, --help output usage information ``` By default, TSLint looks for a configuration file named `tslint.json` in the directory of the file being linted and, if not found, searches ancestor directories. Check out the [rules][0] section for more details on what rules are available. tslint accepts the following command-line options: ``` -c, --config: The location of the configuration file that tslint will use to determine which rules are activated and what options to provide 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-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 as in the non-list case, and the rest of the list are options passed to the rule that will determine what it checks for (such as number of characters for the max-line-length rule, or what functions to ban for the ban rule). -e, --exclude: A filename or glob which indicates files to exclude from linting. This option can be supplied multiple times if you need multiple globs to indicate which files to exclude. --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. -i, --init: Generates a tslint.json config file in the current working directory. -o, --out: A filename to output the results to. By default, tslint outputs to stdout, which is usually the console where you're running it from. --outputAbsolutePaths: If true, all paths in the output will be absolute. -r, --rules-dir: An additional rules directory, for user-created rules. tslint will always check its default rules directory, in node_modules/tslint/lib/rules, before checking the user-provided rules directory, so rules in the user-provided rules directory with the same name as the base rules will not be loaded. -s, --formatters-dir: An additional formatters directory, for user-created formatters. Formatters are files that will format the tslint output, before writing it to stdout or the file passed in --out. The default directory, node_modules/tslint/build/formatters, will always be checked first, so user-created formatters with the same names as the base formatters will not be loaded. -t, --format: The formatter to use to format the results of the linter before outputting it to stdout or the file passed in --out. The core formatters are prose (human readable), 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. Additional formatters can be added and used if the --formatters-dir option is set. --test: Runs tslint on matched directories and checks if tslint outputs match the expected output in .lint files. Automatically loads the tslint.json files in the directories 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. -p, --project: The path or directory containing a tsconfig.json file that will be used to determine which files will be linted. This flag also enables rules that require the type checker. --type-check: (deprecated) Checks for type errors before linting a project. --project must be specified in order to enable type checking. -v, --version: The current version of tslint. -h, --help: Prints this help message. ``` #### Exit Codes The CLI process may exit with the following codes: - `0`: Linting succeeded without errors (warnings may have occurred) - `1`: An invalid command line argument or combination thereof was used - `2`: Linting failed with one or more rule violations with severity `error` [0]: {{site.baseurl | append: "/rules/"}} tslint-5.9.1/docs/usage/configuration/000077500000000000000000000000001322551053300177455ustar00rootroot00000000000000tslint-5.9.1/docs/usage/configuration/index.md000066400000000000000000000146641322551053300214110ustar00rootroot00000000000000--- layout: page title: Configuring TSLint permalink: /usage/configuration/ --- ### TSLint Configuration When using [the CLI][0] or many [third-party tools][1], a file named `tslint.json` or `tslint.yaml` is used to configure which rules get run and each of their options. `tslint.json` or `tslint.yaml` files can have the following fields specified: * `extends?: string | string[]`: The name of a built-in configuration preset (see built-in presets below), or a path or array of paths to other configuration files which are extended by this configuration. This value is handled using node module resolution semantics. For example, a value of `"tslint-config"` would tell TSLint to try and load the main file of a module named "tslint-config" as a configuration file. Specific files inside node modules can also be specified, eg. `"tslint-config/path/to/submodule"`. Relative paths to JSON files or JS modules are also supported, e.g. `"./tslint-config"`. * `rulesDirectory?: string | string[]`: A path to a directory or an array of paths to directories of [custom rules][2]. These values are handled using node module resolution semantics, if an `index.js` is placed in your rules directory. We fallback to use relative or absolute paths, if the module can't be resolved. If you want to avoid module resolution you can directly use a relative or absolute path (e.g. with `./`). * `rules?: { [name: string]: RuleSetting }`: A map of rule names to their configuration settings. - These rules are applied to `.ts` and `.tsx` files. - Each rule is associated with an object containing: - `options?: any`: An array of values that are specific to a rule. - `severity?: "default" | "error" | "warning" | "off"`: Severity level. Level "error" will cause exit code 2. - A boolean value may be specified instead of the above object, and is equivalent to setting no options with default severity. - Any rules specified in this block will override those configured in any base configuration being extended. - [Check out the full rules list here][3]. * `jsRules?: any`: Same format as `rules`. These rules are applied to `.js` and `.jsx` files. * `defaultSeverity?: "error" | "warning" | "off"`: The severity level that is applied to rules in this config file as well as rules in any inherited config files which have their severity set to "default". If undefined, "error" is used as the defaultSeverity. * `linterOptions?: { exclude?: string[] }`: - `exclude: string[]`: An array of globs. Any file matching these globs will not be linted. All exclude patterns are relative to the configuration file they were specified in. `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. An example `tslint.json` file might look like this: ```json { "extends": "tslint:recommended", "rulesDirectory": ["path/to/custom/rules/directory/", "another/path/"], "rules": { "max-line-length": { "options": [120] }, "new-parens": true, "no-arg": true, "no-bitwise": true, "no-conditional-assignment": true, "no-consecutive-blank-lines": false, "no-console": { "severity": "warning", "options": [ "debug", "info", "log", "time", "timeEnd", "trace", ] } }, "jsRules": { "max-line-length": { "options": [120] } } } ``` The corresponding YAML file looks like this: ```yaml --- extends: "tslint:recommended" rulesDirectory: - path/to/custom/rules/directory/ - another/path/ rules: max-line-length: options: [120] new-parens: true no-arg: true no-bitwise: true no-conditional-assignment: true no-consecutive-blank-lines: false no-console: severity: warning options: - debug - info - log - time - timeEnd - trace jsRules: max-line-length: options: [120] ... ``` ### Rule severity The severity level of each rule can can be configured to `default`, `error`, `warning`/`warn`, or `off`/`none`. If no severity level is specified, `default` is used. The `defaultSeverity` top-level option replaces the severity level for each rule that uses severity level `default` in the current file. Valid values for `defaultSeverity` include `error`, `warning`/`warn`, and `off`/`none`. ### Configuration presets TSLint ships with a handful of built-in configurations presets. You may inspect their source [here](https://github.com/palantir/tslint/tree/master/src/configs). __`tslint:recommended`__ is a stable, somewhat opinionated set of rules which we encourage for general TypeScript programming. This configuration follows semver, so it will _not_ have breaking changes across minor or patch releases. __`tslint:latest`__ extends `tslint:recommended` and is continuously updated to include configuration for the latest rules in every TSLint release. Using this config may introduce breaking changes across minor releases as new rules are enabled which cause lint failures in your code. When TSLint reaches a major version bump, `tslint:recommended` will be updated to be identical to `tslint:latest`. __`tslint:all`__ turns on all rules to their strictest settings. This will use type checking, so it must be combined with the `--project` option. (Exceptions include rules such as [`"ban"`][rule-ban], [`"import-blacklist"`][rule-import-blacklist], and [`"file-header"`][rule-file-header], which have no sensible defaults, and deprecated rules.) ### Custom rules If TSLint's core rules don't have all the lint checks you're looking for, you may [write your own custom rules][2] or use custom rules that others have developed. Some commonly used custom rule packages in the TSLint community are listed in the [README](https://github.com/palantir/tslint/blob/master/README.md). [0]: {{site.baseurl | append: "/usage/cli"}} [1]: {{site.baseurl | append: "/usage/third-party-tools"}} [2]: {{site.baseurl | append: "/develop/custom-rules"}} [3]: {{site.baseurl | append: "/rules"}} [rule-ban]: {{site.baseurl | append: "/rules/ban"}} [rule-import-blacklist]: {{site.baseurl | append: "/rules/import-blacklist"}} [rule-file-header]: {{site.baseurl | append: "/rules/file-header"}} tslint-5.9.1/docs/usage/library/000077500000000000000000000000001322551053300165425ustar00rootroot00000000000000tslint-5.9.1/docs/usage/library/index.md000066400000000000000000000033331322551053300201750ustar00rootroot00000000000000--- layout: page title: Using TSLint as a Node.js library permalink: /usage/library/ --- ### Installation ```sh npm install tslint typescript # or yarn add tslint typescript ``` {% include peer_dependencies.md %} ### Library usage Please ensure that the TypeScript source files compile correctly _before_ running the linter. #### TypeScript This code will need to be transpiled to JavaScript to run under Node.js. ```ts import { Linter, Configuration } from "tslint"; import * as fs from "fs"; const fileName = "Specify input file name"; const configurationFilename = "Specify configuration file name"; const options = { fix: false, formatter: "json", rulesDirectory: "customRules/", formattersDirectory: "customFormatters/" }; const fileContents = fs.readFileSync(fileName, "utf8"); const linter = new Linter(options); const configuration = Configuration.findConfiguration(configurationFilename, fileName).results; linter.lint(fileName, fileContents, configuration); const result = linter.getResult(); ``` #### JavaScript (ES5) This code will run directly under Node.js, including if it's called from the command line. ```js "use strict"; var tslint = require("tslint"); var fs = require("fs"); var fileName = "Specify input file name"; var configurationFilename = "Specify configuration file name"; var options = { fix: false, formatter: "json", rulesDirectory: "customRules/", formattersDirectory: "customFormatters/" }; var fileContents = fs.readFileSync(fileName, "utf8"); var linter = new tslint.Linter(options); var configuration = tslint.Configuration.findConfiguration(configurationFilename, fileName).results; linter.lint(fileName, fileContents, configuration); var result = linter.getResult(); ```tslint-5.9.1/docs/usage/rule-flags/000077500000000000000000000000001322551053300171375ustar00rootroot00000000000000tslint-5.9.1/docs/usage/rule-flags/index.md000066400000000000000000000037151322551053300205760ustar00rootroot00000000000000--- layout: page title: TSLint rule flags permalink: /usage/rule-flags/ --- ### Comment flags in source code In addition to [global configuration][0], you may also enable/disable linting or a subset of lint rules within a file with the following comment rule flags: * `/* tslint:disable */` - Disable all rules for the rest of the file * `/* tslint:enable */` - Enable all rules for the rest of the file * `/* tslint:disable:rule1 rule2 rule3... */` - Disable the listed rules for the rest of the file * `/* tslint:enable:rule1 rule2 rule3... */` - Enable the listed rules for the rest of the file * `// tslint:disable-next-line` - Disables all rules for the following line * `someCode(); // tslint:disable-line` - Disables all rules for the current line * `// tslint:disable-next-line:rule1 rule2 rule3...` - Disables the listed rules for the next line * etc. Rules flags enable or disable rules as they are parsed. Disabling an already disabled rule or enabling an already enabled rule has no effect. Enabling a rule that is not present or disabled in `tslint.json` has also no effect. For example, imagine the directive `/* tslint:disable */` on the first line of a file, `/* tslint:enable:ban class-name */` on the 10th line and `/* tslint:enable */` on the 20th. No rules will be checked between the 1st and 10th lines, only the `ban` and `class-name` rules will be checked between the 10th and 20th, and all rules will be checked for the remainder of the file. Here's an example: ```ts function validRange (range: any) { return range.min <= range.middle && range.middle <= range.max; } /* tslint:disable:object-literal-sort-keys */ const range = { min: 5, middle: 10, // TSLint will *not* warn about unsorted keys here max: 20 }; /* tslint:enable:object-literal-sort-keys */ const point = { x: 3, z: 5, // TSLint will warn about unsorted keys here y: 4, } console.log(validRange(range)); ``` [0]: {{site.baseurl | append: "/usage/configuration"}} tslint-5.9.1/docs/usage/third-party-tools/000077500000000000000000000000001322551053300205035ustar00rootroot00000000000000tslint-5.9.1/docs/usage/third-party-tools/index.md000066400000000000000000000031651322551053300221410ustar00rootroot00000000000000--- layout: page title: Third-Party Tools permalink: /usage/third-party-tools/ --- A variety of tools and libraries are available to help you integrate TSLint automatically into your build process or IDE. Please see their respective sites for usage. _Note: Most of these tools are not maintained by TSLint._ * [grunt-tslint][0] ([Grunt][1]) * [gulp-tslint][2] ([Gulp][3]) * [eclipse-tslint][4] ([Eclipse][5]) * [linter-tslint][6] ([Atom][7]) * [vscode-tslint][8] ([Visual Studio Code][9]) * [syntastic][10] ([VIM][11]) * [Web Analyzer][12] ([Visual Studio][13]) * [Webstorm][14] * [mocha-tslint][15] ([Mocha][16]) * [tslint.tmbundle][17] ([TextMate][18]) * [generator-tslint][19] * [Flycheck][20] ([Emacs][21]) [0]: https://github.com/palantir/grunt-tslint [1]: http://gruntjs.com/ [2]: https://github.com/panuhorsmalahti/gulp-tslint [3]: http://gulpjs.com/ [4]: https://github.com/palantir/eclipse-tslint [5]: http://www.eclipse.org/ [6]: https://github.com/AtomLinter/linter-tslint [7]: https://atom.io/ [8]: https://github.com/Microsoft/vscode-tslint/tree/master/tslint [9]: https://code.visualstudio.com/ [10]: https://github.com/scrooloose/syntastic [11]: http://www.vim.org/ [12]: https://visualstudiogallery.msdn.microsoft.com/6edc26d4-47d8-4987-82ee-7c820d79be1d [13]: https://www.visualstudio.com/ [14]: https://www.jetbrains.com/help/webstorm/2016.1/tslint.html [15]: https://github.com/t-sauer/mocha-tslint [16]: https://mochajs.org/ [17]: https://github.com/natesilva/tslint.tmbundle [18]: https://macromates.com [19]: https://github.com/greybax/generator-tslint [20]: http://www.flycheck.org/ [21]: https://www.gnu.org/software/emacs/ tslint-5.9.1/docs/usage/type-checking/000077500000000000000000000000001322551053300176305ustar00rootroot00000000000000tslint-5.9.1/docs/usage/type-checking/index.md000066400000000000000000000035561322551053300212720ustar00rootroot00000000000000--- title: Type Checking layout: page permalink: /usage/type-checking/ --- #### Semantic lint rules Some TSLint rules go further than linting code syntax. Semantic rules use the compiler's program APIs to inspect static types and validate code patterns. ##### CLI When using the CLI, use the `--project` flag and specify your `tsconfig.json` to enable rules that work with the type checker. TSLint will lint all files included in your project as specified in `tsconfig.json`. ```sh tslint --project tsconfig.json --config tslint.json # lints every file in your project tslint -p . -c tslint.json # shorthand of the command above tslint -p tsconfig.json --exclude '**/*.d.ts' # lint all files in the project excluding declaration files tslint -p tsconfig.json **/*.ts # ignores files in tsconfig.json and uses the provided glob instead ``` ##### Library 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. ```js import { Linter, Configuration } from "tslint"; const configurationFilename = "Specify configuration file name"; const options = { fix: false, formatter: "json", rulesDirectory: "customRules/", formattersDirectory: "customFormatters/" }; const program = Linter.createProgram("tsconfig.json", "projectDir/"); const linter = new Linter(options, program); const files = Linter.getFileNames(program); files.forEach(file => { const fileContents = program.getSourceFile(file).getFullText(); const configuration = Configuration.findConfiguration(configurationFilename, file).results; linter.lint(file, fileContents, configuration); }); const results = linter.getResult(); ``` tslint-5.9.1/package.json000066400000000000000000000053471322551053300153410ustar00rootroot00000000000000{ "name": "tslint", "version": "5.9.1", "description": "An extensible static analysis linter for the TypeScript language", "bin": { "tslint": "./bin/tslint" }, "main": "./lib/index.js", "typings": "./lib/index.d.ts", "repository": { "type": "git", "url": "https://github.com/palantir/tslint.git" }, "keywords": [ "cli", "typescript", "linter" ], "scripts": { "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:global lint:from-bin", "lint:global": "tslint --project test/tsconfig.json --format stylish # test includes 'src' too", "lint:from-bin": "node bin/tslint --project test/tsconfig.json --format stylish", "publish:local": "./scripts/npmPublish.sh", "test": "npm-run-all test:pre -p test:mocha test:rules", "test:pre": "cd ./test/config && npm install --no-save", "test:mocha": "mocha --reporter spec --colors \"build/test/**/*Tests.js\"", "test:rules": "node ./build/test/ruleTestRunner.js", "verify": "npm-run-all clean compile lint test docs", "coverage": "rimraf coverage .nyc_output && nyc npm test" }, "dependencies": { "babel-code-frame": "^6.22.0", "builtin-modules": "^1.1.1", "chalk": "^2.3.0", "commander": "^2.12.1", "diff": "^3.2.0", "glob": "^7.1.1", "js-yaml": "^3.7.0", "minimatch": "^3.0.4", "resolve": "^1.3.2", "semver": "^5.3.0", "tslib": "^1.8.0", "tsutils": "^2.12.1" }, "peerDependencies": { "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev" }, "devDependencies": { "@types/babel-code-frame": "^6.20.0", "@types/chai": "^3.5.0", "@types/diff": "^3.2.0", "@types/glob": "^5.0.30", "@types/js-yaml": "^3.5.31", "@types/minimatch": "^2.0.29", "@types/mocha": "^2.2.35", "@types/node": "^7.0.29", "@types/resolve": "^0.0.4", "@types/rimraf": "^2.0.2", "@types/semver": "^5.3.30", "chai": "^3.5.0", "github": "^8.2.1", "json-stringify-pretty-compact": "^1.0.3", "mocha": "^3.2.0", "npm-run-all": "^4.0.2", "nyc": "^10.2.0", "rimraf": "^2.5.4", "ts-node": "^3.3.0", "tslint": "^5.8.0", "tslint-test-config-non-relative": "file:test/external/tslint-test-config-non-relative", "typescript": "~2.6.1" }, "license": "Apache-2.0", "engines": { "node": ">=4.8.0" } } tslint-5.9.1/scripts/000077500000000000000000000000001322551053300145315ustar00rootroot00000000000000tslint-5.9.1/scripts/buildDocs.ts000066400000000000000000000160751322551053300170220ustar00rootroot00000000000000/* * 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. */ /* * This TS script reads the metadata from each TSLint built-in rule * and serializes it in a format appropriate for the docs website. * * This script expects there to be a tslint-gh-pages directory * parallel to the main tslint directory. The tslint-gh-pages should * have the gh-pages branch of the TSLint repo checked out. * One easy way to do this is with the following Git command: * * ``` * git worktree add -b gh-pages ../tslint-gh-pages origin/gh-pages * ``` * * See http://palantir.github.io/tslint/develop/docs/ for more info * */ import * as fs from "fs"; import * as glob from "glob"; import stringify = require("json-stringify-pretty-compact"); import * as yaml from "js-yaml"; import * as path from "path"; import * as rimraf from "rimraf"; import {IFormatterMetadata} from "../lib/language/formatter/formatter"; import {IRuleMetadata} from "../lib/language/rule/rule"; type Metadata = IRuleMetadata | IFormatterMetadata; interface 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"; 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 modulePaths = glob.sync(documentation.globPattern); const metadataJson = modulePaths.map((modulePath: string) => buildSingleModuleDocumentation(documentation, modulePath)); // Delete outdated directories const rulesDirs = metadataJson.map((metadata: any) => metadata[documentation.nameMetadataKey]); deleteOutdatedDocumentation(documentation.subDirectory, rulesDirs); // Create a data file with details of every module. buildDocumentationDataFile(documentation, metadataJson); } /** * Deletes directories which are outdated * @param directory Path from which outdated subdirectories have to be checked and removed * @param rulesDirs The names of the current and new rules documentation directories */ function deleteOutdatedDocumentation(directory: string, rulesDirs: string[]) { // find if the thing at particular location is a directory const isDirectory = (source: string) => fs.lstatSync(source).isDirectory(); // get all subdirectories in source directory const getDirectories = (source: string) => fs.readdirSync(source).filter((name) => isDirectory(path.join(source, name))); const subDirs = getDirectories(directory); const outdatedDirs = subDirs.filter((dir) => rulesDirs.indexOf(dir) < 0); outdatedDirs.forEach((outdatedDir) => rimraf.sync(path.join(directory, outdatedDir))); } /** * 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 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(documentation.subDirectory)) { fs.mkdirSync(documentation.subDirectory); } if (!fs.existsSync(fileDirectory)) { fs.mkdirSync(fileDirectory); } fs.writeFileSync(path.join(fileDirectory, "index.html"), fileData); return metadata; } } 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, layout: string, type: string, name: string): any { return { ...metadata, layout, title: `${type}: ${name}`, }; } /** * Based off a rule's metadata, generates a Jekyll "HTML" file * that only consists of a YAML front matter block. */ function generateRuleFile(metadata: IRuleMetadata): string { if (metadata.optionExamples) { metadata = { ...metadata }; metadata.optionExamples = (metadata.optionExamples as any[]).map((example) => typeof example === "string" ? example : stringify(example)); } const yamlData = generateJekyllData(metadata, "rule", "Rule", metadata.ruleName); yamlData.optionsJSON = JSON.stringify(metadata.options, undefined, 2); return `---\n${yaml.safeDump(yamlData, {lineWidth: 140} as any)}---`; } /** * 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", "TSLint formatter", metadata.formatterName); return `---\n${yaml.safeDump(yamlData, {lineWidth: 140} as any)}---`; } buildDocumentation(ruleDocumentation); buildDocumentation(formatterDocumentation); tslint-5.9.1/scripts/custom-typings.d.ts000066400000000000000000000001631322551053300203300ustar00rootroot00000000000000declare module "json-stringify-pretty-compact" { function stringify(x: any): string; export = stringify; } tslint-5.9.1/scripts/generate-changelog.ts000066400000000000000000000132101322551053300206150ustar00rootroot00000000000000/* * Copyright 2017 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Generates entries for CHANGELOG.md from pull requests * * Reads changelog entries from pull requests merged since the last release tag. * Changelog entries are lines within the first PR comment that matches /^\[[a-z\-]+\]/ like `[new-rule]` and `[bugfix]` */ // tslint:disable:no-console import GitHubApi = require("github"); import * as fs from "fs"; import * as os from "os"; import * as path from "path"; import { camelize } from "../lib/utils"; const github = new GitHubApi({ host: "api.github.com", protocol: "https", timeout: 5000, }); const repoInfo = { owner: "palantir", repo: "tslint", }; const tokenFile = path.join(os.homedir(), "github_token.txt"); // authenticate const auth: GitHubApi.Auth = { token: fs.readFileSync(tokenFile, "utf8").toString().trim(), type: "oauth", }; console.log("Using OAuth token " + auth.token + "\n"); // process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; // ignores TLS certificate error github.authenticate(auth); const commits: ICommit[] = []; github.repos.getLatestRelease(repoInfo).then((value) => { console.log("Getting commits " + value.tag_name + "..master"); // get the commits between the most recent release and the head of master return github.repos.compareCommits({ base: value.tag_name, head: "master", ...repoInfo, }); }).then((value) => { // for each commit, get the PR, and extract changelog entries const promises: Array> = []; for (const commitInfo of value.commits) { const commit: ICommit = { fields: [], sha: commitInfo.sha, submitter: commitInfo.commit.author.name != null ? commitInfo.commit.author.name : commitInfo.author.login, title: commitInfo.commit.message, }; commits.push(commit); // check for a pull request number in the commit title const match = (commitInfo.commit.message as string).match(/\(#(\d+)\)/); if (match && match.length > 1) { commit.pushRequestNum = Number.parseInt(match[1], 10); // get the PR text promises.push(github.issues.get({ number: commit.pushRequestNum, ...repoInfo, }).then((comment) => { // extract the changelog entries const lines = (comment.body as string).split("\r\n"); for (const line of lines) { const fieldMatch = line.match(/^(\[[a-z\-]+\])/); if (fieldMatch) { commit.fields.push({ tag: fieldMatch[1], text: addLinks(line) + " (#" + commit.pushRequestNum + ")", }); } } })); } } return Promise.all(promises); }).then(() => { const entries: IField[] = []; const noFields: string[] = []; const contributors = new Set(); for (const commit of commits) { if (commit.fields.length > 0) { for (const field of commit.fields) { if (field.tag !== "[no-log]") { entries.push(field); } } } else { noFields.push(commit.title); } contributors.add(commit.submitter); } entries.sort((a, b) => { return a.tag.localeCompare(b.tag); }); console.log("\n---- formatted changelog entries: ----"); for (const entry of entries) { console.log("- " + entry.text); } console.log("\n---- PRs with missing changelog entries: ----"); for (const missing of noFields) { console.log("- " + missing.replace(/[\r\n]+/, "\r\n ")); } console.log("\n---- thanks ----"); console.log("Thanks to our contributors!"); contributors.forEach((contributor) => { console.log("- " + contributor); }); }).catch((error) => { console.log("Error:" + error); }); const cache = new Map(); function isRule(ruleName: string): boolean { let result = cache.get(ruleName); if (result === undefined) { result = fs.existsSync(`./src/rules/${camelize(ruleName)}Rule.ts`); cache.set(ruleName, result); } return result; } /** Replace rule names with links to the docs website */ function addLinks(text: string): string { let result = ""; let lastIndex = 0; // match everything that looks like a rule name and is enclosed in backticks const regex = /`([a-z][-a-z]*[a-z])+`/g; let match = regex.exec(text); while (match !== null) { if (isRule(match[1])) { result += text.slice(lastIndex, match.index) + `[${match[0]}](https://palantir.github.io/tslint/rules/${match[1]}/)`; lastIndex = regex.lastIndex; } match = regex.exec(text); } return result + text.slice(lastIndex); } interface IField { tag: string; text: string; } interface ICommit { pushRequestBody?: string; pushRequestNum?: number; submitter: string; sha: string; title: string; fields: IField[]; } tslint-5.9.1/scripts/npmPublish.sh000077500000000000000000000013301322551053300172060ustar00rootroot00000000000000#!/usr/bin/env bash # Publishes TSLint to NPM based on the current version in package.json # This script must be run with yarn: "yarn run publish:local" # A user running this script must have Palantir NPM organization credentials set -e rm -rf tempPublish mkdir tempPublish git clone git@github.com:palantir/tslint.git tempPublish cd tempPublish git checkout $npm_package_version yarn install --pure-lockfile yarn run verify # courtesy of https://stackoverflow.com/a/3232082/3124288 read -r -p "Are you sure you want to publish version $npm_package_version? [y/N] " response if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then yarn publish --tag latest else echo "Publishing aborted" fi cd .. rm -rf tempPublish tslint-5.9.1/scripts/tsconfig.json000066400000000000000000000004071322551053300172410ustar00rootroot00000000000000{ "version": "2.2.2", "compilerOptions": { "module": "commonjs", "noImplicitAny": true, "noUnusedParameters": true, "noUnusedLocals": true, "sourceMap": true, "target": "es5", "lib": ["es6"] } } tslint-5.9.1/src/000077500000000000000000000000001322551053300136315ustar00rootroot00000000000000tslint-5.9.1/src/configs/000077500000000000000000000000001322551053300152615ustar00rootroot00000000000000tslint-5.9.1/src/configs/all.ts000066400000000000000000000213631322551053300164060ustar00rootroot00000000000000/** * @license * Copyright 2017 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { join as joinPaths } from "path"; import { findRule } from "../ruleLoader"; import { hasOwnProperty } from "../utils"; // tslint:disable object-literal-sort-keys // tslint:disable object-literal-key-quotes export const rules = { // TypeScript Specific "adjacent-overload-signatures": true, "ban-types": { options: [ ["Object", "Avoid using the `Object` type. Did you mean `object`?"], ["Function", "Avoid using the `Function` type. Prefer a specific function type, like `() => void`."], ["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"], ["Number", "Avoid using the `Number` type. Did you mean `number`?"], ["String", "Avoid using the `String` type. Did you mean `string`?"], ["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"], ], }, "member-access": [true, "check-accessor", "check-constructor", "check-parameter-property"], "member-ordering": [true, { "order": "statics-first", "alphabetize": true, }], "no-any": true, "no-empty-interface": true, "no-import-side-effect": true, // Technically this is not the strictest setting, but don't want to conflict with "typedef" "no-inferrable-types": [true, "ignore-params"], "no-internal-module": true, "no-magic-numbers": true, "no-namespace": true, "no-non-null-assertion": true, "no-reference": true, "no-this-assignment": true, "no-var-requires": true, "only-arrow-functions": true, "prefer-for-of": true, "prefer-readonly": true, "promise-function-async": true, "typedef": [ true, "call-signature", "arrow-call-signature", "parameter", "arrow-parameter", "property-declaration", "variable-declaration", "member-variable-declaration", ], "typedef-whitespace": [ true, { "call-signature": "nospace", "index-signature": "nospace", "parameter": "nospace", "property-declaration": "nospace", "variable-declaration": "nospace", }, { "call-signature": "onespace", "index-signature": "onespace", "parameter": "onespace", "property-declaration": "onespace", "variable-declaration": "onespace", }, ], "unified-signatures": true, // Functionality "await-promise": true, // "ban": no sensible default "ban-comma-operator": true, "curly": true, "forin": true, // "import-blacklist": no sensible default "label-position": true, "no-arg": true, "no-bitwise": true, "no-conditional-assignment": true, "no-console": true, "no-construct": true, "no-debugger": true, "no-duplicate-super": true, "no-duplicate-switch-case": true, "no-duplicate-variable": [ true, "check-parameters", ], "no-dynamic-delete": true, "no-empty": true, "no-eval": true, "no-floating-promises": true, "no-for-in-array": true, "no-implicit-dependencies": true, "no-inferred-empty-object-type": true, "no-invalid-template-strings": true, // "no-invalid-this": Won't this be deprecated? "no-misused-new": true, "no-null-keyword": true, "no-object-literal-type-assertion": true, "no-return-await": true, "no-shadowed-variable": true, "no-string-literal": true, "no-string-throw": true, "no-sparse-arrays": true, "no-submodule-imports": true, "no-unbound-method": true, "no-unnecessary-class": [true, "allow-empty-class"], "no-unsafe-any": true, "no-unsafe-finally": true, "no-unused-expression": true, "no-unused-variable": true, "no-use-before-declare": true, "no-var-keyword": true, "no-void-expression": true, "prefer-conditional-expression": true, "radix": true, "restrict-plus-operands": true, "strict-boolean-expressions": true, "strict-type-predicates": true, "switch-default": true, "triple-equals": true, "use-default-type-parameter": true, "use-isnan": true, // Maintainability "cyclomatic-complexity": true, "eofline": true, "indent": [true, "spaces"], "linebreak-style": [true, "LF"], "max-classes-per-file": [true, 1], "max-file-line-count": [true, 1000], "max-line-length": [true, 120], "no-default-export": true, "no-duplicate-imports": true, "no-irregular-whitespace": true, "no-mergeable-namespace": true, "no-parameter-reassignment": true, "no-require-imports": true, "no-trailing-whitespace": true, "object-literal-sort-keys": true, "prefer-const": true, "trailing-comma": [true, { "multiline": "always", "singleline": "never", }], // Style "align": [ true, "parameters", "arguments", "statements", "elements", "members", ], "array-type": [true, "array-simple"], "arrow-parens": true, "arrow-return-shorthand": [true, "multiline"], "binary-expression-operand-order": true, "callable-types": true, "class-name": true, "comment-format": [ true, "check-space", "check-uppercase", ], "completed-docs": true, // "file-header": No sensible default "deprecation": true, "encoding": true, "import-spacing": true, "interface-name": true, "interface-over-type-literal": true, "jsdoc-format": [true, "check-multiline-start"], "match-default-export-name": true, "new-parens": true, "newline-before-return": true, "newline-per-chained-call": true, "no-angle-bracket-type-assertion": true, "no-boolean-literal-compare": true, "no-consecutive-blank-lines": true, "no-parameter-properties": true, "no-redundant-jsdoc": true, "no-reference-import": true, "no-unnecessary-callback-wrapper": true, "no-unnecessary-initializer": true, "no-unnecessary-qualifier": true, "no-unnecessary-type-assertion": true, "number-literal-format": true, "object-literal-key-quotes": [true, "consistent-as-needed"], "object-literal-shorthand": true, "one-line": [ true, "check-catch", "check-else", "check-finally", "check-open-brace", "check-whitespace", ], "one-variable-per-declaration": true, "ordered-imports": [true, { "import-sources-order": "case-insensitive", "named-imports-order": "case-insensitive", "module-source-path": "full", }], "prefer-function-over-method": true, "prefer-method-signature": true, "prefer-object-spread": true, "prefer-switch": true, "prefer-template": true, "quotemark": [ true, "double", "avoid-escape", "avoid-template", ], "return-undefined": true, "semicolon": [true, "always"], "space-before-function-paren": [true, { "anonymous": "never", "asyncArrow": "always", "constructor": "never", "method": "never", "named": "never", }], "space-within-parens": [true, 0], "switch-final-break": true, "type-literal-delimiter": true, "variable-name": [ true, "ban-keywords", "check-format", ], "whitespace": [ true, "check-branch", "check-decl", "check-operator", "check-module", "check-separator", "check-type", "check-typecast", "check-preblock", "check-type-operator", "check-rest-spread", ], }; export const RULES_EXCLUDED_FROM_ALL_CONFIG = ["ban", "fileHeader", "importBlacklist", "noInvalidThis", "noSwitchCaseFallThrough", "typeofCompare"]; // Exclude typescript-only rules from jsRules, otherwise it's identical. export const jsRules: { [key: string]: any } = {}; for (const key in rules) { if (!hasOwnProperty(rules, key)) { continue; } const Rule = findRule(key, joinPaths(__dirname, "..", "rules")); if (Rule === undefined) { throw new Error(`Couldn't find rule '${key}'.`); } if (!Rule.metadata.typescriptOnly) { jsRules[key] = (rules as any)[key]; } } tslint-5.9.1/src/configs/latest.ts000066400000000000000000000040731322551053300171310ustar00rootroot00000000000000/** * @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 object-literal-sort-keys // tslint:disable:object-literal-key-quotes export const rules = { // added in v5.1 "align": { options: [ "parameters", "statements", "members", ], }, "no-invalid-template-strings": true, "no-sparse-arrays": true, // added in v5.2 "no-object-literal-type-assertion": true, // added in v5.3 "prefer-conditional-expression": true, "prefer-object-spread": true, // added in v5.4 "no-duplicate-variable": [ true, "check-parameters", ], // added in v5.5 "no-this-assignment": true, // added in v5.6 "no-duplicate-imports": true, "space-within-parens": [true, 0], "no-submodule-imports": true, // added in v5.7 "whitespace": { options: [ "check-branch", "check-decl", "check-operator", "check-separator", "check-type", "check-typecast", "check-type-operator", "check-rest-spread", ], }, // added in v5.8 "ban-comma-operator": true, "jsdoc-format": { options: "check-multiline-start", }, "no-duplicate-switch-case": true, "no-implicit-dependencies": true, "no-return-await": true, }; // tslint:enable object-literal-sort-keys // work around "extends" being a keyword const xtends = "tslint:recommended"; export { xtends as extends }; tslint-5.9.1/src/configs/recommended.ts000066400000000000000000000200541322551053300201140ustar00rootroot00000000000000/** * @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. */ export const rules = { "adjacent-overload-signatures": true, "align": { options: [ "parameters", "statements", ], }, "array-type": { options: ["array-simple"], }, "arrow-parens": true, "arrow-return-shorthand": true, "ban-types": { options: [ ["Object", "Avoid using the `Object` type. Did you mean `object`?"], ["Function", "Avoid using the `Function` type. Prefer a specific function type, like `() => void`."], ["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"], ["Number", "Avoid using the `Number` type. Did you mean `number`?"], ["String", "Avoid using the `String` type. Did you mean `string`?"], ["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"], ], }, "callable-types": true, "class-name": true, "comment-format": { options: ["check-space"], }, "curly": true, "cyclomatic-complexity": false, "eofline": true, "forin": true, "import-spacing": true, "indent": { options: ["spaces"], }, "interface-name": { options: ["always-prefix"], }, "interface-over-type-literal": true, "jsdoc-format": true, "label-position": true, "max-classes-per-file": { options: [1], }, "max-line-length": { options: [120], }, "member-access": true, "member-ordering": { options: { order: "statics-first", }, }, "new-parens": true, "no-angle-bracket-type-assertion": true, "no-any": false, "no-arg": true, "no-bitwise": true, "no-conditional-assignment": true, "no-consecutive-blank-lines": true, "no-console": true, "no-construct": true, "no-debugger": true, "no-duplicate-super": true, "no-empty": true, "no-empty-interface": true, "no-eval": true, "no-internal-module": true, "no-invalid-this": false, "no-misused-new": true, "no-namespace": true, "no-parameter-properties": false, "no-reference": true, "no-reference-import": true, "no-shadowed-variable": true, "no-string-literal": true, "no-string-throw": true, "no-switch-case-fall-through": false, "no-trailing-whitespace": true, "no-unnecessary-initializer": true, "no-unsafe-finally": true, "no-unused-expression": true, // 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": { options: ["consistent-as-needed"], }, "object-literal-shorthand": true, "object-literal-sort-keys": true, "one-line": { options: [ "check-catch", "check-else", "check-finally", "check-open-brace", "check-whitespace", ], }, "one-variable-per-declaration": { options: ["ignore-for-loop"], }, "only-arrow-functions": { options: [ "allow-declarations", "allow-named-functions", ], }, "ordered-imports": { options: { "import-sources-order": "case-insensitive", "module-source-path": "full", "named-imports-order": "case-insensitive", }, }, "prefer-const": true, "prefer-for-of": true, "quotemark": { options: [ "double", "avoid-escape", ], }, "radix": true, "semicolon": { options: ["always"], }, "space-before-function-paren": { options: { anonymous: "never", asyncArrow: "always", constructor: "never", method: "never", named: "never", }, }, "trailing-comma": { options: { multiline: "always", singleline: "never", }, }, "triple-equals": { options: ["allow-null-check"], }, "typedef": false, "typedef-whitespace": { options: [ { "call-signature": "nospace", "index-signature": "nospace", "parameter": "nospace", "property-declaration": "nospace", "variable-declaration": "nospace", }, { "call-signature": "onespace", "index-signature": "onespace", "parameter": "onespace", "property-declaration": "onespace", "variable-declaration": "onespace", }, ], }, "typeof-compare": false, // deprecated in TSLint 5.9.0 "unified-signatures": true, "use-isnan": true, "variable-name": { options: [ "ban-keywords", "check-format", "allow-pascal-case", ], }, "whitespace": { options: [ "check-branch", "check-decl", "check-operator", "check-separator", "check-type", "check-typecast", ], }, }; export const jsRules = { "align": { options: [ "parameters", "statements", ], }, "class-name": true, "curly": true, "eofline": true, "forin": true, "import-spacing": true, "indent": { options: ["spaces"], }, "jsdoc-format": true, "label-position": true, "max-line-length": { options: [120], }, "new-parens": true, "no-arg": true, "no-bitwise": true, "no-conditional-assignment": true, "no-consecutive-blank-lines": true, "no-console": true, "no-construct": true, "no-debugger": true, "no-duplicate-super": true, "no-duplicate-variable": true, "no-empty": true, "no-eval": true, "no-reference": true, "no-shadowed-variable": true, "no-string-literal": true, "no-string-throw": true, "no-switch-case-fall-through": false, "no-trailing-whitespace": true, "no-unused-expression": 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": { options: [ "check-catch", "check-else", "check-finally", "check-open-brace", "check-whitespace", ], }, "one-variable-per-declaration": { options: ["ignore-for-loop"], }, "quotemark": { options: [ "double", "avoid-escape", ], }, "radix": true, "semicolon": { options: ["always"], }, "space-before-function-paren": { options: { anonymous: "never", asyncArrow: "always", constructor: "never", method: "never", named: "never", }, }, "trailing-comma": { options: { multiline: "always", singleline: "never", }, }, "triple-equals": { options: ["allow-null-check"], }, "use-isnan": true, "variable-name": { options: [ "ban-keywords", "check-format", "allow-pascal-case", ], }, "whitespace": { options: [ "check-branch", "check-decl", "check-operator", "check-separator", "check-type", "check-typecast", ], }, }; tslint-5.9.1/src/configuration.ts000066400000000000000000000523711322551053300170600ustar00rootroot00000000000000/** * @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 yaml from "js-yaml"; import * as os from "os"; import * as path from "path"; import * as resolve from "resolve"; import { FatalError, showWarningOnce } from "./error"; import { IOptions, RuleSeverity } from "./language/rule/rule"; import { arrayify, hasOwnProperty, stripComments } from "./utils"; export interface IConfigurationFile { /** * @deprecated property is never set * * The severity that is applied to rules in this config file as well as rules * in any inherited config files which have their severity set to "default". * Not inherited. */ defaultSeverity?: RuleSeverity; /** * An array of config files whose rules are inherited by this config file. */ extends: string[]; /** * Rules that are used to lint to JavaScript files. */ jsRules: Map>; /** * A subset of the CLI options. */ linterOptions?: Partial<{ exclude: string[]; }>; /** * Directories containing custom rules. Resolved using node module semantics. */ rulesDirectory: string[]; /** * Rules that are used to lint TypeScript files. */ rules: Map>; } export interface IConfigurationLoadResult { path?: string; results?: IConfigurationFile; } // Note: eslint prefers yaml over json, while tslint prefers json over yaml // for backward-compatibility. export const JSON_CONFIG_FILENAME = "tslint.json"; /** @deprecated use `JSON_CONFIG_FILENAME` or `CONFIG_FILENAMES` instead. */ export const CONFIG_FILENAME = JSON_CONFIG_FILENAME; export const CONFIG_FILENAMES = [JSON_CONFIG_FILENAME, "tslint.yaml", "tslint.yml"]; export const DEFAULT_CONFIG: IConfigurationFile = { defaultSeverity: "error", extends: ["tslint:recommended"], jsRules: new Map>(), rules: new Map>(), rulesDirectory: [], }; export const EMPTY_CONFIG: IConfigurationFile = { defaultSeverity: "error", extends: [], jsRules: new Map>(), rules: new Map>(), rulesDirectory: [], }; const BUILT_IN_CONFIG = /^tslint:(.*)$/; /** * Searches for a TSLint configuration and returns the data from the config. * @param configFile A path to a config file, this can be null if the location of a config is not known * @param inputFilePath A path containing the current file being linted. This is the starting location * of the search for a configuration. * @returns Load status for a TSLint configuration object */ export function findConfiguration(configFile: string | null, inputFilePath: string): IConfigurationLoadResult; export function findConfiguration(configFile: string, inputFilePath?: string): IConfigurationLoadResult; export function findConfiguration(configFile: string | null, inputFilePath?: string): IConfigurationLoadResult { const configPath = findConfigurationPath(configFile, inputFilePath!); const loadResult: IConfigurationLoadResult = { path: configPath }; try { loadResult.results = loadConfigurationFromPath(configPath); return loadResult; } catch (error) { throw new FatalError(`Failed to load ${configPath}: ${(error as Error).message}`, error as Error); } } /** * Searches for a TSLint configuration and returns the path to it. * Could return undefined if not configuration is found. * @param suppliedConfigFilePath A path to an known config file supplied by a user. Pass null here if * the location of the config file is not known and you want to search for one. * @param inputFilePath A path to the current file being linted. This is the starting location * of the search for a configuration. * @returns An absolute path to a tslint.json or tslint.yml or tslint.yaml file * or undefined if neither can be found. */ export function findConfigurationPath(suppliedConfigFilePath: string | null, inputFilePath: string): string | undefined; export function findConfigurationPath(suppliedConfigFilePath: string, inputFilePath?: string): string | undefined; export function findConfigurationPath(suppliedConfigFilePath: string | null, inputFilePath?: string): string | undefined { if (suppliedConfigFilePath != undefined) { if (!fs.existsSync(suppliedConfigFilePath)) { throw new FatalError(`Could not find config file at: ${path.resolve(suppliedConfigFilePath)}`); } else { return path.resolve(suppliedConfigFilePath); } } else { // convert to dir if it's a file or doesn't exist let useDirName = false; try { const stats = fs.statSync(inputFilePath!); if (stats.isFile()) { useDirName = true; } } catch (e) { // throws if file doesn't exist useDirName = true; } if (useDirName) { inputFilePath = path.dirname(inputFilePath!); } // search for tslint.json from input file location let configFilePath = findup(CONFIG_FILENAMES, path.resolve(inputFilePath!)); if (configFilePath !== undefined) { return configFilePath; } // search for tslint.json in home directory const homeDir = os.homedir(); for (const configFilename of CONFIG_FILENAMES) { configFilePath = path.join(homeDir, configFilename); if (fs.existsSync(configFilePath)) { return path.resolve(configFilePath); } } // no path could be found return undefined; } } /** * Find a file by names in a directory or any ancestor directory. * Will try each filename in filenames before recursing to a parent directory. * This is case-insensitive, so it can find 'TsLiNt.JsOn' when searching for 'tslint.json'. */ function findup(filenames: string[], directory: string): string | undefined { while (true) { const res = findFile(directory); if (res !== undefined) { return path.join(directory, res); } const parent = path.dirname(directory); if (parent === directory) { return undefined; } directory = parent; } function findFile(cwd: string): string | undefined { const dirFiles = fs.readdirSync(cwd); for (const filename of filenames) { const index = dirFiles.indexOf(filename); if (index > -1) { return filename; } // TODO: remove in v6.0.0 // Try reading in the entire directory and looking for a file with different casing. const result = dirFiles.find((entry) => entry.toLowerCase() === filename); if (result !== undefined) { showWarningOnce(`Using mixed case ${filename} is deprecated. Found: ${path.join(cwd, result)}`); return result; } } return undefined; } } /** * Used Node semantics to load a configuration file given configFilePath. * For example: * '/path/to/config' will be treated as an absolute path * './path/to/config' will be treated as a relative path * 'path/to/config' will attempt to load a to/config file inside a node module named path * @param configFilePath The configuration to load * @param originalFilePath (deprecated) The entry point configuration file * @returns a configuration object for TSLint loaded from the file at configFilePath */ export function loadConfigurationFromPath(configFilePath?: string, _originalFilePath?: string) { if (configFilePath == undefined) { return DEFAULT_CONFIG; } else { const resolvedConfigFilePath = resolveConfigurationPath(configFilePath); const rawConfigFile = readConfigurationFile(resolvedConfigFilePath); return parseConfigFile(rawConfigFile, path.dirname(resolvedConfigFilePath), readConfigurationFile); } } /** Reads the configuration file from disk and parses it as raw JSON, YAML or JS depending on the extension. */ export function readConfigurationFile(filepath: string): RawConfigFile { const resolvedConfigFileExt = path.extname(filepath); if (/\.(json|ya?ml)/.test(resolvedConfigFileExt)) { const fileContent = fs.readFileSync(filepath, "utf8").replace(/^\uFEFF/, ""); try { if (resolvedConfigFileExt === ".json") { return JSON.parse(stripComments(fileContent)) as RawConfigFile; } else { return yaml.safeLoad(fileContent, { // Note: yaml.LoadOptions expects a schema value of type "any", // but this trips up the no-unsafe-any rule. // tslint:disable-next-line:no-unsafe-any schema: yaml.JSON_SCHEMA, strict: true, }) as RawConfigFile; } } catch (e) { const error = e as Error; // include the configuration file being parsed in the error since it may differ from the directly referenced config throw new Error(`${error.message} in ${filepath}`); } } else { const rawConfigFile = require(filepath) as RawConfigFile; // tslint:disable-next-line no-dynamic-delete delete (require.cache as { [key: string]: any })[filepath]; return rawConfigFile; } } /** * Resolve configuration file path or node_module reference * @param filePath Relative ("./path"), absolute ("/path"), node module ("path"), or built-in ("tslint:path") */ function resolveConfigurationPath(filePath: string, relativeTo?: string) { const matches = filePath.match(BUILT_IN_CONFIG); const isBuiltInConfig = matches !== null && matches.length > 0; if (isBuiltInConfig) { const configName = matches![1]; try { return require.resolve(`./configs/${configName}`); } catch (err) { throw new Error(`${filePath} is not a built-in config, try "tslint:recommended" instead.`); } } const basedir = relativeTo !== undefined ? relativeTo : process.cwd(); try { return resolve.sync(filePath, { basedir }); } catch (err) { try { return require.resolve(filePath); } catch (err) { throw new Error(`Invalid "extends" configuration value - could not require "${filePath}". ` + "Review the Node lookup algorithm (https://nodejs.org/api/modules.html#modules_all_together) " + "for the approximate method TSLint uses to find the referenced configuration file."); } } } export function extendConfigurationFile(targetConfig: IConfigurationFile, nextConfigSource: IConfigurationFile): IConfigurationFile { function combineProperties(targetProperty: T | undefined, nextProperty: T | undefined): T { const combinedProperty: { [key: string]: any } = {}; add(targetProperty); // next config source overwrites the target config object add(nextProperty); return combinedProperty as T; function add(property: T | undefined): void { if (property !== undefined) { for (const name in property) { if (hasOwnProperty(property, name)) { combinedProperty[name] = property[name]; } } } } } function combineMaps(target: Map>, next: Map>) { const combined = new Map>(); target.forEach((options, ruleName) => { combined.set(ruleName, options); }); next.forEach((options, ruleName) => { const combinedRule = combined.get(ruleName); if (combinedRule !== undefined) { combined.set(ruleName, combineProperties(combinedRule, options)); } else { combined.set(ruleName, options); } }); return combined; } const combinedRulesDirs = targetConfig.rulesDirectory.concat(nextConfigSource.rulesDirectory); const dedupedRulesDirs = Array.from(new Set(combinedRulesDirs)); return { extends: [], jsRules: combineMaps(targetConfig.jsRules, nextConfigSource.jsRules), linterOptions: combineProperties(targetConfig.linterOptions, nextConfigSource.linterOptions), rules: combineMaps(targetConfig.rules, nextConfigSource.rules), rulesDirectory: dedupedRulesDirs, }; } /** * returns the absolute path (contrary to what the name implies) * * @deprecated use `path.resolve` instead */ export function getRelativePath(directory?: string | null, relativeTo?: string) { if (directory != undefined) { const basePath = relativeTo !== undefined ? relativeTo : process.cwd(); return path.resolve(basePath, directory); } return undefined; } // check if directory should be used as path or if it should be resolved like a module // matches if directory starts with '/', './', '../', 'node_modules/' or equals '.' or '..' export function useAsPath(directory: string) { return /^(?:\.?\.?(?:\/|$)|node_modules\/)/.test(directory); } /** * @param directories A path(s) to a directory of custom rules * @param relativeTo A path that directories provided are relative to. * For example, if the directories come from a tslint.json file, this path * should be the path to the tslint.json file. * @return An array of absolute paths to directories potentially containing rules */ export function getRulesDirectories(directories?: string | string[], relativeTo?: string): string[] { return arrayify(directories) .map((dir) => { if (!useAsPath(dir)) { try { return path.dirname(resolve.sync(dir, { basedir: relativeTo })); } catch (err) { // swallow error and fallback to using directory as path } } const absolutePath = relativeTo === undefined ? path.resolve(dir) : path.resolve(relativeTo, dir); if (absolutePath !== undefined) { if (!fs.existsSync(absolutePath)) { throw new FatalError(`Could not find custom rule directory: ${dir}`); } } return absolutePath; }); } /** * Parses the options of a single rule and upgrades legacy settings such as `true`, `[true, "option"]` * * @param ruleConfigValue The raw option setting of a rule */ function parseRuleOptions(ruleConfigValue: RawRuleConfig, rawDefaultRuleSeverity: string | undefined): Partial { let ruleArguments: any[] | undefined; let defaultRuleSeverity: RuleSeverity = "error"; if (rawDefaultRuleSeverity !== undefined) { switch (rawDefaultRuleSeverity.toLowerCase()) { case "warn": case "warning": defaultRuleSeverity = "warning"; break; case "off": case "none": defaultRuleSeverity = "off"; break; default: defaultRuleSeverity = "error"; } } let ruleSeverity = defaultRuleSeverity; if (ruleConfigValue == undefined) { ruleArguments = []; ruleSeverity = "off"; } else if (Array.isArray(ruleConfigValue)) { if (ruleConfigValue.length > 0) { // old style: array ruleArguments = ruleConfigValue.slice(1); ruleSeverity = ruleConfigValue[0] === true ? defaultRuleSeverity : "off"; } } else if (typeof ruleConfigValue === "boolean") { // old style: boolean ruleArguments = []; ruleSeverity = ruleConfigValue ? defaultRuleSeverity : "off"; } else if (typeof ruleConfigValue === "object") { if (ruleConfigValue.severity !== undefined) { switch (ruleConfigValue.severity.toLowerCase()) { case "default": ruleSeverity = defaultRuleSeverity; break; case "error": ruleSeverity = "error"; break; case "warn": case "warning": ruleSeverity = "warning"; break; case "off": case "none": ruleSeverity = "off"; break; default: console.warn(`Invalid severity level: ${ruleConfigValue.severity}`); ruleSeverity = defaultRuleSeverity; } } if (ruleConfigValue.options != undefined) { ruleArguments = arrayify(ruleConfigValue.options); } } return { ruleArguments, ruleSeverity, }; } export interface RawConfigFile { extends?: string | string[]; linterOptions?: IConfigurationFile["linterOptions"]; rulesDirectory?: string | string[]; defaultSeverity?: string; rules?: RawRulesConfig; jsRules?: RawRulesConfig; } export interface RawRulesConfig { [key: string]: RawRuleConfig; } export type RawRuleConfig = null | undefined | boolean | any[] | { severity?: RuleSeverity | "warn" | "none" | "default"; options?: any; }; /** * Parses a config file and normalizes legacy config settings. * If `configFileDir` and `readConfig` are provided, this function will load all base configs and reduce them to the final configuration. * * @param configFile The raw object read from the JSON of a config file * @param configFileDir The directory of the config file * @param readConfig Will be used to load all base configurations while parsing. The function is called with the resolved path. */ export function parseConfigFile( configFile: RawConfigFile, configFileDir?: string, readConfig?: (path: string) => RawConfigFile, ): IConfigurationFile { let defaultSeverity = configFile.defaultSeverity; if (readConfig === undefined || configFileDir === undefined) { return parse(configFile, configFileDir); } return loadExtendsRecursive(configFile, configFileDir) .map(({dir, config}) => parse(config, dir)) .reduce(extendConfigurationFile, EMPTY_CONFIG); /** Read files in order, depth first, and assign `defaultSeverity` (last config in extends wins). */ function loadExtendsRecursive(raw: RawConfigFile, dir: string) { const configs: Array<{dir: string; config: RawConfigFile}> = []; for (const relativePath of arrayify(raw.extends)) { const resolvedPath = resolveConfigurationPath(relativePath, dir); const extendedRaw = readConfig!(resolvedPath); configs.push(...loadExtendsRecursive(extendedRaw, path.dirname(resolvedPath))); } if (raw.defaultSeverity !== undefined) { defaultSeverity = raw.defaultSeverity; } configs.push({dir, config: raw}); return configs; } function parse(config: RawConfigFile, dir?: string): IConfigurationFile { return { extends: arrayify(config.extends), jsRules: parseRules(config.jsRules), linterOptions: parseLinterOptions(config.linterOptions, dir), rules: parseRules(config.rules), rulesDirectory: getRulesDirectories(config.rulesDirectory, dir), }; } function parseRules(config: RawRulesConfig | undefined): Map> { const map = new Map>(); if (config !== undefined) { for (const ruleName in config) { if (hasOwnProperty(config, ruleName)) { map.set(ruleName, parseRuleOptions(config[ruleName], defaultSeverity)); } } } return map; } function parseLinterOptions(raw: RawConfigFile["linterOptions"], dir?: string): IConfigurationFile["linterOptions"] { if (raw === undefined || raw.exclude === undefined) { return {}; } return { exclude: arrayify(raw.exclude).map( (pattern) => dir === undefined ? path.resolve(pattern) : path.resolve(dir, pattern), ), }; } } /** * Fills in default values for `IOption` properties and outputs an array of `IOption` */ export function convertRuleOptions(ruleConfiguration: Map>): IOptions[] { const output: IOptions[] = []; ruleConfiguration.forEach(({ ruleArguments, ruleSeverity }, ruleName) => { const options: IOptions = { disabledIntervals: [], // deprecated, so just provide an empty array. ruleArguments: ruleArguments != undefined ? ruleArguments : [], ruleName, ruleSeverity: ruleSeverity != undefined ? ruleSeverity : "error", }; output.push(options); }); return output; } tslint-5.9.1/src/custom-types.d.ts000066400000000000000000000001241322551053300170740ustar00rootroot00000000000000declare module "builtin-modules" { let result: string[]; export = result; } tslint-5.9.1/src/enableDisableRules.ts000066400000000000000000000153011322551053300177260ustar00rootroot00000000000000/** * @license * 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. */ // tslint:disable object-literal-sort-keys import * as utils from "tsutils"; import * as ts from "typescript"; import { RuleFailure } from "./language/rule/rule"; /** * regex is: start of string followed by any amount of whitespace * followed by tslint and colon * followed by either "enable" or "disable" * followed optionally by -line or -next-line * followed by either colon, whitespace or end of string */ export const ENABLE_DISABLE_REGEX = /^\s*tslint:(enable|disable)(?:-(line|next-line))?(:|\s|$)/; export function removeDisabledFailures(sourceFile: ts.SourceFile, failures: RuleFailure[]): RuleFailure[] { if (failures.length === 0) { // Usually there won't be failures anyway, so no need to look for "tslint:disable". return failures; } const failingRules = new Set(failures.map((f) => f.getRuleName())); const map = getDisableMap(sourceFile, failingRules); return failures.filter((failure) => { const disabledIntervals = map.get(failure.getRuleName()); return disabledIntervals === undefined || !disabledIntervals.some(({ pos, end }) => { const failPos = failure.getStartPosition().getPosition(); const failEnd = failure.getEndPosition().getPosition(); return failEnd >= pos && (end === -1 || failPos < end); }); }); } /** * The map will have an array of TextRange for each disable of a rule in a file. * (It will have no entry if the rule is never disabled, meaning all arrays are non-empty.) */ function getDisableMap(sourceFile: ts.SourceFile, failingRules: Set): ReadonlyMap { const map = new Map(); utils.forEachComment(sourceFile, (fullText, comment) => { const commentText = comment.kind === ts.SyntaxKind.SingleLineCommentTrivia ? fullText.substring(comment.pos + 2, comment.end) : fullText.substring(comment.pos + 2, comment.end - 2); const parsed = parseComment(commentText); if (parsed !== undefined) { const { rulesList, isEnabled, modifier } = parsed; const switchRange = getSwitchRange(modifier, comment, sourceFile); if (switchRange !== undefined) { const rulesToSwitch = rulesList === "all" ? Array.from(failingRules) : rulesList.filter((r) => failingRules.has(r)); for (const ruleToSwitch of rulesToSwitch) { switchRuleState(ruleToSwitch, isEnabled, switchRange.pos, switchRange.end); } } } }); return map; function switchRuleState(ruleName: string, isEnable: boolean, start: number, end: number): void { const disableRanges = map.get(ruleName); if (isEnable) { if (disableRanges !== undefined) { const lastDisable = disableRanges[disableRanges.length - 1]; if (lastDisable.end === -1) { lastDisable.end = start; if (end !== -1) { // Disable it again after the enable range is over. disableRanges.push({ pos: end, end: -1 }); } } } } else { // disable if (disableRanges === undefined) { map.set(ruleName, [{ pos: start, end }]); } else if (disableRanges[disableRanges.length - 1].end !== -1) { disableRanges.push({ pos: start, end }); } } } } /** End will be -1 to indicate no end. */ function getSwitchRange(modifier: Modifier, range: ts.TextRange, sourceFile: ts.SourceFile): ts.TextRange | undefined { const lineStarts = sourceFile.getLineStarts(); switch (modifier) { case "line": return { // start at the beginning of the line where comment starts pos: getStartOfLinePosition(range.pos), // end at the beginning of the line following the comment end: getStartOfLinePosition(range.end, 1), }; case "next-line": // start at the beginning of the line following the comment const pos = getStartOfLinePosition(range.end, 1); if (pos === -1) { // no need to switch anything, there is no next line return undefined; } // end at the beginning of the line following the next line return { pos, end: getStartOfLinePosition(range.end, 2) }; default: // switch rule for the rest of the file // start at the current position, but skip end position return { pos: range.pos, end: -1 }; } /** Returns -1 for last line. */ function getStartOfLinePosition(position: number, lineOffset = 0): number { const line = ts.getLineAndCharacterOfPosition(sourceFile, position).line + lineOffset; return line >= lineStarts.length ? -1 : lineStarts[line]; } } type Modifier = "line" | "next-line" | undefined; function parseComment(commentText: string): { rulesList: string[] | "all"; isEnabled: boolean; modifier: Modifier } | undefined { const match = ENABLE_DISABLE_REGEX.exec(commentText); if (match === null) { return undefined; } // remove everything matched by the previous regex to get only the specified rules // split at whitespaces // filter empty items coming from whitespaces at start, at end or empty list let rulesList: string[] | "all" = splitOnSpaces(commentText.substr(match[0].length)); if (rulesList.length === 0 && match[3] === ":") { // nothing to do here: an explicit separator was specified but no rules to switch return undefined; } if (rulesList.length === 0 || rulesList.indexOf("all") !== -1) { // if list is empty we default to all enabled rules // if `all` is specified we ignore the other rules and take all enabled rules rulesList = "all"; } return { rulesList, isEnabled: match[1] === "enable", modifier: match[2] as Modifier }; } function splitOnSpaces(str: string): string[] { return str.split(/\s+/).filter((s) => s !== ""); } tslint-5.9.1/src/error.ts000066400000000000000000000034221322551053300153330ustar00rootroot00000000000000/** * @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. */ const shownWarnings = new Set(); /** * 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; // Fix prototype chain for target ES5 Object.setPrototypeOf(this, FatalError.prototype); } } export function isError(possibleError: any): possibleError is Error { return possibleError != undefined && (possibleError as Error).message !== undefined; } export function showWarningOnce(message: string) { if (!shownWarnings.has(message)) { console.warn(message); shownWarnings.add(message); } } tslint-5.9.1/src/formatterLoader.ts000066400000000000000000000062541322551053300173420ustar00rootroot00000000000000/** * @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 path from "path"; import * as resolve from "resolve"; import { FormatterConstructor } from "./index"; import { camelize } from "./utils"; const CORE_FORMATTERS_DIRECTORY = path.resolve(__dirname, "formatters"); export function findFormatter(name: string | FormatterConstructor, formattersDirectory?: string): FormatterConstructor | undefined { if (typeof name === "function") { return name; } else if (typeof name === "string") { name = name.trim(); const camelizedName = camelize(`${name}Formatter`); // first check for core formatters let Formatter = loadFormatter(CORE_FORMATTERS_DIRECTORY, camelizedName, true); if (Formatter !== undefined) { return Formatter; } // then check for rules within the first level of rulesDirectory if (formattersDirectory !== undefined) { Formatter = loadFormatter(formattersDirectory, camelizedName); if (Formatter !== undefined) { return Formatter; } } // else try to resolve as module return loadFormatterModule(name); } else { // If an something else is passed as a name (e.g. object) throw new Error(`Name of type ${typeof name} is not supported.`); } } function loadFormatter(directory: string, name: string, isCore?: boolean): FormatterConstructor | undefined { const formatterPath = path.resolve(path.join(directory, name)); let fullPath: string; if (isCore) { fullPath = `${formatterPath}.js`; if (!fs.existsSync(fullPath)) { return undefined; } } else { // Resolve using node's path resolution to allow developers to write custom formatters in TypeScript which can be loaded by TS-Node try { fullPath = require.resolve(formatterPath); } catch { return undefined; } } return (require(fullPath) as { Formatter: FormatterConstructor }).Formatter; } function loadFormatterModule(name: string): FormatterConstructor | undefined { let src: string; try { // first try to find a module in the dependencies of the currently linted project src = resolve.sync(name, {basedir: process.cwd()}); } catch { try { // if there is no local module, try relative to the installation of TSLint (might be global) src = require.resolve(name); } catch { return undefined; } } return (require(src) as { Formatter: FormatterConstructor }).Formatter; } tslint-5.9.1/src/formatters.ts000066400000000000000000000013151322551053300163670ustar00rootroot00000000000000/** * @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. */ export * from "./language/formatter/abstractFormatter"; export * from "./formatters/index"; tslint-5.9.1/src/formatters/000077500000000000000000000000001322551053300160175ustar00rootroot00000000000000tslint-5.9.1/src/formatters/checkstyleFormatter.ts000066400000000000000000000066431322551053300224220ustar00rootroot00000000000000/** * @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 { 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 = ''; if (failures.length !== 0) { const failuresSorted = failures.sort( (a, b) => a.getFileName().localeCompare(b.getFileName())); let previousFilename: string | null = null; for (const failure of failuresSorted) { const severity = failure.getRuleSeverity(); if (failure.getFileName() !== previousFilename) { if (previousFilename !== null) { output += ""; } previousFilename = failure.getFileName(); output += ``; } output += `dotdot output += `source="failure.tslint.${this.escapeXml(failure.getRuleName())}" />`; } if (previousFilename !== null) { output += ""; } } output += ""; return output; } private escapeXml(str: string): string { return str .replace(/&/g, "&") .replace(//g, ">") .replace(/'/g, "'") .replace(/"/g, """); } } tslint-5.9.1/src/formatters/codeFrameFormatter.ts000066400000000000000000000070421322551053300221430ustar00rootroot00000000000000/** * @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 { AbstractFormatter } from "../language/formatter/abstractFormatter"; import { IFormatterMetadata } from "../language/formatter/formatter"; import { RuleFailure } from "../language/rule/rule"; import codeFrame = require("babel-code-frame"); import chalk from "chalk"; import * as Utils from "../utils"; export class Formatter extends AbstractFormatter { /* tslint:disable:object-literal-sort-keys */ public static metadata: IFormatterMetadata = { formatterName: "codeFrame", description: "Framed formatter which creates a frame of error code.", descriptionDetails: Utils.dedent` Prints syntax highlighted code in a frame with a pointer to where exactly lint error is happening.`, sample: Utils.dedent` src/components/Payment.tsx Parentheses are required around the parameters of an arrow function definition (arrow-parens) 21 | public componentDidMount() { 22 | this.input.focus(); > 23 | loadStripe().then(Stripe => Stripe.pay()); | ^ 24 | } 25 | 26 | public render() {`, consumer: "human", }; /* tslint:enable:object-literal-sort-keys */ public format(failures: RuleFailure[]): string { if (typeof failures[0] === "undefined") { return "\n"; } failures = this.sortFailures(failures); const outputLines: string[] = []; let currentFile: string | undefined; for (const failure of failures) { const fileName = failure.getFileName(); // Output the name of each file once if (currentFile !== fileName) { outputLines.push(""); outputLines.push(fileName); currentFile = fileName; } let failureString = failure.getFailure(); failureString = failure.getRuleSeverity() === "warning" ? chalk.yellow(failureString) : chalk.red(failureString); // Rule let ruleName = failure.getRuleName(); ruleName = chalk.gray(`(${ruleName})`); // Frame const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const frame = codeFrame( failure.getRawLines(), lineAndCharacter.line + 1, // babel-code-frame is 1 index lineAndCharacter.character, { forceColor: chalk.enabled, highlightCode: true, }, ); // Ouput outputLines.push(`${failureString} ${ruleName}`); outputLines.push(frame); outputLines.push(""); } // Removes initial blank line if (outputLines[0] === "") { outputLines.shift(); } return `${outputLines.join("\n")}\n`; } } tslint-5.9.1/src/formatters/fileslistFormatter.ts000066400000000000000000000032361322551053300222550ustar00rootroot00000000000000/** * @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 { 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 ""; } const files: string[] = []; let currentFile: string | undefined; for (const failure of failures) { const fileName = failure.getFileName(); if (fileName !== currentFile) { files.push(fileName); currentFile = fileName; } } return `${files.join("\n")}\n`; } } tslint-5.9.1/src/formatters/index.ts000066400000000000000000000022771322551053300175060ustar00rootroot00000000000000/** * @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. */ export { Formatter as JsonFormatter } from "./jsonFormatter"; export { Formatter as PmdFormatter } from "./pmdFormatter"; export { Formatter as ProseFormatter } from "./proseFormatter"; export { Formatter as VerboseFormatter } from "./verboseFormatter"; export { Formatter as StylishFormatter } from "./stylishFormatter"; export { Formatter as FileslistFormatter } from "./fileslistFormatter"; export { Formatter as CodeFrameFormatter } from "./codeFrameFormatter"; export { Formatter as TapFormatter } from "./tapFormatter"; export { Formatter as JUnitFormatter } from "./junitFormatter"; tslint-5.9.1/src/formatters/jsonFormatter.ts000066400000000000000000000037701322551053300212330ustar00rootroot00000000000000/** * @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 { 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": { "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); } } tslint-5.9.1/src/formatters/junitFormatter.ts000066400000000000000000000065661322551053300214210ustar00rootroot00000000000000/** * @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 { 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: "junit", description: "Formats errors as through they were JUnit output.", descriptionDetails: Utils.dedent` Imitates the JUnit XML Output`, sample: Utils.dedent` Missing semicolon `, consumer: "machine", }; /* tslint:enable:object-literal-sort-keys */ public format(failures: RuleFailure[]): string { let output = ''; if (failures.length !== 0) { const failuresSorted = failures.sort( (a, b) => a.getFileName().localeCompare(b.getFileName())); let previousFilename: string | null = null; for (const failure of failuresSorted) { const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const message = this.escapeXml(failure.getFailure()); const rule = this.escapeXml(failure.getRuleName()); const severity = failure.getRuleSeverity(); if (failure.getFileName() !== previousFilename) { if (previousFilename !== null) { output += ""; } previousFilename = failure.getFileName(); output += ``; } output += ``; output += `${message}`; output += ""; } if (previousFilename !== null) { output += ""; } } output += ""; return output; } private escapeXml(str: string): string { return str .replace(/&/g, "&") .replace(//g, ">") .replace(/'/g, "'") .replace(/"/g, """); } } tslint-5.9.1/src/formatters/msbuildFormatter.ts000066400000000000000000000041021322551053300217070ustar00rootroot00000000000000/** * @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 path from "path"; import { AbstractFormatter } from "../language/formatter/abstractFormatter"; import { IFormatterMetadata } from "../language/formatter/formatter"; import { RuleFailure } from "../language/rule/rule"; import { camelize } 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: "The output is compatible with both msbuild and Visual Studio.", 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 = path.normalize(failure.getFileName()); const failureString = failure.getFailure(); const camelizedRule = camelize(failure.getRuleName()); const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const positionTuple = `(${lineAndCharacter.line + 1},${lineAndCharacter.character + 1})`; const severity = failure.getRuleSeverity(); return `${fileName}${positionTuple}: ${severity} ${camelizedRule}: ${failureString}`; }); return `${outputLines.join("\n")}\n`; } } tslint-5.9.1/src/formatters/pmdFormatter.ts000066400000000000000000000047221322551053300210400ustar00rootroot00000000000000/** * @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 { 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 = ""; for (const failure of failures) { const failureString = failure.getFailure() .replace(/&/g, "&") .replace(//g, ">") .replace(/'/g, "'") .replace(/"/g, """); const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const priority = failure.getRuleSeverity() === "warning" ? 4 : 3; output += ``; } output += ""; return output; } } tslint-5.9.1/src/formatters/proseFormatter.ts000066400000000000000000000051421322551053300214050ustar00rootroot00000000000000/** * @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 { 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: "prose", description: "The default formatter which outputs simple human-readable messages.", sample: "ERROR: 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 === undefined || fixes.length === 0)) { return "\n"; } failures = this.sortFailures(failures); const fixLines: string[] = []; if (fixes !== undefined) { const perFileFixes = new Map(); for (const fix of fixes) { const prevFixes = perFileFixes.get(fix.getFileName()); perFileFixes.set(fix.getFileName(), (prevFixes !== undefined ? prevFixes : 0) + 1); } perFileFixes.forEach((fixCount, fixedFile) => { fixLines.push(`Fixed ${fixCount} error(s) in ${fixedFile}`); }); fixLines.push(""); // add a blank line between fixes and failures } const errorLines = failures.map((failure: RuleFailure) => { const fileName = failure.getFileName(); const failureString = failure.getFailure(); const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const positionTuple = `[${lineAndCharacter.line + 1}, ${lineAndCharacter.character + 1}]`; return `${failure.getRuleSeverity().toUpperCase()}: ${fileName}${positionTuple}: ${failureString}`; }); return `${fixLines.concat(errorLines).join("\n")}\n`; } } tslint-5.9.1/src/formatters/stylishFormatter.ts000066400000000000000000000107761322551053300217650ustar00rootroot00000000000000/** * @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 { AbstractFormatter } from "../language/formatter/abstractFormatter"; import { IFormatterMetadata } from "../language/formatter/formatter"; import { RuleFailure } from "../language/rule/rule"; import chalk from "chalk"; 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 what is produced by ESLint's stylish formatter. Its readability is 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 { failures = this.sortFailures(failures); const outputLines = this.mapToMessages(failures); // Removes initial blank line if (outputLines[0] === "") { outputLines.shift(); } return `${outputLines.join("\n")}\n`; } private mapToMessages(failures: RuleFailure[]): string[] { if (failures.length === 0) { return []; } const outputLines: string[] = []; const positionMaxSize = this.getPositionMaxSize(failures); const ruleMaxSize = this.getRuleMaxSize(failures); let currentFile: string | undefined; for (const failure of failures) { const fileName = failure.getFileName(); const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); let positionTuple = `${lineAndCharacter.line + 1}:${lineAndCharacter.character + 1}`; // Output the name of each file once if (currentFile !== fileName) { outputLines.push(""); outputLines.push(`${fileName}${chalk.hidden(`:${positionTuple}`)}`); currentFile = fileName; } let failureString = failure.getFailure(); failureString = chalk.yellow(failureString); // Rule let ruleName = failure.getRuleName(); ruleName = this.pad(ruleName, ruleMaxSize); ruleName = chalk.grey(ruleName); // Lines positionTuple = this.pad(positionTuple, positionMaxSize); positionTuple = failure.getRuleSeverity() === "warning" ? chalk.blue(`${failure.getRuleSeverity().toUpperCase()}: ${positionTuple}`) : chalk.red(`${failure.getRuleSeverity().toUpperCase()}: ${positionTuple}`); // Output const output = `${positionTuple} ${ruleName} ${failureString}`; outputLines.push(output); } return outputLines; } private pad(str: string, len: number): string { const padder = Array(len + 1).join(" "); return (str + padder).substring(0, padder.length); } private getPositionMaxSize(failures: RuleFailure[]): number { let positionMaxSize = 0; for (const failure of failures) { const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const positionSize = `${lineAndCharacter.line + 1}:${lineAndCharacter.character + 1}`.length; if (positionSize > positionMaxSize) { positionMaxSize = positionSize; } } return positionMaxSize; } private getRuleMaxSize(failures: RuleFailure[]): number { let ruleMaxSize = 0; for (const failure of failures) { const ruleSize = failure.getRuleName().length; if (ruleSize > ruleMaxSize) { ruleMaxSize = ruleSize; } } return ruleMaxSize; } } tslint-5.9.1/src/formatters/tapFormatter.ts000066400000000000000000000063631322551053300210470ustar00rootroot00000000000000/** * @license * Copyright 2017 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { 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: "tap", description: "Formats output as TAP stream.", descriptionDetails: "Provides error messages output in TAP13 format which can be consumed by any TAP formatter.", sample: Utils.dedent` TAP version 13 1..1 not ok 1 - Some error --- message: Variable has any type severity: error data: ruleName: no-any fileName: test-file.ts line: 10 character: 10 failureString: Some error rawLines: Some raw output ...`, consumer: "machine", }; /* tslint:enable:object-literal-sort-keys */ public format(failures: RuleFailure[]): string { let output: string[] = ["TAP version 13"]; if (failures.length === 0) { output = output.concat([ "1..0 # SKIP No failures", ]); } else { output = output.concat([`1..${failures.length}`]).concat(this.mapToMessages(failures)); } return `${output.join("\n")}\n`; } private mapToMessages(failures: RuleFailure[]): string[] { return failures.map((failure: RuleFailure, i: number) => { const fileName = failure.getFileName(); const failureString = failure.getFailure(); const ruleName = failure.getRuleName(); const failureMessage = failure.getFailure(); const failureSeverity = failure.getRuleSeverity(); const failureRaw = failure.getRawLines(); const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); return Utils.dedent` not ok ${String(i + 1)} - ${failureMessage} --- message : ${failureMessage} severity: ${failureSeverity} data: ruleName: ${ruleName} fileName: ${fileName} line: ${String(lineAndCharacter.line)} character: ${String(lineAndCharacter.character)} failureString: ${failureString} rawLines: ${failureRaw} ...`; }); } } tslint-5.9.1/src/formatters/verboseFormatter.ts000066400000000000000000000041571322551053300217270ustar00rootroot00000000000000/** * @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 { 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: "ERROR: (semicolon) myFile.ts[1, 14]: Missing semicolon", consumer: "human", }; /* tslint:enable:object-literal-sort-keys */ public format(failures: RuleFailure[]): string { failures = this.sortFailures(failures); return `${this.mapToMessages(failures).join("\n")}\n`; } private mapToMessages(failures: RuleFailure[]): string[] { return failures.map((failure: RuleFailure) => { const fileName = failure.getFileName(); const failureString = failure.getFailure(); const ruleName = failure.getRuleName(); const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const positionTuple = `[${lineAndCharacter.line + 1}, ${lineAndCharacter.character + 1}]`; return `${failure.getRuleSeverity().toUpperCase()}: (${ruleName}) ${fileName}${positionTuple}: ${failureString}`; }); } } tslint-5.9.1/src/formatters/vsoFormatter.ts000066400000000000000000000043331322551053300210650ustar00rootroot00000000000000/** * @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 { 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(); const failureString = failure.getFailure(); const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const line = lineAndCharacter.line + 1; const character = lineAndCharacter.character + 1; const code = failure.getRuleName(); const properties = `sourcepath=${fileName};linenumber=${line};columnnumber=${character};code=${code};`; return `##vso[task.logissue type=warning;${properties}]${failureString}`; }); return `${outputLines.join("\n")}\n`; } } tslint-5.9.1/src/index.ts000066400000000000000000000032001322551053300153030ustar00rootroot00000000000000/** * @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 Configuration from "./configuration"; import * as Formatters from "./formatters"; import { FormatterConstructor } from "./language/formatter/formatter"; import { RuleFailure } from "./language/rule/rule"; import * as Rules from "./rules"; import * as Test from "./test"; import * as Utils from "./utils"; export { Configuration, Formatters, Rules, Test, Utils }; export * from "./linter"; export * from "./language/rule/rule"; export * from "./enableDisableRules"; export * from "./formatterLoader"; export * from "./ruleLoader"; export * from "./language/utils"; export * from "./language/walker"; export * from "./language/formatter/formatter"; export interface LintResult { errorCount: number; warningCount: number; failures: RuleFailure[]; fixes?: RuleFailure[]; format: string | FormatterConstructor; output: string; } export interface ILinterOptions { fix: boolean; formatter?: string | FormatterConstructor; formattersDirectory?: string; rulesDirectory?: string | string[]; } tslint-5.9.1/src/language/000077500000000000000000000000001322551053300154145ustar00rootroot00000000000000tslint-5.9.1/src/language/formatter/000077500000000000000000000000001322551053300174175ustar00rootroot00000000000000tslint-5.9.1/src/language/formatter/abstractFormatter.ts000066400000000000000000000020221322551053300234520ustar00rootroot00000000000000/** * @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 { RuleFailure } from "../rule/rule"; import { IFormatter, IFormatterMetadata } from "./formatter"; export abstract class AbstractFormatter implements IFormatter { public static metadata: IFormatterMetadata; public abstract format(failures: RuleFailure[]): string; protected sortFailures(failures: RuleFailure[]): RuleFailure[] { return failures.slice().sort(RuleFailure.compare); } } tslint-5.9.1/src/language/formatter/formatter.ts000066400000000000000000000030631322551053300217740ustar00rootroot00000000000000/** * @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 { 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 FormatterConstructor { new(): IFormatter; } export interface IFormatter { /** * Formats linter results * @param failures Linter failures that were not fixed * @param fixes Fixed linter failures. Available when the `--fix` argument is used on the command line */ format(failures: RuleFailure[], fixes?: RuleFailure[]): string; } tslint-5.9.1/src/language/rule/000077500000000000000000000000001322551053300163635ustar00rootroot00000000000000tslint-5.9.1/src/language/rule/abstractRule.ts000066400000000000000000000052531322551053300213730ustar00rootroot00000000000000/** * @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 { IWalker, WalkContext } from "../walker"; import { IOptions, IRule, IRuleMetadata, RuleFailure, RuleSeverity } from "./rule"; export type NoInfer = T & {[K in keyof T]: T[K]}; export abstract class AbstractRule implements IRule { public static metadata: IRuleMetadata; protected readonly ruleArguments: any[]; protected readonly ruleSeverity: RuleSeverity; public ruleName: string; constructor(private readonly options: IOptions) { this.ruleName = options.ruleName; this.ruleArguments = options.ruleArguments; this.ruleSeverity = options.ruleSeverity; } public getOptions(): IOptions { return this.options; } public abstract apply(sourceFile: ts.SourceFile): RuleFailure[]; public applyWithWalker(walker: IWalker): RuleFailure[] { walker.walk(walker.getSourceFile()); return walker.getFailures(); } public isEnabled(): boolean { return this.ruleSeverity !== "off"; } protected applyWithFunction(sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext) => void): RuleFailure[]; protected applyWithFunction(sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext) => void, options: NoInfer): RuleFailure[]; protected applyWithFunction( sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext, programOrChecker: U) => void, options: NoInfer, checker: NoInfer, ): RuleFailure[]; protected applyWithFunction( sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext, programOrChecker?: U) => void, options?: T, programOrChecker?: U, ): RuleFailure[] { const ctx = new WalkContext(sourceFile, this.ruleName, options); walkFn(ctx, programOrChecker); return ctx.failures; } /** * @deprecated * Failures will be filtered based on `tslint:disable` comments by tslint. * This method now does nothing. */ protected filterFailures(failures: RuleFailure[]) { return failures; } } tslint-5.9.1/src/language/rule/optionallyTypedRule.ts000066400000000000000000000016641322551053300227720ustar00rootroot00000000000000/** * @license * Copyright 2017 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as ts from "typescript"; import { AbstractRule } from "./abstractRule"; import { ITypedRule, RuleFailure } from "./rule"; export abstract class OptionallyTypedRule extends AbstractRule implements ITypedRule { public abstract applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[]; } tslint-5.9.1/src/language/rule/rule.ts000066400000000000000000000222311322551053300177020ustar00rootroot00000000000000/** * @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 { arrayify, flatMap } from "../../utils"; import { IWalker } from "../walker"; export interface RuleConstructor { metadata: IRuleMetadata; new(options: IOptions): IRule; } export interface IRuleMetadata { /** * The kebab-case name of the rule. */ ruleName: string; /** * The type of the rule - its overall purpose */ type: RuleType; /** * A rule deprecation message, if applicable. */ deprecationMessage?: string; /** * A short, one line description of what the rule does. */ description: string; /** * More elaborate details about the rule. */ descriptionDetails?: string; /** * Whether or not the rule will provide fix suggestions. */ hasFix?: boolean; /** * An explanation of the available options for the rule. */ optionsDescription: string; /** * Schema of the options the rule accepts. * The first boolean for whether the rule is enabled or not is already implied. * This field describes the options after that boolean. * If null, this rule has no options and is not configurable. */ options: any; /** * Examples of what a standard config for the rule might look like. * Using a string[] here is deprecated. Write the options as a JSON object instead. */ optionExamples?: Array | string[]; /** * An explanation of why the rule is useful. */ rationale?: string; /** * 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"; export type RuleSeverity = "warning" | "error" | "off"; export interface IOptions { ruleArguments: any[]; ruleSeverity: RuleSeverity; ruleName: string; /** * @deprecated * Tslint now handles disables itself. * This will be empty. */ disabledIntervals: IDisabledInterval[]; // tslint:disable-line deprecation } /** * @deprecated * These are now handled internally. */ export interface IDisabledInterval { startPosition: number; endPosition: number; } export interface IRule { getOptions(): IOptions; isEnabled(): boolean; apply(sourceFile: ts.SourceFile): RuleFailure[]; applyWithWalker(walker: IWalker): RuleFailure[]; } export interface ITypedRule extends IRule { applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[]; } export interface IRuleFailureJson { endPosition: IRuleFailurePositionJson; failure: string; fix?: FixJson; name: string; ruleSeverity: string; ruleName: string; startPosition: IRuleFailurePositionJson; } export interface IRuleFailurePositionJson { character: number; line: number; position: number; } export function isTypedRule(rule: IRule): rule is ITypedRule { return "applyWithProgram" in rule; } export interface ReplacementJson { innerStart: number; innerLength: number; innerText: string; } export class Replacement { public static applyFixes(content: string, fixes: Fix[]): string { return this.applyAll(content, flatMap(fixes, arrayify)); } public static applyAll(content: string, replacements: Replacement[]) { // sort in reverse so that diffs are properly applied replacements.sort((a, b) => b.end !== a.end ? b.end - a.end : b.start - a.start); return replacements.reduce((text, r) => r.apply(text), content); } public static replaceNode(node: ts.Node, text: string, sourceFile?: ts.SourceFile): Replacement { return this.replaceFromTo(node.getStart(sourceFile), node.getEnd(), text); } public static replaceFromTo(start: number, end: number, text: string) { return new Replacement(start, end - start, text); } public static deleteText(start: number, length: number) { return new Replacement(start, length, ""); } public static deleteFromTo(start: number, end: number) { return new Replacement(start, end - start, ""); } public static appendText(start: number, text: string) { return new Replacement(start, 0, text); } constructor(readonly start: number, readonly length: number, readonly text: string) {} get end() { return this.start + this.length; } public apply(content: string) { return content.substring(0, this.start) + this.text + content.substring(this.start + this.length); } public toJson(): ReplacementJson { // tslint:disable object-literal-sort-keys return { innerStart: this.start, innerLength: this.length, innerText: this.text, }; // tslint:enable object-literal-sort-keys } } export class RuleFailurePosition { constructor(private readonly position: number, private readonly lineAndCharacter: ts.LineAndCharacter) { } public getPosition() { return this.position; } public getLineAndCharacter() { return this.lineAndCharacter; } public toJson(): IRuleFailurePositionJson { return { character: this.lineAndCharacter.character, line: this.lineAndCharacter.line, position: this.position, }; } public equals(ruleFailurePosition: RuleFailurePosition) { const ll = this.lineAndCharacter; const rr = ruleFailurePosition.lineAndCharacter; return this.position === ruleFailurePosition.position && ll.line === rr.line && ll.character === rr.character; } } export type Fix = Replacement | Replacement[]; export type FixJson = ReplacementJson | ReplacementJson[]; export class RuleFailure { private readonly fileName: string; private readonly startPosition: RuleFailurePosition; private readonly endPosition: RuleFailurePosition; private readonly rawLines: string; private ruleSeverity: RuleSeverity; public static compare(a: RuleFailure, b: RuleFailure): number { if (a.fileName !== b.fileName) { return a.fileName < b.fileName ? -1 : 1; } return a.startPosition.getPosition() - b.startPosition.getPosition(); } constructor(private readonly sourceFile: ts.SourceFile, start: number, end: number, private readonly failure: string, private readonly ruleName: string, private readonly fix?: Fix) { this.fileName = sourceFile.fileName; this.startPosition = this.createFailurePosition(start); this.endPosition = this.createFailurePosition(end); this.rawLines = sourceFile.text; this.ruleSeverity = "error"; } public getFileName() { return this.fileName; } public getRuleName() { return this.ruleName; } public getStartPosition(): RuleFailurePosition { return this.startPosition; } public getEndPosition(): RuleFailurePosition { return this.endPosition; } public getFailure() { return this.failure; } public hasFix() { return this.fix !== undefined; } public getFix() { return this.fix; } public getRawLines() { return this.rawLines; } public getRuleSeverity() { return this.ruleSeverity; } public setRuleSeverity(value: RuleSeverity) { this.ruleSeverity = value; } public toJson(): IRuleFailureJson { return { endPosition: this.endPosition.toJson(), failure: this.failure, fix: this.fix === undefined ? undefined : Array.isArray(this.fix) ? this.fix.map((r) => r.toJson()) : this.fix.toJson(), name: this.fileName, ruleName: this.ruleName, ruleSeverity: this.ruleSeverity.toUpperCase(), startPosition: this.startPosition.toJson(), }; } public equals(ruleFailure: RuleFailure) { return this.failure === ruleFailure.getFailure() && this.fileName === ruleFailure.getFileName() && this.startPosition.equals(ruleFailure.getStartPosition()) && this.endPosition.equals(ruleFailure.getEndPosition()); } private createFailurePosition(position: number) { const lineAndCharacter = this.sourceFile.getLineAndCharacterOfPosition(position); return new RuleFailurePosition(position, lineAndCharacter); } } tslint-5.9.1/src/language/rule/typedRule.ts000066400000000000000000000022631322551053300207130ustar00rootroot00000000000000/** * @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 { showWarningOnce } from "../../error"; import { AbstractRule } from "./abstractRule"; import { ITypedRule, RuleFailure } from "./rule"; export abstract class TypedRule extends AbstractRule implements ITypedRule { public apply(): RuleFailure[] { // if no program is given to the linter, show an error showWarningOnce(`Warning: The '${this.ruleName}' rule requires type information.`); return []; } public abstract applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[]; } tslint-5.9.1/src/language/typeUtils.ts000066400000000000000000000023101322551053300177620ustar00rootroot00000000000000/** * @license * Copyright 2017 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as ts from "typescript"; export const typeIsOrHasBaseType = (type: ts.Type, parentType: ts.Type) => { if (type.symbol === undefined || parentType.symbol === undefined) { return false; } const typeAndBaseTypes = [type]; const ancestorTypes = type.getBaseTypes(); if (ancestorTypes !== undefined) { typeAndBaseTypes.push(...ancestorTypes); } for (const baseType of typeAndBaseTypes) { if (baseType.symbol !== undefined && baseType.symbol.name === parentType.symbol.name) { return true; } } return false; }; tslint-5.9.1/src/language/utils.ts000066400000000000000000000504621322551053300171330ustar00rootroot00000000000000/** * @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 path from "path"; import { isBlockScopedVariableDeclarationList, isIdentifier, isPrefixUnaryExpression } from "tsutils"; import * as ts from "typescript"; import { IDisabledInterval, RuleFailure } from "./rule/rule"; export function getSourceFile(fileName: string, source: string): ts.SourceFile { const normalizedName = path.normalize(fileName).replace(/\\/g, "/"); return ts.createSourceFile(normalizedName, source, ts.ScriptTarget.ES5, /*setParentNodes*/ true); } /** @deprecated See IDisabledInterval. */ export function doesIntersect(failure: RuleFailure, disabledIntervals: IDisabledInterval[]): boolean { // tslint:disable-line deprecation return disabledIntervals.some((interval) => { const maxStart = Math.max(interval.startPosition, failure.getStartPosition().getPosition()); const minEnd = Math.min(interval.endPosition, failure.getEndPosition().getPosition()); return maxStart <= minEnd; }); } /** * @returns true if any modifier kinds passed along exist in the given modifiers array * * @deprecated use `hasModifier` from `tsutils` */ export function hasModifier(modifiers: ts.ModifiersArray | undefined, ...modifierKinds: ts.SyntaxKind[]): boolean { if (modifiers === undefined || modifierKinds.length === 0) { return false; } return modifiers.some( (m) => modifierKinds.some((k) => m.kind === k)); } /** * Determines if the appropriate bit in the parent (VariableDeclarationList) is set, * which indicates this is a "let" or "const". * * @deprecated use `isBlockScopedVariableDeclarationList` from `tsutils` */ export function isBlockScopedVariable(node: ts.VariableDeclaration | ts.VariableStatement): boolean { if (node.kind === ts.SyntaxKind.VariableDeclaration) { const parent = node.parent!; return parent.kind === ts.SyntaxKind.CatchClause || isBlockScopedVariableDeclarationList(parent); } else { return isBlockScopedVariableDeclarationList(node.declarationList); } } /** @deprecated use `isBlockScopedVariableDeclarationList` and `getDeclarationOfBindingElement` from `tsutils` */ export function isBlockScopedBindingElement(node: ts.BindingElement): boolean { const variableDeclaration = getBindingElementVariableDeclaration(node); // tslint:disable-line:deprecation // if no variable declaration, it must be a function param, which is block scoped return (variableDeclaration === null) || isBlockScopedVariable(variableDeclaration); // tslint:disable-line:deprecation } /** @deprecated use `getDeclarationOfBindingElement` from `tsutils` */ export function getBindingElementVariableDeclaration(node: ts.BindingElement): ts.VariableDeclaration | null { let currentParent = node.parent! as ts.Node; while (currentParent.kind !== ts.SyntaxKind.VariableDeclaration) { if (currentParent.parent === undefined) { return null; // function parameter, no variable declaration } else { currentParent = currentParent.parent; } } return currentParent as ts.VariableDeclaration; } /** * Finds a child of a given node with a given kind. * Note: This uses `node.getChildren()`, which does extra parsing work to include tokens. * * @deprecated use `getChildOfKind` from `tsutils` */ export function childOfKind(node: ts.Node, kind: ts.SyntaxKind): ts.Node | undefined { return node.getChildren().find((child) => child.kind === kind); } /** * @returns true if some ancestor of `node` satisfies `predicate`, including `node` itself. * * @deprecated no longer used, use a `while` loop instead */ export function someAncestor(node: ts.Node, predicate: (n: ts.Node) => boolean): boolean { return predicate(node) || (node.parent !== undefined && someAncestor(node.parent, predicate)); // tslint:disable-line:deprecation } export function ancestorWhere( node: ts.Node, predicate: ((n: ts.Node) => n is T) | ((n: ts.Node) => boolean), ): T | undefined { let cur: ts.Node | undefined = node; do { if (predicate(cur)) { return cur; } cur = cur.parent; } while (cur !== undefined); return undefined; } /** @deprecated use `isBinaryExpression(node) && isAssignmentKind(node.operatorToken.kind)` with functions from `tsutils` */ export function isAssignment(node: ts.Node) { if (node.kind === ts.SyntaxKind.BinaryExpression) { const binaryExpression = node as ts.BinaryExpression; return binaryExpression.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && binaryExpression.operatorToken.kind <= ts.SyntaxKind.LastAssignment; } else { return false; } } /** * Bitwise check for node flags. * * @deprecated use `isNodeFlagSet` from `tsutils` */ export function isNodeFlagSet(node: ts.Node, flagToCheck: ts.NodeFlags): boolean { // tslint:disable-next-line:no-bitwise return (node.flags & flagToCheck) !== 0; } /** * Bitwise check for combined node flags. * * @deprecated no longer used */ export function isCombinedNodeFlagSet(node: ts.Node, flagToCheck: ts.NodeFlags): boolean { // tslint:disable-next-line:no-bitwise return (ts.getCombinedNodeFlags(node) & flagToCheck) !== 0; } /** * Bitwise check for combined modifier flags. * * @deprecated no longer used */ export function isCombinedModifierFlagSet(node: ts.Node, flagToCheck: ts.ModifierFlags): boolean { // tslint:disable-next-line:no-bitwise return (ts.getCombinedModifierFlags(node) & flagToCheck) !== 0; } /** * Bitwise check for type flags. * * @deprecated use `isTypeFlagSet` from `tsutils` */ export function isTypeFlagSet(type: ts.Type, flagToCheck: ts.TypeFlags): boolean { // tslint:disable-next-line:no-bitwise return (type.flags & flagToCheck) !== 0; } /** * Bitwise check for symbol flags. * * @deprecated use `isSymbolFlagSet` from `tsutils` */ export function isSymbolFlagSet(symbol: ts.Symbol, flagToCheck: ts.SymbolFlags): boolean { // tslint:disable-next-line:no-bitwise return (symbol.flags & flagToCheck) !== 0; } /** * Bitwise check for object flags. * Does not work with TypeScript 2.0.x * * @deprecated use `isObjectFlagSet` from `tsutils` */ export function isObjectFlagSet(objectType: ts.ObjectType, flagToCheck: ts.ObjectFlags): boolean { // tslint:disable-next-line:no-bitwise return (objectType.objectFlags & flagToCheck) !== 0; } /** * @returns true if decl is a nested module declaration, i.e. represents a segment of a dotted module path. * * @deprecated use `decl.parent!.kind === ts.SyntaxKind.ModuleDeclaration` */ 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' // are nested therefore we can depend that a node's position will only match with its name's position for nested // nodes return decl.name.pos === decl.pos; } export function unwrapParentheses(node: ts.Expression) { while (node.kind === ts.SyntaxKind.ParenthesizedExpression) { node = (node as ts.ParenthesizedExpression).expression; } return node; } /** @deprecated use `isFunctionScopeBoundary` from `tsutils` */ export function isScopeBoundary(node: ts.Node): boolean { return node.kind === ts.SyntaxKind.FunctionDeclaration || node.kind === ts.SyntaxKind.FunctionExpression || node.kind === ts.SyntaxKind.PropertyAssignment || node.kind === ts.SyntaxKind.ShorthandPropertyAssignment || node.kind === ts.SyntaxKind.MethodDeclaration || node.kind === ts.SyntaxKind.Constructor || node.kind === ts.SyntaxKind.ModuleDeclaration || node.kind === ts.SyntaxKind.ArrowFunction || node.kind === ts.SyntaxKind.ParenthesizedExpression || node.kind === ts.SyntaxKind.ClassDeclaration || node.kind === ts.SyntaxKind.ClassExpression || node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.GetAccessor || node.kind === ts.SyntaxKind.SetAccessor || node.kind === ts.SyntaxKind.SourceFile && ts.isExternalModule(node as ts.SourceFile); } /** @deprecated use `isBlockScopeBoundary` from `tsutils` */ export function isBlockScopeBoundary(node: ts.Node): boolean { return isScopeBoundary(node) // tslint:disable-line:deprecation || node.kind === ts.SyntaxKind.Block || isLoop(node) // tslint:disable-line:deprecation || node.kind === ts.SyntaxKind.WithStatement || node.kind === ts.SyntaxKind.SwitchStatement || node.parent !== undefined && (node.parent.kind === ts.SyntaxKind.TryStatement || node.parent.kind === ts.SyntaxKind.IfStatement); } /** @deprecated use `isIterationStatement` from `tsutils` or `typescript` */ export function isLoop(node: ts.Node): node is ts.IterationStatement { return node.kind === ts.SyntaxKind.DoStatement || node.kind === ts.SyntaxKind.WhileStatement || node.kind === ts.SyntaxKind.ForStatement || node.kind === ts.SyntaxKind.ForInStatement || node.kind === ts.SyntaxKind.ForOfStatement; } /** * @returns Whether node is a numeric expression. */ export function isNumeric(node: ts.Expression) { while (isPrefixUnaryExpression(node) && (node.operator === ts.SyntaxKind.PlusToken || node.operator === ts.SyntaxKind.MinusToken)) { node = node.operand; } return node.kind === ts.SyntaxKind.NumericLiteral || isIdentifier(node) && (node.text === "NaN" || node.text === "Infinity"); } export interface TokenPosition { /** The start of the token including all trivia before it */ fullStart: number; /** The start of the token */ tokenStart: number; /** The end of the token */ end: number; } export type ForEachTokenCallback = (fullText: string, kind: ts.SyntaxKind, pos: TokenPosition, parent: ts.Node) => void; export type ForEachCommentCallback = (fullText: string, kind: ts.SyntaxKind, pos: TokenPosition) => void; export type FilterCallback = (node: ts.Node) => boolean; /** * Iterate over all tokens of `node` * * @description JsDoc comments are treated like regular comments and only visited if `skipTrivia` === false. * * @param node The node whose tokens should be visited * @param skipTrivia If set to false all trivia preceeding `node` or any of its children is included * @param cb Is called for every token of `node`. It gets the full text of the SourceFile and the position of the token within that text. * @param filter If provided, will be called for every Node and Token found. If it returns false `cb` will not be called for this subtree. * * @deprecated use `forEachToken` or `forEachTokenWithTrivia` from `tsutils` */ export function forEachToken(node: ts.Node, skipTrivia: boolean, cb: ForEachTokenCallback, filter?: FilterCallback) { // this function will most likely be called with SourceFile anyways, so there is no need for an additional parameter const sourceFile = node.getSourceFile(); const fullText = sourceFile.text; const iterateFn = filter === undefined ? iterateChildren : iterateWithFilter; const handleTrivia = skipTrivia ? undefined : createTriviaHandler(sourceFile, cb); iterateFn(node); // this function is used to save the if condition for the common case where no filter is provided function iterateWithFilter(child: ts.Node): void { if (filter!(child)) { return iterateChildren(child); } } function iterateChildren(child: ts.Node): void { if (child.kind < ts.SyntaxKind.FirstNode || // for backwards compatibility to typescript 2.0.10 // JsxText was no Token, but a Node in that version child.kind === ts.SyntaxKind.JsxText) { // we found a token, tokens have no children, stop recursing here return callback(child); } /* Exclude everything contained in JsDoc, it will be handled with the other trivia anyway. * When we would handle JsDoc tokens like regular ones, we would scan some trivia multiple times. * Even worse, we would scan for trivia inside the JsDoc comment, which yields unexpected results.*/ if (child.kind !== ts.SyntaxKind.JSDocComment) { // recurse into Node's children to find tokens return child.getChildren(sourceFile).forEach(iterateFn); } } function callback(token: ts.Node) { const tokenStart = token.getStart(sourceFile); if (!skipTrivia && tokenStart !== token.pos) { // we only have to handle trivia before each token, because there is nothing after EndOfFileToken handleTrivia!(token.pos, tokenStart, token); } return cb(fullText, token.kind, {tokenStart, fullStart: token.pos, end: token.end}, token.parent!); } } function createTriviaHandler(sourceFile: ts.SourceFile, cb: ForEachTokenCallback) { const fullText = sourceFile.text; const scanner = ts.createScanner(sourceFile.languageVersion, false, sourceFile.languageVariant, fullText); /** * Scan the specified range to get all trivia tokens. * This includes trailing trivia of the last token and the leading trivia of the current token */ function handleTrivia(start: number, end: number, token: ts.Node) { const parent = token.parent!; // prevent false positives by not scanning inside JsxText if (!canHaveLeadingTrivia(token.kind, parent)) { return; } scanner.setTextPos(start); let position: number; // we only get here if start !== end, so we can scan at least one time do { const kind = scanner.scan(); position = scanner.getTextPos(); cb(fullText, kind, {tokenStart: scanner.getTokenPos(), end: position, fullStart: start}, parent); } while (position < end); } return handleTrivia; } /** * Iterate over all comments owned by `node` or its children * * @deprecated use `forEachComment` from `tsutils` */ export function forEachComment(node: ts.Node, cb: ForEachCommentCallback) { /* Visit all tokens and skip trivia. Comment ranges between tokens are parsed without the need of a scanner. forEachToken also does intentionally not pay attention to the correct comment ownership of nodes as it always scans all trivia before each token, which could include trailing comments of the previous token. Comment onwership is done right in this function*/ return forEachToken(node, true, (fullText, tokenKind, pos, parent) => { // tslint:disable-line:deprecation // don't search for comments inside JsxText if (canHaveLeadingTrivia(tokenKind, parent)) { // Comments before the first token (pos.fullStart === 0) are all considered leading comments, so no need for special treatment const comments = ts.getLeadingCommentRanges(fullText, pos.fullStart); if (comments !== undefined) { for (const comment of comments) { cb(fullText, comment.kind, {fullStart: pos.fullStart, tokenStart: comment.pos, end: comment.end}); } } } if (canHaveTrailingTrivia(tokenKind, parent)) { const comments = ts.getTrailingCommentRanges(fullText, pos.end); if (comments !== undefined) { for (const comment of comments) { cb(fullText, comment.kind, {fullStart: pos.fullStart, tokenStart: comment.pos, end: comment.end}); } } } }); } /** Exclude leading positions that would lead to scanning for trivia inside JsxText */ function canHaveLeadingTrivia(tokenKind: ts.SyntaxKind, parent: ts.Node): boolean { switch (tokenKind) { case ts.SyntaxKind.JsxText: return false; // there is no trivia before JsxText case ts.SyntaxKind.OpenBraceToken: // before a JsxExpression inside a JsxElement's body can only be other JsxChild, but no trivia return parent.kind !== ts.SyntaxKind.JsxExpression || parent.parent!.kind !== ts.SyntaxKind.JsxElement; case ts.SyntaxKind.LessThanToken: switch (parent.kind) { case ts.SyntaxKind.JsxClosingElement: return false; // would be inside the element body case ts.SyntaxKind.JsxOpeningElement: case ts.SyntaxKind.JsxSelfClosingElement: // there can only be leading trivia if we are at the end of the top level element return parent.parent!.parent!.kind !== ts.SyntaxKind.JsxElement; default: return true; } default: return true; } } /** Exclude trailing positions that would lead to scanning for trivia inside JsxText */ function canHaveTrailingTrivia(tokenKind: ts.SyntaxKind, parent: ts.Node): boolean { switch (tokenKind) { case ts.SyntaxKind.JsxText: // there is no trivia after JsxText return false; case ts.SyntaxKind.CloseBraceToken: // after a JsxExpression inside a JsxElement's body can only be other JsxChild, but no trivia return parent.kind !== ts.SyntaxKind.JsxExpression || parent.parent!.kind !== ts.SyntaxKind.JsxElement; case ts.SyntaxKind.GreaterThanToken: switch (parent.kind) { case ts.SyntaxKind.JsxOpeningElement: return false; // would be inside the element case ts.SyntaxKind.JsxClosingElement: case ts.SyntaxKind.JsxSelfClosingElement: // there can only be trailing trivia if we are at the end of the top level element return parent.parent!.parent!.kind !== ts.SyntaxKind.JsxElement; default: return true; } default: return true; } } /** * Checks if there are any comments between `position` and the next non-trivia token * * @param text The text to scan * @param position The position inside `text` where to start scanning. Make sure that this is a valid start position. * This value is typically obtained from `node.getFullStart()` or `node.getEnd()` */ export function hasCommentAfterPosition(text: string, position: number): boolean { return ts.getTrailingCommentRanges(text, position) !== undefined || ts.getLeadingCommentRanges(text, position) !== undefined; } export interface EqualsKind { isPositive: boolean; // True for "===" and "==" isStrict: boolean; // True for "===" and "!==" } export function getEqualsKind(node: ts.BinaryOperatorToken): EqualsKind | undefined { switch (node.kind) { case ts.SyntaxKind.EqualsEqualsToken: return { isPositive: true, isStrict: false }; case ts.SyntaxKind.EqualsEqualsEqualsToken: return { isPositive: true, isStrict: true }; case ts.SyntaxKind.ExclamationEqualsToken: return { isPositive: false, isStrict: false }; case ts.SyntaxKind.ExclamationEqualsEqualsToken: return { isPositive: false, isStrict: true }; default: return undefined; } } export function isStrictNullChecksEnabled(options: ts.CompilerOptions): boolean { return options.strictNullChecks === true || (options.strict === true && options.strictNullChecks !== false); } export function isNegativeNumberLiteral(node: ts.Node): node is ts.PrefixUnaryExpression & { operand: ts.NumericLiteral } { return isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken && node.operand.kind === ts.SyntaxKind.NumericLiteral; } /** Wrapper for compatibility with typescript@<2.3.1 */ export function isWhiteSpace(ch: number): boolean { // tslint:disable-next-line return (ts.isWhiteSpaceLike || (ts as any).isWhiteSpace)(ch); } tslint-5.9.1/src/language/walker/000077500000000000000000000000001322551053300167015ustar00rootroot00000000000000tslint-5.9.1/src/language/walker/blockScopeAwareRuleWalker.ts000066400000000000000000000060171322551053300243170ustar00rootroot00000000000000/** * @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 { IOptions } from "../rule/rule"; import { isBlockScopeBoundary } from "../utils"; import { ScopeAwareRuleWalker } from "./scopeAwareRuleWalker"; // tslint:disable:deprecation (extends deprecated class and uses deprecated utils - doesn't matter because it's deprecated, too) /** * @deprecated See comment on ScopeAwareRuleWalker. * * An AST walker that is aware of block scopes in addition to regular scopes. Block scopes * are a superset of regular scopes (new block scopes are created more frequently in a program). */ export abstract class BlockScopeAwareRuleWalker extends ScopeAwareRuleWalker { private readonly blockScopeStack: U[]; constructor(sourceFile: ts.SourceFile, options: IOptions) { super(sourceFile, options); // initialize with global scope if file is not a module this.blockScopeStack = ts.isExternalModule(sourceFile) ? [] : [this.createBlockScope(sourceFile)]; } public abstract createBlockScope(node: ts.Node): U; // get all block scopes available at this depth public getAllBlockScopes(): U[] { return this.blockScopeStack; } public getCurrentBlockScope(): U { return this.blockScopeStack[this.blockScopeStack.length - 1]; } public getCurrentBlockDepth(): number { return this.blockScopeStack.length; } // callback notifier when a block scope begins public onBlockScopeStart() { return; } // callback notifier when a block scope ends public onBlockScopeEnd() { return; } public findBlockScope(predicate: (scope: U) => boolean) { // look through block scopes from local -> global for (let i = this.blockScopeStack.length - 1; i >= 0; i--) { if (predicate(this.blockScopeStack[i])) { return this.blockScopeStack[i]; } } return undefined; } protected visitNode(node: ts.Node) { const isNewBlockScope = this.isBlockScopeBoundary(node); if (isNewBlockScope) { this.blockScopeStack.push(this.createBlockScope(node)); this.onBlockScopeStart(); } super.visitNode(node); if (isNewBlockScope) { this.onBlockScopeEnd(); this.blockScopeStack.pop(); } } private isBlockScopeBoundary(node: ts.Node): boolean { return isBlockScopeBoundary(node); } } tslint-5.9.1/src/language/walker/index.ts000066400000000000000000000015471322551053300203670ustar00rootroot00000000000000/** * @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. */ export * from "./blockScopeAwareRuleWalker"; export * from "./programAwareRuleWalker"; export * from "./ruleWalker"; export * from "./scopeAwareRuleWalker"; export * from "./syntaxWalker"; export * from "./walkContext"; export * from "./walker"; tslint-5.9.1/src/language/walker/programAwareRuleWalker.ts000066400000000000000000000022751322551053300237040ustar00rootroot00000000000000/** * @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 { IOptions } from "../rule/rule"; import { RuleWalker } from "./ruleWalker"; export class ProgramAwareRuleWalker extends RuleWalker { private readonly typeChecker: ts.TypeChecker; constructor(sourceFile: ts.SourceFile, options: IOptions, private readonly program: ts.Program) { super(sourceFile, options); this.typeChecker = program.getTypeChecker(); } public getProgram(): ts.Program { return this.program; } public getTypeChecker(): ts.TypeChecker { return this.typeChecker; } } tslint-5.9.1/src/language/walker/ruleWalker.ts000066400000000000000000000075221322551053300213740ustar00rootroot00000000000000/** * @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 { Fix, IOptions, Replacement, RuleFailure } from "../rule/rule"; import { SyntaxWalker } from "./syntaxWalker"; import { IWalker } from "./walker"; export class RuleWalker extends SyntaxWalker implements IWalker { private readonly limit: number; private readonly options?: any[]; private readonly failures: RuleFailure[]; private readonly ruleName: string; constructor(private readonly sourceFile: ts.SourceFile, options: IOptions) { super(); this.failures = []; this.options = options.ruleArguments; this.limit = this.sourceFile.getFullWidth(); this.ruleName = options.ruleName; } public getSourceFile(): ts.SourceFile { return this.sourceFile; } public getLineAndCharacterOfPosition(position: number): ts.LineAndCharacter { return this.sourceFile.getLineAndCharacterOfPosition(position); } public getFailures(): RuleFailure[] { return this.failures; } public getLimit() { return this.limit; } public getOptions(): any { return this.options; } public hasOption(option: string): boolean { if (this.options !== undefined) { return this.options.indexOf(option) !== -1; } else { return false; } } /** @deprecated Prefer `addFailureAt` and its variants. */ public createFailure(start: number, width: number, failure: string, fix?: Fix): RuleFailure { const from = (start > this.limit) ? this.limit : start; const to = ((start + width) > this.limit) ? this.limit : (start + width); return new RuleFailure(this.sourceFile, from, to, failure, this.ruleName, fix); } /** @deprecated Prefer `addFailureAt` and its variants. */ public addFailure(failure: RuleFailure) { this.failures.push(failure); } /** Add a failure with any arbitrary span. Prefer `addFailureAtNode` if possible. */ public addFailureAt(start: number, width: number, failure: string, fix?: Fix) { // tslint:disable-next-line deprecation this.addFailure(this.createFailure(start, width, failure, fix)); } /** Like `addFailureAt` but uses start and end instead of start and width. */ public addFailureFromStartToEnd(start: number, end: number, failure: string, fix?: Fix) { this.addFailureAt(start, end - start, failure, fix); } /** Add a failure using a node's span. */ public addFailureAtNode(node: ts.Node, failure: string, fix?: Fix) { this.addFailureAt(node.getStart(this.sourceFile), node.getWidth(this.sourceFile), failure, fix); } public createReplacement(start: number, length: number, text: string): Replacement { return new Replacement(start, length, text); } public appendText(start: number, text: string): Replacement { return this.createReplacement(start, 0, text); } public deleteText(start: number, length: number): Replacement { return this.createReplacement(start, length, ""); } public deleteFromTo(start: number, end: number): Replacement { return this.createReplacement(start, end - start, ""); } public getRuleName(): string { return this.ruleName; } } tslint-5.9.1/src/language/walker/scopeAwareRuleWalker.ts000066400000000000000000000064331322551053300233460ustar00rootroot00000000000000/** * @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 { IOptions } from "../rule/rule"; import { isScopeBoundary } from "../utils"; import { RuleWalker } from "./ruleWalker"; /** * @deprecated Prefer to manually maintain any contextual information. * * For example, imagine a `no-break` rule that warns on `break` in `for` but not in `switch`: * * function walk(ctx: Lint.WalkContext): void { * let isInFor = false; * ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void { * switch (node.kind) { * case ts.SyntaxKind.Break: * if (isInFor) { * ctx.addFailureAtNode(node, "!"); * } * break; * case ts.SyntaxKind.ForStatement: { * const old = isInFor; * isInFor = true; * ts.forEachChild(node, cb); * isInFor = old; * break; * } * case ts.SyntaxKind.SwitchStatement: { * const old = isInFor; * isInFor = false; * ts.forEachChild(node, cb); * isInFor = old; * break; * } * default: * ts.forEachChild(node, cb); * } * }); * } */ export abstract class ScopeAwareRuleWalker extends RuleWalker { private readonly scopeStack: T[]; constructor(sourceFile: ts.SourceFile, options: IOptions) { super(sourceFile, options); // initialize with global scope if file is not a module this.scopeStack = ts.isExternalModule(sourceFile) ? [] : [this.createScope(sourceFile)]; } public abstract createScope(node: ts.Node): T; public getCurrentScope(): T { return this.scopeStack[this.scopeStack.length - 1]; } // get all scopes available at this depth public getAllScopes(): T[] { return this.scopeStack; } public getCurrentDepth(): number { return this.scopeStack.length; } // callback notifier when a scope begins public onScopeStart() { return; } // callback notifier when a scope ends public onScopeEnd() { return; } protected visitNode(node: ts.Node) { const isNewScope = this.isScopeBoundary(node); if (isNewScope) { this.scopeStack.push(this.createScope(node)); this.onScopeStart(); } super.visitNode(node); if (isNewScope) { this.onScopeEnd(); this.scopeStack.pop(); } } protected isScopeBoundary(node: ts.Node): boolean { return isScopeBoundary(node); // tslint:disable-line:deprecation } } tslint-5.9.1/src/language/walker/syntaxWalker.ts000066400000000000000000000525541322551053300217600ustar00rootroot00000000000000/** * @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"; export class SyntaxWalker { public walk(node: ts.Node) { this.visitNode(node); } protected visitAnyKeyword(node: ts.Node) { this.walkChildren(node); } protected visitArrayLiteralExpression(node: ts.ArrayLiteralExpression) { this.walkChildren(node); } protected visitArrayType(node: ts.ArrayTypeNode) { this.walkChildren(node); } protected visitArrowFunction(node: ts.ArrowFunction) { this.walkChildren(node); } protected visitBinaryExpression(node: ts.BinaryExpression) { this.walkChildren(node); } protected visitBindingElement(node: ts.BindingElement) { this.walkChildren(node); } protected visitBindingPattern(node: ts.BindingPattern) { this.walkChildren(node); } protected visitBlock(node: ts.Block) { this.walkChildren(node); } protected visitBreakStatement(node: ts.BreakOrContinueStatement) { this.walkChildren(node); } protected visitCallExpression(node: ts.CallExpression) { this.walkChildren(node); } protected visitCallSignature(node: ts.SignatureDeclaration) { this.walkChildren(node); } protected visitCaseClause(node: ts.CaseClause) { this.walkChildren(node); } protected visitClassDeclaration(node: ts.ClassDeclaration) { this.walkChildren(node); } protected visitClassExpression(node: ts.ClassExpression) { this.walkChildren(node); } protected visitCatchClause(node: ts.CatchClause) { this.walkChildren(node); } protected visitConditionalExpression(node: ts.ConditionalExpression) { this.walkChildren(node); } protected visitConstructSignature(node: ts.ConstructSignatureDeclaration) { this.walkChildren(node); } protected visitConstructorDeclaration(node: ts.ConstructorDeclaration) { this.walkChildren(node); } protected visitConstructorType(node: ts.FunctionOrConstructorTypeNode) { this.walkChildren(node); } protected visitContinueStatement(node: ts.BreakOrContinueStatement) { this.walkChildren(node); } protected visitDebuggerStatement(node: ts.Statement) { this.walkChildren(node); } protected visitDefaultClause(node: ts.DefaultClause) { this.walkChildren(node); } protected visitDoStatement(node: ts.DoStatement) { this.walkChildren(node); } protected visitElementAccessExpression(node: ts.ElementAccessExpression) { this.walkChildren(node); } protected visitEndOfFileToken(node: ts.Node) { this.walkChildren(node); } protected visitEnumDeclaration(node: ts.EnumDeclaration) { this.walkChildren(node); } protected visitEnumMember(node: ts.EnumMember) { this.walkChildren(node); } protected visitExportAssignment(node: ts.ExportAssignment) { this.walkChildren(node); } protected visitExpressionStatement(node: ts.ExpressionStatement) { this.walkChildren(node); } protected visitForStatement(node: ts.ForStatement) { this.walkChildren(node); } protected visitForInStatement(node: ts.ForInStatement) { this.walkChildren(node); } protected visitForOfStatement(node: ts.ForOfStatement) { this.walkChildren(node); } protected visitFunctionDeclaration(node: ts.FunctionDeclaration) { this.walkChildren(node); } protected visitFunctionExpression(node: ts.FunctionExpression) { this.walkChildren(node); } protected visitFunctionType(node: ts.FunctionOrConstructorTypeNode) { this.walkChildren(node); } protected visitGetAccessor(node: ts.AccessorDeclaration) { this.walkChildren(node); } protected visitIdentifier(node: ts.Identifier) { this.walkChildren(node); } protected visitIfStatement(node: ts.IfStatement) { this.walkChildren(node); } protected visitImportDeclaration(node: ts.ImportDeclaration) { this.walkChildren(node); } protected visitImportEqualsDeclaration(node: ts.ImportEqualsDeclaration) { this.walkChildren(node); } protected visitIndexSignatureDeclaration(node: ts.IndexSignatureDeclaration) { this.walkChildren(node); } protected visitInterfaceDeclaration(node: ts.InterfaceDeclaration) { this.walkChildren(node); } protected visitJsxAttribute(node: ts.JsxAttribute) { this.walkChildren(node); } protected visitJsxElement(node: ts.JsxElement) { this.walkChildren(node); } protected visitJsxExpression(node: ts.JsxExpression) { this.walkChildren(node); } protected visitJsxSelfClosingElement(node: ts.JsxSelfClosingElement) { this.walkChildren(node); } protected visitJsxSpreadAttribute(node: ts.JsxSpreadAttribute) { this.walkChildren(node); } protected visitLabeledStatement(node: ts.LabeledStatement) { this.walkChildren(node); } protected visitMethodDeclaration(node: ts.MethodDeclaration) { this.walkChildren(node); } protected visitMethodSignature(node: ts.SignatureDeclaration) { this.walkChildren(node); } protected visitModuleDeclaration(node: ts.ModuleDeclaration) { this.walkChildren(node); } protected visitNamedImports(node: ts.NamedImports) { this.walkChildren(node); } protected visitNamespaceImport(node: ts.NamespaceImport) { this.walkChildren(node); } protected visitNewExpression(node: ts.NewExpression) { this.walkChildren(node); } protected visitNonNullExpression(node: ts.NonNullExpression) { this.walkChildren(node); } protected visitNumericLiteral(node: ts.NumericLiteral) { this.walkChildren(node); } protected visitObjectLiteralExpression(node: ts.ObjectLiteralExpression) { this.walkChildren(node); } protected visitParameterDeclaration(node: ts.ParameterDeclaration) { this.walkChildren(node); } protected visitPostfixUnaryExpression(node: ts.PostfixUnaryExpression) { this.walkChildren(node); } protected visitPrefixUnaryExpression(node: ts.PrefixUnaryExpression) { this.walkChildren(node); } protected visitPropertyAccessExpression(node: ts.PropertyAccessExpression) { this.walkChildren(node); } protected visitPropertyAssignment(node: ts.PropertyAssignment) { this.walkChildren(node); } protected visitPropertyDeclaration(node: ts.PropertyDeclaration) { this.walkChildren(node); } protected visitPropertySignature(node: ts.Node) { this.walkChildren(node); } protected visitRegularExpressionLiteral(node: ts.Node) { this.walkChildren(node); } protected visitReturnStatement(node: ts.ReturnStatement) { this.walkChildren(node); } protected visitSetAccessor(node: ts.AccessorDeclaration) { this.walkChildren(node); } protected visitSourceFile(node: ts.SourceFile) { this.walkChildren(node); } protected visitStringLiteral(node: ts.StringLiteral) { this.walkChildren(node); } protected visitSwitchStatement(node: ts.SwitchStatement) { this.walkChildren(node); } protected visitTemplateExpression(node: ts.TemplateExpression) { this.walkChildren(node); } protected visitThrowStatement(node: ts.ThrowStatement) { this.walkChildren(node); } protected visitTryStatement(node: ts.TryStatement) { this.walkChildren(node); } protected visitTupleType(node: ts.TupleTypeNode) { this.walkChildren(node); } protected visitTypeAliasDeclaration(node: ts.TypeAliasDeclaration) { this.walkChildren(node); } protected visitTypeAssertionExpression(node: ts.TypeAssertion) { this.walkChildren(node); } protected visitTypeLiteral(node: ts.TypeLiteralNode) { this.walkChildren(node); } protected visitTypeReference(node: ts.TypeReferenceNode) { this.walkChildren(node); } protected visitVariableDeclaration(node: ts.VariableDeclaration) { this.walkChildren(node); } protected visitVariableDeclarationList(node: ts.VariableDeclarationList) { this.walkChildren(node); } protected visitVariableStatement(node: ts.VariableStatement) { this.walkChildren(node); } protected visitWhileStatement(node: ts.WhileStatement) { this.walkChildren(node); } protected visitWithStatement(node: ts.WithStatement) { this.walkChildren(node); } protected visitNode(node: ts.Node) { switch (node.kind) { case ts.SyntaxKind.AnyKeyword: this.visitAnyKeyword(node); break; case ts.SyntaxKind.ArrayBindingPattern: this.visitBindingPattern(node as ts.BindingPattern); break; case ts.SyntaxKind.ArrayLiteralExpression: this.visitArrayLiteralExpression(node as ts.ArrayLiteralExpression); break; case ts.SyntaxKind.ArrayType: this.visitArrayType(node as ts.ArrayTypeNode); break; case ts.SyntaxKind.ArrowFunction: this.visitArrowFunction(node as ts.ArrowFunction); break; case ts.SyntaxKind.BinaryExpression: this.visitBinaryExpression(node as ts.BinaryExpression); break; case ts.SyntaxKind.BindingElement: this.visitBindingElement(node as ts.BindingElement); break; case ts.SyntaxKind.Block: this.visitBlock(node as ts.Block); break; case ts.SyntaxKind.BreakStatement: this.visitBreakStatement(node as ts.BreakOrContinueStatement); break; case ts.SyntaxKind.CallExpression: this.visitCallExpression(node as ts.CallExpression); break; case ts.SyntaxKind.CallSignature: this.visitCallSignature(node as ts.SignatureDeclaration); break; case ts.SyntaxKind.CaseClause: this.visitCaseClause(node as ts.CaseClause); break; case ts.SyntaxKind.ClassDeclaration: this.visitClassDeclaration(node as ts.ClassDeclaration); break; case ts.SyntaxKind.ClassExpression: this.visitClassExpression(node as ts.ClassExpression); break; case ts.SyntaxKind.CatchClause: this.visitCatchClause(node as ts.CatchClause); break; case ts.SyntaxKind.ConditionalExpression: this.visitConditionalExpression(node as ts.ConditionalExpression); break; case ts.SyntaxKind.ConstructSignature: this.visitConstructSignature(node as ts.ConstructSignatureDeclaration); break; case ts.SyntaxKind.Constructor: this.visitConstructorDeclaration(node as ts.ConstructorDeclaration); break; case ts.SyntaxKind.ConstructorType: this.visitConstructorType(node as ts.FunctionOrConstructorTypeNode); break; case ts.SyntaxKind.ContinueStatement: this.visitContinueStatement(node as ts.BreakOrContinueStatement); break; case ts.SyntaxKind.DebuggerStatement: this.visitDebuggerStatement(node as ts.Statement); break; case ts.SyntaxKind.DefaultClause: this.visitDefaultClause(node as ts.DefaultClause); break; case ts.SyntaxKind.DoStatement: this.visitDoStatement(node as ts.DoStatement); break; case ts.SyntaxKind.ElementAccessExpression: this.visitElementAccessExpression(node as ts.ElementAccessExpression); break; case ts.SyntaxKind.EndOfFileToken: this.visitEndOfFileToken(node); break; case ts.SyntaxKind.EnumDeclaration: this.visitEnumDeclaration(node as ts.EnumDeclaration); break; case ts.SyntaxKind.EnumMember: this.visitEnumMember(node as ts.EnumMember); break; case ts.SyntaxKind.ExportAssignment: this.visitExportAssignment(node as ts.ExportAssignment); break; case ts.SyntaxKind.ExpressionStatement: this.visitExpressionStatement(node as ts.ExpressionStatement); break; case ts.SyntaxKind.ForStatement: this.visitForStatement(node as ts.ForStatement); break; case ts.SyntaxKind.ForInStatement: this.visitForInStatement(node as ts.ForInStatement); break; case ts.SyntaxKind.ForOfStatement: this.visitForOfStatement(node as ts.ForOfStatement); break; case ts.SyntaxKind.FunctionDeclaration: this.visitFunctionDeclaration(node as ts.FunctionDeclaration); break; case ts.SyntaxKind.FunctionExpression: this.visitFunctionExpression(node as ts.FunctionExpression); break; case ts.SyntaxKind.FunctionType: this.visitFunctionType(node as ts.FunctionOrConstructorTypeNode); break; case ts.SyntaxKind.GetAccessor: this.visitGetAccessor(node as ts.AccessorDeclaration); break; case ts.SyntaxKind.Identifier: this.visitIdentifier(node as ts.Identifier); break; case ts.SyntaxKind.IfStatement: this.visitIfStatement(node as ts.IfStatement); break; case ts.SyntaxKind.ImportDeclaration: this.visitImportDeclaration(node as ts.ImportDeclaration); break; case ts.SyntaxKind.ImportEqualsDeclaration: this.visitImportEqualsDeclaration(node as ts.ImportEqualsDeclaration); break; case ts.SyntaxKind.IndexSignature: this.visitIndexSignatureDeclaration(node as ts.IndexSignatureDeclaration); break; case ts.SyntaxKind.InterfaceDeclaration: this.visitInterfaceDeclaration(node as ts.InterfaceDeclaration); break; case ts.SyntaxKind.JsxAttribute: this.visitJsxAttribute(node as ts.JsxAttribute); break; case ts.SyntaxKind.JsxElement: this.visitJsxElement(node as ts.JsxElement); break; case ts.SyntaxKind.JsxExpression: this.visitJsxExpression(node as ts.JsxExpression); break; case ts.SyntaxKind.JsxSelfClosingElement: this.visitJsxSelfClosingElement(node as ts.JsxSelfClosingElement); break; case ts.SyntaxKind.JsxSpreadAttribute: this.visitJsxSpreadAttribute(node as ts.JsxSpreadAttribute); break; case ts.SyntaxKind.LabeledStatement: this.visitLabeledStatement(node as ts.LabeledStatement); break; case ts.SyntaxKind.MethodDeclaration: this.visitMethodDeclaration(node as ts.MethodDeclaration); break; case ts.SyntaxKind.MethodSignature: this.visitMethodSignature(node as ts.SignatureDeclaration); break; case ts.SyntaxKind.ModuleDeclaration: this.visitModuleDeclaration(node as ts.ModuleDeclaration); break; case ts.SyntaxKind.NamedImports: this.visitNamedImports(node as ts.NamedImports); break; case ts.SyntaxKind.NamespaceImport: this.visitNamespaceImport(node as ts.NamespaceImport); break; case ts.SyntaxKind.NewExpression: this.visitNewExpression(node as ts.NewExpression); break; case ts.SyntaxKind.NonNullExpression: this.visitNonNullExpression(node as ts.NonNullExpression); break; case ts.SyntaxKind.NumericLiteral: this.visitNumericLiteral(node as ts.NumericLiteral); break; case ts.SyntaxKind.ObjectBindingPattern: this.visitBindingPattern(node as ts.BindingPattern); break; case ts.SyntaxKind.ObjectLiteralExpression: this.visitObjectLiteralExpression(node as ts.ObjectLiteralExpression); break; case ts.SyntaxKind.Parameter: this.visitParameterDeclaration(node as ts.ParameterDeclaration); break; case ts.SyntaxKind.PostfixUnaryExpression: this.visitPostfixUnaryExpression(node as ts.PostfixUnaryExpression); break; case ts.SyntaxKind.PrefixUnaryExpression: this.visitPrefixUnaryExpression(node as ts.PrefixUnaryExpression); break; case ts.SyntaxKind.PropertyAccessExpression: this.visitPropertyAccessExpression(node as ts.PropertyAccessExpression); break; case ts.SyntaxKind.PropertyAssignment: this.visitPropertyAssignment(node as ts.PropertyAssignment); break; case ts.SyntaxKind.PropertyDeclaration: this.visitPropertyDeclaration(node as ts.PropertyDeclaration); break; case ts.SyntaxKind.PropertySignature: this.visitPropertySignature(node); break; case ts.SyntaxKind.RegularExpressionLiteral: this.visitRegularExpressionLiteral(node); break; case ts.SyntaxKind.ReturnStatement: this.visitReturnStatement(node as ts.ReturnStatement); break; case ts.SyntaxKind.SetAccessor: this.visitSetAccessor(node as ts.AccessorDeclaration); break; case ts.SyntaxKind.SourceFile: this.visitSourceFile(node as ts.SourceFile); break; case ts.SyntaxKind.StringLiteral: this.visitStringLiteral(node as ts.StringLiteral); break; case ts.SyntaxKind.SwitchStatement: this.visitSwitchStatement(node as ts.SwitchStatement); break; case ts.SyntaxKind.TemplateExpression: this.visitTemplateExpression(node as ts.TemplateExpression); break; case ts.SyntaxKind.ThrowStatement: this.visitThrowStatement(node as ts.ThrowStatement); break; case ts.SyntaxKind.TryStatement: this.visitTryStatement(node as ts.TryStatement); break; case ts.SyntaxKind.TupleType: this.visitTupleType(node as ts.TupleTypeNode); break; case ts.SyntaxKind.TypeAliasDeclaration: this.visitTypeAliasDeclaration(node as ts.TypeAliasDeclaration); break; case ts.SyntaxKind.TypeAssertionExpression: this.visitTypeAssertionExpression(node as ts.TypeAssertion); break; case ts.SyntaxKind.TypeLiteral: this.visitTypeLiteral(node as ts.TypeLiteralNode); break; case ts.SyntaxKind.TypeReference: this.visitTypeReference(node as ts.TypeReferenceNode); break; case ts.SyntaxKind.VariableDeclaration: this.visitVariableDeclaration(node as ts.VariableDeclaration); break; case ts.SyntaxKind.VariableDeclarationList: this.visitVariableDeclarationList(node as ts.VariableDeclarationList); break; case ts.SyntaxKind.VariableStatement: this.visitVariableStatement(node as ts.VariableStatement); break; case ts.SyntaxKind.WhileStatement: this.visitWhileStatement(node as ts.WhileStatement); break; case ts.SyntaxKind.WithStatement: this.visitWithStatement(node as ts.WithStatement); break; default: this.walkChildren(node); } } protected walkChildren(node: ts.Node) { ts.forEachChild(node, (child) => this.visitNode(child)); } } tslint-5.9.1/src/language/walker/walkContext.ts000066400000000000000000000032131322551053300215530ustar00rootroot00000000000000/** * @license * Copyright 2017 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as ts from "typescript"; import { Fix, RuleFailure } from "../rule/rule"; export class WalkContext { public readonly failures: RuleFailure[] = []; constructor(public readonly sourceFile: ts.SourceFile, public readonly ruleName: string, public readonly options: T) {} /** Add a failure with any arbitrary span. Prefer `addFailureAtNode` if possible. */ public addFailureAt(start: number, width: number, failure: string, fix?: Fix) { this.addFailure(start, start + width, failure, fix); } public addFailure(start: number, end: number, failure: string, fix?: Fix) { const fileLength = this.sourceFile.end; this.failures.push( new RuleFailure(this.sourceFile, Math.min(start, fileLength), Math.min(end, fileLength), failure, this.ruleName, fix), ); } /** Add a failure using a node's span. */ public addFailureAtNode(node: ts.Node, failure: string, fix?: Fix) { this.addFailure(node.getStart(this.sourceFile), node.getEnd(), failure, fix); } } tslint-5.9.1/src/language/walker/walker.ts000066400000000000000000000022221322551053300205340ustar00rootroot00000000000000/** * @license * Copyright 2017 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as ts from "typescript"; import { RuleFailure } from "../rule/rule"; import { WalkContext } from "./walkContext"; export interface IWalker { getSourceFile(): ts.SourceFile; walk(sourceFile: ts.SourceFile): void; getFailures(): RuleFailure[]; } export abstract class AbstractWalker extends WalkContext implements IWalker { public abstract walk(sourceFile: ts.SourceFile): void; public getSourceFile() { return this.sourceFile; } public getFailures() { return this.failures; } } tslint-5.9.1/src/linter.ts000066400000000000000000000263071322551053300155060ustar00rootroot00000000000000/** * @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 path from "path"; import * as ts from "typescript"; import { convertRuleOptions, DEFAULT_CONFIG, findConfiguration, findConfigurationPath, getRulesDirectories, IConfigurationFile, loadConfigurationFromPath, } from "./configuration"; import { removeDisabledFailures } from "./enableDisableRules"; import { FatalError, isError, showWarningOnce } from "./error"; import { findFormatter } from "./formatterLoader"; import { ILinterOptions, LintResult } from "./index"; import { IRule, isTypedRule, Replacement, RuleFailure, RuleSeverity } from "./language/rule/rule"; import * as utils from "./language/utils"; import { loadRules } from "./ruleLoader"; import { arrayify, dedent, flatMap, mapDefined } from "./utils"; /** * Linter that can lint multiple files in consecutive runs. */ export class Linter { public static VERSION = "5.9.1"; 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 = path.dirname(configFile)): ts.Program { const config = ts.readConfigFile(configFile, ts.sys.readFile); if (config.error !== undefined) { throw new FatalError(ts.formatDiagnostics([config.error], { getCanonicalFileName: (f) => f, getCurrentDirectory: process.cwd, getNewLine: () => "\n", })); } const parseConfigHost: ts.ParseConfigHost = { fileExists: fs.existsSync, readDirectory: ts.sys.readDirectory, readFile: (file) => fs.readFileSync(file, "utf8"), useCaseSensitiveFileNames: true, }; const parsed = ts.parseJsonConfigFileContent(config.config, parseConfigHost, path.resolve(projectDirectory), {noEmit: true}); if (parsed.errors !== undefined) { // ignore warnings and 'TS18003: No inputs were found in config file ...' const errors = parsed.errors.filter((d) => d.category === ts.DiagnosticCategory.Error && d.code !== 18003); if (errors.length !== 0) { throw new FatalError(ts.formatDiagnostics(errors, { getCanonicalFileName: (f) => f, getCurrentDirectory: process.cwd, getNewLine: () => "\n", })); } } 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 mapDefined( program.getSourceFiles(), (file) => file.fileName.endsWith(".d.ts") || program.isSourceFileFromExternalLibrary(file) ? undefined : file.fileName, ); } constructor(private readonly options: ILinterOptions, private program?: ts.Program) { if (typeof options !== "object") { throw new Error(`Unknown Linter options type: ${typeof options}`); } if ((options as any).configuration != undefined) { 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 sourceFile = this.getSourceFile(fileName, source); const isJs = /\.jsx?$/i.test(fileName); const enabledRules = this.getEnabledRules(configuration, isJs); let fileFailures = this.getAllFailures(sourceFile, enabledRules); if (fileFailures.length === 0) { // Usual case: no errors. return; } if (this.options.fix && fileFailures.some((f) => f.hasFix())) { fileFailures = this.applyAllFixes(enabledRules, fileFailures, sourceFile, fileName); } // add rule severity to failures const ruleSeverityMap = new Map(enabledRules.map( (rule): [string, RuleSeverity] => [rule.getOptions().ruleName, rule.getOptions().ruleSeverity])); for (const failure of fileFailures) { const severity = ruleSeverityMap.get(failure.getRuleName()); if (severity === undefined) { throw new Error(`Severity for rule '${failure.getRuleName()}' not found`); } failure.setRuleSeverity(severity); } this.failures = this.failures.concat(fileFailures); } public getResult(): LintResult { const formatterName = this.options.formatter !== undefined ? this.options.formatter : "prose"; const Formatter = findFormatter(formatterName, this.options.formattersDirectory); if (Formatter === undefined) { throw new Error(`formatter '${formatterName}' not found`); } const formatter = new Formatter(); const output = formatter.format(this.failures, this.fixes); const errorCount = this.failures.filter((failure) => failure.getRuleSeverity() === "error").length; return { errorCount, failures: this.failures, fixes: this.fixes, format: formatterName, output, warningCount: this.failures.length - errorCount, }; } private getAllFailures(sourceFile: ts.SourceFile, enabledRules: IRule[]): RuleFailure[] { const failures = flatMap(enabledRules, (rule) => this.applyRule(rule, sourceFile)); return removeDisabledFailures(sourceFile, failures); } private applyAllFixes( enabledRules: IRule[], fileFailures: RuleFailure[], sourceFile: ts.SourceFile, sourceFileName: string): RuleFailure[] { // When fixing, we need to be careful as a fix in one rule may affect other rules. // So fix each rule separately. let source: string = sourceFile.text; for (const rule of enabledRules) { const hasFixes = fileFailures.some((f) => f.hasFix() && f.getRuleName() === rule.getOptions().ruleName); if (hasFixes) { // Get new failures in case the file changed. const updatedFailures = removeDisabledFailures(sourceFile, this.applyRule(rule, sourceFile)); const fixableFailures = updatedFailures.filter((f) => f.hasFix()); this.fixes = this.fixes.concat(fixableFailures); source = this.applyFixes(sourceFileName, source, fixableFailures); sourceFile = this.getSourceFile(sourceFileName, source); } } // If there were fixes, get the *new* list of failures. return this.getAllFailures(sourceFile, enabledRules); } // Only "protected" because a test directly accesses it. // tslint:disable-next-line member-ordering protected applyFixes(sourceFilePath: string, source: string, fixableFailures: RuleFailure[]): string { const fixesByFile = createMultiMap(fixableFailures, (f) => [f.getFileName(), f.getFix()!]); fixesByFile.forEach((fileFixes, filePath) => { let fileNewSource: string; if (path.resolve(filePath) === path.resolve(sourceFilePath)) { source = Replacement.applyFixes(source, fileFixes); fileNewSource = source; } else { const oldSource = fs.readFileSync(filePath, "utf-8"); fileNewSource = Replacement.applyFixes(oldSource, fileFixes); } fs.writeFileSync(filePath, fileNewSource); this.updateProgram(filePath); }); return source; } private updateProgram(sourceFilePath: string) { if (this.program !== undefined && this.program.getSourceFile(sourceFilePath) !== undefined) { const options = this.program.getCompilerOptions(); this.program = ts.createProgram(this.program.getRootFileNames(), options, ts.createCompilerHost(options, true), this.program); } } private applyRule(rule: IRule, sourceFile: ts.SourceFile): RuleFailure[] { try { if (this.program !== undefined && isTypedRule(rule)) { return rule.applyWithProgram(sourceFile, this.program); } else { return rule.apply(sourceFile); } } catch (error) { if (isError(error) && error.stack !== undefined) { showWarningOnce(error.stack); } else { showWarningOnce(String(error)); } return []; } } private getEnabledRules(configuration: IConfigurationFile = DEFAULT_CONFIG, isJs: boolean): IRule[] { const ruleOptionsList = convertRuleOptions(isJs ? configuration.jsRules : configuration.rules); const rulesDirectories = arrayify(this.options.rulesDirectory) .concat(arrayify(configuration.rulesDirectory)); return loadRules(ruleOptionsList, rulesDirectories, isJs); } private getSourceFile(fileName: string, source: string) { if (this.program !== undefined) { const sourceFile = this.program.getSourceFile(fileName); if (sourceFile === undefined) { const INVALID_SOURCE_ERROR = dedent` Invalid source file: ${fileName}. Ensure that the files supplied to lint have a .ts, .tsx, .d.ts, .js or .jsx extension. `; throw new FatalError(INVALID_SOURCE_ERROR); } return sourceFile; } else { return utils.getSourceFile(fileName, source); } } } function createMultiMap(inputs: T[], getPair: (input: T) => [K, V] | undefined): Map { const map = new Map(); for (const input of inputs) { const pair = getPair(input); if (pair !== undefined) { const [k, v] = pair; const vs = map.get(k); if (vs !== undefined) { vs.push(v); } else { map.set(k, [v]); } } } return map; } tslint-5.9.1/src/ruleLoader.ts000066400000000000000000000130131322551053300162750ustar00rootroot00000000000000/** * @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 path from "path"; import { FatalError, showWarningOnce } from "./error"; import { IOptions, IRule, RuleConstructor } from "./language/rule/rule"; import { arrayify, camelize, dedent, find } from "./utils"; const CORE_RULES_DIRECTORY = path.resolve(__dirname, "rules"); const cachedRules = new Map(); export function loadRules(ruleOptionsList: IOptions[], rulesDirectories?: string | string[], isJs = false): IRule[] { const rules: IRule[] = []; const notFoundRules: string[] = []; const notAllowedInJsRules: string[] = []; for (const ruleOptions of ruleOptionsList) { if (ruleOptions.ruleSeverity === "off") { // Perf: don't bother finding the rule if it's disabled. continue; } const ruleName = ruleOptions.ruleName; const Rule = findRule(ruleName, rulesDirectories); if (Rule === undefined) { notFoundRules.push(ruleName); } else if (isJs && Rule.metadata !== undefined && Rule.metadata.typescriptOnly) { notAllowedInJsRules.push(ruleName); } else { const rule = new Rule(ruleOptions); if (rule.isEnabled()) { rules.push(rule); } if (Rule.metadata !== undefined && Boolean(Rule.metadata.deprecationMessage)) { showWarningOnce(`${Rule.metadata.ruleName} is deprecated. ${Rule.metadata.deprecationMessage}`); } } } if (notFoundRules.length > 0) { const warning = dedent` Could not find implementations for the following rules specified in the configuration: ${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. `; showWarningOnce(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. `; showWarningOnce(warning); } if (rules.length === 0) { showWarningOnce("No valid rules have been specified"); } return rules; } /** @internal private API */ export function findRule(name: string, rulesDirectories?: string | string[]): RuleConstructor | undefined { const camelizedName = transformName(name); // first check for core rules const Rule = loadCachedRule(CORE_RULES_DIRECTORY, camelizedName); return Rule !== undefined ? Rule : // then check for rules within the first level of rulesDirectory find(arrayify(rulesDirectories), (dir) => loadCachedRule(dir, camelizedName, true)); } function transformName(name: string): string { // camelize strips out leading and trailing underscores and dashes, so make sure they aren't passed to camelize // the regex matches the groups (leading underscores and dashes)(other characters)(trailing underscores and dashes) const nameMatch = name.match(/^([-_]*)(.*?)([-_]*)$/); if (nameMatch === null) { return `${name}Rule`; } return `${nameMatch[1]}${camelize(nameMatch[2])}${nameMatch[3]}Rule`; } /** * @param directory - An absolute path to a directory of rules * @param ruleName - A name of a rule in filename format. ex) "someLintRule" */ function loadRule(directory: string, ruleName: string): RuleConstructor | "not-found" { let ruleFullPath: string; try { // Resolve using node's path resolution to allow developers to write custom rules in TypeScript which can be loaded by TS-Node ruleFullPath = require.resolve(path.join(directory, ruleName)); } catch { return "not-found"; } return (require(ruleFullPath) as { Rule: RuleConstructor }).Rule; } function loadCachedRule(directory: string, ruleName: string, isCustomPath?: boolean): RuleConstructor | undefined { // use cached value if available const fullPath = path.join(directory, ruleName); const cachedRule = cachedRules.get(fullPath); if (cachedRule !== undefined) { return cachedRule === "not-found" ? undefined : cachedRule; } // treat directory as a relative path (which needs to be resolved) if it's a custom rule directory let absolutePath: string = directory; if (isCustomPath) { absolutePath = path.resolve(directory); if (!fs.existsSync(absolutePath)) { throw new FatalError(`Could not find custom rule directory: ${absolutePath}`); } } const Rule = loadRule(absolutePath, ruleName); cachedRules.set(fullPath, Rule); return Rule === "not-found" ? undefined : Rule; } tslint-5.9.1/src/rules.ts000066400000000000000000000013771322551053300153430ustar00rootroot00000000000000/** * @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. */ export * from "./language/rule/abstractRule"; export * from "./language/rule/typedRule"; export * from "./language/rule/optionallyTypedRule"; tslint-5.9.1/src/rules/000077500000000000000000000000001322551053300147635ustar00rootroot00000000000000tslint-5.9.1/src/rules/adjacentOverloadSignaturesRule.ts000066400000000000000000000125571322551053300235070ustar00rootroot00000000000000/** * @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 utils from "tsutils"; 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: "adjacent-overload-signatures", description: "Enforces function overloads to be consecutive.", 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(name: string): string { return `All '${name}' signatures should be adjacent`; } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithFunction(sourceFile, walk); } } function walk(ctx: Lint.WalkContext): void { const { sourceFile } = ctx; visitStatements(sourceFile.statements); return ts.forEachChild(sourceFile, function cb(node: ts.Node): void { switch (node.kind) { case ts.SyntaxKind.ModuleBlock: visitStatements((node as ts.ModuleBlock).statements); break; case ts.SyntaxKind.InterfaceDeclaration: case ts.SyntaxKind.ClassDeclaration: case ts.SyntaxKind.TypeLiteral: { const { members } = node as ts.InterfaceDeclaration | ts.ClassDeclaration | ts.TypeLiteralNode; addFailures(getMisplacedOverloads(members, (member) => utils.isSignatureDeclaration(member) ? getOverloadKey(member) : undefined)); } } return ts.forEachChild(node, cb); }); function visitStatements(statements: ReadonlyArray): void { addFailures(getMisplacedOverloads(statements, (statement) => utils.isFunctionDeclaration(statement) && statement.name !== undefined ? statement.name.text : undefined)); } function addFailures(misplacedOverloads: ReadonlyArray): void { for (const node of misplacedOverloads) { ctx.addFailureAtNode(node, Rule.FAILURE_STRING(printOverload(node))); } } } /** 'getOverloadName' may return undefined for nodes that cannot be overloads, e.g. a `const` declaration. */ function getMisplacedOverloads( overloads: ReadonlyArray, getKey: (node: T) => string | undefined): ts.SignatureDeclaration[] { const result: ts.SignatureDeclaration[] = []; let lastKey: string | undefined; const seen = new Set(); for (const node of overloads) { if (node.kind === ts.SyntaxKind.SemicolonClassElement) { continue; } const key = getKey(node); if (key !== undefined) { if (seen.has(key) && lastKey !== key) { result.push(node as any as ts.SignatureDeclaration); } seen.add(key); lastKey = key; } else { lastKey = undefined; } } return result; } function printOverload(node: ts.SignatureDeclaration): string { const info = getOverloadInfo(node); return typeof info === "string" ? info : info === undefined ? "" : info.name; } export function getOverloadKey(node: ts.SignatureDeclaration): string | undefined { const info = getOverloadInfo(node); if (info === undefined) { return undefined; } const [computed, name] = typeof info === "string" ? [false, info] : [info.computed, info.name]; const isStatic = utils.hasModifier(node.modifiers, ts.SyntaxKind.StaticKeyword); return (computed ? "0" : "1") + (isStatic ? "0" : "1") + name; } function getOverloadInfo(node: ts.SignatureDeclaration): string | { name: string; computed?: boolean } | undefined { switch (node.kind) { case ts.SyntaxKind.ConstructSignature: case ts.SyntaxKind.Constructor: return "constructor"; case ts.SyntaxKind.CallSignature: return "()"; default: { const { name } = node; if (name === undefined) { return undefined; } switch (name.kind) { case ts.SyntaxKind.Identifier: return name.text; case ts.SyntaxKind.ComputedPropertyName: const { expression } = name; return utils.isLiteralExpression(expression) ? expression.text : { name: expression.getText(), computed: true }; default: return utils.isLiteralExpression(name) ? name.text : undefined; } } } } tslint-5.9.1/src/rules/alignRule.ts000066400000000000000000000212421322551053300172560ustar00rootroot00000000000000/** * @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 { getNextToken, isBlockLike } from "tsutils"; import * as ts from "typescript"; import * as Lint from "../index"; const OPTION_STATEMENTS = "statements"; const OPTION_MEMBERS = "members"; const OPTION_ELEMENTS = "elements"; const OPTION_PARAMETERS = "parameters"; const OPTION_ARGUMENTS = "arguments"; interface Options { statements: boolean; parameters: boolean; arguments: boolean; members: boolean; elements: boolean; } export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { ruleName: "align", description: "Enforces vertical alignment.", hasFix: true, rationale: "Helps maintain a readable, consistent style in your codebase.", optionsDescription: Lint.Utils.dedent` Five arguments may be optionally provided: * \`"${OPTION_PARAMETERS}"\` checks alignment of function parameters. * \`"${OPTION_ARGUMENTS}"\` checks alignment of function call arguments. * \`"${OPTION_STATEMENTS}"\` checks alignment of statements. * \`"${OPTION_MEMBERS}"\` checks alignment of members of classes, interfaces, type literal, object literals and object destructuring. * \`"${OPTION_ELEMENTS}"\` checks alignment of elements of array iterals, array destructuring and tuple types.`, options: { type: "array", items: { type: "string", enum: [OPTION_ARGUMENTS, OPTION_ELEMENTS, OPTION_MEMBERS, OPTION_PARAMETERS, OPTION_STATEMENTS], }, minLength: 1, maxLength: 5, }, optionExamples: [[true, "parameters", "statements"]], type: "style", typescriptOnly: false, }; /* tslint:enable:object-literal-sort-keys */ public static FAILURE_STRING_SUFFIX = " are not aligned"; public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker(new AlignWalker(sourceFile, this.ruleName, { arguments: this.ruleArguments.indexOf(OPTION_ARGUMENTS) !== -1, elements: this.ruleArguments.indexOf(OPTION_ELEMENTS) !== -1, members: this.ruleArguments.indexOf(OPTION_MEMBERS) !== -1, parameters: this.ruleArguments.indexOf(OPTION_PARAMETERS) !== -1, statements: this.ruleArguments.indexOf(OPTION_STATEMENTS) !== -1, })); } } class AlignWalker extends Lint.AbstractWalker { public walk(sourceFile: ts.SourceFile) { const cb = (node: ts.Node): void => { if (this.options.statements && isBlockLike(node)) { this.checkAlignment(node.statements.filter((s) => s.kind !== ts.SyntaxKind.EmptyStatement), OPTION_STATEMENTS); } else { switch (node.kind) { case ts.SyntaxKind.NewExpression: if ((node as ts.NewExpression).arguments === undefined) { break; } // falls through case ts.SyntaxKind.CallExpression: if (this.options.arguments) { this.checkAlignment((node as ts.CallExpression | ts.NewExpression).arguments!, OPTION_ARGUMENTS); } break; case ts.SyntaxKind.FunctionDeclaration: case ts.SyntaxKind.FunctionExpression: case ts.SyntaxKind.Constructor: case ts.SyntaxKind.MethodDeclaration: case ts.SyntaxKind.ArrowFunction: case ts.SyntaxKind.CallSignature: case ts.SyntaxKind.ConstructSignature: case ts.SyntaxKind.MethodSignature: case ts.SyntaxKind.FunctionType: case ts.SyntaxKind.ConstructorType: if (this.options.parameters) { this.checkAlignment((node as ts.SignatureDeclaration).parameters, OPTION_PARAMETERS); } break; case ts.SyntaxKind.ArrayLiteralExpression: case ts.SyntaxKind.ArrayBindingPattern: if (this.options.elements) { this.checkAlignment((node as ts.ArrayBindingOrAssignmentPattern).elements, OPTION_ELEMENTS); } break; case ts.SyntaxKind.TupleType: if (this.options.elements) { this.checkAlignment((node as ts.TupleTypeNode).elementTypes, OPTION_ELEMENTS); } break; case ts.SyntaxKind.ObjectLiteralExpression: if (this.options.members) { this.checkAlignment((node as ts.ObjectLiteralExpression).properties, OPTION_MEMBERS); } break; case ts.SyntaxKind.ObjectBindingPattern: if (this.options.members) { this.checkAlignment((node as ts.ObjectBindingPattern).elements, OPTION_MEMBERS); } break; case ts.SyntaxKind.ClassDeclaration: case ts.SyntaxKind.ClassExpression: if (this.options.members) { this.checkAlignment( (node as ts.ClassLikeDeclaration).members.filter((m) => m.kind !== ts.SyntaxKind.SemicolonClassElement), OPTION_MEMBERS, ); } break; case ts.SyntaxKind.InterfaceDeclaration: case ts.SyntaxKind.TypeLiteral: if (this.options.members) { this.checkAlignment((node as ts.InterfaceDeclaration | ts.TypeLiteralNode).members, OPTION_MEMBERS); } } } return ts.forEachChild(node, cb); }; return cb(sourceFile); } private checkAlignment(nodes: ReadonlyArray, kind: string) { if (nodes.length <= 1) { return; } const sourceFile = this.sourceFile; let pos = getLineAndCharacterWithoutBom(sourceFile, this.getStart(nodes[0])); const alignToColumn = pos.character; let line = pos.line; // skip first node in list for (let i = 1; i < nodes.length; ++i) { const node = nodes[i]; const start = this.getStart(node); pos = ts.getLineAndCharacterOfPosition(sourceFile, start); if (line !== pos.line && pos.character !== alignToColumn) { const diff = alignToColumn - pos.character; let fix: Lint.Fix | undefined; if (diff >= 0) { fix = Lint.Replacement.appendText(start, " ".repeat(diff)); } else if (node.pos <= start + diff && /^\s+$/.test(sourceFile.text.substring(start + diff, start))) { // only delete text if there is only whitespace fix = Lint.Replacement.deleteText(start + diff, -diff); } this.addFailure(start, Math.max(node.end, start), kind + Rule.FAILURE_STRING_SUFFIX, fix); } line = pos.line; } } private getStart(node: ts.Node) { return node.kind !== ts.SyntaxKind.OmittedExpression ? node.getStart(this.sourceFile) // find the comma token following the OmmitedExpression : getNextToken(node, this.sourceFile)!.getStart(this.sourceFile); } } function getLineAndCharacterWithoutBom(sourceFile: ts.SourceFile, pos: number): ts.LineAndCharacter { const result = ts.getLineAndCharacterOfPosition(sourceFile, pos); if (result.line === 0 && sourceFile.text[0] === "\uFEFF") { result.character -= 1; } return result; } tslint-5.9.1/src/rules/arrayTypeRule.ts000066400000000000000000000154371322551053300201550ustar00rootroot00000000000000/** * @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"; type Option = "array" | "generic" | "array-simple"; const OPTION_ARRAY = "array"; const OPTION_GENERIC = "generic"; const OPTION_ARRAY_SIMPLE = "array-simple"; export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { ruleName: "array-type", description: "Requires using either 'T[]' or 'Array' for arrays.", hasFix: true, optionsDescription: Lint.Utils.dedent` One of the following arguments must be provided: * \`"${OPTION_ARRAY}"\` enforces use of \`T[]\` for all types T. * \`"${OPTION_GENERIC}"\` enforces use of \`Array\` for all types T. * \`"${OPTION_ARRAY_SIMPLE}"\` enforces use of \`T[]\` if \`T\` is a simple type (primitive or type reference).`, options: { type: "string", enum: [OPTION_ARRAY, OPTION_GENERIC, OPTION_ARRAY_SIMPLE], }, optionExamples: [[true, OPTION_ARRAY], [true, OPTION_GENERIC], [true, OPTION_ARRAY_SIMPLE]], type: "style", typescriptOnly: true, }; /* tslint:enable:object-literal-sort-keys */ public static FAILURE_STRING_ARRAY = "Array type using 'Array' is forbidden. Use 'T[]' instead."; public static FAILURE_STRING_GENERIC = "Array type using 'T[]' is forbidden. Use 'Array' instead."; public static FAILURE_STRING_ARRAY_SIMPLE = "Array type using 'Array' is forbidden for simple types. Use 'T[]' instead."; public static FAILURE_STRING_GENERIC_SIMPLE = "Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead."; public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithFunction(sourceFile, walk, this.ruleArguments[0] as Option); } } function walk(ctx: Lint.WalkContext