├── .github ├── assignment.yml ├── commands.yml ├── issue_template.md ├── locker.yml └── needs_more_info.yml ├── .gitignore ├── .vscode ├── settings.json └── tasks.json ├── LICENSE ├── README.md ├── SECURITY.md ├── gulpfile.js ├── package-lock.json ├── package.json ├── thirdpartynotices.txt ├── tslint-server ├── .gitignore ├── .vscode │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── package-lock.json ├── package.json ├── src │ ├── delayer.ts │ ├── fixer.ts │ ├── mruCache.ts │ ├── runner.ts │ ├── thenable.d.ts │ ├── tsconfig.json │ └── tslintServer.ts └── test │ ├── autofixes.test.ts │ └── tsconfig.json ├── tslint-tests ├── .vscode │ ├── settings.json │ └── tasks.json ├── multi-root-tests │ ├── folderA │ │ ├── .vscode │ │ │ └── settings.json │ │ ├── no-var-keyword.ts │ │ ├── package.json │ │ └── tslint.json │ ├── folderB │ │ ├── .vscode │ │ │ └── settings.json │ │ ├── no-var-keyword.ts │ │ ├── package.json │ │ └── tslint.json │ └── multi-root-tslint-test.code-workspace ├── no-tslint-test │ ├── no-var-keyword.ts │ ├── package.json │ └── tslint.json ├── package-lock.json ├── package.json ├── tests │ ├── array-type.ts │ ├── arrow-parens.ts │ ├── comment-format.ts │ ├── no-var-keyword.ts │ ├── no_unused-variable.ts │ ├── ordered-imports.ts │ ├── overlapping-fixes.ts │ ├── overlappingfixes2.ts │ ├── quotemark.ts │ ├── selective-auto-fix-on-save.ts │ ├── semicolon.ts │ ├── test-javascript.js │ ├── testcomponent.tsx │ ├── trailing-comma.ts │ ├── triple-equals.ts │ └── whitespace.ts ├── tsconfig.json ├── tslint.json ├── tslint.json-3.7 └── tslint.yaml.test ├── tslint.json ├── tslint ├── .gitignore ├── .vscode │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── License.txt ├── README.md ├── TSLint_icon.png ├── extension.ts ├── package-lock.json ├── package.json └── tsconfig.json └── vscode-tslint.code-workspace /.github/assignment.yml: -------------------------------------------------------------------------------- 1 | { 2 | perform: true, 3 | assignees: [ egamma ] 4 | } 5 | -------------------------------------------------------------------------------- /.github/commands.yml: -------------------------------------------------------------------------------- 1 | { 2 | perform: true, 3 | commands: [ 4 | { 5 | type: 'label', 6 | name: '*question', 7 | action: 'close', 8 | comment: "This issue has been closed because it represents a question. Questions are better addressed on [StackOverflow](https://stackoverflow.com/questions/tagged/language-server-protocol). See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" 9 | }, 10 | { 11 | type: 'label', 12 | name: '*not-reproducible', 13 | action: 'close', 14 | comment: "This issue has been closed because the problem could not be reproduced either because it is already fixed in later versions of the product or because it requires additional details on how to reproduce it. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" 15 | }, 16 | { 17 | type: 'label', 18 | name: '*out-of-scope', 19 | action: 'close', 20 | comment: "This feature request will not be considered in the next 6-12 months and has been closed to keep the number of issues we have to maintain manageable. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nThanks for your understanding and happy coding!" 21 | }, 22 | { 23 | type: 'comment', 24 | name: 'duplicate', 25 | action: 'updateLabels', 26 | addLabel: '*duplicate' 27 | }, 28 | { 29 | type: 'label', 30 | name: '*duplicate', 31 | allowTriggerByBot: true, 32 | action: 'close', 33 | comment: "This issue has been closed because it is already tracked by another issue. See also our [GitHub issues](https://github.com/Microsoft/vscode-languageserver-node/issues) to search for existing issues and our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" 34 | }, 35 | ] 36 | } -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ## This extension is deprecated 2 | 3 | Please migrate to https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-typescript-tslint-plugin 4 | -------------------------------------------------------------------------------- /.github/locker.yml: -------------------------------------------------------------------------------- 1 | { 2 | daysAfterClose: 45, 3 | daysSinceLastUpdate: 3, 4 | perform: true 5 | } -------------------------------------------------------------------------------- /.github/needs_more_info.yml: -------------------------------------------------------------------------------- 1 | { 2 | daysUntilClose: 7, 3 | needsMoreInfoLabel: 'needs more info', 4 | perform: true, 5 | closeComment: "This issue has been closed automatically because it needs more information and has not had recent activity. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" 6 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "editor.insertSpaces": false 4 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "0.1.0", 5 | "command": "gulp", 6 | "isShellCommand": true, 7 | "args": [ 8 | "--no-color" 9 | ], 10 | "tasks": [ 11 | { 12 | "taskName": "tslint", 13 | "args": [], 14 | "problemMatcher": { 15 | "owner": "tslint", 16 | "fileLocation": [ 17 | "relative", 18 | "${workspaceRoot}" 19 | ], 20 | "severity": "warning", 21 | "pattern": { 22 | "regexp": "^(\\S.*)\\[(\\d+), (\\d+)\\]:\\s+(.*)$", 23 | "file": 1, 24 | "line": 2, 25 | "column": 3, 26 | "message": 4 27 | } 28 | } 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation 2 | 3 | All rights reserved. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vscode-tslint 2 | ![Marketplace Version](http://vsmarketplacebadge.apphb.com/version/eg2.tslint.svg "Current Version") ![Market Place Installs](http://vsmarketplacebadge.apphb.com/installs/eg2.tslint.svg "Number of Installs") 3 | 4 | VSCode extension to support tslint. This README describes the development setup, for information about the published extension refer to the [README](tslint/README.md) in the tslint folder. 5 | 6 | ## Development setup 7 | - run npm install inside the `tslint` and `tslint-server` folders 8 | - open VS Code on `tslint` and `tslint-server` or open a workspace with the client and server by opening `vscode-tslint.code-workspace` 9 | - compile the server once (see developing the server) 10 | 11 | ## Developing the server 12 | - open VS Code on `tslint-server` 13 | - run `npm run compile` or `npm run watch` to build the server and copy it into the `tslint` folder 14 | - to debug press F5 which attaches a debugger to the server 15 | - to trace the server communication you can enable the setting: "tslint.trace.server": "verbose", "messages" 16 | 17 | ## Developing the extension/client 18 | - open VS Code on `tslint` 19 | - run F5 to build and debug the extension 20 | 21 | > If you want to debug server and extension at the same time; 1st debug extension and then start server debugging after you have opened a typescript file that activates the extension. 22 | 23 | ## Manual Tests 24 | Manual tests can be found in the `tslint-tests` folder. -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const gulp_tslint = require('gulp-tslint'); 5 | 6 | gulp.task('default', ['tslint']); 7 | 8 | gulp.task('tslint', () => { 9 | return gulp.src(['**/*.ts', '!**/*.d.ts', '!node_modules/**']) 10 | .pipe(gulp_tslint()) 11 | .pipe(gulp_tslint.report()); 12 | }); -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-tslint", 3 | "version": "1.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.12.13", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", 10 | "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 11 | "requires": { 12 | "@babel/highlight": "^7.12.13" 13 | } 14 | }, 15 | "@babel/helper-validator-identifier": { 16 | "version": "7.12.11", 17 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", 18 | "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" 19 | }, 20 | "@babel/highlight": { 21 | "version": "7.12.13", 22 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", 23 | "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", 24 | "requires": { 25 | "@babel/helper-validator-identifier": "^7.12.11", 26 | "chalk": "^2.0.0", 27 | "js-tokens": "^4.0.0" 28 | } 29 | }, 30 | "ansi-styles": { 31 | "version": "3.2.1", 32 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 33 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 34 | "requires": { 35 | "color-convert": "^1.9.0" 36 | } 37 | }, 38 | "argparse": { 39 | "version": "1.0.10", 40 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 41 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 42 | "requires": { 43 | "sprintf-js": "~1.0.2" 44 | } 45 | }, 46 | "balanced-match": { 47 | "version": "1.0.0", 48 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 49 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 50 | }, 51 | "brace-expansion": { 52 | "version": "1.1.11", 53 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 54 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 55 | "requires": { 56 | "balanced-match": "^1.0.0", 57 | "concat-map": "0.0.1" 58 | } 59 | }, 60 | "builtin-modules": { 61 | "version": "1.1.1", 62 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 63 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" 64 | }, 65 | "chalk": { 66 | "version": "2.4.2", 67 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 68 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 69 | "requires": { 70 | "ansi-styles": "^3.2.1", 71 | "escape-string-regexp": "^1.0.5", 72 | "supports-color": "^5.3.0" 73 | } 74 | }, 75 | "color-convert": { 76 | "version": "1.9.3", 77 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 78 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 79 | "requires": { 80 | "color-name": "1.1.3" 81 | } 82 | }, 83 | "color-name": { 84 | "version": "1.1.3", 85 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 86 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 87 | }, 88 | "commander": { 89 | "version": "2.20.3", 90 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 91 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" 92 | }, 93 | "concat-map": { 94 | "version": "0.0.1", 95 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 96 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 97 | }, 98 | "diff": { 99 | "version": "4.0.2", 100 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 101 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" 102 | }, 103 | "escape-string-regexp": { 104 | "version": "1.0.5", 105 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 106 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 107 | }, 108 | "esprima": { 109 | "version": "4.0.1", 110 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 111 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" 112 | }, 113 | "fs.realpath": { 114 | "version": "1.0.0", 115 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 116 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 117 | }, 118 | "function-bind": { 119 | "version": "1.1.1", 120 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 121 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 122 | }, 123 | "glob": { 124 | "version": "7.1.6", 125 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 126 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 127 | "requires": { 128 | "fs.realpath": "^1.0.0", 129 | "inflight": "^1.0.4", 130 | "inherits": "2", 131 | "minimatch": "^3.0.4", 132 | "once": "^1.3.0", 133 | "path-is-absolute": "^1.0.0" 134 | } 135 | }, 136 | "has": { 137 | "version": "1.0.3", 138 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 139 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 140 | "requires": { 141 | "function-bind": "^1.1.1" 142 | } 143 | }, 144 | "has-flag": { 145 | "version": "3.0.0", 146 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 147 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 148 | }, 149 | "inflight": { 150 | "version": "1.0.6", 151 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 152 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 153 | "requires": { 154 | "once": "^1.3.0", 155 | "wrappy": "1" 156 | } 157 | }, 158 | "inherits": { 159 | "version": "2.0.4", 160 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 161 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 162 | }, 163 | "is-core-module": { 164 | "version": "2.2.0", 165 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", 166 | "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", 167 | "requires": { 168 | "has": "^1.0.3" 169 | } 170 | }, 171 | "js-tokens": { 172 | "version": "4.0.0", 173 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 174 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 175 | }, 176 | "js-yaml": { 177 | "version": "3.14.1", 178 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 179 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 180 | "requires": { 181 | "argparse": "^1.0.7", 182 | "esprima": "^4.0.0" 183 | } 184 | }, 185 | "minimatch": { 186 | "version": "3.0.4", 187 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 188 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 189 | "requires": { 190 | "brace-expansion": "^1.1.7" 191 | } 192 | }, 193 | "minimist": { 194 | "version": "1.2.5", 195 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 196 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 197 | }, 198 | "mkdirp": { 199 | "version": "0.5.5", 200 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 201 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 202 | "requires": { 203 | "minimist": "^1.2.5" 204 | } 205 | }, 206 | "once": { 207 | "version": "1.4.0", 208 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 209 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 210 | "requires": { 211 | "wrappy": "1" 212 | } 213 | }, 214 | "path-is-absolute": { 215 | "version": "1.0.1", 216 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 217 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 218 | }, 219 | "path-parse": { 220 | "version": "1.0.6", 221 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 222 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" 223 | }, 224 | "resolve": { 225 | "version": "1.20.0", 226 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 227 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 228 | "requires": { 229 | "is-core-module": "^2.2.0", 230 | "path-parse": "^1.0.6" 231 | } 232 | }, 233 | "semver": { 234 | "version": "5.7.1", 235 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 236 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 237 | }, 238 | "sprintf-js": { 239 | "version": "1.0.3", 240 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 241 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" 242 | }, 243 | "supports-color": { 244 | "version": "5.5.0", 245 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 246 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 247 | "requires": { 248 | "has-flag": "^3.0.0" 249 | } 250 | }, 251 | "tslib": { 252 | "version": "1.14.1", 253 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 254 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 255 | }, 256 | "tslint": { 257 | "version": "5.20.1", 258 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", 259 | "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", 260 | "requires": { 261 | "@babel/code-frame": "^7.0.0", 262 | "builtin-modules": "^1.1.1", 263 | "chalk": "^2.3.0", 264 | "commander": "^2.12.1", 265 | "diff": "^4.0.1", 266 | "glob": "^7.1.1", 267 | "js-yaml": "^3.13.1", 268 | "minimatch": "^3.0.4", 269 | "mkdirp": "^0.5.1", 270 | "resolve": "^1.3.2", 271 | "semver": "^5.3.0", 272 | "tslib": "^1.8.0", 273 | "tsutils": "^2.29.0" 274 | } 275 | }, 276 | "tsutils": { 277 | "version": "2.29.0", 278 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 279 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 280 | "requires": { 281 | "tslib": "^1.8.1" 282 | } 283 | }, 284 | "typescript": { 285 | "version": "2.9.2", 286 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", 287 | "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==" 288 | }, 289 | "wrappy": { 290 | "version": "1.0.2", 291 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 292 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 293 | } 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-tslint", 3 | "version": "1.0.1", 4 | "description": "The umbrella project for the tslint client and server", 5 | "main": " ", 6 | "dependencies": { 7 | "tslint": "^5.7.0", 8 | "typescript": "^2.9.1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/Microsoft/vscode-tslint.git" 13 | }, 14 | "author": "egamma" 15 | } 16 | -------------------------------------------------------------------------------- /thirdpartynotices.txt: -------------------------------------------------------------------------------- 1 | THIRD-PARTY SOFTWARE NOTICES AND INFORMATION 2 | For Microsoft vscode-tslint 3 | 4 | This project incorporates material from the project(s) listed below (collectively, “Third Party Code”). 5 | Microsoft is not the original author of the Third Party Code. The original copyright notice and license 6 | under which Microsoft received such Third Party Code are set out below. This Third Party Code is licensed 7 | to you under their original license terms set forth below. Microsoft reserves all other rights not expressly 8 | granted, whether by implication, estoppel or otherwise. 9 | 10 | 1. DefinitelyTyped version 0.0.1 (https://github.com/borisyankov/DefinitelyTyped) 11 | 12 | This project is licensed under the MIT license. 13 | Copyrights are respective of each contributor listed at the beginning of each definition file. 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in 23 | all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 31 | THE SOFTWARE. 32 | 2. minimatch version 3.0.0 (https://github.com/isaacs/minimatch) -------------------------------------------------------------------------------- /tslint-server/.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | test/out 3 | node_modules -------------------------------------------------------------------------------- /tslint-server/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to server", 6 | "type": "node", 7 | "request": "attach", 8 | "address": "localhost", 9 | "protocol": "inspector", 10 | "port": 6010, 11 | "sourceMaps": true, 12 | "outFiles": ["${workspaceRoot}/../tslint/server/**/*.js"] 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /tslint-server/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "javascript.validate.enable": false, 4 | "files.trimTrailingWhitespace": true, 5 | "editor.insertSpaces": false, 6 | "editor.tabSize": 4, 7 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, 8 | "editor.formatOnSave": false 9 | } 10 | -------------------------------------------------------------------------------- /tslint-server/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "watch", 7 | "problemMatcher": "$tsc-watch", 8 | "isBackground": true, 9 | "presentation": { 10 | "reveal": "never" 11 | }, 12 | "group": { 13 | "kind": "build", 14 | "isDefault": true 15 | } 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /tslint-server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint-server", 3 | "version": "0.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.0.0", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", 10 | "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.0.0" 14 | } 15 | }, 16 | "@babel/highlight": { 17 | "version": "7.5.0", 18 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", 19 | "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", 20 | "dev": true, 21 | "requires": { 22 | "chalk": "^2.0.0", 23 | "esutils": "^2.0.2", 24 | "js-tokens": "^4.0.0" 25 | } 26 | }, 27 | "@types/minimatch": { 28 | "version": "3.0.3", 29 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 30 | "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 31 | "dev": true 32 | }, 33 | "@types/mocha": { 34 | "version": "8.2.1", 35 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.1.tgz", 36 | "integrity": "sha512-NysN+bNqj6E0Hv4CTGWSlPzMW6vTKjDpOteycDkV4IWBsO+PU48JonrPzV9ODjiI2XrjmA05KInLgF5ivZ/YGQ==", 37 | "dev": true 38 | }, 39 | "@types/node": { 40 | "version": "10.3.0", 41 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.3.0.tgz", 42 | "integrity": "sha512-hWzNviaVFIr1TqcRA8ou49JaSHp+Rfabmnqg2kNvusKqLhPU0rIsGPUj5WJJ7ld4Bb7qdgLmIhLfCD1qS08IVA==", 43 | "dev": true 44 | }, 45 | "@types/semver": { 46 | "version": "5.4.0", 47 | "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.4.0.tgz", 48 | "integrity": "sha512-PBHCvO98hNec9A491vBbh0ZNDOVxccwKL1u2pm6fs9oDgm7SEnw0lEHqHfjsYryDxnE3zaf7LvERWEXjOp1hig==", 49 | "dev": true 50 | }, 51 | "ansi-colors": { 52 | "version": "3.2.3", 53 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", 54 | "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", 55 | "dev": true 56 | }, 57 | "ansi-regex": { 58 | "version": "3.0.0", 59 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 60 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 61 | "dev": true 62 | }, 63 | "ansi-styles": { 64 | "version": "3.2.1", 65 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 66 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 67 | "dev": true, 68 | "requires": { 69 | "color-convert": "^1.9.0" 70 | } 71 | }, 72 | "argparse": { 73 | "version": "1.0.10", 74 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 75 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 76 | "dev": true, 77 | "requires": { 78 | "sprintf-js": "~1.0.2" 79 | } 80 | }, 81 | "balanced-match": { 82 | "version": "1.0.0", 83 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 84 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 85 | }, 86 | "brace-expansion": { 87 | "version": "1.1.8", 88 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 89 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 90 | "requires": { 91 | "balanced-match": "^1.0.0", 92 | "concat-map": "0.0.1" 93 | } 94 | }, 95 | "browser-stdout": { 96 | "version": "1.3.1", 97 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 98 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 99 | "dev": true 100 | }, 101 | "builtin-modules": { 102 | "version": "1.1.1", 103 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 104 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 105 | "dev": true 106 | }, 107 | "call-bind": { 108 | "version": "1.0.2", 109 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 110 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 111 | "dev": true, 112 | "requires": { 113 | "function-bind": "^1.1.1", 114 | "get-intrinsic": "^1.0.2" 115 | } 116 | }, 117 | "camelcase": { 118 | "version": "5.3.1", 119 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", 120 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", 121 | "dev": true 122 | }, 123 | "chalk": { 124 | "version": "2.3.0", 125 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", 126 | "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", 127 | "dev": true, 128 | "requires": { 129 | "ansi-styles": "^3.1.0", 130 | "escape-string-regexp": "^1.0.5", 131 | "supports-color": "^4.0.0" 132 | }, 133 | "dependencies": { 134 | "ansi-styles": { 135 | "version": "3.2.0", 136 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", 137 | "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", 138 | "dev": true, 139 | "requires": { 140 | "color-convert": "^1.9.0" 141 | } 142 | }, 143 | "has-flag": { 144 | "version": "2.0.0", 145 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", 146 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", 147 | "dev": true 148 | }, 149 | "supports-color": { 150 | "version": "4.5.0", 151 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", 152 | "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", 153 | "dev": true, 154 | "requires": { 155 | "has-flag": "^2.0.0" 156 | } 157 | } 158 | } 159 | }, 160 | "cliui": { 161 | "version": "5.0.0", 162 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", 163 | "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", 164 | "dev": true, 165 | "requires": { 166 | "string-width": "^3.1.0", 167 | "strip-ansi": "^5.2.0", 168 | "wrap-ansi": "^5.1.0" 169 | }, 170 | "dependencies": { 171 | "ansi-regex": { 172 | "version": "4.1.0", 173 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 174 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 175 | "dev": true 176 | }, 177 | "string-width": { 178 | "version": "3.1.0", 179 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 180 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 181 | "dev": true, 182 | "requires": { 183 | "emoji-regex": "^7.0.1", 184 | "is-fullwidth-code-point": "^2.0.0", 185 | "strip-ansi": "^5.1.0" 186 | } 187 | }, 188 | "strip-ansi": { 189 | "version": "5.2.0", 190 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 191 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 192 | "dev": true, 193 | "requires": { 194 | "ansi-regex": "^4.1.0" 195 | } 196 | } 197 | } 198 | }, 199 | "color-convert": { 200 | "version": "1.9.1", 201 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", 202 | "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", 203 | "dev": true, 204 | "requires": { 205 | "color-name": "^1.1.1" 206 | } 207 | }, 208 | "color-name": { 209 | "version": "1.1.3", 210 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 211 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 212 | "dev": true 213 | }, 214 | "commander": { 215 | "version": "2.20.0", 216 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", 217 | "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", 218 | "dev": true 219 | }, 220 | "concat-map": { 221 | "version": "0.0.1", 222 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 223 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 224 | }, 225 | "debug": { 226 | "version": "3.2.6", 227 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 228 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 229 | "dev": true, 230 | "requires": { 231 | "ms": "^2.1.1" 232 | } 233 | }, 234 | "decamelize": { 235 | "version": "1.2.0", 236 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 237 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 238 | "dev": true 239 | }, 240 | "define-properties": { 241 | "version": "1.1.3", 242 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 243 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 244 | "dev": true, 245 | "requires": { 246 | "object-keys": "^1.0.12" 247 | } 248 | }, 249 | "diff": { 250 | "version": "3.5.0", 251 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 252 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 253 | "dev": true 254 | }, 255 | "emoji-regex": { 256 | "version": "7.0.3", 257 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 258 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 259 | "dev": true 260 | }, 261 | "es-abstract": { 262 | "version": "1.18.0-next.2", 263 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", 264 | "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", 265 | "dev": true, 266 | "requires": { 267 | "call-bind": "^1.0.2", 268 | "es-to-primitive": "^1.2.1", 269 | "function-bind": "^1.1.1", 270 | "get-intrinsic": "^1.0.2", 271 | "has": "^1.0.3", 272 | "has-symbols": "^1.0.1", 273 | "is-callable": "^1.2.2", 274 | "is-negative-zero": "^2.0.1", 275 | "is-regex": "^1.1.1", 276 | "object-inspect": "^1.9.0", 277 | "object-keys": "^1.1.1", 278 | "object.assign": "^4.1.2", 279 | "string.prototype.trimend": "^1.0.3", 280 | "string.prototype.trimstart": "^1.0.3" 281 | }, 282 | "dependencies": { 283 | "object.assign": { 284 | "version": "4.1.2", 285 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", 286 | "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", 287 | "dev": true, 288 | "requires": { 289 | "call-bind": "^1.0.0", 290 | "define-properties": "^1.1.3", 291 | "has-symbols": "^1.0.1", 292 | "object-keys": "^1.1.1" 293 | } 294 | } 295 | } 296 | }, 297 | "es-to-primitive": { 298 | "version": "1.2.1", 299 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 300 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 301 | "dev": true, 302 | "requires": { 303 | "is-callable": "^1.1.4", 304 | "is-date-object": "^1.0.1", 305 | "is-symbol": "^1.0.2" 306 | } 307 | }, 308 | "escape-string-regexp": { 309 | "version": "1.0.5", 310 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 311 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 312 | "dev": true 313 | }, 314 | "esprima": { 315 | "version": "4.0.1", 316 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 317 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 318 | "dev": true 319 | }, 320 | "esutils": { 321 | "version": "2.0.2", 322 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 323 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 324 | "dev": true 325 | }, 326 | "find-up": { 327 | "version": "3.0.0", 328 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 329 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 330 | "dev": true, 331 | "requires": { 332 | "locate-path": "^3.0.0" 333 | } 334 | }, 335 | "flat": { 336 | "version": "4.1.1", 337 | "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", 338 | "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", 339 | "dev": true, 340 | "requires": { 341 | "is-buffer": "~2.0.3" 342 | } 343 | }, 344 | "fs.realpath": { 345 | "version": "1.0.0", 346 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 347 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 348 | "dev": true 349 | }, 350 | "function-bind": { 351 | "version": "1.1.1", 352 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 353 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 354 | "dev": true 355 | }, 356 | "get-caller-file": { 357 | "version": "2.0.5", 358 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 359 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 360 | "dev": true 361 | }, 362 | "get-intrinsic": { 363 | "version": "1.1.1", 364 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", 365 | "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", 366 | "dev": true, 367 | "requires": { 368 | "function-bind": "^1.1.1", 369 | "has": "^1.0.3", 370 | "has-symbols": "^1.0.1" 371 | } 372 | }, 373 | "glob": { 374 | "version": "7.1.4", 375 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", 376 | "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", 377 | "dev": true, 378 | "requires": { 379 | "fs.realpath": "^1.0.0", 380 | "inflight": "^1.0.4", 381 | "inherits": "2", 382 | "minimatch": "^3.0.4", 383 | "once": "^1.3.0", 384 | "path-is-absolute": "^1.0.0" 385 | } 386 | }, 387 | "growl": { 388 | "version": "1.10.5", 389 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 390 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 391 | "dev": true 392 | }, 393 | "has": { 394 | "version": "1.0.3", 395 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 396 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 397 | "dev": true, 398 | "requires": { 399 | "function-bind": "^1.1.1" 400 | } 401 | }, 402 | "has-flag": { 403 | "version": "3.0.0", 404 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 405 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 406 | "dev": true 407 | }, 408 | "has-symbols": { 409 | "version": "1.0.1", 410 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", 411 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", 412 | "dev": true 413 | }, 414 | "he": { 415 | "version": "1.2.0", 416 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 417 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 418 | "dev": true 419 | }, 420 | "inflight": { 421 | "version": "1.0.6", 422 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 423 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 424 | "dev": true, 425 | "requires": { 426 | "once": "^1.3.0", 427 | "wrappy": "1" 428 | } 429 | }, 430 | "inherits": { 431 | "version": "2.0.3", 432 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 433 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 434 | "dev": true 435 | }, 436 | "is-buffer": { 437 | "version": "2.0.5", 438 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", 439 | "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", 440 | "dev": true 441 | }, 442 | "is-callable": { 443 | "version": "1.2.3", 444 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", 445 | "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", 446 | "dev": true 447 | }, 448 | "is-date-object": { 449 | "version": "1.0.2", 450 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", 451 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", 452 | "dev": true 453 | }, 454 | "is-fullwidth-code-point": { 455 | "version": "2.0.0", 456 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 457 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 458 | "dev": true 459 | }, 460 | "is-negative-zero": { 461 | "version": "2.0.1", 462 | "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", 463 | "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", 464 | "dev": true 465 | }, 466 | "is-regex": { 467 | "version": "1.1.2", 468 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", 469 | "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", 470 | "dev": true, 471 | "requires": { 472 | "call-bind": "^1.0.2", 473 | "has-symbols": "^1.0.1" 474 | } 475 | }, 476 | "is-symbol": { 477 | "version": "1.0.3", 478 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 479 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", 480 | "dev": true, 481 | "requires": { 482 | "has-symbols": "^1.0.1" 483 | } 484 | }, 485 | "isexe": { 486 | "version": "2.0.0", 487 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 488 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 489 | "dev": true 490 | }, 491 | "js-tokens": { 492 | "version": "4.0.0", 493 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 494 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 495 | "dev": true 496 | }, 497 | "js-yaml": { 498 | "version": "3.13.1", 499 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 500 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 501 | "dev": true, 502 | "requires": { 503 | "argparse": "^1.0.7", 504 | "esprima": "^4.0.0" 505 | } 506 | }, 507 | "locate-path": { 508 | "version": "3.0.0", 509 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 510 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 511 | "dev": true, 512 | "requires": { 513 | "p-locate": "^3.0.0", 514 | "path-exists": "^3.0.0" 515 | } 516 | }, 517 | "lodash": { 518 | "version": "4.17.21", 519 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 520 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 521 | "dev": true 522 | }, 523 | "log-symbols": { 524 | "version": "2.2.0", 525 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", 526 | "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", 527 | "dev": true, 528 | "requires": { 529 | "chalk": "^2.0.1" 530 | } 531 | }, 532 | "minimatch": { 533 | "version": "3.0.4", 534 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 535 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 536 | "requires": { 537 | "brace-expansion": "^1.1.7" 538 | } 539 | }, 540 | "minimist": { 541 | "version": "1.2.5", 542 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 543 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 544 | "dev": true 545 | }, 546 | "mkdirp": { 547 | "version": "0.5.5", 548 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 549 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 550 | "dev": true, 551 | "requires": { 552 | "minimist": "^1.2.5" 553 | }, 554 | "dependencies": { 555 | "minimist": { 556 | "version": "1.2.5", 557 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 558 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 559 | "dev": true 560 | } 561 | } 562 | }, 563 | "mocha": { 564 | "version": "6.2.3", 565 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", 566 | "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", 567 | "dev": true, 568 | "requires": { 569 | "ansi-colors": "3.2.3", 570 | "browser-stdout": "1.3.1", 571 | "debug": "3.2.6", 572 | "diff": "3.5.0", 573 | "escape-string-regexp": "1.0.5", 574 | "find-up": "3.0.0", 575 | "glob": "7.1.3", 576 | "growl": "1.10.5", 577 | "he": "1.2.0", 578 | "js-yaml": "3.13.1", 579 | "log-symbols": "2.2.0", 580 | "minimatch": "3.0.4", 581 | "mkdirp": "0.5.4", 582 | "ms": "2.1.1", 583 | "node-environment-flags": "1.0.5", 584 | "object.assign": "4.1.0", 585 | "strip-json-comments": "2.0.1", 586 | "supports-color": "6.0.0", 587 | "which": "1.3.1", 588 | "wide-align": "1.1.3", 589 | "yargs": "13.3.2", 590 | "yargs-parser": "13.1.2", 591 | "yargs-unparser": "1.6.0" 592 | }, 593 | "dependencies": { 594 | "glob": { 595 | "version": "7.1.3", 596 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 597 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 598 | "dev": true, 599 | "requires": { 600 | "fs.realpath": "^1.0.0", 601 | "inflight": "^1.0.4", 602 | "inherits": "2", 603 | "minimatch": "^3.0.4", 604 | "once": "^1.3.0", 605 | "path-is-absolute": "^1.0.0" 606 | } 607 | }, 608 | "mkdirp": { 609 | "version": "0.5.4", 610 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", 611 | "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", 612 | "dev": true, 613 | "requires": { 614 | "minimist": "^1.2.5" 615 | } 616 | } 617 | } 618 | }, 619 | "ms": { 620 | "version": "2.1.1", 621 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 622 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 623 | "dev": true 624 | }, 625 | "node-environment-flags": { 626 | "version": "1.0.5", 627 | "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", 628 | "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", 629 | "dev": true, 630 | "requires": { 631 | "object.getownpropertydescriptors": "^2.0.3", 632 | "semver": "^5.7.0" 633 | }, 634 | "dependencies": { 635 | "semver": { 636 | "version": "5.7.1", 637 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 638 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 639 | "dev": true 640 | } 641 | } 642 | }, 643 | "object-inspect": { 644 | "version": "1.9.0", 645 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", 646 | "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", 647 | "dev": true 648 | }, 649 | "object-keys": { 650 | "version": "1.1.1", 651 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 652 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 653 | "dev": true 654 | }, 655 | "object.assign": { 656 | "version": "4.1.0", 657 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 658 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 659 | "dev": true, 660 | "requires": { 661 | "define-properties": "^1.1.2", 662 | "function-bind": "^1.1.1", 663 | "has-symbols": "^1.0.0", 664 | "object-keys": "^1.0.11" 665 | } 666 | }, 667 | "object.getownpropertydescriptors": { 668 | "version": "2.1.1", 669 | "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz", 670 | "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==", 671 | "dev": true, 672 | "requires": { 673 | "call-bind": "^1.0.0", 674 | "define-properties": "^1.1.3", 675 | "es-abstract": "^1.18.0-next.1" 676 | } 677 | }, 678 | "once": { 679 | "version": "1.4.0", 680 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 681 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 682 | "dev": true, 683 | "requires": { 684 | "wrappy": "1" 685 | } 686 | }, 687 | "p-limit": { 688 | "version": "2.3.0", 689 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 690 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 691 | "dev": true, 692 | "requires": { 693 | "p-try": "^2.0.0" 694 | } 695 | }, 696 | "p-locate": { 697 | "version": "3.0.0", 698 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 699 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 700 | "dev": true, 701 | "requires": { 702 | "p-limit": "^2.0.0" 703 | } 704 | }, 705 | "p-try": { 706 | "version": "2.2.0", 707 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 708 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 709 | "dev": true 710 | }, 711 | "path-exists": { 712 | "version": "3.0.0", 713 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 714 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 715 | "dev": true 716 | }, 717 | "path-is-absolute": { 718 | "version": "1.0.1", 719 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 720 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 721 | "dev": true 722 | }, 723 | "path-parse": { 724 | "version": "1.0.6", 725 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 726 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 727 | "dev": true 728 | }, 729 | "require-directory": { 730 | "version": "2.1.1", 731 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 732 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 733 | "dev": true 734 | }, 735 | "require-main-filename": { 736 | "version": "2.0.0", 737 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", 738 | "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", 739 | "dev": true 740 | }, 741 | "resolve": { 742 | "version": "1.11.1", 743 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", 744 | "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", 745 | "dev": true, 746 | "requires": { 747 | "path-parse": "^1.0.6" 748 | } 749 | }, 750 | "semver": { 751 | "version": "5.4.1", 752 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", 753 | "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" 754 | }, 755 | "set-blocking": { 756 | "version": "2.0.0", 757 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 758 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 759 | "dev": true 760 | }, 761 | "sprintf-js": { 762 | "version": "1.0.3", 763 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 764 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 765 | "dev": true 766 | }, 767 | "string-width": { 768 | "version": "2.1.1", 769 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 770 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 771 | "dev": true, 772 | "requires": { 773 | "is-fullwidth-code-point": "^2.0.0", 774 | "strip-ansi": "^4.0.0" 775 | } 776 | }, 777 | "string.prototype.trimend": { 778 | "version": "1.0.3", 779 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", 780 | "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", 781 | "dev": true, 782 | "requires": { 783 | "call-bind": "^1.0.0", 784 | "define-properties": "^1.1.3" 785 | } 786 | }, 787 | "string.prototype.trimstart": { 788 | "version": "1.0.3", 789 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", 790 | "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", 791 | "dev": true, 792 | "requires": { 793 | "call-bind": "^1.0.0", 794 | "define-properties": "^1.1.3" 795 | } 796 | }, 797 | "strip-ansi": { 798 | "version": "4.0.0", 799 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 800 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 801 | "dev": true, 802 | "requires": { 803 | "ansi-regex": "^3.0.0" 804 | } 805 | }, 806 | "strip-json-comments": { 807 | "version": "2.0.1", 808 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 809 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 810 | "dev": true 811 | }, 812 | "supports-color": { 813 | "version": "6.0.0", 814 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", 815 | "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", 816 | "dev": true, 817 | "requires": { 818 | "has-flag": "^3.0.0" 819 | } 820 | }, 821 | "tslib": { 822 | "version": "1.10.0", 823 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", 824 | "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", 825 | "dev": true 826 | }, 827 | "tslint": { 828 | "version": "5.18.0", 829 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", 830 | "integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", 831 | "dev": true, 832 | "requires": { 833 | "@babel/code-frame": "^7.0.0", 834 | "builtin-modules": "^1.1.1", 835 | "chalk": "^2.3.0", 836 | "commander": "^2.12.1", 837 | "diff": "^3.2.0", 838 | "glob": "^7.1.1", 839 | "js-yaml": "^3.13.1", 840 | "minimatch": "^3.0.4", 841 | "mkdirp": "^0.5.1", 842 | "resolve": "^1.3.2", 843 | "semver": "^5.3.0", 844 | "tslib": "^1.8.0", 845 | "tsutils": "^2.29.0" 846 | } 847 | }, 848 | "tsutils": { 849 | "version": "2.29.0", 850 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 851 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 852 | "dev": true, 853 | "requires": { 854 | "tslib": "^1.8.1" 855 | } 856 | }, 857 | "typescript": { 858 | "version": "3.0.1", 859 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.0.1.tgz", 860 | "integrity": "sha512-zQIMOmC+372pC/CCVLqnQ0zSBiY7HHodU7mpQdjiZddek4GMj31I3dUJ7gAs9o65X7mnRma6OokOkc6f9jjfBg==", 861 | "dev": true 862 | }, 863 | "vscode-jsonrpc": { 864 | "version": "3.6.2", 865 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.6.2.tgz", 866 | "integrity": "sha512-T24Jb5V48e4VgYliUXMnZ379ItbrXgOimweKaJshD84z+8q7ZOZjJan0MeDe+Ugb+uqERDVV8SBmemaGMSMugA==" 867 | }, 868 | "vscode-languageserver": { 869 | "version": "5.0.3", 870 | "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.0.3.tgz", 871 | "integrity": "sha512-itOImvZfDueQXMhy4pm2SwPKa3AShZvILXFcK/5X3ruiYdZozmx3OeD5Y92dVBt0OzTdbVD9MZcEelH4E7Eu3g==", 872 | "requires": { 873 | "vscode-languageserver-protocol": "^3.10.3", 874 | "vscode-uri": "^1.0.5" 875 | }, 876 | "dependencies": { 877 | "vscode-uri": { 878 | "version": "1.0.6", 879 | "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.6.tgz", 880 | "integrity": "sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==" 881 | } 882 | } 883 | }, 884 | "vscode-languageserver-protocol": { 885 | "version": "3.10.3", 886 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.10.3.tgz", 887 | "integrity": "sha512-R9hKsmXmpIXBLpy6I0eztfAcWU0KHr1lADJiJq+VCmdiHGVUJugMIvU6qVCzLP9wRtZ02AF98j09NAKq10hWeQ==", 888 | "requires": { 889 | "vscode-jsonrpc": "^3.6.2", 890 | "vscode-languageserver-types": "^3.10.1" 891 | } 892 | }, 893 | "vscode-languageserver-types": { 894 | "version": "3.10.1", 895 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.10.1.tgz", 896 | "integrity": "sha512-HeQ1BPYJDly4HfKs0h2TUAZyHfzTAhgQsCwsa1tW9PhuvGGsd2r3Q53FFVugwP7/2bUv3GWPoTgAuIAkIdBc4w==" 897 | }, 898 | "vscode-uri": { 899 | "version": "1.0.1", 900 | "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.1.tgz", 901 | "integrity": "sha1-Eahr7+rDxKo+wIYjZRo8gabQu8g=" 902 | }, 903 | "which": { 904 | "version": "1.3.1", 905 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 906 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 907 | "dev": true, 908 | "requires": { 909 | "isexe": "^2.0.0" 910 | } 911 | }, 912 | "which-module": { 913 | "version": "2.0.0", 914 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", 915 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", 916 | "dev": true 917 | }, 918 | "wide-align": { 919 | "version": "1.1.3", 920 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 921 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 922 | "dev": true, 923 | "requires": { 924 | "string-width": "^1.0.2 || 2" 925 | } 926 | }, 927 | "wrap-ansi": { 928 | "version": "5.1.0", 929 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", 930 | "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", 931 | "dev": true, 932 | "requires": { 933 | "ansi-styles": "^3.2.0", 934 | "string-width": "^3.0.0", 935 | "strip-ansi": "^5.0.0" 936 | }, 937 | "dependencies": { 938 | "ansi-regex": { 939 | "version": "4.1.0", 940 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 941 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 942 | "dev": true 943 | }, 944 | "string-width": { 945 | "version": "3.1.0", 946 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 947 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 948 | "dev": true, 949 | "requires": { 950 | "emoji-regex": "^7.0.1", 951 | "is-fullwidth-code-point": "^2.0.0", 952 | "strip-ansi": "^5.1.0" 953 | } 954 | }, 955 | "strip-ansi": { 956 | "version": "5.2.0", 957 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 958 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 959 | "dev": true, 960 | "requires": { 961 | "ansi-regex": "^4.1.0" 962 | } 963 | } 964 | } 965 | }, 966 | "wrappy": { 967 | "version": "1.0.2", 968 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 969 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 970 | "dev": true 971 | }, 972 | "y18n": { 973 | "version": "4.0.1", 974 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", 975 | "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", 976 | "dev": true 977 | }, 978 | "yargs": { 979 | "version": "13.3.2", 980 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", 981 | "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", 982 | "dev": true, 983 | "requires": { 984 | "cliui": "^5.0.0", 985 | "find-up": "^3.0.0", 986 | "get-caller-file": "^2.0.1", 987 | "require-directory": "^2.1.1", 988 | "require-main-filename": "^2.0.0", 989 | "set-blocking": "^2.0.0", 990 | "string-width": "^3.0.0", 991 | "which-module": "^2.0.0", 992 | "y18n": "^4.0.0", 993 | "yargs-parser": "^13.1.2" 994 | }, 995 | "dependencies": { 996 | "ansi-regex": { 997 | "version": "4.1.0", 998 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 999 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1000 | "dev": true 1001 | }, 1002 | "string-width": { 1003 | "version": "3.1.0", 1004 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1005 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1006 | "dev": true, 1007 | "requires": { 1008 | "emoji-regex": "^7.0.1", 1009 | "is-fullwidth-code-point": "^2.0.0", 1010 | "strip-ansi": "^5.1.0" 1011 | } 1012 | }, 1013 | "strip-ansi": { 1014 | "version": "5.2.0", 1015 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1016 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1017 | "dev": true, 1018 | "requires": { 1019 | "ansi-regex": "^4.1.0" 1020 | } 1021 | } 1022 | } 1023 | }, 1024 | "yargs-parser": { 1025 | "version": "13.1.2", 1026 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", 1027 | "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", 1028 | "dev": true, 1029 | "requires": { 1030 | "camelcase": "^5.0.0", 1031 | "decamelize": "^1.2.0" 1032 | } 1033 | }, 1034 | "yargs-unparser": { 1035 | "version": "1.6.0", 1036 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", 1037 | "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", 1038 | "dev": true, 1039 | "requires": { 1040 | "flat": "^4.1.0", 1041 | "lodash": "^4.17.15", 1042 | "yargs": "^13.3.0" 1043 | } 1044 | } 1045 | } 1046 | } 1047 | -------------------------------------------------------------------------------- /tslint-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint-server", 3 | "version": "0.2.0", 4 | "description": "TSLint Linter Server", 5 | "engines": { 6 | "node": "*" 7 | }, 8 | "private": true, 9 | "dependencies": { 10 | "minimatch": "^3.0.0", 11 | "vscode-languageserver": "^5.0.3", 12 | "semver": "^5.1.0", 13 | "vscode-uri": "^1.0.1" 14 | }, 15 | "devDependencies": { 16 | "@types/minimatch": "^3.0.3", 17 | "@types/mocha": "^8.2.1", 18 | "@types/node": "^10.3.0", 19 | "@types/semver": "^5.3.30", 20 | "mocha": "^6.2.3", 21 | "tslint": "^5.18.0", 22 | "typescript": "^3.0.1" 23 | }, 24 | "scripts": { 25 | "compile": "installServerIntoExtension ../tslint ./package.json ./src/tsconfig.json && tsc -p ./src", 26 | "watch": "installServerIntoExtension ../tslint ./package.json ./src/tsconfig.json && tsc --watch -p ./src", 27 | "pretest": "tsc -p ./test", 28 | "test": "mocha test/out/test" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tslint-server/src/delayer.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * A helper to delay execution of a task that is being requested often. 4 | * 5 | * Following the throttler, now imagine the mail man wants to optimize the number of 6 | * trips proactively. The trip itself can be long, so the he decides not to make the trip 7 | * as soon as a letter is submitted. Instead he waits a while, in case more 8 | * letters are submitted. After said waiting period, if no letters were submitted, he 9 | * decides to make the trip. Imagine that N more letters were submitted after the first 10 | * one, all within a short period of time between each other. Even though N+1 11 | * submissions occurred, only 1 delivery was made. 12 | * 13 | * The delayer offers this behavior via the trigger() method, into which both the task 14 | * to be executed and the waiting period (delay) must be passed in as arguments. Following 15 | * the example: 16 | * 17 | * var delayer = new Delayer(WAITING_PERIOD); 18 | * var letters = []; 19 | * 20 | * function letterReceived(l) { 21 | * letters.push(l); 22 | * delayer.trigger(() => { return makeTheTrip(); }); 23 | * } 24 | */ 25 | export interface ITask { 26 | (): T; 27 | } 28 | 29 | export interface ValueCallback { 30 | (value:any):any; 31 | } 32 | 33 | export class Delayer { 34 | private timeout: NodeJS.Timer | null; 35 | private completionPromise: Promise | null; 36 | private onSuccess: ValueCallback | null; 37 | private task: ITask | null; 38 | 39 | constructor(public defaultDelay: number) { 40 | this.timeout = null; 41 | this.completionPromise = null; 42 | this.onSuccess = null; 43 | this.task = null; 44 | } 45 | 46 | public trigger(task: ITask, delay: number = this.defaultDelay): Promise { 47 | this.task = task; 48 | this.cancelTimeout(); 49 | 50 | 51 | if (!this.completionPromise) { 52 | this.completionPromise = new Promise((resolve) => { 53 | this.onSuccess = resolve; 54 | }).then(() => { 55 | this.completionPromise = null; 56 | this.onSuccess = null; 57 | var result = this.task!(); 58 | this.task = null; 59 | return result; 60 | }); 61 | } 62 | 63 | 64 | 65 | if (!this.completionPromise) { 66 | this.completionPromise = new Promise((resolve) => { 67 | this.onSuccess = resolve; 68 | }).then(() => { 69 | this.completionPromise = null; 70 | this.onSuccess = null; 71 | const task = this.task; 72 | this.task = null; 73 | return task!(); 74 | }); 75 | } 76 | 77 | this.timeout = setTimeout(() => { 78 | this.timeout = null; 79 | this.onSuccess!(null); 80 | }, delay); 81 | 82 | return this.completionPromise; 83 | } 84 | 85 | public isTriggered(): boolean { 86 | return this.timeout !== null; 87 | } 88 | 89 | public cancel(): void { 90 | this.cancelTimeout(); 91 | this.completionPromise = null; 92 | } 93 | private cancelTimeout(): void { 94 | if (this.timeout !== null) { 95 | clearTimeout(this.timeout); 96 | this.timeout = null; 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /tslint-server/src/fixer.ts: -------------------------------------------------------------------------------- 1 | import * as server from 'vscode-languageserver'; 2 | import * as tslint from 'tslint'; // this is a dev dependency only 3 | 4 | // Tslint fixers provided by the extensions 5 | 6 | export interface TSLintAutofixEdit { 7 | range: [server.Position, server.Position]; 8 | text: string; 9 | } 10 | 11 | type FixResult = TSLintAutofixEdit | undefined; 12 | 13 | interface FixCreator { 14 | (problem: tslint.RuleFailure, document: server.TextDocument): FixResult; 15 | } 16 | 17 | let fixes = new Map(); 18 | 19 | let quoteFixCreator: FixCreator = (problem: tslint.RuleFailure, document: server.TextDocument): FixResult => { 20 | // error message: ' should be " or " should be ' 21 | const wrongQuote = problem.getFailure()[0]; 22 | const fixedQuote = wrongQuote === "'" ? '"' : "'"; 23 | const contents = document.getText().slice(problem.getStartPosition().getPosition() + 1, problem.getEndPosition().getPosition() - 1); 24 | return { 25 | range: convertProblemPositionsToRange(problem), 26 | text: `${fixedQuote}${contents}${fixedQuote}` 27 | }; 28 | }; 29 | fixes['quotemark'] = quoteFixCreator; 30 | 31 | let whiteSpaceFixCreator: FixCreator = (problem: tslint.RuleFailure, document: server.TextDocument): FixResult => { 32 | // error message: 'missing whitespace' 33 | if (problem.getFailure() !== 'missing whitespace') { 34 | return undefined; 35 | } 36 | const contents = document.getText().slice(problem.getStartPosition().getPosition(), problem.getEndPosition().getPosition()); 37 | return { 38 | range: convertProblemPositionsToRange(problem), 39 | text: ` ${contents}` 40 | }; 41 | }; 42 | fixes['whitespace'] = whiteSpaceFixCreator; 43 | 44 | let tripleEqualsFixCreator: FixCreator = (problem: tslint.RuleFailure, _document: server.TextDocument): FixResult => { 45 | // error message: '== should be ===' or '!= should be !==' 46 | let contents: string | undefined = undefined; 47 | if (problem.getFailure() === '== should be ===') { 48 | contents = '==='; 49 | } else if (problem.getFailure() === '!= should be !==') { 50 | contents = '!=='; 51 | } else { 52 | return undefined; 53 | } 54 | return { 55 | range: convertProblemPositionsToRange(problem), 56 | text: `${contents}` 57 | }; 58 | }; 59 | fixes['triple-equals'] = tripleEqualsFixCreator; 60 | 61 | let commentFormatFixCreator: FixCreator = (problem: tslint.RuleFailure, document: server.TextDocument): FixResult => { 62 | // error messages: 63 | // 'comment must start with a space' 64 | // 'comment must start with lowercase letter' 65 | // 'comment must start with uppercase letter' 66 | function swapCase(contents: string, toLower: boolean): string { 67 | let i = contents.search(/\S/); 68 | if (i === -1) { 69 | return contents; 70 | } 71 | let prefix = contents.substring(0, i); 72 | let swap = toLower ? contents[i].toLowerCase() : contents[i].toUpperCase(); 73 | let suffix = contents.substring(i + 1); 74 | return `${prefix}${swap}${suffix}`; 75 | } 76 | 77 | let replacement; 78 | const contents = document.getText().slice(problem.getStartPosition().getPosition(), problem.getEndPosition().getPosition()); 79 | 80 | switch (problem.getFailure()) { 81 | case 'comment must start with a space': 82 | replacement = ` ${contents}`; 83 | break; 84 | case 'comment must start with lowercase letter': 85 | replacement = swapCase(contents, true); 86 | break; 87 | case 'comment must start with uppercase letter': 88 | replacement = swapCase(contents, false); 89 | break; 90 | default: 91 | return undefined; 92 | } 93 | return { 94 | range: convertProblemPositionsToRange(problem), 95 | text: replacement 96 | }; 97 | }; 98 | 99 | fixes['comment-format'] = commentFormatFixCreator; 100 | 101 | function convertToServerPosition(position: tslint.RuleFailurePosition): server.Position { 102 | return { 103 | character: position.getLineAndCharacter().character, 104 | line: position.getLineAndCharacter().line 105 | }; 106 | } 107 | 108 | function convertProblemPositionsToRange(problem: tslint.RuleFailure): [server.Position, server.Position] { 109 | let startPosition = convertToServerPosition(problem.getStartPosition()); 110 | let endPosition = convertToServerPosition(problem.getEndPosition()); 111 | return [startPosition, endPosition]; 112 | } 113 | 114 | export function createVscFixForRuleFailure(problem: tslint.RuleFailure, document: server.TextDocument): TSLintAutofixEdit | undefined { 115 | let creator = fixes[problem.getRuleName()]; 116 | if (creator) { 117 | return creator(problem, document); 118 | } 119 | return undefined; 120 | } 121 | -------------------------------------------------------------------------------- /tslint-server/src/mruCache.ts: -------------------------------------------------------------------------------- 1 | export class MruCache { 2 | 3 | private readonly _map = new Map(); 4 | private readonly _entries = new Set(); 5 | 6 | public constructor( 7 | private readonly _maxSize: number 8 | ) {} 9 | 10 | public set(filePath: string, entry: T): void { 11 | this._map.set(filePath, entry); 12 | this._entries.add(filePath); 13 | for (const key of this._entries.keys()) { 14 | if (this._entries.size <= this._maxSize) { 15 | break; 16 | } 17 | this._map.delete(key); 18 | this._entries.delete(key); 19 | } 20 | } 21 | 22 | public has(filePath: string): boolean { 23 | return this._map.has(filePath); 24 | } 25 | 26 | public get(filePath: string): (T) | undefined { 27 | if (this._entries.has(filePath)) { 28 | this._entries.delete(filePath); 29 | this._entries.add(filePath); 30 | } 31 | return this._map.get(filePath); 32 | } 33 | } -------------------------------------------------------------------------------- /tslint-server/src/runner.ts: -------------------------------------------------------------------------------- 1 | import * as cp from 'child_process'; 2 | import * as fs from 'fs'; 3 | import * as minimatch from 'minimatch'; 4 | import * as path from 'path'; 5 | import * as tslint from 'tslint'; // this is a dev dependency only 6 | import * as typescript from 'typescript'; // this is a dev dependency only 7 | import * as util from 'util'; 8 | import * as server from 'vscode-languageserver'; 9 | import { MruCache } from './mruCache'; 10 | 11 | export interface RunConfiguration { 12 | readonly jsEnable?: boolean; 13 | readonly rulesDirectory?: string | string[]; 14 | readonly configFile?: string; 15 | readonly ignoreDefinitionFiles?: boolean; 16 | readonly exclude?: string | string[]; 17 | readonly validateWithDefaultConfig?: boolean; 18 | readonly nodePath?: string; 19 | readonly packageManager?: 'npm' | 'yarn'; 20 | readonly traceLevel?: 'verbose' | 'normal'; 21 | readonly workspaceFolderPath?: string; 22 | } 23 | 24 | interface Configuration { 25 | readonly linterConfiguration: tslint.Configuration.IConfigurationFile | undefined; 26 | isDefaultLinterConfig: boolean; 27 | readonly path?: string; 28 | } 29 | 30 | class ConfigCache { 31 | public configuration: Configuration | undefined; 32 | 33 | private filePath: string | undefined; 34 | 35 | constructor() { 36 | this.filePath = undefined; 37 | this.configuration = undefined; 38 | } 39 | 40 | public set(filePath: string, configuration: Configuration) { 41 | this.filePath = filePath; 42 | this.configuration = configuration; 43 | } 44 | 45 | public get(forPath: string): Configuration | undefined { 46 | return forPath === this.filePath ? this.configuration : undefined; 47 | } 48 | 49 | public isDefaultLinterConfig(): boolean { 50 | return !!(this.configuration && this.configuration.isDefaultLinterConfig); 51 | } 52 | 53 | public flush() { 54 | this.filePath = undefined; 55 | this.configuration = undefined; 56 | } 57 | } 58 | 59 | export interface RunResult { 60 | readonly lintResult: tslint.LintResult; 61 | readonly warnings: string[]; 62 | readonly workspaceFolderPath?: string; 63 | readonly configFilePath?: string; 64 | } 65 | 66 | const emptyLintResult: tslint.LintResult = { 67 | errorCount: 0, 68 | warningCount: 0, 69 | failures: [], 70 | fixes: [], 71 | format: '', 72 | output: '', 73 | }; 74 | 75 | const emptyResult: RunResult = { 76 | lintResult: emptyLintResult, 77 | warnings: [], 78 | }; 79 | 80 | export class TsLintRunner { 81 | private readonly tslintPath2Library = new Map(); 82 | private readonly document2LibraryCache = new MruCache<() => typeof tslint | undefined>(100); 83 | 84 | // map stores undefined values to represent failed resolutions 85 | private readonly globalPackageManagerPath = new Map(); 86 | private readonly configCache = new ConfigCache(); 87 | 88 | constructor( 89 | private trace: (data: string) => void, 90 | ) { } 91 | 92 | public runTsLint( 93 | filePath: string, 94 | contents: string | typescript.Program, 95 | configuration: RunConfiguration, 96 | ): RunResult { 97 | this.trace('start validateTextDocument'); 98 | 99 | this.trace('validateTextDocument: about to load tslint library'); 100 | 101 | const warnings: string[] = []; 102 | 103 | if (!this.document2LibraryCache.has(filePath)) { 104 | this.loadLibrary(filePath, configuration, warnings); 105 | } 106 | this.trace('validateTextDocument: loaded tslint library'); 107 | 108 | if (!this.document2LibraryCache.has(filePath)) { 109 | return emptyResult; 110 | } 111 | 112 | const library = this.document2LibraryCache.get(filePath)!(); 113 | if (!library) { 114 | return { 115 | lintResult: emptyLintResult, 116 | warnings: [ 117 | getInstallFailureMessage( 118 | filePath, 119 | configuration.workspaceFolderPath, 120 | configuration.packageManager || 'npm'), 121 | ], 122 | }; 123 | } 124 | 125 | this.trace('About to validate ' + filePath); 126 | return this.doRun(filePath, contents, library, configuration, warnings); 127 | } 128 | 129 | /** 130 | * Filter failures for the given document 131 | */ 132 | public filterProblemsForFile( 133 | filePath: string, 134 | failures: tslint.RuleFailure[], 135 | ): tslint.RuleFailure[] { 136 | const normalizedPath = path.normalize(filePath); 137 | // we only show diagnostics targetting this open document, some tslint rule return diagnostics for other documents/files 138 | const normalizedFiles = new Map(); 139 | return failures.filter((each) => { 140 | const fileName = each.getFileName(); 141 | if (!normalizedFiles.has(fileName)) { 142 | normalizedFiles.set(fileName, path.normalize(fileName)); 143 | } 144 | return normalizedFiles.get(fileName) === normalizedPath; 145 | }); 146 | } 147 | 148 | public onConfigFileChange(_tsLintFilePath: string) { 149 | this.configCache.flush(); 150 | } 151 | 152 | public getNonOverlappingReplacements(failures: tslint.RuleFailure[]): tslint.Replacement[] { 153 | function overlaps(a: tslint.Replacement, b: tslint.Replacement): boolean { 154 | return a.end >= b.start; 155 | } 156 | 157 | let sortedFailures = this.sortFailures(failures); 158 | let nonOverlapping: tslint.Replacement[] = []; 159 | for (let i = 0; i < sortedFailures.length; i++) { 160 | let replacements = this.getReplacements(sortedFailures[i].getFix()); 161 | if (i === 0 || !overlaps(nonOverlapping[nonOverlapping.length - 1], replacements[0])) { 162 | nonOverlapping.push(...replacements); 163 | } 164 | } 165 | return nonOverlapping; 166 | } 167 | 168 | private getReplacements(fix: tslint.Fix | undefined): tslint.Replacement[] { 169 | let replacements: tslint.Replacement[] | null = null; 170 | // in tslint4 a Fix has a replacement property with the Replacements 171 | if ((fix).replacements) { 172 | // tslint4 173 | replacements = (fix).replacements; 174 | } else { 175 | // in tslint 5 a Fix is a Replacement | Replacement[] 176 | if (!Array.isArray(fix)) { 177 | replacements = [fix]; 178 | } else { 179 | replacements = fix; 180 | } 181 | } 182 | return replacements || []; 183 | } 184 | 185 | private getReplacement(failure: tslint.RuleFailure, at: number): tslint.Replacement { 186 | return this.getReplacements(failure.getFix())[at]; 187 | } 188 | 189 | private sortFailures(failures: tslint.RuleFailure[]): tslint.RuleFailure[] { 190 | // The failures.replacements are sorted by position, we sort on the position of the first replacement 191 | return failures.sort((a, b) => { 192 | return this.getReplacement(a, 0).start - this.getReplacement(b, 0).start; 193 | }); 194 | } 195 | 196 | private loadLibrary(filePath: string, configuration: RunConfiguration, warningsOutput: string[]): void { 197 | this.trace(`loadLibrary for ${filePath}`); 198 | const getGlobalPath = () => this.getGlobalPackageManagerPath(configuration.packageManager); 199 | const directory = path.dirname(filePath); 200 | 201 | let np: string | undefined = undefined; 202 | if (configuration && configuration.nodePath) { 203 | const exists = fs.existsSync(configuration.nodePath); 204 | if (exists) { 205 | np = configuration.nodePath; 206 | } else { 207 | warningsOutput.push(`The setting 'tslint.nodePath' refers to '${configuration.nodePath}', but this path does not exist. The setting will be ignored.`); 208 | } 209 | } 210 | 211 | let tsLintPath: string; 212 | 213 | if (np) { 214 | try { 215 | tsLintPath = this.resolveTsLint(np, np!); 216 | if (tsLintPath.length === 0) { 217 | tsLintPath = this.resolveTsLint(getGlobalPath(), directory); 218 | } 219 | } catch { 220 | tsLintPath = this.resolveTsLint(getGlobalPath(), directory); 221 | } 222 | } else { 223 | try { 224 | tsLintPath = this.resolveTsLint(undefined, directory); 225 | if (tsLintPath.length === 0) { 226 | tsLintPath = this.resolveTsLint(getGlobalPath(), directory); 227 | } 228 | } catch { 229 | tsLintPath = this.resolveTsLint(getGlobalPath(), directory); 230 | } 231 | } 232 | 233 | this.document2LibraryCache.set(filePath, () => { 234 | let library; 235 | if (!this.tslintPath2Library.has(tsLintPath)) { 236 | try { 237 | library = require(tsLintPath); 238 | } catch (e) { 239 | this.tslintPath2Library.set(tsLintPath, undefined); 240 | return; 241 | } 242 | this.tslintPath2Library.set(tsLintPath, library); 243 | } 244 | return this.tslintPath2Library.get(tsLintPath); 245 | }); 246 | } 247 | 248 | private getGlobalPackageManagerPath(packageManager: string | undefined): string | undefined { 249 | this.trace(`Begin - Resolve Global Package Manager Path for: ${packageManager}`); 250 | 251 | if (!packageManager) { 252 | packageManager = 'npm'; 253 | } 254 | 255 | if (!this.globalPackageManagerPath.has(packageManager)) { 256 | let path: string | undefined; 257 | if (packageManager === 'npm') { 258 | path = server.Files.resolveGlobalNodePath(this.trace); 259 | } else if (packageManager === 'yarn') { 260 | path = server.Files.resolveGlobalYarnPath(this.trace); 261 | } 262 | this.globalPackageManagerPath.set(packageManager, path!); 263 | } 264 | this.trace(`Done - Resolve Global Package Manager Path for: ${packageManager}`); 265 | return this.globalPackageManagerPath.get(packageManager); 266 | } 267 | 268 | private doRun( 269 | filePath: string, 270 | contents: string | typescript.Program, 271 | library: typeof import('tslint'), 272 | configuration: RunConfiguration, 273 | warnings: string[], 274 | ): RunResult { 275 | this.trace('start doValidate ' + filePath); 276 | const uri = filePath; 277 | 278 | if (this.fileIsExcluded(configuration, filePath)) { 279 | this.trace(`No linting: file ${filePath} is excluded`); 280 | return emptyResult; 281 | } 282 | 283 | if (configuration.workspaceFolderPath) { 284 | this.trace(`Changed directory to ${configuration.workspaceFolderPath}`); 285 | process.chdir(configuration.workspaceFolderPath); 286 | } 287 | 288 | const configFile = configuration.configFile || null; 289 | let linterConfiguration: Configuration | undefined; 290 | this.trace('validateTextDocument: about to getConfiguration'); 291 | try { 292 | linterConfiguration = this.getConfiguration(uri, filePath, library, configFile); 293 | } catch (err) { 294 | this.trace(`No linting: exception when getting tslint configuration for ${filePath}, configFile= ${configFile}`); 295 | warnings.push(getConfigurationFailureMessage(err)); 296 | return { 297 | lintResult: emptyLintResult, 298 | warnings, 299 | }; 300 | } 301 | 302 | if (!linterConfiguration) { 303 | this.trace(`No linting: no tslint configuration`); 304 | return emptyResult; 305 | } 306 | this.trace('validateTextDocument: configuration fetched'); 307 | 308 | if (isJsDocument(filePath) && !configuration.jsEnable) { 309 | this.trace(`No linting: a JS document, but js linting is disabled`); 310 | return emptyResult; 311 | } 312 | 313 | if (configuration.validateWithDefaultConfig === false && this.configCache.configuration!.isDefaultLinterConfig) { 314 | this.trace(`No linting: linting with default tslint configuration is disabled`); 315 | return emptyResult; 316 | } 317 | 318 | if (isExcludedFromLinterOptions(linterConfiguration.linterConfiguration, filePath)) { 319 | this.trace(`No linting: file is excluded using linterOptions.exclude`); 320 | return emptyResult; 321 | } 322 | 323 | let result: tslint.LintResult; 324 | const options: tslint.ILinterOptions = { 325 | formatter: "json", 326 | fix: false, 327 | rulesDirectory: configuration.rulesDirectory || undefined, 328 | formattersDirectory: undefined, 329 | }; 330 | if (configuration.traceLevel && configuration.traceLevel === 'verbose') { 331 | this.traceConfigurationFile(linterConfiguration.linterConfiguration); 332 | } 333 | 334 | // tslint writes warnings using console.warn, capture these warnings and send them to the client 335 | const originalConsoleWarn = console.warn; 336 | const captureWarnings = (message?: any) => { 337 | warnings.push(message); 338 | originalConsoleWarn(message); 339 | }; 340 | console.warn = captureWarnings; 341 | 342 | try { // clean up if tslint crashes 343 | const tslint = new library.Linter(options, typeof contents === 'string' ? undefined : contents); 344 | this.trace(`Linting: start linting`); 345 | tslint.lint(filePath, typeof contents === 'string' ? contents : '', linterConfiguration.linterConfiguration); 346 | result = tslint.getResult(); 347 | this.trace(`Linting: ended linting`); 348 | } finally { 349 | console.warn = originalConsoleWarn; 350 | } 351 | 352 | return { 353 | lintResult: result, 354 | warnings, 355 | workspaceFolderPath: configuration.workspaceFolderPath, 356 | configFilePath: linterConfiguration.path, 357 | }; 358 | } 359 | 360 | private getConfiguration(uri: string, filePath: string, library: typeof tslint, configFileName: string | null): Configuration | undefined { 361 | this.trace('getConfiguration for' + uri); 362 | 363 | const config = this.configCache.get(filePath); 364 | if (config) { 365 | return config; 366 | } 367 | 368 | let isDefaultConfig = false; 369 | let linterConfiguration: tslint.Configuration.IConfigurationFile | undefined = undefined; 370 | 371 | const linter = library.Linter; 372 | if (linter.findConfigurationPath) { 373 | isDefaultConfig = linter.findConfigurationPath(configFileName, filePath) === undefined; 374 | } 375 | const configurationResult = linter.findConfiguration(configFileName, filePath); 376 | 377 | // between tslint 4.0.1 and tslint 4.0.2 the attribute 'error' has been removed from IConfigurationLoadResult 378 | // in 4.0.2 findConfiguration throws an exception as in version ^3.0.0 379 | if ((configurationResult as any).error) { 380 | throw (configurationResult as any).error; 381 | } 382 | linterConfiguration = configurationResult.results; 383 | 384 | // In tslint version 5 the 'no-unused-variable' rules breaks the TypeScript language service plugin. 385 | // See https://github.com/Microsoft/TypeScript/issues/15344 386 | // Therefore we remove the rule from the configuration. 387 | // 388 | // In tslint 5 the rules are stored in a Map, in earlier versions they were stored in an Object 389 | if (linterConfiguration) { 390 | if (linterConfiguration.rules && linterConfiguration.rules instanceof Map) { 391 | linterConfiguration.rules.delete('no-unused-variable'); 392 | } 393 | if (linterConfiguration.jsRules && linterConfiguration.jsRules instanceof Map) { 394 | linterConfiguration.jsRules.delete('no-unused-variable'); 395 | } 396 | } 397 | 398 | const configuration: Configuration = { 399 | isDefaultLinterConfig: isDefaultConfig, 400 | linterConfiguration, 401 | path: configurationResult.path 402 | }; 403 | 404 | this.configCache.set(filePath, configuration); 405 | return this.configCache.configuration; 406 | } 407 | 408 | private fileIsExcluded(settings: RunConfiguration, filePath: string): boolean { 409 | if (settings.ignoreDefinitionFiles) { 410 | if (filePath.endsWith('.d.ts')) { 411 | return true; 412 | } 413 | } 414 | 415 | if (settings.exclude) { 416 | if (Array.isArray(settings.exclude)) { 417 | for (const pattern of settings.exclude) { 418 | if (testForExclusionPattern(filePath, pattern)) { 419 | return true; 420 | } 421 | } 422 | } else if (testForExclusionPattern(filePath, settings.exclude)) { 423 | return true; 424 | } 425 | } 426 | return false; 427 | } 428 | 429 | private traceConfigurationFile(configuration: tslint.Configuration.IConfigurationFile | undefined) { 430 | if (!configuration) { 431 | this.trace("no tslint configuration"); 432 | return; 433 | } 434 | this.trace("tslint configuration:" + util.inspect(configuration, undefined, 4)); 435 | } 436 | 437 | private resolveTsLint(nodePath: string | undefined, cwd: string): string { 438 | const nodePathKey = 'NODE_PATH'; 439 | const app = [ 440 | "console.log(require.resolve('tslint'));", 441 | ].join(''); 442 | 443 | const env = process.env; 444 | const newEnv = Object.create(null); 445 | Object.keys(env).forEach(key => newEnv[key] = env[key]); 446 | if (nodePath) { 447 | if (newEnv[nodePathKey]) { 448 | newEnv[nodePathKey] = nodePath + path.delimiter + newEnv[nodePathKey]; 449 | } else { 450 | newEnv[nodePathKey] = nodePath; 451 | } 452 | this.trace(`NODE_PATH value is: ${newEnv[nodePathKey]}`); 453 | } 454 | newEnv.ELECTRON_RUN_AS_NODE = '1'; 455 | const spanwResults = cp.spawnSync(process.argv0, ['-e', app], { cwd, env: newEnv }); 456 | return spanwResults.stdout.toString().trim(); 457 | } 458 | } 459 | 460 | function testForExclusionPattern(filePath: string, pattern: string): boolean { 461 | return minimatch(filePath, pattern, { dot: true }); 462 | } 463 | 464 | function getInstallFailureMessage(filePath: string, workspaceFolder: string | undefined, packageManager: 'npm' | 'yarn'): string { 465 | const localCommands = { 466 | npm: 'npm install tslint', 467 | yarn: 'yarn add tslint', 468 | }; 469 | const globalCommands = { 470 | npm: 'npm install -g tslint', 471 | yarn: 'yarn global add tslint', 472 | }; 473 | if (workspaceFolder) { // workspace opened on a folder 474 | return [ 475 | '', 476 | `Failed to load the TSLint library for the document ${filePath}`, 477 | '', 478 | `To use TSLint in this workspace please install tslint using \'${localCommands[packageManager]}\' or globally using \'${globalCommands[packageManager]}\'.`, 479 | 'TSLint has a peer dependency on `typescript`, make sure that `typescript` is installed as well.', 480 | 'You need to reopen the workspace after installing tslint.', 481 | ].join('\n'); 482 | } else { 483 | return [ 484 | `Failed to load the TSLint library for the document ${filePath}`, 485 | `To use TSLint for single file install tslint globally using \'${globalCommands[packageManager]}\'.`, 486 | 'TSLint has a peer dependency on `typescript`, make sure that `typescript` is installed as well.', 487 | 'You need to reopen VS Code after installing tslint.', 488 | ].join('\n'); 489 | } 490 | } 491 | 492 | function isJsDocument(filePath: string) { 493 | return filePath.match(/\.jsx?$/i); 494 | } 495 | 496 | function isExcludedFromLinterOptions( 497 | config: tslint.Configuration.IConfigurationFile | undefined, 498 | fileName: string, 499 | ): boolean { 500 | if (config === undefined || config.linterOptions === undefined || config.linterOptions.exclude === undefined) { 501 | return false; 502 | } 503 | return config.linterOptions.exclude.some((pattern) => testForExclusionPattern(fileName, pattern)); 504 | } 505 | 506 | function getConfigurationFailureMessage(err: any): string { 507 | let errorMessage = `unknown error`; 508 | if (typeof err.message === 'string' || err.message instanceof String) { 509 | errorMessage = err.message; 510 | } 511 | return `vscode-tslint: Cannot read tslint configuration - '${errorMessage}'`; 512 | } -------------------------------------------------------------------------------- /tslint-server/src/thenable.d.ts: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | * ------------------------------------------------------------------------------------------ */ 5 | interface Thenable extends PromiseLike { } -------------------------------------------------------------------------------- /tslint-server/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "allowSyntheticDefaultImports": true, 7 | "noUnusedLocals": true, 8 | "noUnusedParameters": true, 9 | "strictNullChecks": true, 10 | "sourceMap": true, 11 | "outDir": "../../tslint/server", 12 | "lib": [ 13 | "es6" 14 | ] 15 | }, 16 | "exclude": [ 17 | "node_modules" 18 | ] 19 | } -------------------------------------------------------------------------------- /tslint-server/src/tslintServer.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 'use strict'; 5 | 6 | import * as server from 'vscode-languageserver'; 7 | import Uri from 'vscode-uri'; 8 | 9 | import * as tslint from 'tslint'; // this is a dev dependency only 10 | 11 | import { Delayer } from './delayer'; 12 | import { createVscFixForRuleFailure, TSLintAutofixEdit } from './fixer'; 13 | import { TsLintRunner, RunConfiguration} from './runner'; 14 | 15 | // Settings as defined in VS Code 16 | interface Settings { 17 | enable: boolean; 18 | jsEnable: boolean; 19 | rulesDirectory: string | string[]; 20 | configFile: string; 21 | ignoreDefinitionFiles: boolean; 22 | exclude: string | string[]; 23 | validateWithDefaultConfig: boolean; 24 | nodePath: string | undefined; 25 | run: 'onSave' | 'onType'; 26 | alwaysShowRuleFailuresAsWarnings: boolean; 27 | alwaysShowStatus: boolean; 28 | autoFixOnSave: boolean | string[]; 29 | packageManager: 'npm' | 'yarn'; 30 | trace: any; 31 | workspaceFolderPath: string | undefined; 32 | } 33 | 34 | class SettingsCache { 35 | uri: string | undefined; 36 | promise: Promise | undefined; 37 | 38 | constructor() { 39 | this.uri = undefined; 40 | this.promise = undefined; 41 | } 42 | 43 | async get(uri: string): Promise { 44 | if (uri === this.uri) { 45 | trace('SettingsCache: cache hit for ' + this.uri); 46 | return this.promise!; 47 | } 48 | if (scopedSettingsSupport) { 49 | this.uri = uri; 50 | return this.promise = new Promise(async (resolve, _reject) => { 51 | trace('SettingsCache: cache updating cache for' + this.uri); 52 | let configRequestParam = { items: [{ scopeUri: uri, section: 'tslint' }] }; 53 | let settings = await connection.sendRequest(server.ConfigurationRequest.type, configRequestParam); 54 | resolve(settings[0]); 55 | }); 56 | } 57 | this.promise = Promise.resolve(globalSettings); 58 | return this.promise; 59 | } 60 | 61 | flush() { 62 | this.uri = undefined; 63 | this.promise = undefined; 64 | } 65 | } 66 | 67 | let settingsCache = new SettingsCache(); 68 | let globalSettings: Settings = {}; 69 | let scopedSettingsSupport = false; 70 | 71 | process.on('unhandledRejection', (reason, p) => { 72 | connection.console.info(`Unhandled Rejection at: Promise ${p} reason:, ${reason}`); 73 | }); 74 | 75 | function computeKey(diagnostic: server.Diagnostic): string { 76 | let range = diagnostic.range; 77 | return `[${range.start.line},${range.start.character},${range.end.line},${range.end.character}]-${diagnostic.code}`; 78 | } 79 | 80 | export interface AutoFix { 81 | label: string; 82 | documentVersion: number; 83 | problem: tslint.RuleFailure; 84 | edits: TSLintAutofixEdit[]; 85 | } 86 | 87 | enum Status { 88 | ok = 1, 89 | warn = 2, 90 | error = 3 91 | } 92 | 93 | interface StatusParams { 94 | state: Status; 95 | } 96 | 97 | namespace StatusNotification { 98 | export const type = new server.NotificationType('tslint/status'); 99 | } 100 | 101 | let validationDelayer = new Map>(); // key is the URI of the document 102 | 103 | function makeDiagnostic(settings: Settings | undefined, problem: tslint.RuleFailure): server.Diagnostic { 104 | let severity; 105 | let alwaysWarning = settings && settings.alwaysShowRuleFailuresAsWarnings; 106 | // tslint5 supports to assign severities to rules 107 | if (!alwaysWarning && problem.getRuleSeverity && problem.getRuleSeverity() === 'error') { 108 | severity = server.DiagnosticSeverity.Error; 109 | } else { 110 | severity = server.DiagnosticSeverity.Warning; 111 | } 112 | 113 | let diagnostic: server.Diagnostic = { 114 | severity: severity, 115 | message: problem.getFailure(), 116 | range: { 117 | start: { 118 | line: problem.getStartPosition().getLineAndCharacter().line, 119 | character: problem.getStartPosition().getLineAndCharacter().character 120 | }, 121 | end: { 122 | line: problem.getEndPosition().getLineAndCharacter().line, 123 | character: problem.getEndPosition().getLineAndCharacter().character 124 | }, 125 | }, 126 | code: problem.getRuleName(), 127 | source: 'tslint' 128 | }; 129 | 130 | return diagnostic; 131 | } 132 | 133 | let codeFixActions = new Map>(); 134 | let codeDisableRuleActions = new Map>(); 135 | 136 | function recordCodeAction(document: server.TextDocument, diagnostic: server.Diagnostic, problem: tslint.RuleFailure): void { 137 | let documentDisableRuleFixes: Map = codeDisableRuleActions[document.uri]; 138 | if (!documentDisableRuleFixes) { 139 | documentDisableRuleFixes = Object.create(null); 140 | codeDisableRuleActions[document.uri] = documentDisableRuleFixes; 141 | } 142 | documentDisableRuleFixes[computeKey(diagnostic)] = createDisableRuleFix(problem, document); 143 | 144 | let fix: AutoFix | undefined = undefined; 145 | 146 | 147 | // tslint can return a fix with an empty replacements array, these fixes are ignored 148 | if (problem.getFix && problem.getFix() && !replacementsAreEmpty(problem.getFix())) { // tslint fixes are not available in tslint < 3.17 149 | fix = createAutoFix(problem, document, problem.getFix()!); 150 | } 151 | if (!fix) { 152 | let vscFix = createVscFixForRuleFailure(problem, document); 153 | if (vscFix) { 154 | fix = createAutoFix(problem, document, vscFix); 155 | } 156 | } 157 | if (!fix) { 158 | return; 159 | } 160 | 161 | let documentAutoFixes: Map = codeFixActions[document.uri]; 162 | if (!documentAutoFixes) { 163 | documentAutoFixes = Object.create(null); 164 | codeFixActions[document.uri] = documentAutoFixes; 165 | } 166 | documentAutoFixes[computeKey(diagnostic)] = fix; 167 | } 168 | 169 | function convertReplacementToAutoFix(document: server.TextDocument, repl: tslint.Replacement): TSLintAutofixEdit { 170 | let start: server.Position = document.positionAt(repl.start); 171 | let end: server.Position = document.positionAt(repl.end); 172 | return { 173 | range: [start, end], 174 | text: repl.text, 175 | }; 176 | } 177 | 178 | function getErrorMessage(err: any, document: server.TextDocument): string { 179 | let errorMessage = `unknown error`; 180 | if (typeof err.message === 'string' || err.message instanceof String) { 181 | errorMessage = err.message; 182 | } 183 | let fsPath = server.Files.uriToFilePath(document.uri); 184 | let message = `vscode-tslint: '${errorMessage}' while validating: ${fsPath} stacktrace: ${err.stack}`; 185 | return message; 186 | } 187 | 188 | function getConfigurationFailureMessage(err: any): string { 189 | let errorMessage = `unknown error`; 190 | if (typeof err.message === 'string' || err.message instanceof String) { 191 | errorMessage = err.message; 192 | } 193 | return `vscode-tslint: Cannot read tslint configuration - '${errorMessage}'`; 194 | 195 | } 196 | 197 | function validateAllTextDocuments(conn: server.IConnection, documents: server.TextDocument[]): void { 198 | trace('validateAllTextDocuments'); 199 | let tracker = new server.ErrorMessageTracker(); 200 | documents.forEach(document => { 201 | try { 202 | validateTextDocument(conn, document); 203 | } catch (err) { 204 | tracker.add(getErrorMessage(err, document)); 205 | } 206 | }); 207 | } 208 | 209 | let tslintRunner: TsLintRunner | undefined = undefined; 210 | 211 | async function validateTextDocument(connection: server.IConnection, document: server.TextDocument) { 212 | trace('start validateTextDocument'); 213 | 214 | let uri = document.uri; 215 | 216 | let settings = await settingsCache.get(uri); 217 | trace('validateTextDocument: settings fetched'); 218 | if (settings && !settings.enable) { 219 | // send diagnostics event to flush existing warnings 220 | connection.sendDiagnostics({ uri: uri, diagnostics: [] }); 221 | return; 222 | } 223 | 224 | let diagnostics: server.Diagnostic[] = []; 225 | delete codeFixActions[uri]; 226 | delete codeDisableRuleActions[uri]; 227 | 228 | // tslint can only validate files on disk 229 | if (Uri.parse(uri).scheme !== 'file') { 230 | trace(`No linting: file is not saved on disk`); 231 | return diagnostics; 232 | } 233 | 234 | let fsPath = server.Files.uriToFilePath(uri); 235 | 236 | if (!settings) { 237 | trace('No linting: settings could not be loaded'); 238 | return diagnostics; 239 | } 240 | if (!settings.enable) { 241 | trace('No linting: tslint is disabled'); 242 | return diagnostics; 243 | } 244 | 245 | if (!tslintRunner) { 246 | tslintRunner = new TsLintRunner(trace); 247 | } 248 | 249 | let traceLevel: 'normal' | 'verbose' = 'normal'; 250 | if (settings.trace && settings.trace.server && settings.trace.server === 'verbose') { 251 | traceLevel = 'verbose'; 252 | } 253 | 254 | let runConfiguration: RunConfiguration = { 255 | workspaceFolderPath: settings.workspaceFolderPath, 256 | configFile: settings.configFile, 257 | jsEnable: settings.jsEnable, 258 | exclude: settings.exclude, 259 | ignoreDefinitionFiles: settings.ignoreDefinitionFiles, 260 | nodePath: settings.nodePath, 261 | packageManager: settings.packageManager, 262 | rulesDirectory: settings.rulesDirectory, 263 | validateWithDefaultConfig: settings.validateWithDefaultConfig, 264 | traceLevel: traceLevel 265 | }; 266 | 267 | let result = tslintRunner.runTsLint(fsPath!, document.getText(), runConfiguration); 268 | 269 | if (result.warnings.length > 0) { 270 | connection.sendNotification(StatusNotification.type, { state: Status.warn }); 271 | result.warnings.forEach(each => { 272 | connection.console.warn(each); 273 | }); 274 | } 275 | 276 | let filterdFailures = tslintRunner.filterProblemsForFile(fsPath!, result.lintResult.failures); 277 | 278 | filterdFailures.forEach(each => { 279 | let diagnostic = makeDiagnostic(settings, each); 280 | diagnostics.push(diagnostic); 281 | recordCodeAction(document, diagnostic, each); 282 | }); 283 | connection.sendDiagnostics({ uri, diagnostics }); 284 | } 285 | 286 | let connection: server.IConnection = server.createConnection(new server.IPCMessageReader(process), new server.IPCMessageWriter(process)); 287 | let documents: server.TextDocuments = new server.TextDocuments(); 288 | 289 | documents.listen(connection); 290 | 291 | function trace(message: string, verbose?: string): void { 292 | connection.tracer.log(message, verbose); 293 | } 294 | 295 | connection.onInitialize((params) => { 296 | function hasClientCapability(name: string) { 297 | let keys = name.split('.'); 298 | let c = params.capabilities; 299 | for (let i = 0; c && i < keys.length; i++) { 300 | c = c[keys[i]]; 301 | } 302 | return !!c; 303 | } 304 | scopedSettingsSupport = hasClientCapability('workspace.configuration'); 305 | return { 306 | capabilities: { 307 | textDocumentSync: documents.syncKind, 308 | codeActionProvider: true 309 | } 310 | }; 311 | }); 312 | 313 | documents.onDidOpen(async (event) => { 314 | trace('onDidOpen'); 315 | triggerValidateDocument(event.document); 316 | }); 317 | 318 | documents.onDidChangeContent(async (event) => { 319 | trace('onDidChangeContent'); 320 | let settings = await settingsCache.get(event.document.uri); 321 | trace('onDidChangeContent: settings' + settings); 322 | if (settings && settings.run === 'onType') { 323 | trace('onDidChangeContent: triggerValidateDocument'); 324 | triggerValidateDocument(event.document); 325 | } 326 | // clear the diagnostics when validating on save and when the document is modified 327 | else if (settings && settings.run === 'onSave') { 328 | connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] }); 329 | } 330 | }); 331 | 332 | documents.onDidSave(async (event) => { 333 | let settings = await settingsCache.get(event.document.uri); 334 | if (settings && settings.run === 'onSave') { 335 | triggerValidateDocument(event.document); 336 | } 337 | }); 338 | 339 | documents.onDidClose((event) => { 340 | // A text document was closed we clear the diagnostics 341 | trace('onDidClose' + event.document.uri); 342 | connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] }); 343 | }); 344 | 345 | function triggerValidateDocument(document: server.TextDocument) { 346 | let d = validationDelayer[document.uri]; 347 | trace('triggerValidation on ' + document.uri); 348 | if (!d) { 349 | d = new Delayer(200); 350 | validationDelayer[document.uri] = d; 351 | } 352 | d.trigger(async () => { 353 | trace('trigger validateTextDocument'); 354 | forceValidation(connection, document); 355 | }); 356 | } 357 | 358 | async function forceValidation(connection: server.IConnection, document: server.TextDocument) { 359 | if (validationDelayer[document.uri]) { 360 | await validateTextDocument(connection, document); 361 | delete validationDelayer[document.uri]; 362 | } 363 | } 364 | 365 | function tslintConfigurationValid(): boolean { 366 | try { 367 | documents.all().forEach((each) => { 368 | let fsPath = server.Files.uriToFilePath(each.uri); 369 | if (fsPath) { 370 | // TODO getConfiguration(fsPath, configFile); 371 | } 372 | }); 373 | } catch (err) { 374 | connection.console.info(getConfigurationFailureMessage(err)); 375 | connection.sendNotification(StatusNotification.type, { state: Status.error }); 376 | return false; 377 | } 378 | return true; 379 | } 380 | 381 | // The VS Code tslint settings have changed. Revalidate all documents. 382 | connection.onDidChangeConfiguration((params) => { 383 | trace('onDidChangeConfiguraton'); 384 | 385 | globalSettings = params.settings; 386 | if (tslintRunner) { 387 | tslintRunner.onConfigFileChange(''); 388 | } 389 | settingsCache.flush(); 390 | validateAllTextDocuments(connection, documents.all()); 391 | }); 392 | 393 | // The watched tslint.json has changed. Revalidate all documents, IF the configuration is valid. 394 | connection.onDidChangeWatchedFiles((params) => { 395 | // Tslint 3.7 started to load configuration files using 'require' and they are now 396 | // cached in the node module cache. To ensure that the extension uses 397 | // the latest configuration file we remove the config file from the module cache. 398 | params.changes.forEach(element => { 399 | let configFilePath = server.Files.uriToFilePath(element.uri); 400 | if (configFilePath) { 401 | let cached = require.cache[configFilePath]; 402 | if (cached) { 403 | delete require.cache[configFilePath]; 404 | } 405 | } 406 | }); 407 | 408 | if (tslintRunner) { 409 | tslintRunner.onConfigFileChange(''); 410 | } 411 | if (tslintConfigurationValid()) { 412 | validateAllTextDocuments(connection, documents.all()); 413 | } 414 | }); 415 | 416 | connection.onCodeAction((params) => { 417 | let result: server.CodeAction[] = []; 418 | let uri = params.textDocument.uri; 419 | let documentVersion: number = -1; 420 | let ruleId: string | undefined = undefined; 421 | 422 | let documentFixes = codeFixActions[uri]; 423 | if (documentFixes) { 424 | for (let diagnostic of params.context.diagnostics) { 425 | let autoFix = documentFixes[computeKey(diagnostic)]; 426 | if (autoFix) { 427 | documentVersion = autoFix.documentVersion; 428 | ruleId = autoFix.problem.getRuleName(); 429 | let command = server.Command.create(autoFix.label, '_tslint.applySingleFix', uri, documentVersion, createTextEdit(autoFix)); 430 | let codeAction = server.CodeAction.create( 431 | autoFix.label, 432 | command, 433 | server.CodeActionKind.QuickFix 434 | ); 435 | codeAction.diagnostics = [diagnostic]; 436 | result.push(codeAction); 437 | } 438 | } 439 | if (result.length > 0) { 440 | let same: AutoFix[] = []; 441 | let all: AutoFix[] = []; 442 | let fixes: AutoFix[] = Object.keys(documentFixes).map(key => documentFixes[key]); 443 | 444 | fixes = sortFixes(fixes); 445 | 446 | for (let autofix of fixes) { 447 | if (documentVersion === -1) { 448 | documentVersion = autofix.documentVersion; 449 | } 450 | if (autofix.problem.getRuleName() === ruleId && !overlaps(getLastEdit(same), autofix)) { 451 | same.push(autofix); 452 | } 453 | if (!overlaps(getLastEdit(all), autofix)) { 454 | all.push(autofix); 455 | } 456 | } 457 | 458 | // if the same rule warning exists more than once, provide a command to fix all these warnings 459 | if (same.length > 1) { 460 | let label = `Fix all: ${same[0].problem.getFailure()}`; 461 | let command = server.Command.create( 462 | label, 463 | '_tslint.applySameFixes', 464 | uri, 465 | documentVersion, concatenateEdits(same) 466 | ); 467 | result.push( 468 | server.CodeAction.create( 469 | label, 470 | command, 471 | server.CodeActionKind.QuickFix 472 | ) 473 | ); 474 | } 475 | 476 | // create a command to fix all the warnings with fixes 477 | if (all.length > 1) { 478 | let label = `Fix all auto-fixable problems`; 479 | let command = server.Command.create( 480 | label, 481 | '_tslint.applyAllFixes', 482 | uri, 483 | documentVersion, 484 | concatenateEdits(all) 485 | ); 486 | // Contribute both a kind = Source and kind = Quick Fix. Then 487 | // action appears in the light bulb (for backward compatibility) and the Source... quick pick. 488 | result.push( 489 | server.CodeAction.create( 490 | `${label} (tslint)`, 491 | command, 492 | server.CodeActionKind.Source 493 | ), 494 | server.CodeAction.create( 495 | label, 496 | command, 497 | server.CodeActionKind.QuickFix 498 | ), 499 | 500 | ); 501 | } 502 | } 503 | } 504 | // add the fix to disable the rule 505 | let disableRuleFixes = codeDisableRuleActions[uri]; 506 | if (disableRuleFixes) { 507 | for (let diagnostic of params.context.diagnostics) { 508 | let autoFix = disableRuleFixes[computeKey(diagnostic)]; 509 | if (autoFix) { 510 | documentVersion = autoFix.documentVersion; 511 | ruleId = autoFix.problem.getRuleName(); 512 | let command = server.Command.create( 513 | autoFix.label, 514 | '_tslint.applyDisableRule', 515 | uri, 516 | documentVersion, 517 | createTextEdit(autoFix) 518 | ); 519 | let codeAction = server.CodeAction.create( 520 | autoFix.label, 521 | command, 522 | server.CodeActionKind.QuickFix 523 | ); 524 | codeAction.diagnostics = [diagnostic]; 525 | result.push( 526 | codeAction 527 | ); 528 | } 529 | } 530 | } 531 | // quick fix to show the rule documentation 532 | if (documentFixes) { 533 | for (let diagnostic of params.context.diagnostics) { 534 | let autoFix = disableRuleFixes[computeKey(diagnostic)]; 535 | if (autoFix) { 536 | documentVersion = autoFix.documentVersion; 537 | let ruleId = autoFix.problem.getRuleName(); 538 | let label = `Show documentation for "${ruleId}"`; 539 | let command = server.Command.create( 540 | label, 541 | '_tslint.showRuleDocumentation', 542 | uri, 543 | documentVersion, 544 | undefined, 545 | ruleId 546 | ); 547 | let codeAction = server.CodeAction.create( 548 | label, 549 | command, 550 | server.CodeActionKind.QuickFix 551 | ); 552 | codeAction.diagnostics = [diagnostic]; 553 | result.push( 554 | codeAction 555 | ); 556 | } 557 | } 558 | } 559 | 560 | return result; 561 | }); 562 | 563 | 564 | function replacementsAreEmpty(fix: tslint.Fix | undefined): boolean { 565 | // in tslint 4 a Fix has a replacement property witht the Replacements 566 | if ((fix).replacements) { 567 | return (fix).replacements.length === 0; 568 | } 569 | // tslint 5 570 | if (Array.isArray(fix)) { 571 | return fix.length === 0; 572 | } 573 | return false; 574 | } 575 | 576 | function createAutoFix(problem: tslint.RuleFailure, document: server.TextDocument, fix: tslint.Fix | TSLintAutofixEdit): AutoFix { 577 | let edits: TSLintAutofixEdit[] = []; 578 | 579 | function isTslintAutofixEdit(fix: tslint.Fix | TSLintAutofixEdit | undefined): fix is TSLintAutofixEdit { 580 | return (fix).range !== undefined; 581 | } 582 | 583 | if (isTslintAutofixEdit(fix)) { 584 | edits = [fix]; 585 | } else { 586 | let ff: any = fix; 587 | // in tslint4 a Fix has a replacement property with the Replacements 588 | if (ff.replacements) { 589 | // tslint4 590 | edits = ff.replacements.map(each => convertReplacementToAutoFix(document, each)); 591 | } else { 592 | // in tslint 5 a Fix is a Replacment | Replacement[] 593 | if (!Array.isArray(fix)) { 594 | fix = [fix]; 595 | } 596 | edits = fix.map(each => convertReplacementToAutoFix(document, each)); 597 | } 598 | } 599 | 600 | let autofix: AutoFix = { 601 | label: `Fix: ${problem.getFailure()}`, 602 | documentVersion: document.version, 603 | problem: problem, 604 | edits: edits, 605 | }; 606 | return autofix; 607 | } 608 | 609 | function createDisableRuleFix(problem: tslint.RuleFailure, document: server.TextDocument): AutoFix { 610 | 611 | let pos: server.Position = { 612 | character: 0, 613 | line: problem.getStartPosition().getLineAndCharacter().line 614 | }; 615 | 616 | let disableEdit: TSLintAutofixEdit = { 617 | range: [pos, pos], 618 | // prefix to the text will be inserted on the client 619 | text: `// tslint:disable-next-line:${problem.getRuleName()}\n` 620 | }; 621 | 622 | let disableFix: AutoFix = { 623 | label: `Disable rule "${problem.getRuleName()}" for this line`, 624 | documentVersion: document.version, 625 | problem: problem, 626 | edits: [disableEdit] 627 | }; 628 | return disableFix; 629 | } 630 | 631 | function sortFixes(fixes: AutoFix[]): AutoFix[] { 632 | // The AutoFix.edits are sorted, so we sort on the first edit 633 | return fixes.sort((a, b) => { 634 | let editA: TSLintAutofixEdit = a.edits[0]; 635 | let editB: TSLintAutofixEdit = b.edits[0]; 636 | 637 | if (editA.range[0] < editB.range[0]) { 638 | return -1; 639 | } 640 | if (editA.range[0] > editB.range[0]) { 641 | return 1; 642 | } 643 | // lines are equal 644 | if (editA.range[1] < editB.range[1]) { 645 | return -1; 646 | } 647 | if (editA.range[1] > editB.range[1]) { 648 | return 1; 649 | } 650 | // characters are equal 651 | return 0; 652 | }); 653 | } 654 | 655 | export function overlaps(lastFix: AutoFix | undefined, nextFix: AutoFix): boolean { 656 | if (!lastFix) { 657 | return false; 658 | } 659 | let doesOverlap = false; 660 | lastFix.edits.some(last => { 661 | return nextFix.edits.some(next => { 662 | if (last.range[1].line > next.range[0].line) { 663 | doesOverlap = true; 664 | return true; 665 | } else if (last.range[1].line < next.range[0].line) { 666 | return false; 667 | } else if (last.range[1].character >= next.range[0].character) { 668 | doesOverlap = true; 669 | return true; 670 | } 671 | return false; 672 | }); 673 | }); 674 | return doesOverlap; 675 | } 676 | 677 | function getLastEdit(array: AutoFix[]): AutoFix | undefined { 678 | let length = array.length; 679 | if (length === 0) { 680 | return undefined; 681 | } 682 | return array[length - 1]; 683 | } 684 | 685 | export function getAllNonOverlappingFixes(fixes: AutoFix[]): [AutoFix[], boolean] { 686 | let nonOverlapping: AutoFix[] = []; 687 | let hasOverlappingFixes = false; 688 | fixes = sortFixes(fixes); 689 | for (let autofix of fixes) { 690 | if (!overlaps(getLastEdit(nonOverlapping), autofix)) { 691 | nonOverlapping.push(autofix); 692 | } else { 693 | hasOverlappingFixes = true; 694 | } 695 | } 696 | return [nonOverlapping, hasOverlappingFixes]; 697 | } 698 | 699 | function createTextEdit(autoFix: AutoFix): server.TextEdit[] { 700 | return autoFix.edits.map(each => server.TextEdit.replace(server.Range.create(each.range[0], each.range[1]), each.text || '')); 701 | } 702 | 703 | interface AllFixesParams { 704 | textDocument: server.TextDocumentIdentifier; 705 | isOnSave: boolean; 706 | } 707 | 708 | interface AllFixesResult { 709 | documentVersion: number; 710 | edits: server.TextEdit[]; 711 | overlappingFixes: boolean; 712 | } 713 | 714 | namespace AllFixesRequest { 715 | export const type = new server.RequestType('textDocument/tslint/allFixes'); 716 | } 717 | 718 | connection.onRequest(AllFixesRequest.type, async (params) => { 719 | let result: AllFixesResult | undefined = undefined; 720 | let uri = params.textDocument.uri; 721 | let isOnSave = params.isOnSave; 722 | let document = documents.get(uri); 723 | 724 | if (!document) { 725 | return undefined; 726 | } 727 | 728 | await forceValidation(connection, document); 729 | 730 | let documentFixes = codeFixActions[uri]; 731 | let documentVersion: number = -1; 732 | let settings = await settingsCache.get(uri); 733 | 734 | if (!documentFixes) { 735 | return undefined; 736 | } 737 | 738 | let fixes: AutoFix[] = Object.keys(documentFixes).map(key => documentFixes[key]); 739 | 740 | for (let fix of fixes) { 741 | if (documentVersion === -1) { 742 | documentVersion = fix.documentVersion; 743 | break; 744 | } 745 | } 746 | 747 | // Filter out fixes for problems that aren't defined to be autofixable on save 748 | if (isOnSave && settings && Array.isArray(settings.autoFixOnSave)) { 749 | const autoFixOnSave = settings.autoFixOnSave as Array; 750 | fixes = fixes.filter(fix => autoFixOnSave.indexOf(fix.problem.getRuleName()) > -1); 751 | } 752 | 753 | let [allFixes, overlappingEdits] = getAllNonOverlappingFixes(fixes); 754 | 755 | result = { 756 | documentVersion: documentVersion, 757 | edits: concatenateEdits(allFixes), 758 | overlappingFixes: overlappingEdits 759 | }; 760 | return result; 761 | }); 762 | 763 | function concatenateEdits(fixes: AutoFix[]): server.TextEdit[] { 764 | let textEdits: server.TextEdit[] = []; 765 | fixes.forEach(each => { 766 | textEdits = textEdits.concat(createTextEdit(each)); 767 | }); 768 | return textEdits; 769 | } 770 | 771 | connection.listen(); 772 | -------------------------------------------------------------------------------- /tslint-server/test/autofixes.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import { AutoFix, getAllNonOverlappingFixes } from '../src/server'; 3 | import { TSLintAutofixEdit } from '../src/fixer'; 4 | 5 | import * as server from 'vscode-languageserver'; 6 | 7 | function pos(line, char): server.Position { 8 | return server.Position.create(line, char); 9 | } 10 | 11 | function range(startLine, startChar, endLine, endChar): [server.Position, server.Position] { 12 | let start = pos(startLine, startChar); 13 | let end = pos(endLine, endChar); 14 | return [start, end]; 15 | } 16 | 17 | function autoFixEdit(startLine, startChar, endLine, endChar): TSLintAutofixEdit { 18 | return { 19 | range: range(startLine, startChar, endLine, endChar), 20 | text: '' 21 | }; 22 | } 23 | 24 | function autofix(startLine, startChar, endLine, endChar): AutoFix { 25 | return { 26 | label: '', 27 | documentVersion: 1, 28 | problem: undefined, 29 | edits: [autoFixEdit(startLine, startChar, endLine, endChar)] 30 | }; 31 | } 32 | 33 | describe('Array', () => { 34 | describe('overlaps()', () => { 35 | it('non overlapping fixes', ()=> { 36 | assert.equal(1, getAllNonOverlappingFixes([autofix(1, 0, 6, 0)]).length); 37 | assert.equal(1, getAllNonOverlappingFixes([autofix(1, 0, 6, 0), autofix(4, 9, 4, 9)]).length); 38 | assert.equal(1, getAllNonOverlappingFixes([autofix(1, 0, 1, 0), autofix(1, 0, 1, 0)]).length); 39 | assert.equal(1, getAllNonOverlappingFixes([autofix(1, 0, 6, 0), autofix(1, 0, 6, 0)]).length); 40 | assert.equal(1, getAllNonOverlappingFixes([autofix(1, 0, 6, 0), autofix(6, 0, 6, 0)]).length); 41 | assert.equal(2, getAllNonOverlappingFixes([autofix(1, 0, 6, 0), autofix(7, 0, 7, 0)]).length); 42 | assert.equal(2, getAllNonOverlappingFixes([autofix(1, 0, 6, 0), autofix(6, 1, 6, 1)]).length); 43 | }); 44 | }); 45 | }); -------------------------------------------------------------------------------- /tslint-server/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "allowSyntheticDefaultImports": true, 7 | "outDir": "out", 8 | "sourceMap": true, 9 | "lib": [ 10 | "es6" 11 | ] 12 | }, 13 | "exclude": [ 14 | "node_modules" 15 | ] 16 | } -------------------------------------------------------------------------------- /tslint-tests/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "gulp.autoDetect": "off", 4 | "files.autoSave": "off", 5 | //"tslint.autoFixOnSave": true, 6 | //"tslint.autoFixOnSave": [ 7 | // "comment-format" 8 | // ], 9 | // "editor.codeActionsOnSave": { 10 | // "source.organizeImports": true 11 | // }, 12 | //"tslint.run": "onSave", 13 | //"tslint.packageManager": "yarn", 14 | // "tslint.autoFixOnSave": false, 15 | //"tslint.nodePath": "tmp", 16 | "tslint.jsEnable": true 17 | //"tslint.rulesDirectory": ["tmp1", "tmp2"], 18 | //"tslint.enable": true 19 | //"tslint.configFile": "tslint.json", 20 | //"tslint.trace.server": "verbose" 21 | // "tslint.alwaysShowRuleFailuresAsWarnings": false 22 | } 23 | -------------------------------------------------------------------------------- /tslint-tests/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "lint", 9 | "problemMatcher": { 10 | "base": "$tslint5", 11 | "fileLocation": "relative" 12 | } 13 | }, 14 | { 15 | "type": "gulp", 16 | "task": "tslint", 17 | "problemMatcher": [ 18 | "$tslint5" 19 | ] 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /tslint-tests/multi-root-tests/folderA/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "tslint.alwaysShowRuleFailuresAsWarnings": true 4 | // "tslint.autoFixOnSave": false, 5 | // "tslint.ignoreDefinitionFiles": true, 6 | // "tslint.jsEnable": false, 7 | // "tslint.configFile": "tslint.json" 8 | // "tslint.exclude": "", 9 | // "tslint.rulesDirectory": "", 10 | // "tslint.nodePath": "", 11 | // "tslint.enable": true, 12 | // "tslint.run": "onType", 13 | // "tslint.validateWithDefaultConfig": false 14 | } -------------------------------------------------------------------------------- /tslint-tests/multi-root-tests/folderA/no-var-keyword.ts: -------------------------------------------------------------------------------- 1 | 2 | var anakin: string = "jedi"; 3 | 4 | console.log(`variable is used:${anakin}`); -------------------------------------------------------------------------------- /tslint-tests/multi-root-tests/folderA/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint-issues", 3 | "version": "1.0.0", 4 | "description": "dummy project containing dummies files to raise tslint problems and check that correction are working fine", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "tslint ../../tests/*.ts -t verbose" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "gulp": "^3.9.1", 13 | "gulp-tslint": "^8.0.0", 14 | "tslint": "^5.0.0" 15 | }, 16 | "devDependencies": { 17 | "typescript": "^2.2.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tslint-tests/multi-root-tests/folderA/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-var-keyword": true, 4 | "no-unused-variable": [ 5 | true, 6 | { 7 | "ignore-pattern": "^_" 8 | } 9 | ], 10 | "trailing-comma": [ 11 | true, 12 | { 13 | "multiline": "always", 14 | "singleline": "never" 15 | } 16 | ], 17 | "class-name": true, 18 | "comment-format": [ 19 | true, 20 | "check-space" 21 | ], 22 | "indent": [ 23 | true, 24 | "spaces" 25 | ], 26 | "no-eval": true, 27 | "no-internal-module": true, 28 | "no-trailing-whitespace": true, 29 | "one-line": [ 30 | true, 31 | "check-open-brace", 32 | "check-whitespace" 33 | ], 34 | "quotemark": [ 35 | true, 36 | "double" 37 | ], 38 | "semicolon": [ 39 | true, 40 | "always" 41 | ], 42 | "triple-equals": [ 43 | true, 44 | "allow-null-check" 45 | ], 46 | "typedef-whitespace": [ 47 | true, 48 | { 49 | "call-signature": "nospace", 50 | "index-signature": "nospace", 51 | "parameter": "nospace", 52 | "property-declaration": "nospace", 53 | "variable-declaration": "nospace" 54 | } 55 | ], 56 | "variable-name": [ 57 | true, 58 | "ban-keywords" 59 | ], 60 | "whitespace": [ 61 | true, 62 | "check-branch", 63 | "check-decl", 64 | "check-operator", 65 | "check-separator", 66 | "check-type" 67 | ] 68 | }, 69 | "jsRules": { 70 | "triple-equals": [ 71 | true, 72 | "allow-null-check" 73 | ] 74 | }, 75 | "defaultSeverity": "error" 76 | } -------------------------------------------------------------------------------- /tslint-tests/multi-root-tests/folderB/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "tslint.alwaysShowRuleFailuresAsWarnings": false 4 | // "tslint.doNotShowStatusWhenOk": true, 5 | // "tslint.autoFixOnSave": false, 6 | // "tslint.ignoreDefinitionFiles": true, 7 | // "tslint.jsEnable": false, 8 | // "tslint.configFile": "" 9 | // "tslint.exclude": "", 10 | // "tslint.rulesDirectory": "", 11 | // "tslint.nodePath": "", 12 | // "tslint.enable": false, 13 | // "tslint.run": "onType", 14 | // "tslint.validateWithDefaultConfig": false 15 | } -------------------------------------------------------------------------------- /tslint-tests/multi-root-tests/folderB/no-var-keyword.ts: -------------------------------------------------------------------------------- 1 | 2 | var anakin: string = "jedi"; 3 | 4 | console.log(`variable is used:${anakin}`); -------------------------------------------------------------------------------- /tslint-tests/multi-root-tests/folderB/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint-issues", 3 | "version": "1.0.0", 4 | "description": "dummy project containing dummies files to raise tslint problems and check that correction are working fine", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "tslint tests/*.ts -t verbose" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "gulp": "^3.9.1", 13 | "gulp-tslint": "^8.0.0", 14 | "tslint": "^5.0.0" 15 | }, 16 | "devDependencies": { 17 | "typescript": "^2.2.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tslint-tests/multi-root-tests/folderB/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "array-type": [ 4 | true, 5 | "array-simple" 6 | ], 7 | "arrow-parens": true, 8 | "no-var-keyword": true, 9 | "no-unused-variable": [ 10 | true, 11 | { 12 | "ignore-pattern": "^_" 13 | } 14 | ], 15 | "ordered-imports": [ 16 | true, 17 | { 18 | "import-sources-order": "lowercase-last", 19 | "named-imports-order": "lowercase-first" 20 | } 21 | ], 22 | "trailing-comma": [ 23 | true, 24 | { 25 | "multiline": "always", 26 | "singleline": "never" 27 | } 28 | ], 29 | "class-name": true, 30 | "comment-format": [ 31 | true, 32 | "check-space" 33 | ], 34 | "indent": [ 35 | true, 36 | "spaces" 37 | ], 38 | "no-eval": true, 39 | "no-internal-module": true, 40 | "no-trailing-whitespace": true, 41 | "no-unsafe-finally": true, 42 | "one-line": [ 43 | true, 44 | "check-open-brace", 45 | "check-whitespace" 46 | ], 47 | "quotemark": [ 48 | true, 49 | "double" 50 | ], 51 | "semicolon": [ 52 | true, 53 | "always" 54 | ], 55 | "triple-equals": [ 56 | true, 57 | "allow-null-check" 58 | ], 59 | "typedef-whitespace": [ 60 | true, 61 | { 62 | "call-signature": "nospace", 63 | "index-signature": "nospace", 64 | "parameter": "nospace", 65 | "property-declaration": "nospace", 66 | "variable-declaration": "nospace" 67 | } 68 | ], 69 | "variable-name": [ 70 | true, 71 | "ban-keywords" 72 | ], 73 | "whitespace": [ 74 | true, 75 | "check-branch", 76 | "check-decl", 77 | "check-operator", 78 | "check-separator", 79 | "check-type" 80 | ] 81 | }, 82 | "jsRules": { 83 | "triple-equals": [ 84 | true, 85 | "allow-null-check" 86 | ] 87 | }, 88 | "defaultSeverity": "error" 89 | } -------------------------------------------------------------------------------- /tslint-tests/multi-root-tests/multi-root-tslint-test.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "folderA" 5 | }, 6 | { 7 | "path": "folderB" 8 | } 9 | ], 10 | "settings": { 11 | "files.autoSave": "off", 12 | "tslint.alwaysShowRuleFailuresAsWarnings": false, 13 | "tslint.enable": true 14 | //"tslint.trace.server": "verbose" 15 | } 16 | } -------------------------------------------------------------------------------- /tslint-tests/no-tslint-test/no-var-keyword.ts: -------------------------------------------------------------------------------- 1 | 2 | var anakin: string = "jedi"; 3 | 4 | console.log(`variable is used:${anakin}`); -------------------------------------------------------------------------------- /tslint-tests/no-tslint-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint-issues", 3 | "version": "1.0.0", 4 | "description": "Setup with no local tslint module installed", 5 | "main": "index.js", 6 | "author": "", 7 | "license": "ISC", 8 | "dependencies": { 9 | }, 10 | "devDependencies": { 11 | "typescript": "^2.2.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tslint-tests/no-tslint-test/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "array-type": [ 4 | true, 5 | "array-simple" 6 | ], 7 | "arrow-parens": true, 8 | "no-var-keyword": true, 9 | "no-unused-variable": [ 10 | true, 11 | { 12 | "ignore-pattern": "^_" 13 | } 14 | ], 15 | "ordered-imports": [ 16 | true, 17 | { 18 | "import-sources-order": "lowercase-last", 19 | "named-imports-order": "lowercase-first" 20 | } 21 | ], 22 | "trailing-comma": [ 23 | true, 24 | { 25 | "multiline": "always", 26 | "singleline": "never" 27 | } 28 | ], 29 | "class-name": true, 30 | "comment-format": [ 31 | true, 32 | "check-space" 33 | ], 34 | "indent": [ 35 | true, 36 | "spaces" 37 | ], 38 | "no-eval": true, 39 | "no-internal-module": true, 40 | "no-trailing-whitespace": true, 41 | "no-unsafe-finally": true, 42 | "one-line": [ 43 | true, 44 | "check-open-brace", 45 | "check-whitespace" 46 | ], 47 | "quotemark": [ 48 | true, 49 | "double" 50 | ], 51 | "semicolon": [ 52 | true, 53 | "always" 54 | ], 55 | "triple-equals": [ 56 | true, 57 | "allow-null-check" 58 | ], 59 | "typedef-whitespace": [ 60 | true, 61 | { 62 | "call-signature": "nospace", 63 | "index-signature": "nospace", 64 | "parameter": "nospace", 65 | "property-declaration": "nospace", 66 | "variable-declaration": "nospace" 67 | } 68 | ], 69 | "variable-name": [ 70 | true, 71 | "ban-keywords" 72 | ], 73 | "whitespace": [ 74 | true, 75 | "check-branch", 76 | "check-decl", 77 | "check-operator", 78 | "check-separator", 79 | "check-type" 80 | ] 81 | }, 82 | "jsRules": { 83 | "triple-equals": [ 84 | true, 85 | "allow-null-check" 86 | ] 87 | }, 88 | "defaultSeverity": "error" 89 | } -------------------------------------------------------------------------------- /tslint-tests/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint-tests", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ansi-regex": { 8 | "version": "2.1.1", 9 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 10 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 11 | "dev": true 12 | }, 13 | "ansi-styles": { 14 | "version": "2.2.1", 15 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 16 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 17 | "dev": true 18 | }, 19 | "argparse": { 20 | "version": "1.0.10", 21 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 22 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 23 | "dev": true, 24 | "requires": { 25 | "sprintf-js": "~1.0.2" 26 | } 27 | }, 28 | "babel-code-frame": { 29 | "version": "6.26.0", 30 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 31 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 32 | "dev": true, 33 | "requires": { 34 | "chalk": "^1.1.3", 35 | "esutils": "^2.0.2", 36 | "js-tokens": "^3.0.2" 37 | }, 38 | "dependencies": { 39 | "chalk": { 40 | "version": "1.1.3", 41 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 42 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 43 | "dev": true, 44 | "requires": { 45 | "ansi-styles": "^2.2.1", 46 | "escape-string-regexp": "^1.0.2", 47 | "has-ansi": "^2.0.0", 48 | "strip-ansi": "^3.0.0", 49 | "supports-color": "^2.0.0" 50 | } 51 | } 52 | } 53 | }, 54 | "balanced-match": { 55 | "version": "1.0.0", 56 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 57 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 58 | "dev": true 59 | }, 60 | "brace-expansion": { 61 | "version": "1.1.11", 62 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 63 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 64 | "dev": true, 65 | "requires": { 66 | "balanced-match": "^1.0.0", 67 | "concat-map": "0.0.1" 68 | } 69 | }, 70 | "builtin-modules": { 71 | "version": "1.1.1", 72 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 73 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 74 | "dev": true 75 | }, 76 | "chalk": { 77 | "version": "2.4.1", 78 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 79 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 80 | "dev": true, 81 | "requires": { 82 | "ansi-styles": "^3.2.1", 83 | "escape-string-regexp": "^1.0.5", 84 | "supports-color": "^5.3.0" 85 | }, 86 | "dependencies": { 87 | "ansi-styles": { 88 | "version": "3.2.1", 89 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 90 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 91 | "dev": true, 92 | "requires": { 93 | "color-convert": "^1.9.0" 94 | } 95 | }, 96 | "supports-color": { 97 | "version": "5.4.0", 98 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 99 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 100 | "dev": true, 101 | "requires": { 102 | "has-flag": "^3.0.0" 103 | } 104 | } 105 | } 106 | }, 107 | "color-convert": { 108 | "version": "1.9.2", 109 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", 110 | "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", 111 | "dev": true, 112 | "requires": { 113 | "color-name": "1.1.1" 114 | } 115 | }, 116 | "color-name": { 117 | "version": "1.1.1", 118 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", 119 | "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", 120 | "dev": true 121 | }, 122 | "commander": { 123 | "version": "2.17.1", 124 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", 125 | "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", 126 | "dev": true 127 | }, 128 | "concat-map": { 129 | "version": "0.0.1", 130 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 131 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 132 | "dev": true 133 | }, 134 | "diff": { 135 | "version": "3.5.0", 136 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 137 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 138 | "dev": true 139 | }, 140 | "escape-string-regexp": { 141 | "version": "1.0.5", 142 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 143 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 144 | "dev": true 145 | }, 146 | "esprima": { 147 | "version": "4.0.1", 148 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 149 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 150 | "dev": true 151 | }, 152 | "esutils": { 153 | "version": "2.0.2", 154 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 155 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 156 | "dev": true 157 | }, 158 | "fs.realpath": { 159 | "version": "1.0.0", 160 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 161 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 162 | "dev": true 163 | }, 164 | "glob": { 165 | "version": "7.1.2", 166 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 167 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 168 | "dev": true, 169 | "requires": { 170 | "fs.realpath": "^1.0.0", 171 | "inflight": "^1.0.4", 172 | "inherits": "2", 173 | "minimatch": "^3.0.4", 174 | "once": "^1.3.0", 175 | "path-is-absolute": "^1.0.0" 176 | } 177 | }, 178 | "has-ansi": { 179 | "version": "2.0.0", 180 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 181 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 182 | "dev": true, 183 | "requires": { 184 | "ansi-regex": "^2.0.0" 185 | } 186 | }, 187 | "has-flag": { 188 | "version": "3.0.0", 189 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 190 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 191 | "dev": true 192 | }, 193 | "inflight": { 194 | "version": "1.0.6", 195 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 196 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 197 | "dev": true, 198 | "requires": { 199 | "once": "^1.3.0", 200 | "wrappy": "1" 201 | } 202 | }, 203 | "inherits": { 204 | "version": "2.0.3", 205 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 206 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 207 | "dev": true 208 | }, 209 | "js-tokens": { 210 | "version": "3.0.2", 211 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 212 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 213 | "dev": true 214 | }, 215 | "js-yaml": { 216 | "version": "3.13.1", 217 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 218 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 219 | "dev": true, 220 | "requires": { 221 | "argparse": "^1.0.7", 222 | "esprima": "^4.0.0" 223 | } 224 | }, 225 | "minimatch": { 226 | "version": "3.0.4", 227 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 228 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 229 | "dev": true, 230 | "requires": { 231 | "brace-expansion": "^1.1.7" 232 | } 233 | }, 234 | "once": { 235 | "version": "1.4.0", 236 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 237 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 238 | "dev": true, 239 | "requires": { 240 | "wrappy": "1" 241 | } 242 | }, 243 | "path-is-absolute": { 244 | "version": "1.0.1", 245 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 246 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 247 | "dev": true 248 | }, 249 | "path-parse": { 250 | "version": "1.0.6", 251 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 252 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 253 | "dev": true 254 | }, 255 | "resolve": { 256 | "version": "1.8.1", 257 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", 258 | "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", 259 | "dev": true, 260 | "requires": { 261 | "path-parse": "^1.0.5" 262 | } 263 | }, 264 | "semver": { 265 | "version": "5.5.0", 266 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", 267 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", 268 | "dev": true 269 | }, 270 | "sprintf-js": { 271 | "version": "1.0.3", 272 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 273 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 274 | "dev": true 275 | }, 276 | "strip-ansi": { 277 | "version": "3.0.1", 278 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 279 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 280 | "dev": true, 281 | "requires": { 282 | "ansi-regex": "^2.0.0" 283 | } 284 | }, 285 | "supports-color": { 286 | "version": "2.0.0", 287 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 288 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 289 | "dev": true 290 | }, 291 | "tslib": { 292 | "version": "1.9.3", 293 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", 294 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", 295 | "dev": true 296 | }, 297 | "tslint": { 298 | "version": "5.11.0", 299 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz", 300 | "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", 301 | "dev": true, 302 | "requires": { 303 | "babel-code-frame": "^6.22.0", 304 | "builtin-modules": "^1.1.1", 305 | "chalk": "^2.3.0", 306 | "commander": "^2.12.1", 307 | "diff": "^3.2.0", 308 | "glob": "^7.1.1", 309 | "js-yaml": "^3.7.0", 310 | "minimatch": "^3.0.4", 311 | "resolve": "^1.3.2", 312 | "semver": "^5.3.0", 313 | "tslib": "^1.8.0", 314 | "tsutils": "^2.27.2" 315 | } 316 | }, 317 | "tsutils": { 318 | "version": "2.29.0", 319 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 320 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 321 | "dev": true, 322 | "requires": { 323 | "tslib": "^1.8.1" 324 | } 325 | }, 326 | "typescript": { 327 | "version": "2.6.2", 328 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", 329 | "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", 330 | "dev": true 331 | }, 332 | "wrappy": { 333 | "version": "1.0.2", 334 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 335 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 336 | "dev": true 337 | } 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /tslint-tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint-tests", 3 | "version": "1.0.0", 4 | "description": "dummy project containing dummies files to raise tslint problems and check that correction are working fine", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "tslint tests/*.ts -t verbose" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "tslint": "^5.11.0", 13 | "typescript": "^2.6.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tslint-tests/tests/array-type.ts: -------------------------------------------------------------------------------- 1 | let t: Array = new Array(); 2 | 3 | console.log(t); 4 | 5 | export function hello() { 6 | 7 | } -------------------------------------------------------------------------------- /tslint-tests/tests/arrow-parens.ts: -------------------------------------------------------------------------------- 1 | [1, 2 ].map( num => console.log(num) ); 2 | -------------------------------------------------------------------------------- /tslint-tests/tests/comment-format.ts: -------------------------------------------------------------------------------- 1 | // VS Code provided fix 2 | // import { hello } from "./array-type"; 3 | 4 | //start with space 5 | -------------------------------------------------------------------------------- /tslint-tests/tests/no-var-keyword.ts: -------------------------------------------------------------------------------- 1 | 2 | var anakin: string = "jedi"; 3 | 4 | console.log(`variable is used:${anakin}`); -------------------------------------------------------------------------------- /tslint-tests/tests/no_unused-variable.ts: -------------------------------------------------------------------------------- 1 | import { } from "diff"; 2 | 3 | import { A, B } from "parse-json"; 4 | 5 | console.log(`use ${A}`); -------------------------------------------------------------------------------- /tslint-tests/tests/ordered-imports.ts: -------------------------------------------------------------------------------- 1 | import {B, A, C} from "diff"; 2 | import {D, E} from "diff"; 3 | 4 | console.log(`use ${A} ${B} ${C} ${D}, ${E}`); -------------------------------------------------------------------------------- /tslint-tests/tests/overlapping-fixes.ts: -------------------------------------------------------------------------------- 1 | // overlapping fix ranges are currently not supported (the ordered import range, and the missing comman do overlap) 2 | import { autorun, computed } from "mbox"; 3 | import { 4 | isEmpty, 5 | isEqual 6 | } from "lodash"; 7 | 8 | console.log(autorun, computed, isEmpty, isEqual); -------------------------------------------------------------------------------- /tslint-tests/tests/overlappingfixes2.ts: -------------------------------------------------------------------------------- 1 | console.log("foo") 2 | 3 | 4 | console.log("bar") 5 | 6 | 7 | console.log("baz") 8 | 9 | -------------------------------------------------------------------------------- /tslint-tests/tests/quotemark.ts: -------------------------------------------------------------------------------- 1 | // VS Code provided fix 2 | let s = 'quotemark'; 3 | 4 | console.log(s); -------------------------------------------------------------------------------- /tslint-tests/tests/selective-auto-fix-on-save.ts: -------------------------------------------------------------------------------- 1 | // Only the 'arrow-parens' rule should be fixed, the 'quotemark' failure 2 | // should not be fixed 3 | // "tslint.autoFixOnSave": ["arrow-parens"], 4 | 5 | [1, 2].map(num => console.log('test: ' + num)); 6 | 7 | -------------------------------------------------------------------------------- /tslint-tests/tests/semicolon.ts: -------------------------------------------------------------------------------- 1 | let test1: string 2 | console.log(`use ${test1}`) -------------------------------------------------------------------------------- /tslint-tests/tests/test-javascript.js: -------------------------------------------------------------------------------- 1 | // test a jsRule trippe equals 2 | let a = 2; 3 | 4 | if (a == 2) { 5 | 6 | } -------------------------------------------------------------------------------- /tslint-tests/tests/testcomponent.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import './App.css'; 3 | import Hello from './components/Hello'; 4 | 5 | const logo = require('./logo.svg'); 6 | 7 | function App() { 8 | return ( 9 |
10 |
11 | logo 12 |

Welcome to React

13 |
14 |

15 | To get started, edit src/App.tsx and save to reload. 16 |

17 | 18 |
19 | ); 20 | } 21 | 22 | export default App; -------------------------------------------------------------------------------- /tslint-tests/tests/trailing-comma.ts: -------------------------------------------------------------------------------- 1 | // a comma is missing at the end 2 | 3 | let test = { 4 | lastName: "smith", 5 | missAComma: "mis" 6 | }; 7 | 8 | let test2 = { 9 | lastName: "smith", 10 | missAComma: "mis" 11 | }; 12 | 13 | console.log(test, test2); -------------------------------------------------------------------------------- /tslint-tests/tests/triple-equals.ts: -------------------------------------------------------------------------------- 1 | // VS Code provided fix 2 | let a = 3; 3 | 4 | if (a == 3) { 5 | console.log(a); 6 | } 7 | 8 | if (a != 3) { 9 | console.log(a); 10 | } -------------------------------------------------------------------------------- /tslint-tests/tests/whitespace.ts: -------------------------------------------------------------------------------- 1 | // VS Code provided fix 2 | let x =3; 3 | 4 | console.log(x); -------------------------------------------------------------------------------- /tslint-tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "noImplicitAny": false, 6 | "sourceMap": false, 7 | "noUnusedLocals": true, 8 | "jsx": "preserve" 9 | } 10 | } -------------------------------------------------------------------------------- /tslint-tests/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | // "linterOptions": { "exclude": [ "./**/arrow-parens.ts" ]}, 3 | "rules": { 4 | "no-consecutive-blank-lines": true, 5 | "array-type": [ 6 | true, 7 | "array-simple" 8 | ], 9 | "arrow-parens": true, 10 | "no-var-keyword": true, 11 | "no-unused-variable": [ 12 | true, 13 | { 14 | "ignore-pattern": "^_" 15 | } 16 | ], 17 | "ordered-imports": [ 18 | true, 19 | { 20 | "import-sources-order": "lowercase-last", 21 | "named-imports-order": "lowercase-first" 22 | } 23 | ], 24 | "trailing-comma": [ 25 | true, 26 | { 27 | "multiline": "always", 28 | "singleline": "never" 29 | } 30 | ], 31 | "class-name": true, 32 | "comment-format": [ 33 | true, 34 | "check-space" 35 | ], 36 | "indent": [ 37 | true, 38 | "spaces" 39 | ], 40 | "no-eval": true, 41 | "no-internal-module": true, 42 | "no-trailing-whitespace": true, 43 | "no-unsafe-finally": true, 44 | "one-line": [ 45 | true, 46 | "check-open-brace", 47 | "check-whitespace" 48 | ], 49 | "quotemark": [ 50 | true, 51 | "double" 52 | ], 53 | "semicolon": [ 54 | true, 55 | "always" 56 | ], 57 | "triple-equals": [ 58 | true, 59 | "allow-null-check" 60 | ], 61 | "typedef-whitespace": [ 62 | true, 63 | { 64 | "call-signature": "nospace", 65 | "index-signature": "nospace", 66 | "parameter": "nospace", 67 | "property-declaration": "nospace", 68 | "variable-declaration": "nospace" 69 | } 70 | ], 71 | "variable-name": [ 72 | true, 73 | "ban-keywords" 74 | ], 75 | "whitespace": [ 76 | true, 77 | "check-branch", 78 | "check-decl", 79 | "check-operator", 80 | "check-separator", 81 | "check-type" 82 | ] 83 | }, 84 | "jsRules": { 85 | "triple-equals": [ 86 | true, 87 | "allow-null-check" 88 | ] 89 | }, 90 | "defaultSeverity": "warning" 91 | } -------------------------------------------------------------------------------- /tslint-tests/tslint.json-3.7: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | 4 | "semicolon": [true, "always"], 5 | 6 | "no-var-keyword": true, 7 | "no-unused-variable": [ 8 | true, 9 | { 10 | "ignore-pattern": "^_" 11 | } 12 | ], 13 | 14 | "trailing-comma": [ 15 | true, 16 | { 17 | "multiline": "always", 18 | "singleline": "never" 19 | } 20 | ], 21 | "class-name": true, 22 | "comment-format": [ 23 | true, 24 | "check-space" 25 | ], 26 | "indent": [ 27 | true, 28 | "spaces" 29 | ], 30 | "no-eval": true, 31 | "no-internal-module": true, 32 | "no-trailing-whitespace": true, 33 | 34 | "one-line": [ 35 | true, 36 | "check-open-brace", 37 | "check-whitespace" 38 | ], 39 | "quotemark": [ 40 | true, 41 | "double" 42 | ], 43 | "semicolon": [ 44 | true, 45 | "always" 46 | ], 47 | "triple-equals": [ 48 | true, 49 | "allow-null-check" 50 | ], 51 | "typedef-whitespace": [ 52 | true, 53 | { 54 | "call-signature": "nospace", 55 | "index-signature": "nospace", 56 | "parameter": "nospace", 57 | "property-declaration": "nospace", 58 | "variable-declaration": "nospace" 59 | } 60 | ], 61 | "variable-name": [ 62 | true, 63 | "ban-keywords" 64 | ], 65 | "whitespace": [ 66 | true, 67 | "check-branch", 68 | "check-decl", 69 | "check-operator", 70 | "check-separator", 71 | "check-type" 72 | ] 73 | }, 74 | "jsRules": { 75 | "triple-equals": [ 76 | true, 77 | "allow-null-check" 78 | ] 79 | }, 80 | "defaultSeverity": "warning" 81 | } -------------------------------------------------------------------------------- /tslint-tests/tslint.yaml.test: -------------------------------------------------------------------------------- 1 | rules: 2 | max-line-length: 3 | options: [120] 4 | new-parens: true 5 | semicolon: true 6 | no-arg: true 7 | no-bitwise: true 8 | no-conditional-assignment: true 9 | no-consecutive-blank-lines: false 10 | no-console: 11 | severity: warning 12 | options: 13 | - debug 14 | - info 15 | - log 16 | - time 17 | - timeEnd 18 | - trace 19 | jsRules: 20 | max-line-length: 21 | options: [120] 22 | defaultSeverity: warning 23 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-unused-expression": true, 4 | "no-duplicate-variable": true, 5 | "no-unused-variable": true, 6 | "curly": true, 7 | "class-name": true, 8 | "semicolon": true, 9 | "triple-equals": true 10 | }, 11 | "defaultSeverity": "warning" 12 | } -------------------------------------------------------------------------------- /tslint/.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | server 3 | node_modules -------------------------------------------------------------------------------- /tslint/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch Extension", 6 | "type": "extensionHost", 7 | "request": "launch", 8 | "runtimeExecutable": "${execPath}", 9 | "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], 10 | "stopOnEntry": false, 11 | "sourceMaps": true, 12 | "outFiles": [ "${workspaceRoot}/out/**/*.js" ], 13 | "preLaunchTask": "npm: watch" 14 | }, 15 | { 16 | "name": "Launch Tests", 17 | "type": "extensionHost", 18 | "request": "launch", 19 | "runtimeExecutable": "${execPath}", 20 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], 21 | "stopOnEntry": false, 22 | "sourceMaps": true, 23 | "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ], 24 | "preLaunchTask": "npm: watch" 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /tslint/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": true, 5 | "bin": true 6 | }, 7 | "search.exclude": { 8 | "out": true, 9 | "bin": true 10 | }, 11 | "files.trimTrailingWhitespace": true, 12 | "editor.insertSpaces": false, 13 | "editor.tabSize": 4, 14 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, 15 | "editor.formatOnSave": false, 16 | "npm.exclude": "**/tslint/server" 17 | } 18 | -------------------------------------------------------------------------------- /tslint/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // A task runner that calls a custom npm script that compiles the extension. 2 | { 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "watch", 8 | "problemMatcher": "$tsc-watch", 9 | "isBackground": true, 10 | "presentation": { 11 | "reveal": "never" 12 | }, 13 | "group": { 14 | "kind": "build", 15 | "isDefault": true 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /tslint/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | typings/** 3 | **/*.ts 4 | **/*.map 5 | .gitignore 6 | tsconfig.json 7 | vsc-extension-quickstart.md 8 | -------------------------------------------------------------------------------- /tslint/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.46 4 | - Declare that the extension requires workspace trust. 5 | ## 1.0.45 6 | - Fix dependabot reported security vulnerabilities 7 | 8 | ## 1.0.44 9 | - Fix dependabot reported security vulnerabilities 10 | 11 | ## 1.0.42 12 | - Fix [#416](https://github.com/Microsoft/vscode-tslint/issues/416) New default for autoFixOnSave broke "Fix-all auto fixable problems" 13 | 14 | ## 1.0.41 15 | - Announce deprecation of vscode-tslint in favor of the [vscode-typescript-tslint-plugin](https://github.com/Microsoft/vscode-typescript-tslint-plugin) 16 | 17 | ## 1.0.40 18 | - Fix [#398](https://github.com/Microsoft/vscode-tslint/issues/398) Avoid that the tslint rule name is shown twice in diagnostic messages. 19 | 20 | ## 1.0.39 21 | - Fix [#387](https://github.com/Microsoft/vscode-tslint/issues/387) Infinite loop when auto fixing does not converge 22 | 23 | ## 1.0.38 24 | - Fix [#384](https://github.com/Microsoft/vscode-tslint/issues/384) Failed to load the TSLint library for the document, when tslint is installed globally 25 | 26 | ## 1.0.37 27 | - Fix [#382](https://github.com/Microsoft/vscode-tslint/issues/382) Fix all auto-fixable problems not fixing all problems (must be applied multiple times) 28 | 29 | ## 1.0.36 30 | - Fix [#379](https://github.com/Microsoft/vscode-tslint/issues/379) Unhandled Promise Reject warning when typescript module is not installed 31 | - Updating the dependencies to use the latest version of the vscode-language libraries 32 | 33 | ## 1.0.35 34 | - Fix [#376](https://github.com/Microsoft/vscode-tslint/issues/376) TS Lint Server crashes when tslint.nodePath does not exist 35 | 36 | ## 1.0.34 37 | - Enable quick fix indicaton in Problems view [#366](https://github.com/Microsoft/vscode-tslint/issues/366) 38 | - Contribute fix all quick fixes as a code action available from the Source menu. 39 | 40 | ## 1.0.33 41 | - Fix for [#343](https://github.com/Microsoft/vscode-tslint/issues/343) Create a 'tslint.json' file" doesn´t work with local tslint install. 42 | - Adopt [#316](https://github.com/Microsoft/vscode-tslint/issues/316) VSCode 1.20's new CodeAction type 43 | 44 | ## 1.0.32 45 | - Support [#309](https://github.com/Microsoft/vscode-tslint/issues/309) autoFixOnSave as a resource setting 46 | - Fix for [#356](https://github.com/Microsoft/vscode-tslint/issues/356) auto save mangles text. 47 | 48 | ## 1.0.30 49 | - Support multi pass fixing when there are overlapping fixes [#295](https://github.com/Microsoft/vscode-tslint/issues/295) 50 | - `editor.codeActionsOnSave` conflict with `tslint.autoFixOnSave` [#347](https://github.com/Microsoft/vscode-tslint/issues/347) 51 | 52 | ## 1.0.29 53 | - Problem matchers now set the source to `tslint` [#331](https://github.com/Microsoft/vscode-tslint/issues/331) 54 | - Add support for tslint configuration files as yaml files [#334](https://github.com/Microsoft/vscode-tslint/issues/334) 55 | - Restrict the documents synchronized to the language server to documents with the scheme `file` [#338](https://github.com/Microsoft/vscode-tslint/issues/338) 56 | 57 | ## 1.0.28 58 | - Added support `linterOptions.exclude` in the `tslint.json` file introduced in version 5.8 of tslint [#326](https://github.com/Microsoft/vscode-tslint/issues/326) 59 | 60 | ## 1.0.27 61 | - Fix for [#260](https://github.com/Microsoft/vscode-tslint/issues/260) TSLint consumes quite some CPU cycles 62 | 63 | ## 1.0.26 64 | 65 | - Fix for [#312](https://github.com/Microsoft/vscode-tslint/issues/213) Comments in tslint.json marked as errors 66 | - Improved the FAQ documentation 67 | - Change the name of the main server file to make it easier recognizable when running code --status 68 | 69 | ## 1.0.24 70 | 71 | - Capture warnings that tslint emits to the console and indicate them in the status bar item. 72 | - Improve wording of the "Disable Rule" quick fix [#298](https://github.com/Microsoft/vscode-tslint/issues/298) 73 | 74 | ## 1.0.23 75 | 76 | - Improve the README, document the work arounds for issue [#287](https://github.com/Microsoft/vscode-tslint/issues/287) Huge linting delays 77 | 78 | ## 1.0.22 79 | 80 | - Fix for [#292](https://github.com/Microsoft/vscode-tslint/issues/292) Relative path using nested extension is broken 81 | 82 | ## 1.0.21 83 | 84 | - Fix for [#287](https://github.com/Microsoft/vscode-tslint/issues/287) Huge linting delays 85 | 86 | ## 1.0.15 87 | 88 | - Added the `"multi-root ready"` keyword. 89 | - Support to load tslint, typescript when they are globally installed using yarn [#178](https://github.com/Microsoft/vscode-tslint/issues/178). To use yarn instead of npm with the tslint extension define `"tslint.packageManager": "yarn"` in your settings. To use npm set the value to `"npm"`. 90 | - Added more trace information to the server 91 | 92 | ## 1.0.12 93 | 94 | - Use icons instead of color to emphasize the tslint status in the status bar. 95 | - When validateOnSave is on, clear warnings when the user makes changes. 96 | - Use the new workspace folder picker API when selecting a target folder for tslint.json generation. 97 | 98 | ## 1.0.11 99 | 100 | - Only show tslint statusbar item when there is an error or warning. Added a setting to control whether the TSLint statusbar item is always shown. The default is false [#268](https://github.com/Microsoft/vscode-tslint/issues/268) 101 | - remove last reference to `rootPath`. 102 | 103 | ## 1.0.9 104 | 105 | - Fix for [#262](https://github.com/Microsoft/vscode-tslint/issues/262) Rule failures reported on .d.ts file 106 | - Fix for [#269](https://github.com/Microsoft/vscode-tslint/issues/264) Constant yellow TSLint status bar warning in diff editor 107 | 108 | ## 1.0.8 109 | 110 | - Fix for [#259](https://github.com/Microsoft/vscode-tslint/issues/259) Support to define tslint.configFile and rulesDirectories with relative paths is broken 111 | - Fix for [#264](https://github.com/Microsoft/vscode-tslint/issues/264) Support relative nodePath settings 112 | 113 | ## 1.0.7 114 | 115 | - Fix for [#259](https://github.com/Microsoft/vscode-tslint/issues/259) tslint.configFile relative to workspace 116 | - Fix for [#261](https://github.com/Microsoft/vscode-tslint/issues/261) Disabling tslint for .js not honored 117 | 118 | ## 1.0.6 119 | 120 | - Fix for [#257](https://github.com/Microsoft/vscode-tslint/issues/257) tslint broke when using tslint version < 4.0 121 | 122 | ## 1.0.5 123 | 124 | - Added more tracing information when `tslint.trace.server` is set to "verbose" 125 | 126 | ## 1.0.4 127 | 128 | - Fix for [#255](https://github.com/Microsoft/vscode-tslint/issues/255) TSLint status shown even when tslint is disabled 129 | - Added an FAQ section to the README 130 | 131 | ## 1.0.3 132 | 133 | - Added support to theme the warning and error color of the status bar item 134 | - Show a warning in the status bar when the tslint library cannot be loaded 135 | 136 | ## 1.0.2 137 | 138 | - Fix for [#252](https://github.com/Microsoft/vscode-tslint/issues/252) The setting nodePath is no longer honored 139 | 140 | ## 1.0.1 141 | 142 | - Added support linting workspaces with multiple root folders. Scoped the tslint settings so that they can be configured per folder. 143 | - Creating a default `tslint.json` is now using `tslint --init` to create the initial contents. 144 | - Loads the tslint library that is nearest to the linted file. 145 | 146 | ## 0.17.0 147 | 148 | - Added support to define which auto fixes should be applied automatically on save [#152](https://github.com/Microsoft/vscode-tslint/issues/152). 149 | 150 | ## 0.16.0 151 | 152 | - Added quick fix to show the documentation of a rule. 153 | - Added description to the contributed variables `tslint4` and `tslint5`. 154 | 155 | ## 0.15.0 156 | 157 | - fix for [#164](https://github.com/Microsoft/vscode-tslint/issues/164) Auto fixer for ordered-imports does not work with multiline named imports 158 | - fix for [#183](https://github.com/Microsoft/vscode-tslint/issues/183) Overlapping fix ranges cause errors which eventually disables `autoFixOnSave` 159 | - fix for [#202](https://github.com/Microsoft/vscode-tslint/issues/202) In TSLint section for settings.json, explain that TSLint settings are configured in tslint.json 160 | - fix for [#206](https://github.com/Microsoft/vscode-tslint/issues/202) Tslint failed to load error should mention that TypeScript is a peer dependency to tslint 161 | 162 | ## 0.14.0 163 | 164 | - fix for [#163](https://github.com/Microsoft/vscode-tslint/issues/163) tslint.autoFixOnSave often goes rogue and adds semi-colons everywhere. 165 | - Auto fix is now only run when the user manually saves a file. 166 | - added a setting to always show rule failures as warnings, independent of the severity configuration in the `tslint.json` configuration [#199](https://github.com/Microsoft/vscode-tslint/issues/199). 167 | - fix for [#103](https://github.com/Microsoft/vscode-tslint/issues/103) After correcting errors in tslint.json, output channel doesn't reflect "ok" state 168 | - fix for [#194](https://github.com/Microsoft/vscode-tslint/issues/194) 'null: Error: null' in devtools console 169 | - fix for [#197](https://github.com/Microsoft/vscode-tslint/issues/197) Spamed by cannot read tslint configuration 170 | 171 | ## 0.12.0 172 | 173 | - support configurable rule severities introduced in [tslint 5.0](https://github.com/palantir/tslint/releases/tag/5.0.0). 174 | - added a ProblemPattern and ProblemMatcher for `tslint5` which matches the reported severities properly. 175 | 176 | ## 0.11.0 177 | 178 | - support [tslint 5.0](https://github.com/palantir/tslint/releases/tag/5.0.0). 179 | 180 | ## 0.10.0 181 | 182 | - contribute a `tslint4` ProblemPattern and a `tslint4` ProblemMatcher. 183 | - updated the task documentation to use the `tslint4` ProblemMatcher. 184 | 185 | ## 0.9.0 186 | 187 | - updated to version 3.0.2 of the language-client and language-server libraries. 188 | - fix for [#174](https://github.com/Microsoft/vscode-tslint/issues/174) error when using tslint 5.0.0-dev.0 189 | - fix for [#180](https://github.com/Microsoft/vscode-tslint/issues/180) tslint.applyAllFixes should not appear in the list of available commands 190 | 191 | ## 0.8.1 192 | 193 | - added a setting to enable/disable the linting of `.js` files with tslint. The default is `false`. **Previously** tslint was enabled by default for `.js` files. 194 | - fix for [#153](https://github.com/Microsoft/vscode-tslint/issues/153) Error shown in wrong file when using rules that lints external html templates 195 | 196 | ## 0.7.1 197 | 198 | - Revived VS Code quick fixes for some additional rules: `comment-format`, `triple-equals`, `whitespace` 199 | 200 | ## 0.7.0 201 | 202 | - Added quickfixes to disable a rule [#110](https://github.com/Microsoft/vscode-tslint/issues/110) 203 | - Bring back the VS Code provided fix for the `quotemark` rule (e.g. ' should be") [#144](https://github.com/Microsoft/vscode-tslint/issues/144) 204 | 205 | ## 0.6.7 206 | 207 | - Support tslint versions < 3.15.0 [#143](https://github.com/Microsoft/vscode-tslint/issues/143) 208 | 209 | ## 0.6.6 210 | 211 | - Support all tslint autofixes [#135](https://github.com/Microsoft/vscode-tslint/issues/135) 212 | 213 | ## 0.6.0 214 | 215 | - Support tslint >= 4.0 216 | 217 | ## 0.5.41 218 | 219 | - Enable linting of `.js` files. 220 | - Extract the release notes into CHANGELOG.md 221 | 222 | ## 0.5.40 223 | 224 | - Add `tslint.autoFixOnSave` setting which enables fixing auto fixable warnings on file save. 225 | - Added support for auto fixes provided by the tslint library. 226 | 227 | ## 0.5.39 228 | 229 | - The status of the TSLint linter is now shown in the status line. 230 | - Add `tslint.nodePath` setting, which enables to load tslint from a different location than the current workspace or the globally installed npm modules`. 231 | - Added command to create an initial `tslint.json` file. 232 | - Added command to show the tslint output channel. 233 | 234 | ## 0.5.38 235 | 236 | - Warnings are now created into a diagnostic collection `tslint` this improves the integration with tslint warnings generated by a [problem matcher](https://code.visualstudio.com/docs/editor/tasks#_processing-task-output-with-problem-matchers). 237 | 238 | ## 0.5.35 239 | 240 | - Added a command `Fix all auto-fixable problems`. 241 | 242 | ## 0.5.34 243 | 244 | - Add a setting to lint on save only. 245 | 246 | ## 0.5.33 247 | 248 | - Only prompt for installing tslint, when the workspace root includes a `tslint.json` file. 249 | 250 | ## 0.5.32 251 | 252 | - Clear errors when document is closed. 253 | 254 | ## 0.5.30 255 | 256 | - More quick fixes. 257 | 258 | ## 0.5.25 259 | 260 | - Add support for quick fixing some warnings. 261 | 262 | ## 0.5.23 263 | 264 | - Updated to version 2.0 of the vscode language protocol. 265 | 266 | ## 0.5.21 267 | 268 | - Added the setting `tslint.validateWithDefaultConfig`. 269 | 270 | ## 0.5.17 271 | 272 | - Added setting `tslint.validateWithDefaultConfig`. 273 | - Added setting `tslint.ignoreDefinitionFiles`. 274 | 275 | ## 0.5.15 276 | 277 | - Watch for changes in the tslint.json when the file is located outside of the workspace. 278 | 279 | ## 0.5.13 280 | 281 | - Handle the case where a user edits a `tslint.json` configuration file and it is in an intermediate inconsistent state gracefully. 282 | 283 | ## 0.5.8 284 | 285 | - protect against exceptions thrown by tslint. 286 | 287 | ## 0.5.5 288 | 289 | - `tslint.json` is now validated using a JSON schema. 290 | - Diagnostic messages produced by tslint are now tagged with `tslint`. 291 | 292 | ## 0.5.4 293 | 294 | - Added the `tslint.configFile` option. 295 | -------------------------------------------------------------------------------- /tslint/License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation 2 | 3 | All rights reserved. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 8 | (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 16 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 17 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /tslint/README.md: -------------------------------------------------------------------------------- 1 | # vscode-tslint (deprecated) 2 | 3 | **Note:** This extension has been deprecated in favor of the [vscode-typescript-tslint-plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-typescript-tslint-plugin). To learn about the differences between vscode-tslint and the new extension please refer to this [document](https://github.com/Microsoft/vscode-typescript-tslint-plugin#differences-with-the-vscode-tslint-extension). 4 | 5 | --- 6 | 7 | Integrates the [tslint](https://github.com/palantir/tslint) linter for the TypeScript language into VS Code. 8 | 9 | Please refer to the tslint [documentation](https://github.com/palantir/tslint) for how to configure the linting rules. 10 | 11 | ## Prerequisites 12 | 13 | The extension requires that the `tslint` and `typescript` modules are installed either locally or globally. The extension will use the tslint module that is installed closest to the linted file. To install tslint and typescript globally you can run `npm install -g tslint typescript`. 14 | 15 | ## FAQ 16 | 17 | ### The tslint `no-unused-variable` rule doesn't report warnings any more? 18 | 19 | Since tslint version 5 the rule [no-unused-variable](https://palantir.github.io/tslint/rules/no-unused-variable/) requires type information. Rules with type information are currently not supported by vscode-tslint, pls see [issue #70](https://github.com/Microsoft/vscode-tslint/issues/70#issuecomment-241041929). The recommended work around is to enable the TypeScript compiler options `noUnusedLocals` and `noUnusedParameters` in your `tsconfig.json` file. 20 | 21 | tsconfig.json 22 | 23 | ```json 24 | { 25 | "compilerOptions": { 26 | "noUnusedLocals": true, 27 | "noUnusedParameters": true, 28 | ... 29 | } 30 | } 31 | ``` 32 | 33 | You can use the TypeScript setting `typescript.reportStyleChecksAsWarnings` to define whether `noUnusedLocals` and `noUnusedParameters` are reported as warnings or errors. By default the setting is true. 34 | 35 | ### How can I use tslint rules that require type information 36 | 37 | The recommended way is to run tslint manually on your project from a [task](https://code.visualstudio.com/docs/editor/tasks). To see the lint warnings in the Problems panel you can associate the task with a [Problem matcher](https://code.visualstudio.com/docs/editor/tasks#_processing-task-output-with-problem-matchers) as described in the section [below](#using-the-extension-with-tasks-running-tslint). 38 | 39 | - First linting is very slow [#287](https://github.com/Microsoft/vscode-tslint/issues/287) 40 | 41 | When you have installed tslint globally using `npm install -g` then you can get hit by a performance issue in npm. The command to determine the location of the global node modules can be very slow with version 5 of npm. This problem could not be reproduce with npm version 4.2. You can work around this issue by: 42 | 43 | 1. installing tslint locally for you project using `npm install tslint` 44 | 45 | 1. define the location of the global node_modules folder using the `tslint.nodePath` setting. 46 | 47 | ### How can I distinguish errors warnings from tslint and TypeScript and how can I suppress them? 48 | 49 | Error or warnings from TypeScript have the prefix `[ts]`, error or warnings from tslint have the prefix `[tslint]`. You can suppress warnings as follows: 50 | - typescript - use the `// @ts-ignore` comment. 51 | - tslint - use the `// tslint:rulename` comment. 52 | 53 | ## Trouble shooting 54 | 55 | Open the tslint output log using the command `TSLint: Show Output`. Verify that there is no error message in the shown log. 56 | 57 | 58 | You can enable more tracing output by adding the setting "tslint.trace.server" with a value of "verbose" or "messages". 59 | 60 | If this doesn't 61 | help then please file an [issue](https://github.com/Microsoft/vscode-tslint/issues/new) and include the trace output produced when running with the setting "tslint.trace.server" set to "verbose". 62 | 63 | There were some reports that vscode-tslint could not be started due to missing files [#342](https://github.com/Microsoft/vscode-tslint/issues/324). Please file an issue when this happens and follow the work around described in the issue. 64 | 65 | ## Configuration options 66 | 67 | **Notice** this configuration settings allow you to configure the behaviour of the vscode-tslint extension. To configure rules and tslint options you should use the `tslint.json` file. 68 | 69 | - `tslint.enable` - enable/disable tslint. 70 | - `tslint.jsEnable` - enable/disable tslint for .js files, default is `false`. 71 | - `tslint.run` - run the linter `onSave` or `onType`, default is `onType`. 72 | - `tslint.rulesDirectory` - an additional rules directory, for user-created rules. 73 | - `tslint.configFile` - the configuration file that tslint should use instead of the default `tslint.json`. 74 | - `tslint.ignoreDefinitionFiles` - control if TypeScript definition files should be ignored, default is `true`. 75 | - `tslint.exclude` - configure glob patterns of file paths to exclude from linting. The pattern is matched against the **absolute path** of the linted file. 76 | - `tslint.validateWithDefaultConfig` - validate a file for which no custom tslint configuration was found. The default is `false`. 77 | - `tslint.nodePath` - custom path to node modules directory, used to load tslint from a different location than the default of the current workspace or the global node modules directory. 78 | - `tslint.autoFixOnSave` - turns auto fix on save on or off, or defines an array of rules (e.g. [`no-var-keyword`]) to auto fix on save. **Note:** Auto-fixing is only done when manually saving a file. It is not performed when the file is automatically saved based on the `files.autoSave` setting. Executing a manual save on an already-saved document will trigger auto-fixing. 79 | - `tslint.alwaysShowStatus` - always show the `TSLint` status bar item and not only when there are errors. The default is `false`. 80 | - `tslint.alwaysShowRuleFailuresAsWarnings` - always show rule failures as warnings, ignoring the severity configuration in the `tslint.json` configuration. 81 | - `tslint.packageManager`: use this package manager to locate the `tslint` and `typescript` modules. Valid values are `"npm"` or `"yarn"`. This setting is only consulted when the modules are installed globally. 82 | 83 | ## Auto-fixing 84 | 85 | The extension supports automatic fixing of warnings to the extent supported by tslint. For warnings which support an auto-fix, a light bulb is shown when the cursor is positioned inside the warning's range. You can apply the quick fix by either: 86 | 87 | - clicking the light bulb appearing or by executing the `Quick Fix`, when the mouse is over the erroneous code 88 | - or using the command `Fix all auto-fixable problems`. 89 | 90 | When there are overlapping auto fixes a user will have to trigger `Fix all auto-fixable problems` more than once. 91 | 92 | ## ProblemPatterns and ProblemMatchers 93 | 94 | The extension contributes a `tslint4` and a `tslint5` `ProblemMatcher` and corresponding problem patterns. You can use these variables when defining a tslint task in your `task.json` file. The `tslint5` problem matcher matches the rule severities introduced in version 5 of tslint. 95 | 96 | The problem matcher is defined as follows: 97 | 98 | ```json 99 | { 100 | "name": "tslint5", 101 | "owner": "tslint", 102 | "applyTo": "closedDocuments", 103 | "fileLocation": "absolute", 104 | "severity": "warning", 105 | "pattern": "$tslint5" 106 | }, 107 | ``` 108 | 109 | The meaning of the different attributes is: 110 | 111 | - the `owner` attribute is set to `tslint` so that the warnings extracted by the problem matcher go into the same collection as the warnings produced by this extension. This will prevent showing duplicate warnings. 112 | 113 | - the `applyTo` attribute is defined so that the problem matcher only runs on documents that are not open in an editor. An open document is already validated by the extension as the user types. 114 | - the `fileLocation` is taken as an absolute path. This is correct for the output from `gulp`. When tslint is launched on the command line directly or from a package.json script then the file location is reported relative and you need to overwrite the value of this attribute (see below). 115 | - the `severity` defaults to `warning` unless the rule is configured to report errors. 116 | 117 | You can easily overwrite the value of these attributes. The following examples overwrites the `fileLocation` attribute to use the problem matcher when tslint is run on the command line or from a package.json script: 118 | 119 | ```json 120 | "problemMatcher": { 121 | "base": "$tslint5", 122 | "fileLocation": "relative" 123 | } 124 | ``` 125 | 126 | See the next section for an example. 127 | 128 | ## Using the extension with tasks running tslint 129 | 130 | The extension lints an individual file only. If you want to lint your entire workspace or project and want to see 131 | the warnings in the `Problems` panel, then you can: 132 | 133 | - use gulp that or define a script inside the `package.json` that runs tslint across your project. 134 | 135 | - define a VS Code [task](https://code.visualstudio.com/docs/editor/tasks) with a [problem matcher (https://code.visualstudio.com/docs/editor/tasks#_processing-task-output-with-problem-matchers) that extracts VS Code warnings from the tslint output. 136 | 137 | For example, here is an excerpt from a package.json file that defines a script to run tslint: 138 | 139 | ```json 140 | { 141 | "name": "tslint-script-demo", 142 | "version": "1.0.0", 143 | "scripts": { 144 | "lint": "tslint tests/*.ts -t verbose" 145 | }, 146 | "devDependencies": { 147 | "typescript": "^2.2.2", 148 | "tslint": "^5.0.0" 149 | } 150 | } 151 | 152 | ``` 153 | 154 | Next, define a Task which runs the npm script with a problem matcher that extracts the tslint errors into warnings. 155 | 156 | ```json 157 | { 158 | "version": "2.0.0", 159 | "tasks": [ 160 | { 161 | "type": "npm", 162 | "script": "lint", 163 | "problemMatcher": { 164 | "base": "$tslint5", 165 | "fileLocation": "relative" 166 | } 167 | } 168 | ] 169 | } 170 | ``` 171 | 172 | Finally, when you then run the `tslint` task you will see the warnings produced by the npm script in the `Problems` panel and you can navigate to the errors from there. 173 | 174 | Here is the complete setup [example setup](https://github.com/Microsoft/vscode-tslint/tree/master/tslint-tests). 175 | -------------------------------------------------------------------------------- /tslint/TSLint_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-tslint/1d7547c643da0da7376f674ea35077e155bcd133/tslint/TSLint_icon.png -------------------------------------------------------------------------------- /tslint/extension.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as fs from 'fs'; 3 | import { 4 | workspace, window, commands, ExtensionContext, StatusBarAlignment, TextEditor, Disposable, TextDocumentSaveReason, Uri, 5 | ProviderResult, Command, Diagnostic, CodeActionContext, WorkspaceFolder, TextDocument, WorkspaceFolderPickOptions, 6 | TextDocumentWillSaveEvent, CodeAction 7 | } from 'vscode'; 8 | import { 9 | LanguageClient, LanguageClientOptions, ServerOptions, TextEdit, 10 | RequestType, TextDocumentIdentifier, State as ClientState, NotificationType, TransportKind, 11 | CancellationToken, WorkspaceMiddleware, ConfigurationParams 12 | } from 'vscode-languageclient'; 13 | import { exec } from 'child_process'; 14 | 15 | interface AllFixesParams { 16 | readonly textDocument: TextDocumentIdentifier; 17 | readonly isOnSave: boolean; 18 | } 19 | 20 | interface AllFixesResult { 21 | readonly documentVersion: number; 22 | readonly edits: TextEdit[]; 23 | readonly ruleId?: string; 24 | readonly overlappingFixes: boolean; 25 | } 26 | 27 | namespace AllFixesRequest { 28 | export const type = new RequestType('textDocument/tslint/allFixes'); 29 | } 30 | 31 | interface NoTSLintLibraryParams { 32 | readonly source: TextDocumentIdentifier; 33 | } 34 | 35 | interface NoTSLintLibraryResult { 36 | } 37 | 38 | namespace NoTSLintLibraryRequest { 39 | export const type = new RequestType('tslint/noLibrary'); 40 | } 41 | 42 | enum Status { 43 | ok = 1, 44 | warn = 2, 45 | error = 3 46 | } 47 | 48 | interface StatusParams { 49 | state: Status; 50 | } 51 | 52 | namespace StatusNotification { 53 | export const type = new NotificationType('tslint/status'); 54 | } 55 | 56 | interface Settings { 57 | enable: boolean; 58 | jsEnable: boolean; 59 | rulesDirectory: string | string[]; 60 | configFile: string; 61 | ignoreDefinitionFiles: boolean; 62 | exclude: string | string[]; 63 | validateWithDefaultConfig: boolean; 64 | nodePath: string | undefined; 65 | run: 'onSave' | 'onType'; 66 | alwaysShowRuleFailuresAsWarnings: boolean; 67 | alwaysShowStatus: boolean; 68 | autoFixOnSave: boolean | string[]; 69 | packageManager: 'npm' | 'yarn'; 70 | trace: any; 71 | workspaceFolderPath: string; // 'virtual' setting sent to the server 72 | } 73 | 74 | let willSaveTextDocumentListener: Disposable; 75 | let configurationChangedListener: Disposable; 76 | 77 | export function activate(context: ExtensionContext) { 78 | 79 | let statusBarItem = window.createStatusBarItem(StatusBarAlignment.Right, 0); 80 | let tslintStatus: Status = Status.ok; 81 | let serverRunning: boolean = false; 82 | 83 | statusBarItem.text = 'TSLint'; 84 | statusBarItem.command = 'tslint.showOutputChannel'; 85 | 86 | function showStatusBarItem(show: boolean): void { 87 | if (show) { 88 | statusBarItem.show(); 89 | } else { 90 | statusBarItem.hide(); 91 | } 92 | } 93 | 94 | function updateStatus(status: Status) { 95 | if (tslintStatus !== Status.ok && status === Status.ok) { // an error got addressed fix, write to the output that the status is OK 96 | client.info('vscode-tslint: Status is OK'); 97 | } 98 | tslintStatus = status; 99 | updateStatusBarVisibility(window.activeTextEditor); 100 | } 101 | 102 | function isTypeScriptDocument(document: TextDocument) { 103 | return document.languageId === 'typescript' || document.languageId === 'typescriptreact'; 104 | } 105 | 106 | function isJavaScriptDocument(languageId) { 107 | return languageId === 'javascript' || languageId === 'javascriptreact'; 108 | } 109 | 110 | function isEnabledForJavaScriptDocument(document: TextDocument) { 111 | let isJsEnable = workspace.getConfiguration('tslint', document.uri).get('jsEnable', true); 112 | if (isJsEnable && isJavaScriptDocument(document.languageId)) { 113 | return true; 114 | } 115 | return false; 116 | } 117 | 118 | function updateStatusBarVisibility(editor: TextEditor | undefined): void { 119 | 120 | switch (tslintStatus) { 121 | case Status.ok: 122 | statusBarItem.text = 'TSLint'; 123 | break; 124 | case Status.warn: 125 | statusBarItem.text = '$(alert) TSLint'; 126 | break; 127 | case Status.error: 128 | statusBarItem.text = '$(issue-opened) TSLint'; 129 | break; 130 | 131 | } 132 | let uri = editor ? editor.document.uri : undefined; 133 | let enabled = workspace.getConfiguration('tslint', uri)['enable']; 134 | let alwaysShowStatus = workspace.getConfiguration('tslint', uri)['alwaysShowStatus']; 135 | 136 | if (!editor || !enabled || (tslintStatus === Status.ok && !alwaysShowStatus)) { 137 | showStatusBarItem(false); 138 | return; 139 | } 140 | 141 | showStatusBarItem( 142 | serverRunning && 143 | (isTypeScriptDocument(editor.document) || isEnabledForJavaScriptDocument(editor.document)) 144 | ); 145 | } 146 | 147 | window.onDidChangeActiveTextEditor(updateStatusBarVisibility); 148 | updateStatusBarVisibility(window.activeTextEditor); 149 | 150 | // We need to go one level up since an extension compile the js code into 151 | // the output folder. 152 | let serverModulePath = path.join(__dirname, '..', 'server', 'tslintServer.js'); 153 | // break on start options 154 | //let debugOptions = { execArgv: ["--nolazy", "--inspect-brk=6010", "--trace-warnings"] }; 155 | let debugOptions = { execArgv: ["--nolazy", "--inspect=6010"], cwd: process.cwd() }; 156 | let runOptions = { cwd: process.cwd() }; 157 | let serverOptions: ServerOptions = { 158 | run: { module: serverModulePath, transport: TransportKind.ipc, options: runOptions }, 159 | debug: { module: serverModulePath, transport: TransportKind.ipc, options: debugOptions } 160 | }; 161 | 162 | let clientOptions: LanguageClientOptions = { 163 | documentSelector: [ 164 | { language: 'typescript', scheme: 'file' }, 165 | { language: 'typescriptreact', scheme: 'file' }, 166 | { language: 'javascript', scheme: 'file' }, 167 | { language: 'javascriptreact', scheme: 'file' } 168 | ], 169 | synchronize: { 170 | configurationSection: 'tslint', 171 | fileEvents: workspace.createFileSystemWatcher('**/tslint.{json,yml,yaml}') 172 | }, 173 | diagnosticCollectionName: 'tslint', 174 | initializationFailedHandler: (error) => { 175 | client.error('Server initialization failed.', error); 176 | client.outputChannel.show(true); 177 | return false; 178 | }, 179 | middleware: { 180 | provideCodeActions: (document, range, context, token, next): ProviderResult<(Command | CodeAction)[]> => { 181 | // do not ask server for code action when the diagnostic isn't from tslint 182 | if (!context.diagnostics || context.diagnostics.length === 0) { 183 | return []; 184 | } 185 | let tslintDiagnostics: Diagnostic[] = []; 186 | for (let diagnostic of context.diagnostics) { 187 | if (diagnostic.source === 'tslint') { 188 | tslintDiagnostics.push(diagnostic); 189 | } 190 | } 191 | if (tslintDiagnostics.length === 0) { 192 | return []; 193 | } 194 | let newContext: CodeActionContext = Object.assign({}, context, { diagnostics: tslintDiagnostics } as CodeActionContext); 195 | return next(document, range, newContext, token); 196 | }, 197 | workspace: { 198 | configuration: (params: ConfigurationParams, token: CancellationToken, next: Function): any[] => { 199 | if (!params.items) { 200 | return []; 201 | } 202 | let result = next(params, token, next); 203 | let scopeUri = ""; 204 | 205 | for (let item of params.items) { 206 | if (!item.scopeUri) { 207 | continue; 208 | } else { 209 | scopeUri = item.scopeUri; 210 | } 211 | } 212 | let resource = client.protocol2CodeConverter.asUri(scopeUri); 213 | let workspaceFolder = workspace.getWorkspaceFolder(resource); 214 | if (workspaceFolder) { 215 | convertToAbsolutePaths(result[0], workspaceFolder); 216 | if (workspaceFolder.uri.scheme === 'file') { 217 | result[0].workspaceFolderPath = workspaceFolder.uri.fsPath; 218 | } 219 | } 220 | return result; 221 | } 222 | } as WorkspaceMiddleware 223 | } 224 | }; 225 | 226 | let client = new LanguageClient('tslint', serverOptions, clientOptions); 227 | client.registerProposedFeatures(); 228 | 229 | const running = 'Linter is running.'; 230 | const stopped = 'Linter has stopped.'; 231 | 232 | client.onDidChangeState((event) => { 233 | if (event.newState === ClientState.Running) { 234 | client.info(running); 235 | statusBarItem.tooltip = running; 236 | serverRunning = true; 237 | } else { 238 | client.info(stopped); 239 | statusBarItem.tooltip = stopped; 240 | serverRunning = false; 241 | } 242 | updateStatusBarVisibility(window.activeTextEditor); 243 | }); 244 | 245 | client.onReady().then(() => { 246 | client.onNotification(StatusNotification.type, (params) => { 247 | updateStatus(params.state); 248 | }); 249 | client.onRequest(NoTSLintLibraryRequest.type, (params) => { 250 | let uri: Uri = Uri.parse(params.source.uri); 251 | let workspaceFolder = workspace.getWorkspaceFolder(uri); 252 | let packageManager = workspace.getConfiguration('tslint', uri).get('packageManager', 'npm'); 253 | client.info(getInstallFailureMessage(uri, workspaceFolder, packageManager)); 254 | updateStatus(Status.warn); 255 | return {}; 256 | }); 257 | }); 258 | 259 | function getInstallFailureMessage(uri: Uri, workspaceFolder: WorkspaceFolder | undefined, packageManager: string): string { 260 | let localCommands = { 261 | npm: 'npm install tslint', 262 | yarn: 'yarn add tslint' 263 | }; 264 | let globalCommands = { 265 | npm: 'npm install -g tslint', 266 | yarn: 'yarn global add tslint' 267 | }; 268 | if (workspaceFolder) { // workspace opened on a folder 269 | return [ 270 | '', 271 | `Failed to load the TSLint library for the document ${uri.fsPath}`, 272 | '', 273 | `To use TSLint in this workspace please install tslint using \'${localCommands[packageManager]}\' or globally using \'${globalCommands[packageManager]}\'.`, 274 | 'TSLint has a peer dependency on `typescript`, make sure that `typescript` is installed as well.', 275 | 'You need to reopen the workspace after installing tslint.', 276 | ].join('\n'); 277 | } else { 278 | return [ 279 | `Failed to load the TSLint library for the document ${uri.fsPath}`, 280 | `To use TSLint for single file install tslint globally using \'${globalCommands[packageManager]}\'.`, 281 | 'TSLint has a peer dependency on `typescript`, make sure that `typescript` is installed as well.', 282 | 'You need to reopen VS Code after installing tslint.', 283 | ].join('\n'); 284 | } 285 | } 286 | 287 | function convertToAbsolutePaths(settings: Settings, folder: WorkspaceFolder) { 288 | let configFile = settings.configFile; 289 | if (configFile) { 290 | settings.configFile = convertAbsolute(configFile, folder); 291 | } 292 | let nodePath = settings.nodePath; 293 | if (nodePath) { 294 | settings.nodePath = convertAbsolute(nodePath, folder); 295 | } 296 | if (settings.rulesDirectory) { 297 | if (Array.isArray(settings.rulesDirectory)) { 298 | for (let i = 0; i < settings.rulesDirectory.length; i++) { 299 | settings.rulesDirectory[i] = convertAbsolute(settings.rulesDirectory[i], folder); 300 | 301 | } 302 | } else { 303 | settings.rulesDirectory = convertAbsolute(settings.rulesDirectory, folder); 304 | } 305 | } 306 | } 307 | 308 | function convertAbsolute(file: string, folder: WorkspaceFolder): string { 309 | if (path.isAbsolute(file)) { 310 | return file; 311 | } 312 | let folderPath = folder.uri.fsPath; 313 | if (!folderPath) { 314 | return file; 315 | } 316 | return path.join(folderPath, file); 317 | } 318 | 319 | async function applyTextEdits(uri: string, documentVersion: number, edits: TextEdit[]): Promise { 320 | let textEditor = window.activeTextEditor; 321 | if (textEditor && textEditor.document.uri.toString() === uri) { 322 | if (documentVersion !== -1 && textEditor.document.version !== documentVersion) { 323 | window.showInformationMessage(`TSLint fixes are outdated and can't be applied to the document.`); 324 | return true; 325 | } 326 | return textEditor.edit(mutator => { 327 | for (let edit of edits) { 328 | mutator.replace(client.protocol2CodeConverter.asRange(edit.range), edit.newText); 329 | } 330 | }); 331 | } 332 | return true; 333 | } 334 | 335 | function applyDisableRuleEdit(uri: string, documentVersion: number, edits: TextEdit[]) { 336 | let textEditor = window.activeTextEditor; 337 | if (textEditor && textEditor.document.uri.toString() === uri) { 338 | if (textEditor.document.version !== documentVersion) { 339 | window.showInformationMessage(`TSLint fixes are outdated and can't be applied to the document.`); 340 | } 341 | // prefix disable comment with same indent as line with the diagnostic 342 | let edit = edits[0]; 343 | let ruleLine = textEditor.document.lineAt(edit.range.start.line); 344 | let prefixIndex = ruleLine.firstNonWhitespaceCharacterIndex; 345 | let prefix = ruleLine.text.substr(0, prefixIndex); 346 | edit.newText = prefix + edit.newText; 347 | applyTextEdits(uri, documentVersion, edits); 348 | } 349 | } 350 | 351 | function showRuleDocumentation(_uri: string, _documentVersion: number, _edits: TextEdit[], ruleId: string) { 352 | const tslintDocBaseURL = "https://palantir.github.io/tslint/rules"; 353 | if (!ruleId) { 354 | return; 355 | } 356 | commands.executeCommand('vscode.open', Uri.parse(tslintDocBaseURL + '/' + ruleId)); 357 | } 358 | 359 | function fixAllProblems(): Thenable | undefined { 360 | // server is not running so there can be no problems to fix 361 | if (!serverRunning) { 362 | return; 363 | } 364 | let textEditor = window.activeTextEditor; 365 | if (!textEditor) { 366 | return; 367 | } 368 | return doFixAllProblems(textEditor.document, undefined); // no time budget 369 | } 370 | 371 | function exists(file: string): Promise { 372 | return new Promise((resolve, _reject) => { 373 | fs.exists(file, (value) => { 374 | resolve(value); 375 | }); 376 | }); 377 | } 378 | 379 | async function findTslint(rootPath: string): Promise { 380 | const platform = process.platform; 381 | if (platform === 'win32' && await exists(path.join(rootPath, 'node_modules', '.bin', 'tslint.cmd'))) { 382 | return path.join('.', 'node_modules', '.bin', 'tslint.cmd'); 383 | } else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(rootPath, 'node_modules', '.bin', 'tslint'))) { 384 | return path.join('.', 'node_modules', '.bin', 'tslint'); 385 | } else { 386 | return 'tslint'; 387 | } 388 | } 389 | 390 | async function createDefaultConfiguration() { 391 | let folders = workspace.workspaceFolders; 392 | let folder: WorkspaceFolder | undefined = undefined; 393 | if (!folders) { 394 | window.showErrorMessage('A TSLint configuration file can only be generated if VS Code is opened on a folder.'); 395 | return; 396 | } 397 | if (folders.length === 1) { 398 | folder = folders[0]; 399 | } else { 400 | const options: WorkspaceFolderPickOptions = { 401 | placeHolder: "Select the folder for generating the 'tslint.json' file" 402 | }; 403 | folder = await window.showWorkspaceFolderPick(options); 404 | if (!folder) { 405 | return; 406 | } 407 | } 408 | const folderPath = folder.uri.fsPath; 409 | const tslintConfigFile = path.join(folderPath, 'tslint.json'); 410 | 411 | if (fs.existsSync(tslintConfigFile)) { 412 | window.showInformationMessage('A TSLint configuration file already exists.'); 413 | let document = await workspace.openTextDocument(tslintConfigFile); 414 | window.showTextDocument(document); 415 | } else { 416 | const tslintCmd = await findTslint(folderPath); 417 | const cmd = `${tslintCmd} --init`; 418 | const p = exec(cmd, { cwd: folderPath, env: process.env }); 419 | p.on('exit', async (code: number, _signal: string) => { 420 | if (code === 0) { 421 | let document = await workspace.openTextDocument(tslintConfigFile); 422 | window.showTextDocument(document); 423 | } else { 424 | window.showErrorMessage('Could not run `tslint` to generate a configuration file. Please verify that you have `tslint` and `typescript` installed.'); 425 | } 426 | }); 427 | } 428 | } 429 | 430 | function willSaveTextDocument(e: TextDocumentWillSaveEvent) { 431 | let config = workspace.getConfiguration('tslint', e.document.uri); 432 | let autoFix = config.get('autoFixOnSave', false); 433 | if (autoFix) { 434 | let document = e.document; 435 | // only auto fix when the document was manually saved by the user 436 | if (!(isTypeScriptDocument(document) || isEnabledForJavaScriptDocument(document)) 437 | || e.reason !== TextDocumentSaveReason.Manual) { 438 | return; 439 | } 440 | e.waitUntil( 441 | doFixAllProblems(document, 500) // total willSave time budget is 1500 442 | ); 443 | } 444 | } 445 | 446 | function configurationChanged() { 447 | updateStatusBarVisibility(window.activeTextEditor); 448 | } 449 | 450 | function doFixAllProblems(document: TextDocument, timeBudget: number | undefined): Thenable { 451 | let start = Date.now(); 452 | let loopCount = 0; 453 | let retry = false; 454 | let lastVersion = document.version; 455 | 456 | let promise = client.sendRequest(AllFixesRequest.type, { textDocument: { uri: document.uri.toString() }, isOnSave: true }).then(async (result) => { 457 | while (true) { 458 | // console.log('duration ', Date.now() - start); 459 | if (timeBudget && Date.now() - start > timeBudget) { 460 | console.log(`TSLint auto fix on save maximum time budget (${timeBudget}ms) exceeded.`); 461 | break; 462 | } 463 | if (loopCount++ > 10) { 464 | console.log(`TSLint auto fix on save maximum retries exceeded.`); 465 | break; 466 | } 467 | if (result) { 468 | // ensure that document versions on the client are in sync 469 | if (lastVersion !== document.version) { 470 | window.showInformationMessage("TSLint: Auto fix on save, fixes could not be applied (client version mismatch)."); 471 | break; 472 | } 473 | retry = false; 474 | if (lastVersion !== result.documentVersion) { 475 | console.log('TSLint auto fix on save, server document version different than client version'); 476 | retry = true; // retry to get the fixes matching the document 477 | } else { 478 | // try to apply the edits from the server 479 | let edits = client.protocol2CodeConverter.asTextEdits(result.edits); 480 | // disable version check by passing -1 as the version, the event loop is blocked during `willSave` 481 | let success = await applyTextEdits(document.uri.toString(), -1, edits); 482 | if (!success) { 483 | window.showInformationMessage("TSLint: Auto fix on save, edits could not be applied"); 484 | break; 485 | } 486 | } 487 | 488 | lastVersion = document.version; 489 | 490 | if (result.overlappingFixes || retry) { 491 | // ask for more non overlapping fixes 492 | result = await client.sendRequest(AllFixesRequest.type, { textDocument: { uri: document.uri.toString() }, isOnSave: true }); 493 | } else { 494 | break; 495 | } 496 | } else { 497 | break; 498 | } 499 | } 500 | return null; 501 | }); 502 | return promise; 503 | } 504 | 505 | configurationChangedListener = workspace.onDidChangeConfiguration(configurationChanged); 506 | willSaveTextDocumentListener = workspace.onWillSaveTextDocument(willSaveTextDocument); 507 | configurationChanged(); 508 | 509 | context.subscriptions.push( 510 | client.start(), 511 | configurationChangedListener, 512 | willSaveTextDocumentListener, 513 | // internal commands 514 | commands.registerCommand('_tslint.applySingleFix', applyTextEdits), 515 | commands.registerCommand('_tslint.applySameFixes', applyTextEdits), 516 | commands.registerCommand('_tslint.applyAllFixes', fixAllProblems), 517 | commands.registerCommand('_tslint.applyDisableRule', applyDisableRuleEdit), 518 | commands.registerCommand('_tslint.showRuleDocumentation', showRuleDocumentation), 519 | // user commands 520 | commands.registerCommand('tslint.fixAllProblems', fixAllProblems), 521 | commands.registerCommand('tslint.createConfig', createDefaultConfiguration), 522 | commands.registerCommand('tslint.showOutputChannel', () => { client.outputChannel.show(); }), 523 | statusBarItem 524 | ); 525 | } 526 | 527 | export function deactivate() { 528 | 529 | } 530 | -------------------------------------------------------------------------------- /tslint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint", 3 | "displayName": "TSLint (deprecated)", 4 | "description": "TSLint for Visual Studio Code", 5 | "version": "1.0.46", 6 | "author": "Microsoft Corporation", 7 | "license": "MIT", 8 | "publisher": "eg2", 9 | "icon": "TSLint_icon.png", 10 | "galleryBanner": { 11 | "color": "#5c2d91", 12 | "theme": "dark" 13 | }, 14 | "workspaceTrust": { 15 | "request": "onStart", 16 | "description": "Custom tslint rules can run arbitrary code from the workspace." 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/Microsoft/vscode-tslint.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/Microsoft/vscode-tslint/issues" 24 | }, 25 | "categories": [ 26 | "Programming Languages", 27 | "Linters" 28 | ], 29 | "keywords": [ 30 | "multi-root ready" 31 | ], 32 | "engines": { 33 | "vscode": "^1.54.0" 34 | }, 35 | 36 | "activationEvents": [ 37 | "onLanguage:typescript", 38 | "onLanguage:typescriptreact", 39 | "onLanguage:javascript", 40 | "onLanguage:javascriptreact", 41 | "onCommand:tslint.fixAllProblems", 42 | "onCommand:tslint.createConfig", 43 | "onCommand:tslint.showOutputChannel" 44 | ], 45 | "main": "./out/extension", 46 | "contributes": { 47 | "languages": [ 48 | { 49 | "id": "jsonc", 50 | "filenames": [ 51 | "tslint.json" 52 | ] 53 | } 54 | ], 55 | "configuration": { 56 | "type": "object", 57 | "title": "TSLint", 58 | "properties": { 59 | "tslint.enable": { 60 | "type": "boolean", 61 | "default": true, 62 | "description": "Control whether tslint is enabled for TypeScript files or not.", 63 | "scope": "resource" 64 | }, 65 | "tslint.jsEnable": { 66 | "type": "boolean", 67 | "default": false, 68 | "description": "Control whether tslint is enabled for JavaScript files or not.", 69 | "scope": "resource" 70 | }, 71 | "tslint.rulesDirectory": { 72 | "type": [ 73 | "string", 74 | "array" 75 | ], 76 | "items": { 77 | "type": "string" 78 | }, 79 | "description": "An additional rules directory", 80 | "default": "", 81 | "scope": "resource" 82 | }, 83 | "tslint.validateWithDefaultConfig": { 84 | "type": "boolean", 85 | "description": "Validate a file when there is only a default tslint configuration is found", 86 | "default": false, 87 | "scope": "resource" 88 | }, 89 | "tslint.configFile": { 90 | "type": "string", 91 | "description": "The path to the rules configuration file", 92 | "default": "", 93 | "scope": "resource" 94 | }, 95 | "tslint.ignoreDefinitionFiles": { 96 | "type": "boolean", 97 | "default": true, 98 | "description": "Control if TypeScript definition files should be ignored", 99 | "scope": "resource" 100 | }, 101 | "tslint.exclude": { 102 | "type": [ 103 | "string", 104 | "array" 105 | ], 106 | "items": { 107 | "type": "string" 108 | }, 109 | "description": "Configure glob patterns of file paths to exclude from linting", 110 | "scope": "resource" 111 | }, 112 | "tslint.run": { 113 | "type": "string", 114 | "enum": [ 115 | "onSave", 116 | "onType" 117 | ], 118 | "default": "onType", 119 | "description": "Run the linter on save (onSave) or on type (onType)", 120 | "scope": "resource" 121 | }, 122 | "tslint.nodePath": { 123 | "type": "string", 124 | "default": "", 125 | "description": "A path added to NODE_PATH when resolving the tslint module.", 126 | "scope": "machine" 127 | }, 128 | "tslint.autoFixOnSave": { 129 | "type": [ 130 | "boolean", 131 | "array" 132 | ], 133 | "items": { 134 | "type": "string" 135 | }, 136 | "default": false, 137 | "description": "Turns auto fix on save on or off, or defines which rules (e.g. `no-var-keyword`) to auto fix on save.", 138 | "scope": "resource" 139 | }, 140 | "tslint.alwaysShowRuleFailuresAsWarnings": { 141 | "type": "boolean", 142 | "default": false, 143 | "description": "Always show rule failures as warnings, independent of the tslint configuration.", 144 | "scope": "resource" 145 | }, 146 | "tslint.alwaysShowStatus": { 147 | "type": "boolean", 148 | "default": false, 149 | "description": "Always show the TSlint status bar item, not only when there are errors or warnings.", 150 | "scope": "window" 151 | }, 152 | "tslint.trace.server": { 153 | "scope": "window", 154 | "type": "string", 155 | "enum": [ 156 | "off", 157 | "messages", 158 | "verbose" 159 | ], 160 | "default": "off", 161 | "description": "Traces the communication between VSCode and the tslint linter service." 162 | }, 163 | "tslint.packageManager": { 164 | "scope": "resource", 165 | "type": "string", 166 | "enum": [ 167 | "npm", 168 | "yarn" 169 | ], 170 | "default": "npm", 171 | "description": "The package manager to use to locate the tslint module." 172 | } 173 | } 174 | }, 175 | "commands": [ 176 | { 177 | "title": "Fix all auto-fixable problems", 178 | "category": "TSLint", 179 | "command": "tslint.fixAllProblems" 180 | }, 181 | { 182 | "title": "Create a 'tslint.json' file", 183 | "category": "TSLint", 184 | "command": "tslint.createConfig" 185 | }, 186 | { 187 | "title": "Show output", 188 | "category": "TSLint", 189 | "command": "tslint.showOutputChannel" 190 | } 191 | ], 192 | "jsonValidation": [ 193 | { 194 | "fileMatch": "tslint.json", 195 | "url": "http://json.schemastore.org/tslint" 196 | } 197 | ], 198 | "problemPatterns": [ 199 | { 200 | "name": "tslint4", 201 | "regexp": "^(\\(\\S*\\)\\s+)?(\\S.*)\\[(\\d+), (\\d+)\\]:\\s+(.*)$", 202 | "file": 2, 203 | "line": 3, 204 | "column": 4, 205 | "message": 5 206 | }, 207 | { 208 | "name": "tslint5", 209 | "regexp": "^(WARNING|ERROR):(\\s+\\(\\S*\\))?\\s+(\\S.*)\\[(\\d+), (\\d+)\\]:\\s+(.*)$", 210 | "severity": 1, 211 | "file": 3, 212 | "line": 4, 213 | "column": 5, 214 | "message": 6 215 | } 216 | ], 217 | "problemMatchers": [ 218 | { 219 | "name": "tslint4", 220 | "label": "tslint (version 4) warnings", 221 | "owner": "tslint", 222 | "source": "tslint", 223 | "applyTo": "closedDocuments", 224 | "fileLocation": "absolute", 225 | "severity": "warning", 226 | "pattern": "$tslint4" 227 | }, 228 | { 229 | "name": "tslint5", 230 | "owner": "tslint", 231 | "source": "tslint", 232 | "label": "tslint (version 5) warnings", 233 | "applyTo": "closedDocuments", 234 | "fileLocation": "absolute", 235 | "severity": "warning", 236 | "pattern": "$tslint5" 237 | } 238 | ] 239 | }, 240 | "scripts": { 241 | "vscode:prepublish": "cd ../tslint-server && npm run compile && cd ../tslint && tsc -p ./", 242 | "compile": "tsc -p ./", 243 | "watch": "tsc -watch -p ./" 244 | }, 245 | "devDependencies": { 246 | "@types/vscode": "^1.54.0", 247 | "@types/glob": "^7.1.3", 248 | "@types/mocha": "^8.0.4", 249 | "@types/node": "^12.11.7", 250 | "eslint": "^7.19.0", 251 | "@typescript-eslint/eslint-plugin": "^4.14.1", 252 | "@typescript-eslint/parser": "^4.14.1", 253 | "glob": "^7.1.6", 254 | "mocha": "^8.2.1", 255 | "typescript": "^4.1.3", 256 | "vscode-test": "^1.5.0" 257 | }, 258 | "dependencies": { 259 | "global": "^4.3.2", 260 | "vscode-languageclient": "^5.0.1" 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /tslint/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "strictNullChecks": true, 7 | "noUnusedLocals": true, 8 | "noUnusedParameters": true, 9 | "lib": [ 10 | "es6" 11 | ], 12 | "sourceMap": true 13 | }, 14 | "exclude": [ 15 | "node_modules", 16 | "server" 17 | ] 18 | } -------------------------------------------------------------------------------- /vscode-tslint.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "tslint" 5 | }, 6 | { 7 | "path": "tslint-server" 8 | }, 9 | { 10 | "path": "tslint-tests" 11 | } 12 | ], 13 | "settings": { 14 | "editor.formatOnSave": false, 15 | "npm.enableScriptExplorer": true, 16 | "npm.exclude": "**/tslint/server/**" 17 | } 18 | } --------------------------------------------------------------------------------