[
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.project\n*.log\n\n# Dependencies\nnode_modules\n\n# Intermediary compilation files\nout\n\n# Deployment files\nlib\n"
  },
  {
    "path": ".npmignore",
    "content": ".npmignore\n/scripts\n/src\n/test\n/dev\n/out/test\n/out/**/*.map\n/images\n/test-data\n/test-workspace\n/documentation\n/e2e\n\ntsconfig.json\ntslint.json\n.travis.yml\n.vscode\n.project\nnode_modules\n*.test.js\n*.js.map"
  },
  {
    "path": ".travis.yml",
    "content": "branches:\r\n  only:\r\n  - master\r\n\r\nlanguage: node_js\r\n\r\nnode_js:\r\n  - '9'\r\n\r\nsudo: false\r\n\r\nmatrix:\r\n  include:\r\n    - os: linux\r\n    - os: mac\r\n    - os: windows\r\n\r\nenv:\r\n  - YARN_GPG=no\r\n  \r\ninstall:\r\n  - npm install \r\n  - (cd e2e ; npm install)\r\n\r\nscript:\r\n  - npm run compile\r\n  - npm run test\r\n  - npm run e2e\r\n  - npm run lint\r\n\r\nafter_failure:\r\n  - cat e2e/server-fixture/server.log\r\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"type\": \"node\",\n            \"request\": \"attach\",\n            \"name\": \"Attach\",\n            \"port\": 9999,\n            \"skipFiles\": [\n                \"<node_internals>/**\"\n            ]\n        }\n    ]\n}"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"typescript.preferences.quoteStyle\": \"single\",\n    \"tslint.configFile\": \"tslint.main.json\"\n}"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## 1.0.2 - March 31, 2022\n- Deprecate package as eslint is now preferred for TypeScript linting.\n- Try ignoring in-memory files which can crash tslint.\n\n## 1.0.1 - December 14, 2020\n- Catch error when resolving global tslint fails. Thanks @nickjs!\n\n## 1.0.0 - November 30, 2020\n- Restricts when tslint is loaded from the workspace. This fix was made in response to [CVE-2020-17150](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2020-17150).\n    - Global TSLint versions can always be loaded.\n    - TSLint versions installed next to the plugin can always be loaded.\n    - Otherwise, the consumer of the plugin must use `onConfigurationChanged` and explicitly enable `allowWorkspaceLibraryExecution`.\n    - You can also force allow workspace versions of TSLint to be loaded by setting a `TS_TSLINT_ENABLE_WORKSPACE_LIBRARY_EXECUTION`  environment variable.\n\n## 0.5.5 - November 11, 2019\n- Restore old cwd after linting finishes.\n\n## 0.5.4 - July 10, 2019\n- Make sure we pass along packageManager from plugin.\n\n## 0.5.3 - June 28, 2019\n- Fixed the disable quick fix not having correct indentation.\n\n## 0.5.2 - June 21, 2019\n- Fixes the config file diagnostic not having `tslint` as its source.\n\n## 0.5.1 - June 21, 2019\n- Fixes `mjs` files being linted by default.\n\n## 0.5.0 - June 10, 2019\n- Add pnpm as `packageManager` option.\n\n## 0.4.0 - May 21, 2019\n- Try to help users better understand why tslint is not enabled by generating warnings if there is a `tslint.json` and the tslint library cannot be found or generates an error.\n\n## 0.3.1 - January 31, 2019\n- Fix the `fix-all` action show up even on non-autofixable errors.\n\n## 0.3.0 - January 21, 2019\n- Set `fixName` on returned actions. Thanks @kondi!\n- Fix TS Lint's fix all quick fix showing up on non-tslint errors.\n- Use `getCombinedQuickFixes` to compute 'fix all of X' errors. \n\n## 0.2.1 - December 14, 2018\n- Fix `ignoreDefinitionFiles` defaulting to false.\n\n## 0.2.0 - December 12, 2018\n- Allowing configuring `excluded` files. Thanks @vemoo!\n- Default `alwaysShowRuleFailuresAsWarnings` to true. Set `\"alwaysShowRuleFailuresAsWarnings\": false` to restore the old behavior.\n- Removing logic for older TS lint versions. Only TSlint5 was ever officially supported but there was still some logic for handling older tslint4.\n- Don't show error in editor if `tslint` can't be found. We still log an error in the TS Server but do not generate an editor warning.\n\n## 0.1.2 - November 28, 2018\n- Always show a disable rule fix for TSLint errors. Thanks @reduckted!\n\n## 0.1.1 - November 27, 2018\n- Fix bug that could cause TS Lint to use a different version of TypeScript than the version being used by the plugin. This would result in unexpected behavior.\n\n## 0.1.0 - November 16, 2018\n- Add support for configuring the plugin from an editor.\n- Correctly observe changes to the `tsconfig`/`jsconfig`.\n- Fix error that could cause duplicate tslint errors to be reported.\n\n## 0.0.7 - November 15, 2018\n- Fix potential state corruption error when using TS 3.2.\n\n## 0.0.6 - November 13, 2018\n- Add `enableJs` option to enable/disable validating js. Default to `false`.\n\n## 0.0.5 - November 5, 2018\n- Use diagnostic as label for quick fixes\n- Enable for js files included in tsconfig.\n\n## 0.0.4 - October 23, 2018\n- Fix spelling of setting name\n\n## 0.0.3 - October 22, 2018\n- Don't call `getProgram` directly since it may corrupt the TS Server state\n- Exclude some files from npm package.\n\n## 0.0.2 - October 19, 2018\n\n- Initial release"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# TypeScript TSLint Language Service Plugin\n\n[![Build Status](https://travis-ci.org/Microsoft/typescript-tslint-plugin.svg?branch=master)](https://travis-ci.org/Microsoft/typescript-tslint-plugin)\n\n> **❗IMPORTANT**: TSLint [has been deprecated](https://medium.com/palantir/tslint-in-2019-1a144c2317a9) in favor of ESLint and this plug-in has also been deprecated in favor of eslint.\n>\n> Please look into [migrating your projects to ESLint](https://github.com/typescript-eslint/typescript-eslint#typescript-eslint).\n\nTypeScript [language service plugin](https://blogs.msdn.microsoft.com/typescript/2017/04/27/announcing-typescript-2-3/) for [TSLint][tslint].\n\nTo use the plugin:\n\n* Install TSLint 5+ in your workspace or globally (if you are using a local TSLint, see [workspace library execution](#workspace-library-execution))\n\n* Install the plugin with `npm install typescript-tslint-plugin` \n\n* Enable the plugin in your `tsconfig.json` file:\n\n    ```json\n    {\n      \"compilerOptions\": {\n        \"plugins\": [\n          { \"name\": \"typescript-tslint-plugin\" }\n        ]\n      }\n    }\n    ```\n\nSee [editor support](#editor-support) for more detailed setup instructions.\n\n## Workspace Library Execution\n\nBy default this plugin will not load TSLint or custom rules from the workspace if you are using a global version of TypeScript. This is done for security reasons. The plugin always allows using the global version of TSLint.\n\nTo use enable using a local TSLint install and custom rules from the workspace, you must either:\n\n- Use a workspace version of TypeScript that is installed alongside TSLint.\n\n- Enable workspace library execution in your editor of choice. This must be done through an editor and cannot be configured in a `tsconfig`.\n\n    In VS Code for example, you can run the `TSLint: Manage Workspace Library Execution` command to enable using the TSLint for the current workspace or for all workspaces.\n\n- Set a `TS_TSLINT_ENABLE_WORKSPACE_LIBRARY_EXECUTION=1` environment variable and make sure the TypeScript server is run in an environment where this variable is set to true.\n\n## Configuration options\n\n**Notice**: This configuration settings allow you to configure the behavior of the typescript-tslint-plugin itself. To configure rules and tslint options you should use the `tslint.json` file.\n\n * `configFile` - The configuration file that tslint should use instead of the default tslint.json. A relative file path is resolved relative to the project root.\n * `jsEnable` - Enable/disable tslint for `.js` files, default is `false`.\n * `ignoreDefinitionFiles` - Control if TypeScript definition files should be ignored. Default is `true`\n * `alwaysShowRuleFailuresAsWarnings` - Always show rule failures as warnings, ignoring the severity configuration in the tslint.json configuration. Default is `true`.\n * `suppressWhileTypeErrorsPresent` - Suppress tslint errors from being reported while other errors are present.\n * `exclude` - List of files to exclude from tslint.\n * `packageManager` - Package manager used, either: `npm`, `yarn`, or `pnpm`. This is currently only used for error message instructions about how to install tslint. Default is `npm`.\n \nHere is a configuration sample:\n\n```json\n{\n  \"compilerOptions\": {\n    \"plugins\": [\n      {\n        \"name\": \"typescript-tslint-plugin\",\n        \"alwaysShowRuleFailuresAsWarnings\": false,\n        \"ignoreDefinitionFiles\": true,\n        \"configFile\": \"../tslint.json\",\n        \"suppressWhileTypeErrorsPresent\": false\n      }\n    ]\n  }\n}\n```\n\n**Notice**: due to an issue in the implementation of the `no-unused-variable` rule ([palantir/tslint#2469](https://github.com/palantir/tslint/issues/2649)), this rule will be disabled by the plugin. You can use the typescript compiler options `noUnusedLocals` and `noUnusedParameters` instead. \n\n\n# Editor Support\nThis plugin requires TypeScript 3.0 or later. It can provide intellisense in both JavaScript and TypeScript files within any editors that uses TypeScript to power their language features.\n\n## With VS Code\n*If you also have the [vscode-tslint](https://marketplace.visualstudio.com/items?itemName=eg2.tslint) extension in VS Code installed, please disable it to avoid that files are linted twice.*\n\nThe simplest way to use this plugin is to install the [TypeScript TSLint Plugin VS Code extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-typescript-tslint-plugin). This extension enables the plugin when using VS Code's version of TypeScript.\n\nIf you are using a workspace version of TypeScript, you must manually install the plugin alongside the version of TypeScript in your workspace:\n\n```bash\nnpm install --save-dev typescript-tslint-plugin typescript\n```\n\nThen add a `plugins` section to your [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) or [`jsconfig.json`](https://code.visualstudio.com/Docs/languages/javascript#_javascript-project-jsconfigjson)\n\n```json\n{\n  \"compilerOptions\": {\n    \"plugins\": [\n      {\n        \"name\": \"typescript-tslint-plugin\"\n      }\n    ]\n  }\n}\n```\n\nFinally, run the `Select TypeScript version` command in VS Code to switch to use the workspace version of TypeScript for VS Code's JavaScript and TypeScript language support. You can find more information about managing typescript versions [in the VS Code documentation](https://code.visualstudio.com/Docs/languages/typescript#_using-newer-typescript-versions).\n\n![Usage with VS Code](documentation/example-vscode.png)\n\nThe most important differences between the `vscode-tslint` extension and `typescript-tslint-plugin` are:\n\n* The plugin shares the program representation with TypeScript. This is more efficient than the `vscode-tslint` extension which needs \n  to reanalyze the document.\n* Since `vscode-tslint` lints one file a time only, it cannot support tslint rules that require the type checker. The plugin doesn't have this limitation.\n* `vscode-tslint` provides additional [features](https://marketplace.visualstudio.com/items?itemName=eg2.tslint), please file issue requests for the features you are missing.\n\n\n### With Atom\nThis plugin works with the [Atom TypeScript plugin](https://atom.io/packages/atom-typescript).\n\nFirst install the plugin and a copy of TypeScript in your workspace:\n\n```bash\nnpm install --save-dev typescript-tslint-plugin typescript\n```\n\nThen add a `plugins` section to your [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) or [`jsconfig.json`](https://code.visualstudio.com/Docs/languages/javascript#_javascript-project-jsconfigjson) and restart Atom.\n\n```json\n{\n  \"compilerOptions\": {\n    \"plugins\": [\n      {\n        \"name\": \"typescript-tslint-plugin\"\n      }\n    ]\n  }\n}\n```\n\n![Usage with atom](documentation/example-atom.png)\n\n\n### With Sublime\nThis plugin works with the [Sublime TypeScript plugin](https://github.com/Microsoft/TypeScript-Sublime-Plugin).\n\nFirst install the plugin and a copy of TypeScript in your workspace:\n\n```bash\nnpm install --save-dev typescript-tslint-plugin typescript\n```\n\nAnd configure Sublime to use the workspace version of TypeScript by [setting the `typescript_tsdk`](https://github.com/Microsoft/TypeScript-Sublime-Plugin#note-using-different-versions-of-typescript) setting in Sublime:\n\n```json\n{\n  \"typescript_tsdk\": \"/Users/me/my-amazing-project/node_modules/typescript/lib\"\n}\n```\n\nFinally add a `plugins` section to your [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) or [`jsconfig.json`](https://code.visualstudio.com/Docs/languages/javascript#_javascript-project-jsconfigjson) and restart Sublime.\n\n```json\n{\n  \"compilerOptions\": {\n    \"plugins\": [\n      {\n        \"name\": \"typescript-tslint-plugin\"\n      }\n    ]\n  }\n}\n```\n\n![Usage with Sublime](documentation/example-sublime.png)\n\n### With Visual Studio\nThis plugin works [Visual Studio 2017](https://www.visualstudio.com) using the TypeScript 2.5+ SDK.\n\nFirst install the plugin in your project:\n\n```bash\nnpm install --save-dev typescript-tslint-plugin\n```\n\nThen add a `plugins` section to your [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html).\n\n```json\n{\n  \"compilerOptions\": {\n    \"plugins\": [\n      {\n        \"name\": \"typescript-tslint-plugin\"\n      }\n    ]\n  }\n}\n```\n\nThen reload your project to make sure the plugin has been loaded properly. Note that `jsconfig.json` projects are currently not supported in Visual Studio.\n\n### With vim and neovim\n\nUse [coc-tslint-plugin](https://github.com/neoclide/coc-tslint-plugin) as extension of [coc.nvim](https://github.com/neoclide/coc.nvim).\n\nRun command in your vim after coc.nvim installed:\n\n```\n:CocInstall coc-tsserver coc-tslint-plugin\n```\n\nRun command `:CocConfig` to open configuration file.\n\n# Contributing\nTo build the typescript-tslint-plugin, you'll need [Git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/).\n\nFirst, [fork](https://help.github.com/articles/fork-a-repo/) the typescript-tslint-plugin repo and clone your fork:\n\n```bash\ngit clone https://github.com/YOUR_GITHUB_ACCOUNT_NAME/typescript-tslint-plugin.git\ncd typescript-tslint-plugin\n```\n\nThen install dev dependencies:\n\n```bash\nnpm install\n```\n\nThe plugin is written in [TypeScript](http://www.typescriptlang.org). The source code is in the `src/` directory with the compiled JavaScript output to the `lib/` directory. Kick off a build using the `compile` script:\n\n```bash\nnpm run compile\n```\n\nPlease also see our [Code of Conduct](CODE_OF_CONDUCT.md).\n\n## VS Code\n\nTo test the newly compiled program, open the `test-workspace` folder in VS Code and use the TypeScript version picker to [switch to the local version of TypeScript](https://code.visualstudio.com/Docs/languages/typescript#_using-newer-typescript-versions).\n\nTo debug you use two versions of VS Code, e.g., the stable and the insider version. The idea is that one of them is configured to support attaching a debugger to the Typescript language server:\n\n- Use the insider version for development and open it on the typescript-tslint-plugin workspace.\n- Use the stable version for debugging opened on the `test-workspace` folder of the tslint-language service.\n\nTo setup the stable version for debugging, you need to set the environment variable `TSS_DEBUG` to port 5859. In a command prompt/shell:\n\n- make sure that the stable version isn't running already\n- `set TSS_DEBUG=5859`\n- cd to the `dev` folder\n- `code .`\n\nTo debug the plugin press `F5`. The `dev` workspace has a launch configuration that attaches through port 5859 to the language server. \n\n# Credits\n\nThis project was forked from  https://github.com/angelozerr/tslint-language-service which itself is based on https://github.com/Microsoft/vscode-tslint/\n\n\n[tslint]: https://github.com/palantir/tslint\n"
  },
  {
    "path": "e2e/package.json",
    "content": "{\n  \"name\": \"e2e\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"directories\": {\n    \"test\": \"tests\"\n  },\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"typescript\": \"3.1.3\",\n    \"typescript-tslint-plugin\": \"file:./..\"\n  }\n}\n"
  },
  {
    "path": "e2e/project-fixture/.vscode/settings.json",
    "content": "{\n    \"typescript.tsdk\": \"node_modules/typescript/lib\"\n}"
  },
  {
    "path": "e2e/project-fixture/main.ts",
    "content": ""
  },
  {
    "path": "e2e/project-fixture/tsconfig.json",
    "content": "{\r\n    \"compilerOptions\": {\r\n        \"plugins\": [\r\n            {\r\n                \"name\": \"typescript-tslint-plugin\",\r\n                \"alwaysShowRuleFailuresAsWarnings\": false,\r\n                \"ignoreDefinitionFiles\": true\r\n                //\"configFile\": \"../tslint.json\",\r\n            }\r\n        ],\r\n        \"module\": \"commonjs\",\r\n        \"target\": \"es6\",\r\n        \"allowJs\": true,\r\n        \"noImplicitAny\": false,\r\n        \"sourceMap\": false,\r\n        \"noEmit\": true\r\n    }\r\n}"
  },
  {
    "path": "e2e/project-fixture/tslint.json",
    "content": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ],\n        \"no-unused-expression\": true,\n        \"arrow-parens\": true,\n        \"no-var-keyword\": true,\n        \"no-unused-variable\": [\n            true,\n            {\n                \"ignore-pattern\": \"^_\"\n            }\n        ],\n        \"ordered-imports\": [\n            true,\n            {\n                \"import-sources-order\": \"lowercase-last\",\n                \"named-imports-order\": \"lowercase-first\"\n            }\n        ],\n        \"trailing-comma\": [\n            true,\n            {\n                \"multiline\": \"always\",\n                \"singleline\": \"never\"\n            }\n        ],\n        \"class-name\": true,\n        \"comment-format\": [\n            true,\n            \"check-space\"\n        ],\n        \"indent\": [\n            true,\n            \"spaces\"\n        ],\n        \"no-eval\": true,\n        \"no-internal-module\": true,\n        \"no-trailing-whitespace\": true,\n        \"no-unsafe-finally\": true,\n        \"one-line\": [\n            true,\n            \"check-open-brace\",\n            \"check-whitespace\"\n        ],\n        \"quotemark\": [\n            true,\n            \"double\"\n        ],\n        \"semicolon\": [\n            true,\n            \"always\"\n        ],\n        \"triple-equals\": [\n            true,\n            \"allow-null-check\"\n        ],\n        \"typedef-whitespace\": [\n            true,\n            {\n                \"call-signature\": \"nospace\",\n                \"index-signature\": \"nospace\",\n                \"parameter\": \"nospace\",\n                \"property-declaration\": \"nospace\",\n                \"variable-declaration\": \"nospace\"\n            }\n        ],\n        \"variable-name\": [\n            true,\n            \"ban-keywords\"\n        ],\n        \"whitespace\": [\n            true,\n            \"check-branch\",\n            \"check-decl\",\n            \"check-operator\",\n            \"check-separator\",\n            \"check-type\"\n        ]\n    },\n    \"jsRules\": {\n        \"triple-equals\": [\n            true,\n            \"allow-null-check\"\n        ],\n        \"arrow-parens\": true\n    },\n    \"defaultSeverity\": \"warning\"\n}"
  },
  {
    "path": "e2e/server-fixture/index.js",
    "content": "const { fork } = require('child_process');\nconst path = require('path');\nconst readline = require('readline');\n\nclass TSServer {\n    constructor(project) {\n        const logfile = path.join(__dirname, 'server.log');\n        const tsserverPath = path.join(__dirname, '..', 'node_modules', 'typescript', 'lib', 'tsserver');\n        const server = fork(tsserverPath, [\n            '--logVerbosity', 'verbose',\n            '--logFile', logfile,\n            '--pluginProbeLocations', path.join(__dirname, '..')\n        ], {\n                cwd: path.join(__dirname, '..', project),\n                stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n            });\n        this._exitPromise = new Promise((resolve, reject) => {\n            server.on('exit', code => resolve(code));\n            server.on('error', reason => reject(reason));\n        });\n        server.stdout.setEncoding('utf-8');\n        readline.createInterface({\n            input: server.stdout\n        }).on('line', line => {\n            if (line[0] !== '{') {\n                return;\n            }\n            try {\n                const result = JSON.parse(line);\n                if (result.type === 'response') {\n                    this.responses.push(result);\n                    --this._pendingResponses;\n\n                    if (this._pendingResponses <= 0 && this._isClosed) {\n                        this._shutdown();\n                    }\n                }\n            } catch (e) {\n                // noop\n            }\n\n        });\n\n        this._isClosed = false;\n        this._server = server;\n        this._seq = 0;\n        this.responses = [];\n        this._pendingResponses = 0;\n    }\n\n    send(command, responseExpected) {\n        if (this._isClosed) {\n            throw new Error('server is closed');\n        }\n        if (responseExpected) {\n            ++this._pendingResponses;\n        }\n        const seq = ++this._seq;\n        const req = JSON.stringify(Object.assign({ seq: seq, type: 'request' }, command)) + '\\n';\n        this._server.stdin.write(req);\n    }\n\n    sendCommand(name, args) {\n        this.send({ command: name, arguments: args }, true);\n    }\n\n    close() {\n        if (!this._isClosed) {\n            this._isClosed = true;\n            if (this._pendingResponses <= 0) {\n                this._shutdown();\n            }\n        }\n        return this._exitPromise;\n    }\n\n    _shutdown() {\n        this._server.stdin.end();\n    }\n}\n\nfunction createServer(project) {\n    return new TSServer(project || 'project-fixture');\n}\n\nmodule.exports = createServer;\n"
  },
  {
    "path": "e2e/tests/assert.js",
    "content": "// @ts-check\n\nconst assert = require('chai').assert;\n\n/**\n * @param {{ start: { line: number, offset: number }, end: { line: number, offset: number }}} span\n * @param {{ line: number, offset: number }} start\n * @param {{ line: number, offset: number }} end\n */\nfunction assertSpan(span, start, end) {\n    assertPosition(span.start, start.line, start.offset);\n    assertPosition(span.end, end.line, end.offset);\n};\n\n/**\n * @param {{ line: number, offset: number }} pos\n * @param {number} line \n * @param {number} offset\n */\nfunction assertPosition(pos, line, offset) {\n    assert.strictEqual(pos.line, line);\n    assert.strictEqual(pos.offset, offset);\n};\n\nmodule.exports = {\n    assertPosition,\n    assertSpan\n};"
  },
  {
    "path": "e2e/tests/codeFixes.test.js",
    "content": "// @ts-check\nconst { assertSpan } = require('./assert');\nconst assert = require('chai').assert;\nconst path = require('path');\nconst createServer = require('../server-fixture');\nconst { openMockFile, getFirstResponseOfType } = require('./helpers');\n\n\nconst mockFileName = path.join(__dirname, '..', 'project-fixture', 'main.ts').replace(/\\\\/g, '/');\n\n/**\n * @param {string[]} fileContents \n */\nfunction createServerForFile(...fileContents) {\n    const server = createServer();\n    openMockFile(server, mockFileName, fileContents.join('\\n'));\n    return server;\n}\n\n/**\n * @param {*} server \n * @param {{ startLine: number, startOffset: number, endLine: number, endOffset: number, additionalErrorCodes?: number[] }} data\n */\nconst getCodeFixes = async (server, data) => {\n\n    // Generate diagnostics \n    server.sendCommand('semanticDiagnosticsSync', { file: mockFileName });\n\n    return server.sendCommand('getCodeFixes', {\n        file: mockFileName,\n        startLine: data.startLine,\n        startOffset: data.startOffset,\n        endLine: data.endLine,\n        endOffset: data.endOffset,\n        errorCodes: [1, ...(data.additionalErrorCodes || [])]\n    });\n};\n\nconst getCombinedCodeFixes = (server, fixId) => {\n    return server.sendCommand('getCombinedCodeFix', {\n        scope: {\n            type: 'file',\n            args: { file: mockFileName }\n        },\n        fixId: fixId,\n    });\n};\n\ndescribe('CodeFixes', () => {\n    let server = undefined;\n\n    after(() => {\n        if (server) {\n            server.close();\n            server = undefined;\n        }\n    })\n\n    it('should return fix and disables for single error', async () => {\n        server = createServerForFile(\n            `let t: Array<string> = new Array<string>(); console.log(t);`\n        );\n        await getCodeFixes(server, {\n            startLine: 1,\n            startOffset: 8,\n            endLine: 1,\n            endOffset: 21,\n        });\n        await server.close();\n        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);\n\n        assert.isTrue(codeFixesResponse.success);\n        assert.deepEqual(codeFixesResponse.body, [\n            {\n                \"fixName\": \"tslint:array-type\",\n                \"description\": \"Fix: Array type using 'Array<T>' is forbidden for simple types. Use 'T[]' instead.\",\n                \"changes\": [\n                    {\n                        \"fileName\": mockFileName,\n                        \"textChanges\": [\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 8\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 14\n                                },\n                                \"newText\": \"\"\n                            },\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 20\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 21\n                                },\n                                \"newText\": \"[]\"\n                            }\n                        ]\n                    }\n                ]\n            },\n            {\n                \"fixName\": \"tslint:fix-all\",\n                \"description\": \"Fix all auto-fixable tslint failures\",\n                \"changes\": [\n                    {\n                        \"fileName\": mockFileName,\n                        \"textChanges\": [\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 8\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 14\n                                },\n                                \"newText\": \"\"\n                            },\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 20\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 21\n                                },\n                                \"newText\": \"[]\"\n                            }\n                        ]\n                    }\n                ]\n            },\n            {\n                \"fixName\": \"tslint:disable:array-type\",\n                \"description\": \"Disable rule 'array-type'\",\n                \"changes\": [\n                    {\n                        \"fileName\": mockFileName,\n                        \"textChanges\": [\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 1\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 1\n                                },\n                                \"newText\": \"// tslint:disable-next-line: array-type\\n\"\n                            }\n                        ]\n                    }\n                ]\n            }\n        ]);\n    });\n\n    it('should return individual fixes and fix all for multiple errors of same type in file', async () => {\n        server = createServerForFile(\n            `let x: Array<string> = new Array<string>(); console.log(x);\\nlet y: Array<string> = new Array<string>(); console.log(y);`,\n        );\n        await getCodeFixes(server, {\n            startLine: 1,\n            startOffset: 8,\n            endLine: 1,\n            endOffset: 21,\n        });\n        await getCombinedCodeFixes(server, 'tslint:array-type');\n\n        await server.close();\n\n        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);\n        const combinedFixesResponse = await getFirstResponseOfType('getCombinedCodeFix', server);\n\n        assert.isTrue(codeFixesResponse.success);\n        assert.strictEqual(codeFixesResponse.body.length, 3);\n\n        assert.deepEqual(codeFixesResponse.body, [\n            {\n                \"fixName\": \"tslint:array-type\",\n                \"description\": \"Fix: Array type using 'Array<T>' is forbidden for simple types. Use 'T[]' instead.\",\n                \"fixAllDescription\": \"Fix all 'array-type'\",\n                \"fixId\": \"tslint:array-type\",\n                \"changes\": [\n                    {\n                        \"fileName\": mockFileName,\n                        \"textChanges\": [\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 8\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 14\n                                },\n                                \"newText\": \"\"\n                            },\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 20\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 21\n                                },\n                                \"newText\": \"[]\"\n                            }\n                        ]\n                    }\n                ]\n            },\n            {\n                \"fixName\": \"tslint:fix-all\",\n                \"description\": \"Fix all auto-fixable tslint failures\",\n                \"changes\": [\n                    {\n                        \"fileName\": mockFileName,\n                        \"textChanges\": [\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 8\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 14\n                                },\n                                \"newText\": \"\"\n                            },\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 20\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 21\n                                },\n                                \"newText\": \"[]\"\n                            },\n                            {\n                                \"start\": {\n                                    \"line\": 2,\n                                    \"offset\": 8\n                                },\n                                \"end\": {\n                                    \"line\": 2,\n                                    \"offset\": 14\n                                },\n                                \"newText\": \"\"\n                            },\n                            {\n                                \"start\": {\n                                    \"line\": 2,\n                                    \"offset\": 20\n                                },\n                                \"end\": {\n                                    \"line\": 2,\n                                    \"offset\": 21\n                                },\n                                \"newText\": \"[]\"\n                            }\n                        ]\n                    }\n                ]\n            },\n            {\n                \"fixName\": \"tslint:disable:array-type\",\n                \"description\": \"Disable rule 'array-type'\",\n                \"changes\": [\n                    {\n                        \"fileName\": mockFileName,\n                        \"textChanges\": [\n                            {\n                                \"start\": {\n                                    \"line\": 1,\n                                    \"offset\": 1\n                                },\n                                \"end\": {\n                                    \"line\": 1,\n                                    \"offset\": 1\n                                },\n                                \"newText\": \"// tslint:disable-next-line: array-type\\n\"\n                            }\n                        ]\n                    }\n                ]\n            }\n        ]);\n\n        assert.isTrue(combinedFixesResponse.success);\n        assert.deepEqual(combinedFixesResponse.body, {\n            \"changes\": [\n                {\n                    \"fileName\": mockFileName,\n                    \"textChanges\": [\n                        {\n                            \"start\": {\n                                \"line\": 1,\n                                \"offset\": 8\n                            },\n                            \"end\": {\n                                \"line\": 1,\n                                \"offset\": 14\n                            },\n                            \"newText\": \"\"\n                        },\n                        {\n                            \"start\": {\n                                \"line\": 1,\n                                \"offset\": 20\n                            },\n                            \"end\": {\n                                \"line\": 1,\n                                \"offset\": 21\n                            },\n                            \"newText\": \"[]\"\n                        }\n                    ]\n                },\n                {\n                    \"fileName\": mockFileName,\n                    \"textChanges\": [\n                        {\n                            \"start\": {\n                                \"line\": 2,\n                                \"offset\": 8\n                            },\n                            \"end\": {\n                                \"line\": 2,\n                                \"offset\": 14\n                            },\n                            \"newText\": \"\"\n                        },\n                        {\n                            \"start\": {\n                                \"line\": 2,\n                                \"offset\": 20\n                            },\n                            \"end\": {\n                                \"line\": 2,\n                                \"offset\": 21\n                            },\n                            \"newText\": \"[]\"\n                        }\n                    ]\n                }\n            ]\n        });\n    });\n\n    it('should not return ts-lint fixes on non-tslint errors', async () => {\n        server = createServerForFile(\n            `const a = 1; a = 2`\n        );\n        await getCodeFixes(server, {\n            startLine: 1,\n            startOffset: 13,\n            endLine: 1,\n            endOffset: 14,\n        });\n        await server.close();\n        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);\n\n        assert.isTrue(codeFixesResponse.success);\n        assert.deepEqual(codeFixesResponse.body, []);\n    });\n\n    it('should not return TS Lint fix-all for non-fixable errors', async () => {\n        server = createServerForFile(\n            `const foo = 123; food`\n        );\n        await getCodeFixes(server, {\n            startLine: 1,\n            startOffset: 18,\n            endLine: 1,\n            endOffset: 22,\n            additionalErrorCodes: [2552]\n        });\n        await server.close();\n        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);\n\n        assert.isTrue(codeFixesResponse.success);\n        assert.deepEqual(codeFixesResponse.body.length, 2);\n        assert.deepEqual(codeFixesResponse.body[0].fixName, 'spelling');\n        assert.deepEqual(codeFixesResponse.body[1].fixName, 'tslint:disable:no-unused-expression');\n    });\n\n    it('disable comment should be correctly indented', async () => {\n        server = createServerForFile(\n            '{',\n            '    const a = 1',\n            '}'\n        );\n        await getCodeFixes(server, {\n            startLine: 2,\n            startOffset: 16,\n            endLine: 2,\n            endOffset: 16,\n            additionalErrorCodes: [2552]\n        });\n        await server.close();\n        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);\n\n        assert.isTrue(codeFixesResponse.success);\n        assert.deepEqual(codeFixesResponse.body.length, 3);\n        const disableFix = codeFixesResponse.body[2];\n        const change = disableFix.changes[0].textChanges[0];\n        assert.strictEqual(change.start.line, 2);\n        assert.strictEqual(change.start.offset, 1);\n        assert.strictEqual(change.newText, '    // tslint:disable-next-line: semicolon\\n');\n    });\n});\n"
  },
  {
    "path": "e2e/tests/errors.test.js",
    "content": "// @ts-check\nconst { assertSpan } = require('./assert');\nconst assert = require('chai').assert;\nconst path = require('path');\nconst createServer = require('../server-fixture');\nconst { openMockFile, getFirstResponseOfType } = require('./helpers');\n\nconst tslintSource = 'tslint';\n\nconst mockFileName = path.join(__dirname, '..', 'project-fixture', 'main.ts');\n\nconst getSemanticDiagnosticsForFile = (fileContents) => {\n    const server = createServer();\n    openMockFile(server, mockFileName, fileContents);\n    server.sendCommand('semanticDiagnosticsSync', { file: mockFileName });\n\n    return server.close().then(_ => {\n        return getFirstResponseOfType('semanticDiagnosticsSync', server);\n    });\n}\n\ndescribe('Errors', () => {\n    it('array-type', async () => {\n        const errorResponse = await getSemanticDiagnosticsForFile(\n            `let t: Array<string> = new Array<string>(); console.log(t);`);\n\n        assert.isTrue(errorResponse.success);\n        assert.strictEqual(errorResponse.body.length, 1);\n\n        const [error1] = errorResponse.body;\n        assert.strictEqual(error1.source, tslintSource);\n        assertSpan(error1, { line: 1, offset: 8 }, { line: 1, offset: 21 });\n        assert.strictEqual(error1.text, `Array type using 'Array<T>' is forbidden for simple types. Use 'T[]' instead. (array-type)`);\n    });\n\n    it('arrow-parens', async () => {\n        const errorResponse = await getSemanticDiagnosticsForFile(\n            `[1, 2 ].map( num => console.log(num) );`);\n\n        assert.isTrue(errorResponse.success);\n        assert.strictEqual(errorResponse.body.length, 1);\n\n        const [error1] = errorResponse.body;\n        assert.strictEqual(error1.source, tslintSource);\n        assertSpan(error1, { line: 1, offset: 14 }, { line: 1, offset: 17 });\n        assert.strictEqual(error1.text, `Parentheses are required around the parameters of an arrow function definition (arrow-parens)`);\n    });\n});\n"
  },
  {
    "path": "e2e/tests/helpers.js",
    "content": "const assert = require('chai').assert;\n\nexports.openMockFile = (server, mockFileName, fileContent) => {\n    server.send({\n        command: 'open',\n        arguments: {\n            file: mockFileName,\n            fileContent,\n            scriptKindName: 'TS'\n        }\n    });\n    return server;\n};\n\n\nexports.getFirstResponseOfType = (command, server) => {\n    const response = server.responses.find(response => response.command === command);\n    assert.isTrue(response !== undefined);\n    return response;\n};\n\nexports.getResponsesOfType = (command, server) => {\n    return server.responses.filter(response => response.command === command);\n};"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"typescript-tslint-plugin\",\n  \"version\": \"1.0.2\",\n  \"description\": \"TypeScript tslint language service plugin\",\n  \"main\": \"out/index.js\",\n  \"author\": \"Microsoft\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/microsoft/typescript-tslint-plugin.git\"\n  },\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"compile\": \"tsc\",\n    \"test\": \"TS_TSLINT_ENABLE_WORKSPACE_LIBRARY_EXECUTION=1 mocha ./out/**/*.test.js --slow 2000 --timeout 10000\",\n    \"lint\": \"tslint -c tslint.main.json 'src/**/*.ts'\",\n    \"e2e\": \"TS_TSLINT_ENABLE_WORKSPACE_LIBRARY_EXECUTION=1 mocha ./e2e/tests/**/*.test.js --slow 2000 --timeout 10000\"\n  },\n  \"dependencies\": {\n    \"minimatch\": \"^3.0.4\",\n    \"mock-require\": \"^3.0.3\",\n    \"vscode-languageserver\": \"^5.2.1\"\n  },\n  \"devDependencies\": {\n    \"@types/chai\": \"^4.1.6\",\n    \"@types/minimatch\": \"^3.0.3\",\n    \"@types/mocha\": \"^8.2.0\",\n    \"@types/mock-require\": \"^2.0.0\",\n    \"@types/node\": \"^12.12.0\",\n    \"chai\": \"^4.2.0\",\n    \"mocha\": \"^9.2.2\",\n    \"tslint\": \"^6.1.3\",\n    \"typescript\": \"^4.0.0\"\n  }\n}\n"
  },
  {
    "path": "src/config.ts",
    "content": "export const pluginId = 'typescript-tslint-plugin';\nexport const TSLINT_ERROR_CODE = 1;\nexport const TSLINT_ERROR_SOURCE = 'tslint';"
  },
  {
    "path": "src/configFileWatcher.ts",
    "content": "import * as ts_module from 'typescript/lib/tsserverlibrary';\n\nexport class ConfigFileWatcher {\n    private readonly _watchedConfigs = new Set<string>();\n\n    public constructor(\n        private readonly ts: typeof ts_module,\n        private readonly onChange: (fileName: string) => void\n    ) { }\n\n    public ensureWatching(file: string) {\n        if (!this.ts.sys.watchFile) {\n            return;\n        }\n        if (this._watchedConfigs.has(file)) {\n            return;\n        }\n        this._watchedConfigs.add(file);\n        this.ts.sys.watchFile(file, (fileName: string, eventKind: ts.FileWatcherEventKind) => {\n            if (eventKind === this.ts.FileWatcherEventKind.Changed) {\n                this.onChange(fileName);\n            }\n        });\n    }\n}"
  },
  {
    "path": "src/index.ts",
    "content": "import { TSLintPlugin } from './plugin';\nimport * as ts_module from 'typescript/lib/tsserverlibrary';\nimport { Logger } from './logger';\nimport { ConfigurationManager } from './settings';\nimport * as mockRequire from 'mock-require';\nimport { WorkspaceLibraryExecution } from './runner';\n\nconst enableWorkspaceLibraryExecutionEnvVar = 'TS_TSLINT_ENABLE_WORKSPACE_LIBRARY_EXECUTION';\n\nexport = function init({ typescript }: { typescript: typeof ts_module }) {\n    const configManager = new ConfigurationManager(typescript);\n    let logger: Logger | undefined;\n    let plugin: TSLintPlugin | undefined;\n\n    // Make sure TS Lint imports the correct version of TS\n    mockRequire('typescript', typescript);\n\n    return {\n        create(info: ts.server.PluginCreateInfo) {\n            logger = Logger.forPlugin(info);\n            logger.info('Create');\n\n            configManager.setProject(info.project, logger);\n            configManager.updateFromPluginConfig(info.config);\n\n            if (!isValidTypeScriptVersion(typescript)) {\n                logger.info('Invalid typescript version detected. The TSLint plugin requires TypeScript 3.x');\n                return info.languageService;\n            }\n\n            plugin = new TSLintPlugin(typescript, info.languageServiceHost, logger, info.project, configManager);\n\n            // Allow clients that don't use onConfigurationChanged to still securely enable\n            // workspace library execution with an env var.\n            const workspaceLibraryFromEnv = process.env[enableWorkspaceLibraryExecutionEnvVar] ? WorkspaceLibraryExecution.Allow : WorkspaceLibraryExecution.Unknown;\n            plugin.updateWorkspaceTrust(workspaceLibraryFromEnv);\n\n            return plugin.decorate(info.languageService);\n        },\n        onConfigurationChanged(config: any) {\n            if (logger) {\n                logger.info('onConfigurationChanged');\n            }\n\n            if (plugin) {\n                if ('allowWorkspaceLibraryExecution' in config) {\n                    plugin.updateWorkspaceTrust(config.allowWorkspaceLibraryExecution ? WorkspaceLibraryExecution.Allow : WorkspaceLibraryExecution.Disallow);\n                }\n            }\n\n            configManager.updateFromPluginConfig(config);\n        },\n    };\n};\n\nfunction isValidTypeScriptVersion(typescript: typeof ts_module): boolean {\n    const [major] = typescript.version.split('.');\n    return +major >= 3;\n}\n"
  },
  {
    "path": "src/logger.ts",
    "content": "import * as ts_module from 'typescript/lib/tsserverlibrary';\n\nimport { pluginId } from './config';\n\nexport class Logger {\n    public static forPlugin(info: ts_module.server.PluginCreateInfo) {\n        return new Logger(info.project.projectService.logger);\n    }\n\n    private constructor(\n        private readonly _logger: ts_module.server.Logger\n    ) { }\n\n    public info(message: string) {\n        this._logger.info(`[${pluginId}] ${JSON.stringify(message)}`);\n    }\n}"
  },
  {
    "path": "src/plugin.ts",
    "content": "import * as tslint from 'tslint';\nimport * as path from 'path';\nimport * as ts_module from 'typescript/lib/tsserverlibrary';\nimport { TSLINT_ERROR_CODE, TSLINT_ERROR_SOURCE } from './config';\nimport { ConfigFileWatcher } from './configFileWatcher';\nimport { Logger } from './logger';\nimport { RunResult, TsLintRunner, toPackageManager, WorkspaceLibraryExecution } from './runner';\nimport { ConfigurationManager } from './settings';\nimport { getNonOverlappingReplacements, filterProblemsForFile, getReplacements } from './runner/failures';\n\nconst isTsLintLanguageServiceMarker = Symbol('__isTsLintLanguageServiceMarker__');\n\ninterface Problem {\n    failure: tslint.RuleFailure;\n    fixable: boolean;\n}\n\nclass TsLintFixId {\n    public static fromFailure(failure: tslint.RuleFailure) {\n        return `tslint:${failure.getRuleName()}`;\n    }\n\n    public static toRuleName(fixId: {}): undefined | string {\n        if (typeof fixId !== 'string' || !fixId.startsWith('tslint:')) {\n            return undefined;\n        }\n        return fixId.replace(/^tslint:/, '');\n    }\n}\n\nclass ProblemMap {\n    private readonly _map = new Map<string, Problem>();\n\n    public get(start: number, end: number) {\n        return this._map.get(this.key(start, end));\n    }\n\n    public set(start: number, end: number, problem: Problem): void {\n        this._map.set(this.key(start, end), problem);\n    }\n\n    public values() {\n        return this._map.values();\n    }\n\n    // key to identify a rule failure\n    private key(start: number, end: number): string {\n        return `[${start},${end}]`;\n    }\n}\n\nexport class TSLintPlugin {\n    private readonly codeFixActions = new Map<string, ProblemMap>();\n    private readonly configFileWatcher: ConfigFileWatcher;\n\n    private runner: TsLintRunner;\n\n    private workspaceTrust = WorkspaceLibraryExecution.Unknown;\n\n    public constructor(\n        private readonly ts: typeof ts_module,\n        private readonly languageServiceHost: ts_module.LanguageServiceHost,\n        private readonly logger: Logger,\n        private readonly project: ts_module.server.Project,\n        private readonly configurationManager: ConfigurationManager,\n    ) {\n        this.logger.info('loaded');\n\n        this.runner = new TsLintRunner(message => { this.logger.info(message); });\n\n        this.configFileWatcher = new ConfigFileWatcher(ts, filePath => {\n            this.logger.info('TSlint file changed');\n            this.runner.onConfigFileChange(filePath);\n            this.project.refreshDiagnostics();\n        });\n\n        this.configurationManager.onUpdatedConfig(() => {\n            this.logger.info('TSConfig configuration changed');\n            project.refreshDiagnostics();\n        });\n    }\n\n    public decorate(languageService: ts.LanguageService) {\n        if ((languageService as any)[isTsLintLanguageServiceMarker]) {\n            // Already decorated\n            return;\n        }\n\n        const oldGetSupportedCodeFixes = this.ts.getSupportedCodeFixes.bind(this.ts);\n        this.ts.getSupportedCodeFixes = (): string[] => {\n            return [\n                ...oldGetSupportedCodeFixes(),\n                '' + TSLINT_ERROR_CODE,\n            ];\n        };\n\n        const intercept: Partial<ts.LanguageService> = Object.create(null);\n\n        const oldGetSemanticDiagnostics = languageService.getSemanticDiagnostics.bind(languageService);\n        intercept.getSemanticDiagnostics = (...args) => {\n            return this.getSemanticDiagnostics(oldGetSemanticDiagnostics, ...args);\n        };\n\n        const oldGetCodeFixesAtPosition = languageService.getCodeFixesAtPosition.bind(languageService);\n        intercept.getCodeFixesAtPosition = (...args): ReadonlyArray<ts.CodeFixAction> => {\n            return this.getCodeFixesAtPosition(oldGetCodeFixesAtPosition, ...args);\n        };\n\n        const oldGetCombinedCodeFix = languageService.getCombinedCodeFix.bind(languageService);\n        intercept.getCombinedCodeFix = (...args): ts_module.CombinedCodeActions => {\n            return this.getCombinedCodeFix(oldGetCombinedCodeFix, ...args);\n        };\n\n        return new Proxy(languageService, {\n            get: (target: any, property: keyof ts.LanguageService & typeof isTsLintLanguageServiceMarker) => {\n                if (property === isTsLintLanguageServiceMarker) {\n                    return true;\n                }\n                return intercept[property] || target[property];\n            },\n        });\n    }\n\n    public updateWorkspaceTrust(workspaceTrust: WorkspaceLibraryExecution) {\n        this.workspaceTrust = workspaceTrust;\n\n        // Reset the runner\n        this.runner = new TsLintRunner(message => { this.logger.info(message); });\n    }\n\n    private getSemanticDiagnostics(\n        delegate: (fileName: string) => ts_module.Diagnostic[],\n        fileName: string,\n    ): ts_module.Diagnostic[] {\n        const diagnostics = delegate(fileName);\n\n        if (isInMemoryFile(fileName)) {\n            // In-memory file. TS-lint crashes on these so ignore them\n            return diagnostics;\n        }\n\n        const config = this.configurationManager.config;\n        if (diagnostics.length > 0 && config.suppressWhileTypeErrorsPresent) {\n            return diagnostics;\n        }\n\n        try {\n            this.logger.info(`Computing tslint semantic diagnostics for '${fileName}'`);\n\n            if (this.codeFixActions.has(fileName)) {\n                this.codeFixActions.delete(fileName);\n            }\n\n            if (config.ignoreDefinitionFiles && fileName.endsWith('.d.ts')) {\n                return diagnostics;\n            }\n\n            let result: RunResult;\n            try { // protect against tslint crashes\n                result = this.runner.runTsLint(fileName, this.getProgram(), {\n                    configFile: config.configFile,\n                    ignoreDefinitionFiles: config.ignoreDefinitionFiles,\n                    jsEnable: config.jsEnable,\n                    exclude: config.exclude\n                        ? Array.isArray(config.exclude) ? config.exclude : [config.exclude]\n                        : [],\n                    packageManager: toPackageManager(config.packageManager),\n                    workspaceLibraryExecution: this.workspaceTrust,\n                });\n                if (result.configFilePath) {\n                    this.configFileWatcher.ensureWatching(result.configFilePath);\n                }\n            } catch (err: any) {\n                let errorMessage = `unknown error`;\n                if (typeof err.message === 'string' || err.message instanceof String) {\n                    errorMessage = err.message as string;\n                }\n                this.logger.info('tslint error ' + errorMessage);\n                return diagnostics;\n            }\n\n            const program = this.getProgram();\n            const file = program.getSourceFile(fileName)!;\n            if (result.warnings) {\n                const defaultTsconfigJsonPath = path.join(program.getCurrentDirectory(), 'tslint.json');\n                if ((result.configFilePath && this.ts.sys.fileExists(result.configFilePath)) || this.ts.sys.fileExists(defaultTsconfigJsonPath)) {\n                    // If we have a config file, the user likely wanted to lint. The fact that linting has a\n                    // warning should be reported to them.\n                    for (const warning of result.warnings) {\n                        diagnostics.unshift({\n                            file,\n                            start: 0,\n                            length: 1,\n                            category: this.ts.DiagnosticCategory.Warning,\n                            source: TSLINT_ERROR_SOURCE,\n                            code: TSLINT_ERROR_CODE,\n                            messageText: warning,\n                        });\n                    }\n                } else {\n                    // If we have not found a config file, then we don't want to annoy users by generating warnings\n                    // about tslint not being installed or misconfigured. In many cases, the user is opening a\n                    // file/project that was not intended to be linted.\n                    for (const warning of result.warnings) {\n                        this.logger.info(`[tslint] ${warning}`);\n                    }\n                }\n            }\n\n            const tslintProblems = filterProblemsForFile(fileName, result.lintResult.failures);\n            for (const problem of tslintProblems) {\n                diagnostics.push(this.makeDiagnostic(problem, file));\n                this.recordCodeAction(problem, file);\n            }\n        } catch (e: any) {\n            this.logger.info(`tslint-language service error: ${e.toString()}`);\n            this.logger.info(`Stack trace: ${e.stack}`);\n        }\n\n        return diagnostics;\n    }\n\n    private getCodeFixesAtPosition(\n        delegate: ts.LanguageService['getCodeFixesAtPosition'],\n        fileName: string,\n        start: number,\n        end: number,\n        errorCodes: ReadonlyArray<number>,\n        formatOptions: ts.FormatCodeSettings,\n        userPreferences: ts.UserPreferences\n    ): ReadonlyArray<ts.CodeFixAction> {\n        const fixes = Array.from(delegate(fileName, start, end, errorCodes, formatOptions, userPreferences));\n\n        if (isInMemoryFile(fileName)) {\n            return fixes; // We don't have any tslint errors for these files\n        }\n\n        if (this.configurationManager.config.suppressWhileTypeErrorsPresent && fixes.length > 0) {\n            return fixes;\n        }\n\n        this.logger.info(`getCodeFixes ${errorCodes[0]}`);\n        this.logger.info(JSON.stringify(fixes));\n\n        const documentFixes = this.codeFixActions.get(fileName);\n        if (documentFixes) {\n            const problem = documentFixes.get(start, end);\n            if (problem) {\n                if (problem.fixable) {\n                    const fix = problem.failure.getFix();\n                    if (fix) {\n                        const codeFixAction = this.getRuleFailureQuickFix(problem.failure, fileName);\n                        fixes.push(codeFixAction);\n\n                        const fixAll = this.getRuleFailureFixAllQuickFix(problem.failure.getRuleName(), documentFixes, fileName);\n                        if (fixAll) {\n                            codeFixAction.fixId = TsLintFixId.fromFailure(problem.failure);\n                            codeFixAction.fixAllDescription = `Fix all '${problem.failure.getRuleName()}'`;\n                        }\n\n                        fixes.push(this.getFixAllAutoFixableQuickFix(documentFixes, fileName));\n                    }\n                }\n\n                fixes.push(this.getDisableRuleQuickFix(problem.failure, fileName, this.getProgram().getSourceFile(fileName)!));\n            }\n        }\n\n        return fixes;\n    }\n\n    private getCombinedCodeFix(\n        delegate: ts.LanguageService['getCombinedCodeFix'],\n        scope: ts_module.CombinedCodeFixScope,\n        fixId: {},\n        formatOptions: ts_module.FormatCodeSettings,\n        preferences: ts_module.UserPreferences\n    ): ts_module.CombinedCodeActions {\n        const ruleName = TsLintFixId.toRuleName(fixId);\n        if (!ruleName) {\n            return delegate(scope, fixId, formatOptions, preferences);\n        }\n\n        const documentFixes = this.codeFixActions.get(scope.fileName);\n        if (documentFixes) {\n            const fixAll = this.getRuleFailureFixAllQuickFix(ruleName, documentFixes, scope.fileName);\n            if (fixAll) {\n                return {\n                    changes: fixAll.changes,\n                    commands: fixAll.commands,\n                };\n            }\n        }\n\n        return { changes: [] };\n    }\n\n    private recordCodeAction(failure: tslint.RuleFailure, file: ts.SourceFile) {\n        // tslint can return a fix with an empty replacements array, these fixes are ignored\n        const fixable = !!(failure.getFix && failure.getFix() && !replacementsAreEmpty(failure.getFix()));\n\n        let documentAutoFixes = this.codeFixActions.get(file.fileName);\n        if (!documentAutoFixes) {\n            documentAutoFixes = new ProblemMap();\n            this.codeFixActions.set(file.fileName, documentAutoFixes);\n        }\n        documentAutoFixes.set(failure.getStartPosition().getPosition(), failure.getEndPosition().getPosition(), { failure, fixable });\n    }\n\n    private getRuleFailureQuickFix(failure: tslint.RuleFailure, fileName: string): ts_module.CodeFixAction {\n        return {\n            description: `Fix: ${failure.getFailure()}`,\n            fixName: `tslint:${failure.getRuleName()}`,\n            changes: [failureToFileTextChange(failure, fileName)],\n        };\n    }\n\n    /**\n     * Generate a code action that fixes all instances of ruleName.\n     */\n    private getRuleFailureFixAllQuickFix(ruleName: string, problems: ProblemMap, fileName: string): ts_module.CodeFixAction | undefined {\n        const changes: ts_module.FileTextChanges[] = [];\n\n        for (const problem of problems.values()) {\n            if (problem.fixable) {\n                if (problem.failure.getRuleName() === ruleName) {\n                    changes.push(failureToFileTextChange(problem.failure, fileName));\n                }\n            }\n        }\n\n        // No need for this action if there's only one instance.\n        if (changes.length < 2) {\n            return undefined;\n        }\n\n        return {\n            description: `Fix all '${ruleName}'`,\n            fixName: `tslint:fix-all:${ruleName}`,\n            changes,\n        };\n    }\n\n    private getDisableRuleQuickFix(failure: tslint.RuleFailure, fileName: string, file: ts_module.SourceFile): ts_module.CodeFixAction {\n        const line = failure.getStartPosition().getLineAndCharacter().line;\n        const lineStarts = file.getLineStarts();\n        const lineStart = lineStarts[line];\n        let prefix = '';\n        const snapshot = this.languageServiceHost.getScriptSnapshot(fileName);\n        if (snapshot) {\n            const lineEnd = line < lineStarts.length - 1 ? lineStarts[line + 1] : file.end;\n            const lineText = snapshot.getText(lineStart, lineEnd);\n            const leadingSpace = lineText.match(/^([ \\t]+)/);\n            if (leadingSpace) {\n                prefix = leadingSpace[0];\n            }\n        }\n\n        return {\n            description: `Disable rule '${failure.getRuleName()}'`,\n            fixName: `tslint:disable:${failure.getRuleName()}`,\n            changes: [{\n                fileName,\n                textChanges: [{\n                    newText: `${prefix}// tslint:disable-next-line: ${failure.getRuleName()}\\n`,\n                    span: { start: lineStart, length: 0 },\n                }],\n            }],\n        };\n    }\n\n    private getFixAllAutoFixableQuickFix(documentFixes: ProblemMap, fileName: string): ts_module.CodeFixAction {\n        const allReplacements = getNonOverlappingReplacements(Array.from(documentFixes.values()).filter(x => x.fixable).map(x => x.failure));\n        return {\n            description: `Fix all auto-fixable tslint failures`,\n            fixName: `tslint:fix-all`,\n            changes: [{\n                fileName,\n                textChanges: allReplacements.map(convertReplacementToTextChange),\n            }],\n        };\n    }\n\n    private getProgram() {\n        return this.project.getLanguageService().getProgram()!;\n    }\n\n    private makeDiagnostic(failure: tslint.RuleFailure, file: ts.SourceFile): ts.Diagnostic {\n        const message = (failure.getRuleName() !== null)\n            ? `${failure.getFailure()} (${failure.getRuleName()})`\n            : `${failure.getFailure()}`;\n\n        const category = this.getDiagnosticCategory(failure);\n        return {\n            file,\n            start: failure.getStartPosition().getPosition(),\n            length: failure.getEndPosition().getPosition() - failure.getStartPosition().getPosition(),\n            messageText: message,\n            category,\n            source: TSLINT_ERROR_SOURCE,\n            code: TSLINT_ERROR_CODE,\n        };\n    }\n\n    private getDiagnosticCategory(failure: tslint.RuleFailure): ts.DiagnosticCategory {\n        if (this.configurationManager.config.alwaysShowRuleFailuresAsWarnings || typeof this.configurationManager.config.alwaysShowRuleFailuresAsWarnings === 'undefined') {\n            return this.ts.DiagnosticCategory.Warning;\n        }\n        if (failure.getRuleSeverity && failure.getRuleSeverity() === 'error') {\n            return this.ts.DiagnosticCategory.Error;\n        }\n        return this.ts.DiagnosticCategory.Warning;\n    }\n}\n\nfunction isInMemoryFile(fileName: string) {\n    return fileName.startsWith('^');\n}\n\nfunction convertReplacementToTextChange(repl: tslint.Replacement): ts_module.TextChange {\n    return {\n        newText: repl.text,\n        span: { start: repl.start, length: repl.length },\n    };\n}\n\nfunction failureToFileTextChange(failure: tslint.RuleFailure, fileName: string): ts_module.FileTextChanges {\n    const fix = failure.getFix();\n    const replacements: tslint.Replacement[] = getReplacements(fix);\n\n    return {\n        fileName,\n        textChanges: replacements.map(convertReplacementToTextChange),\n    };\n}\n\nfunction replacementsAreEmpty(fix: tslint.Fix | undefined): boolean {\n    if (Array.isArray(fix)) {\n        return fix.length === 0;\n    }\n    return false;\n}\n"
  },
  {
    "path": "src/runner/failures.ts",
    "content": "import { normalize } from 'path';\nimport * as tslint from 'tslint'; // this is a dev dependency only\n\n/**\n * Filter failures for the given document\n */\nexport function filterProblemsForFile(\n    filePath: string,\n    failures: tslint.RuleFailure[],\n): tslint.RuleFailure[] {\n    const normalizedPath = normalize(filePath);\n    // we only show diagnostics targetting this open document, some tslint rule return diagnostics for other documents/files\n    const normalizedFiles = new Map<string, string>();\n    return failures.filter(each => {\n        const fileName = each.getFileName();\n        if (!normalizedFiles.has(fileName)) {\n            normalizedFiles.set(fileName, normalize(fileName));\n        }\n        return normalizedFiles.get(fileName) === normalizedPath;\n    });\n}\n\nexport function getReplacements(fix: tslint.Fix | undefined): tslint.Replacement[] {\n    if (!fix) {\n        return [];\n    } else if (Array.isArray(fix)) {\n        return fix;\n    } else {\n        return [fix];\n    }\n}\n\nfunction getReplacement(failure: tslint.RuleFailure, at: number): tslint.Replacement {\n    return getReplacements(failure.getFix())[at];\n}\n\nexport function sortFailures(failures: tslint.RuleFailure[]): tslint.RuleFailure[] {\n    // The failures.replacements are sorted by position, we sort on the position of the first replacement\n    return failures.sort((a, b) => {\n        return getReplacement(a, 0).start - getReplacement(b, 0).start;\n    });\n}\n\nexport function getNonOverlappingReplacements(failures: tslint.RuleFailure[]): tslint.Replacement[] {\n    function overlaps(a: tslint.Replacement, b: tslint.Replacement): boolean {\n        return a.end >= b.start;\n    }\n\n    const sortedFailures = sortFailures(failures);\n    const nonOverlapping: tslint.Replacement[] = [];\n    for (let i = 0; i < sortedFailures.length; i++) {\n        const replacements = getReplacements(sortedFailures[i].getFix());\n        if (i === 0 || !overlaps(nonOverlapping[nonOverlapping.length - 1], replacements[0])) {\n            nonOverlapping.push(...replacements);\n        }\n    }\n    return nonOverlapping;\n}\n"
  },
  {
    "path": "src/runner/index.ts",
    "content": "import * as cp from 'child_process';\nimport * as minimatch from 'minimatch';\nimport { dirname, join, normalize, relative, sep } from 'path';\nimport type * as tslint from 'tslint';\nimport type { IConfigurationFile } from 'tslint/lib/configuration';\nimport type * as typescript from 'typescript';\nimport * as util from 'util';\nimport * as server from 'vscode-languageserver';\nimport { MruCache } from './mruCache';\n\nexport type PackageManager = 'npm' | 'pnpm' | 'yarn';\n\nexport function toPackageManager(manager: string | undefined): PackageManager | undefined {\n    switch (manager && manager.toLowerCase()) {\n        case 'npm': return 'npm';\n        case 'pnpm': return 'pnpm';\n        case 'yarn': return 'yarn';\n        default: return undefined;\n    }\n}\n\nexport interface RunConfiguration {\n    readonly jsEnable: boolean;\n    readonly rulesDirectory?: string | string[];\n    readonly configFile?: string;\n    readonly ignoreDefinitionFiles: boolean;\n    readonly exclude: string[];\n    readonly validateWithDefaultConfig?: boolean;\n    readonly packageManager?: PackageManager;\n    readonly traceLevel?: 'verbose' | 'normal';\n    readonly workspaceFolderPath?: string;\n\n    /**\n     * Controls where TSlint and other scripts can be loaded from.\n     */\n    readonly workspaceLibraryExecution: WorkspaceLibraryExecution;\n}\n\n/**\n * Controls where TSlint and other scripts can be loaded from.\n */\nexport enum WorkspaceLibraryExecution {\n    /**\n     * Block executing TSLint, linter rules, and other scripts from the current workspace.\n     */\n    Disallow = 1,\n    /**\n     * Enable loading TSLint and rules from the workspace.\n     */\n    Allow = 2,\n    /**\n     * The workspace library execution has not yet been configured or cannot be determined.\n     */\n    Unknown = 3,\n}\n\ninterface Configuration {\n    readonly linterConfiguration: tslint.Configuration.IConfigurationFile | undefined;\n    isDefaultLinterConfig: boolean;\n    readonly path?: string;\n}\n\nclass ConfigCache {\n    public configuration: Configuration | undefined;\n\n    private filePath: string | undefined;\n\n    constructor() {\n        this.filePath = undefined;\n        this.configuration = undefined;\n    }\n\n    public set(filePath: string, configuration: Configuration) {\n        this.filePath = filePath;\n        this.configuration = configuration;\n    }\n\n    public get(forPath: string): Configuration | undefined {\n        return forPath === this.filePath ? this.configuration : undefined;\n    }\n\n    public isDefaultLinterConfig(): boolean {\n        return !!(this.configuration && this.configuration.isDefaultLinterConfig);\n    }\n\n    public flush() {\n        this.filePath = undefined;\n        this.configuration = undefined;\n    }\n}\n\nexport interface RunResult {\n    readonly lintResult: tslint.LintResult;\n    readonly warnings: string[];\n    readonly workspaceFolderPath?: string;\n    readonly configFilePath?: string;\n}\n\nconst emptyLintResult: tslint.LintResult = {\n    errorCount: 0,\n    warningCount: 0,\n    failures: [],\n    fixes: [],\n    format: '',\n    output: '',\n};\n\nconst emptyResult: RunResult = {\n    lintResult: emptyLintResult,\n    warnings: [],\n};\n\nexport class TsLintRunner {\n    private readonly tslintPath2Library = new Map<string, { tslint: typeof tslint, path: string } | undefined>();\n\n    private readonly document2LibraryCache = new MruCache<{\n        readonly workspaceTslintPath: string | undefined,\n        readonly globalTsLintPath: string | undefined,\n        getTSLint(isTrusted: boolean): { tslint: typeof tslint, path: string } | undefined\n    }>(100);\n\n    // map stores undefined values to represent failed resolutions\n    private readonly globalPackageManagerPath = new Map<PackageManager, string | undefined>();\n    private readonly configCache = new ConfigCache();\n\n    constructor(\n        private readonly trace: (data: string) => void,\n    ) { }\n\n    public runTsLint(\n        filePath: string,\n        contents: string | typescript.Program,\n        configuration: RunConfiguration,\n    ): RunResult {\n        this.traceMethod('runTsLint', 'start');\n\n        const warnings: string[] = [];\n        if (!this.document2LibraryCache.has(filePath)) {\n            this.loadLibrary(filePath, configuration);\n        }\n        this.traceMethod('runTsLint', 'Loaded tslint library');\n\n        if (!this.document2LibraryCache.has(filePath)) {\n            return emptyResult;\n        }\n\n        const cacheEntry = this.document2LibraryCache.get(filePath)!;\n\n        let library: { tslint: typeof tslint, path: string } | undefined;\n\n        switch (configuration.workspaceLibraryExecution) {\n            case WorkspaceLibraryExecution.Disallow:\n                library = cacheEntry.getTSLint(false);\n                break;\n\n            case WorkspaceLibraryExecution.Allow:\n                library = cacheEntry.getTSLint(true);\n                break;\n\n            default:\n                if (cacheEntry.workspaceTslintPath) {\n                    if (this.isWorkspaceImplicitlyTrusted(cacheEntry.workspaceTslintPath)) {\n                        configuration = { ...configuration, workspaceLibraryExecution: WorkspaceLibraryExecution.Allow };\n                        library = cacheEntry.getTSLint(true);\n                        break;\n                    }\n\n                    // If the user has not explicitly trusted/not trusted the workspace AND we have a workspace TS version\n                    // show a special error that lets the user trust/untrust the workspace\n                    return {\n                        lintResult: emptyLintResult,\n                        warnings: [\n                            getWorkspaceNotTrustedMessage(filePath),\n                        ],\n                    };\n                } else if (cacheEntry.globalTsLintPath) {\n                    library = cacheEntry.getTSLint(false);\n                }\n                break;\n        }\n\n        if (!library) {\n            return {\n                lintResult: emptyLintResult,\n                warnings: [\n                    getInstallFailureMessage(\n                        filePath,\n                        configuration.packageManager || 'npm'),\n                ],\n            };\n        }\n\n        this.traceMethod('runTsLint', 'About to validate ' + filePath);\n        return this.doRun(filePath, contents, library, configuration, warnings);\n    }\n\n    public onConfigFileChange(_tsLintFilePath: string) {\n        this.configCache.flush();\n    }\n\n    private traceMethod(method: string, message: string) {\n        this.trace(`(${method}) ${message}`);\n    }\n\n    private loadLibrary(filePath: string, configuration: RunConfiguration): void {\n        this.traceMethod('loadLibrary', `trying to load ${filePath}`);\n        const directory = dirname(filePath);\n\n        const tsLintPaths = this.getTsLintPaths(directory, configuration.packageManager);\n\n        this.traceMethod('loadLibrary', `Resolved tslint to workspace: '${tsLintPaths.workspaceTsLintPath}' global: '${tsLintPaths.globalTsLintPath}'`);\n\n        this.document2LibraryCache.set(filePath, {\n            workspaceTslintPath: tsLintPaths.workspaceTsLintPath || undefined,\n            globalTsLintPath: tsLintPaths.globalTsLintPath || undefined,\n            getTSLint: (allowWorkspaceLibraryExecution: boolean) => {\n                const tsLintPath = allowWorkspaceLibraryExecution\n                    ? tsLintPaths.workspaceTsLintPath || tsLintPaths.globalTsLintPath\n                    : tsLintPaths.globalTsLintPath;\n\n                if (!tsLintPath) {\n                    return;\n                }\n\n                let library;\n                if (!this.tslintPath2Library.has(tsLintPath)) {\n                    try {\n                        library = require(tsLintPath);\n                    } catch (e) {\n                        this.tslintPath2Library.set(tsLintPath, undefined);\n                        return;\n                    }\n                    this.tslintPath2Library.set(tsLintPath, { tslint: library, path: tsLintPath });\n                }\n                return this.tslintPath2Library.get(tsLintPath);\n            }\n        });\n    }\n\n    private getTsLintPaths(directory: string, packageManager: PackageManager | undefined) {\n        const globalPath = this.getGlobalPackageManagerPath(packageManager);\n\n        let workspaceTsLintPath: string | undefined;\n        try {\n            workspaceTsLintPath = this.resolveTsLint({ nodePath: undefined, cwd: directory }) || undefined;\n        } catch {\n            // noop\n        }\n\n        let globalTSLintPath: string | undefined;\n        try {\n            globalTSLintPath = this.resolveTsLint({ nodePath: undefined, cwd: globalPath })\n                || this.resolveTsLint({ nodePath: globalPath, cwd: globalPath });\n        } catch {\n            // noop\n        }\n\n        return { workspaceTsLintPath, globalTsLintPath: globalTSLintPath };\n    }\n\n    private getGlobalPackageManagerPath(packageManager: PackageManager = 'npm'): string | undefined {\n        this.traceMethod('getGlobalPackageManagerPath', `Begin - Resolve Global Package Manager Path for: ${packageManager}`);\n\n        if (!this.globalPackageManagerPath.has(packageManager)) {\n            let path: string | undefined;\n            if (packageManager === 'npm') {\n                path = server.Files.resolveGlobalNodePath(this.trace);\n            } else if (packageManager === 'yarn') {\n                path = server.Files.resolveGlobalYarnPath(this.trace);\n            } else if (packageManager === 'pnpm') {\n                path = cp.execSync('pnpm root -g').toString().trim();\n            }\n            this.globalPackageManagerPath.set(packageManager, path);\n        }\n        this.traceMethod('getGlobalPackageManagerPath', `Done - Resolve Global Package Manager Path for: ${packageManager}`);\n        return this.globalPackageManagerPath.get(packageManager);\n    }\n\n    private doRun(\n        filePath: string,\n        contents: string | typescript.Program,\n        library: { tslint: typeof tslint, path: string },\n        configuration: RunConfiguration,\n        warnings: string[],\n    ): RunResult {\n        this.traceMethod('doRun', `starting validation for ${filePath}`);\n\n        let cwd = configuration.workspaceFolderPath;\n        if (!cwd && typeof contents === \"object\") {\n            cwd = contents.getCurrentDirectory();\n        }\n\n        if (this.fileIsExcluded(configuration, filePath, cwd)) {\n            this.traceMethod('doRun', `No linting: file ${filePath} is excluded`);\n            return emptyResult;\n        }\n\n        let cwdToRestore: string | undefined;\n        if (cwd && configuration.workspaceLibraryExecution === WorkspaceLibraryExecution.Allow) {\n            this.traceMethod('doRun', `Changed directory to ${cwd}`);\n            cwdToRestore = process.cwd();\n            process.chdir(cwd);\n        }\n\n        try {\n            const configFile = configuration.configFile || null;\n            let linterConfiguration: Configuration | undefined;\n            this.traceMethod('doRun', 'About to getConfiguration');\n            try {\n                linterConfiguration = this.getConfiguration(filePath, filePath, library.tslint, configFile);\n            } catch (err) {\n                this.traceMethod('doRun', `No linting: exception when getting tslint configuration for ${filePath}, configFile= ${configFile}`);\n                warnings.push(getConfigurationFailureMessage(err));\n                return {\n                    lintResult: emptyLintResult,\n                    warnings,\n                };\n            }\n\n            if (!linterConfiguration) {\n                this.traceMethod('doRun', `No linting: no tslint configuration`);\n                return emptyResult;\n            }\n            this.traceMethod('doRun', 'Configuration fetched');\n\n            if (isJsDocument(filePath) && !configuration.jsEnable) {\n                this.traceMethod('doRun', `No linting: a JS document, but js linting is disabled`);\n                return emptyResult;\n            }\n\n            if (configuration.validateWithDefaultConfig === false && this.configCache.configuration!.isDefaultLinterConfig) {\n                this.traceMethod('doRun', `No linting: linting with default tslint configuration is disabled`);\n                return emptyResult;\n            }\n\n            if (isExcludedFromLinterOptions(linterConfiguration.linterConfiguration, filePath)) {\n                this.traceMethod('doRun', `No linting: file is excluded using linterOptions.exclude`);\n                return emptyResult;\n            }\n\n            let result: tslint.LintResult;\n\n            const isTrustedWorkspace = configuration.workspaceLibraryExecution === WorkspaceLibraryExecution.Allow;\n\n            // Only allow using a custom rules directory if the workspace has been trusted by the user\n            const rulesDirectory = isTrustedWorkspace ? configuration.rulesDirectory : [];\n\n            const options: tslint.ILinterOptions = {\n                formatter: \"json\",\n                fix: false,\n                rulesDirectory,\n                formattersDirectory: undefined,\n            };\n            if (configuration.traceLevel && configuration.traceLevel === 'verbose') {\n                this.traceConfigurationFile(linterConfiguration.linterConfiguration);\n            }\n\n            // tslint writes warnings using console.warn, capture these warnings and send them to the client\n            const originalConsoleWarn = console.warn;\n            const captureWarnings = (message?: any) => {\n                warnings.push(message);\n                originalConsoleWarn(message);\n            };\n            console.warn = captureWarnings;\n\n            const sanitizedLintConfiguration = { ...linterConfiguration.linterConfiguration } as IConfigurationFile;\n            // Only allow using a custom rules directory if the workspace has been trusted by the user\n            if (!isTrustedWorkspace) {\n                sanitizedLintConfiguration.rulesDirectory = [];\n            }\n\n            try { // clean up if tslint crashes\n                const linter = new library.tslint.Linter(options, typeof contents === 'string' ? undefined : contents);\n                this.traceMethod('doRun', `Linting: start linting`);\n                linter.lint(filePath, typeof contents === 'string' ? contents : '', sanitizedLintConfiguration);\n                result = linter.getResult();\n                this.traceMethod('doRun', `Linting: ended linting`);\n            } finally {\n                console.warn = originalConsoleWarn;\n            }\n\n            return {\n                lintResult: result,\n                warnings,\n                workspaceFolderPath: configuration.workspaceFolderPath,\n                configFilePath: linterConfiguration.path,\n            };\n        } finally {\n            if (typeof cwdToRestore === 'string') {\n                process.chdir(cwdToRestore);\n            }\n        }\n    }\n\n    /**\n     * Check if `tslintPath` is next to the running TS version. This indicates that the user has\n     * implicitly trusted the workspace since they are already running TS from it.\n     */\n    private isWorkspaceImplicitlyTrusted(tslintPath: string): boolean {\n        const tsPath = process.argv[1];\n        const nodeModulesPath = join(tsPath, '..', '..', '..');\n\n        const rel = relative(nodeModulesPath, normalize(tslintPath));\n        if (rel === `tslint${sep}lib${sep}index.js`) {\n            return true;\n        }\n        return false;\n    }\n\n    private getConfiguration(uri: string, filePath: string, library: typeof tslint, configFileName: string | null): Configuration | undefined {\n        this.traceMethod('getConfiguration', `Starting for ${uri}`);\n\n        const config = this.configCache.get(filePath);\n        if (config) {\n            return config;\n        }\n\n        let isDefaultConfig = false;\n        let linterConfiguration: tslint.Configuration.IConfigurationFile | undefined;\n\n        const linter = library.Linter;\n        if (linter.findConfigurationPath) {\n            isDefaultConfig = linter.findConfigurationPath(configFileName, filePath) === undefined;\n        }\n        const configurationResult = linter.findConfiguration(configFileName, filePath);\n\n        linterConfiguration = configurationResult.results;\n\n        // In tslint version 5 the 'no-unused-variable' rules breaks the TypeScript language service plugin.\n        // See https://github.com/Microsoft/TypeScript/issues/15344\n        // Therefore we remove the rule from the configuration.\n        if (linterConfiguration) {\n            if (linterConfiguration.rules) {\n                linterConfiguration.rules.delete('no-unused-variable');\n            }\n            if (linterConfiguration.jsRules) {\n                linterConfiguration.jsRules.delete('no-unused-variable');\n            }\n        }\n\n        const configuration: Configuration = {\n            isDefaultLinterConfig: isDefaultConfig,\n            linterConfiguration,\n            path: configurationResult.path,\n        };\n\n        this.configCache.set(filePath, configuration);\n        return this.configCache.configuration;\n    }\n\n    private fileIsExcluded(settings: RunConfiguration, filePath: string, cwd: string | undefined): boolean {\n        if (settings.ignoreDefinitionFiles && filePath.endsWith('.d.ts')) {\n            return true;\n        }\n        return settings.exclude.some(pattern => testForExclusionPattern(filePath, pattern, cwd));\n    }\n\n    private traceConfigurationFile(configuration: tslint.Configuration.IConfigurationFile | undefined) {\n        if (!configuration) {\n            this.trace(\"no tslint configuration\");\n            return;\n        }\n        this.trace(\"tslint configuration:\" + util.inspect(configuration, undefined, 4));\n    }\n\n    private resolveTsLint(options: { nodePath: string | undefined; cwd: string | undefined; }): string | undefined {\n        const nodePathKey = 'NODE_PATH';\n        const app = [\n            \"console.log(require.resolve('tslint'));\",\n        ].join('');\n\n        const env = process.env;\n        const newEnv = Object.create(null);\n        Object.keys(env).forEach(key => newEnv[key] = env[key]);\n        if (options.nodePath) {\n            newEnv[nodePathKey] = options.nodePath;\n        }\n        newEnv.ELECTRON_RUN_AS_NODE = '1';\n\n        const spawnResults = cp.spawnSync(process.argv0, ['-e', app], { cwd: options.cwd, env: newEnv });\n        return spawnResults.stdout.toString().trim() || undefined;\n    }\n}\n\nfunction testForExclusionPattern(filePath: string, pattern: string, cwd: string | undefined): boolean {\n    if (cwd) {\n        // try first as relative\n        const relPath = relative(cwd, filePath);\n        if (minimatch(relPath, pattern, { dot: true })) {\n            return true;\n        }\n        if (relPath === filePath) {\n            return false;\n        }\n    }\n\n    return minimatch(filePath, pattern, { dot: true });\n}\n\nfunction getInstallFailureMessage(filePath: string, packageManager: PackageManager): string {\n    const localCommands = {\n        npm: 'npm install tslint',\n        pnpm: 'pnpm install tslint',\n        yarn: 'yarn add tslint',\n    };\n    const globalCommands = {\n        npm: 'npm install -g tslint',\n        pnpm: 'pnpm install -g tslint',\n        yarn: 'yarn global add tslint',\n    };\n\n    return [\n        `Failed to load the TSLint library for '${filePath}'`,\n        `To use TSLint, please install tslint using \\'${localCommands[packageManager]}\\' or globally using \\'${globalCommands[packageManager]}\\'.`,\n        'Be sure to restart your editor after installing tslint.',\n    ].join('\\n');\n}\n\nfunction getWorkspaceNotTrustedMessage(filePath: string) {\n    return [\n        `Not using the local TSLint version found for '${filePath}'`,\n        'To enable code execution from the current workspace you must enable workspace library execution.',\n    ].join('\\n');\n}\n\nfunction isJsDocument(filePath: string): boolean {\n    return /\\.(jsx?|mjs)$/i.test(filePath);\n}\n\nfunction isExcludedFromLinterOptions(\n    config: tslint.Configuration.IConfigurationFile | undefined,\n    fileName: string,\n): boolean {\n    if (config === undefined || config.linterOptions === undefined || config.linterOptions.exclude === undefined) {\n        return false;\n    }\n    return config.linterOptions.exclude.some(pattern => testForExclusionPattern(fileName, pattern, undefined));\n}\n\nfunction getConfigurationFailureMessage(err: any): string {\n    let errorMessage = `unknown error`;\n    if (typeof err.message === 'string' || err.message instanceof String) {\n        errorMessage = err.message;\n    }\n    return `Cannot read tslint configuration - '${errorMessage}'`;\n}\n"
  },
  {
    "path": "src/runner/mruCache.ts",
    "content": "export class MruCache<T> {\n\n    private readonly _map = new Map<string, T>();\n    private readonly _entries = new Set<string>();\n\n    public constructor(\n        private readonly _maxSize: number\n    ) { }\n\n    public set(filePath: string, entry: T): void {\n        this._map.set(filePath, entry);\n        this._entries.add(filePath);\n        for (const key of this._entries.keys()) {\n            if (this._entries.size <= this._maxSize) {\n                break;\n            }\n            this._map.delete(key);\n            this._entries.delete(key);\n        }\n    }\n\n    public has(filePath: string): boolean {\n        return this._map.has(filePath);\n    }\n\n    public get(filePath: string): (T) | undefined {\n        if (this._entries.has(filePath)) {\n            this._entries.delete(filePath);\n            this._entries.add(filePath);\n        }\n        return this._map.get(filePath);\n    }\n}"
  },
  {
    "path": "src/runner/test/mruCache.test.ts",
    "content": "import { expect } from 'chai';\nimport 'mocha';\nimport { MruCache } from '../mruCache';\n\ndescribe('MruCache', () => {\n    it('should remove old entries', () => {\n        const size = 10;\n        const cache = new MruCache<number>(size);\n\n        expect(cache.has('0')).to.equal(false);\n        cache.set('0', 0);\n\n        expect(cache.get('0')).to.equal(0);\n\n        for (let i = 1; i < size + 1; ++i) {\n            cache.set(i.toString(), i);\n        }\n\n        expect(cache.has('0')).to.equal(false);\n    });\n});\n"
  },
  {
    "path": "src/runner/test/runner.test.ts",
    "content": "import { expect } from 'chai';\nimport * as fs from 'fs';\nimport 'mocha';\nimport * as path from 'path';\nimport { RunConfiguration, TsLintRunner, WorkspaceLibraryExecution } from '../index';\nimport { getNonOverlappingReplacements, filterProblemsForFile } from '../failures';\n\nconst testDataRoot = path.join(__dirname, '..', '..', '..', 'test-data');\n\nconst defaultRunConfiguration: RunConfiguration = {\n    exclude: [],\n    jsEnable: false,\n    ignoreDefinitionFiles: true,\n    workspaceLibraryExecution: WorkspaceLibraryExecution.Unknown\n};\n\ndescribe('TSLintRunner', () => {\n    describe('runTsLint', () => {\n        // Must come first. TS lint only reports warnings once.\n        it.skip('should report warnings', () => {\n            const filePath = path.join(testDataRoot, 'no-unused-variables', 'test.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);\n\n            expect(result.lintResult.errorCount).to.equal(0);\n            expect(result.warnings.length).to.equal(2);\n        });\n\n        it('should not return any errors for empty file', () => {\n            const result = createTsLintRunner().runTsLint('', '', defaultRunConfiguration);\n            expect(result.lintResult.errorCount).to.equal(0);\n        });\n\n        it('should return an error for test file', () => {\n            const folderPath = path.join(testDataRoot, 'with-tslint');\n            const filePath = path.join(folderPath, 'test.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);\n\n            expect(result.lintResult.errorCount).to.equal(1);\n            expect(result.lintResult.warningCount).to.equal(0);\n\n            const firstFailure = result.lintResult.failures[0];\n            expect(path.normalize(firstFailure.getFileName())).to.equal(filePath);\n            expect(firstFailure.getRuleName()).to.equal('array-type');\n\n            const fix = firstFailure.getFix();\n            expect(fix).to.not.equal(undefined);\n            expect(fix!.length).to.equal(2);\n\n            expect(result.configFilePath).to.equal(path.join(folderPath, 'tslint.json'));\n        });\n\n        it('should not validate using if no tslint.json exists and validateWithDefaultConfig is false', () => {\n            const filePath = path.join(testDataRoot, 'no-tslint', 'test.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {\n                ...defaultRunConfiguration,\n                validateWithDefaultConfig: false,\n            });\n\n            expect(result.lintResult.errorCount).to.equal(0);\n            expect(result.lintResult.warningCount).to.equal(0);\n        });\n\n        it('should use correct config for each file', () => {\n            const warningFilePath = path.join(testDataRoot, 'warnings', 'test.ts');\n            const warnResult = createTsLintRunner().runTsLint(warningFilePath, fs.readFileSync(warningFilePath).toString(), defaultRunConfiguration);\n\n            expect(warnResult.lintResult.errorCount).to.equal(0);\n            expect(warnResult.lintResult.warningCount).to.equal(1);\n\n            const errorFilePath = path.join(testDataRoot, 'with-tslint', 'test.ts');\n            const errorResult = createTsLintRunner().runTsLint(errorFilePath, fs.readFileSync(warningFilePath).toString(), defaultRunConfiguration);\n\n            expect(errorResult.lintResult.errorCount).to.equal(1);\n            expect(errorResult.lintResult.warningCount).to.equal(0);\n        });\n\n        it('should not return any errors for excluded file (absolute path)', () => {\n            const filePath = path.join(testDataRoot, 'with-tslint', 'test.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {\n                ...defaultRunConfiguration,\n                exclude: [filePath],\n            });\n\n            expect(result.lintResult.errorCount).to.equal(0);\n        });\n\n        it('should not return any errors for excluded file (relative path)', () => {\n            const root = path.join(testDataRoot, 'with-tslint');\n            const filePath = path.join(root, 'test.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {\n                ...defaultRunConfiguration,\n                workspaceFolderPath: root,\n                exclude: ['test.ts'],\n            });\n\n            expect(result.lintResult.errorCount).to.equal(0);\n        });\n\n        it('should set working directory to workspace path', () => {\n            const workspacePath = path.join(testDataRoot, 'with-tslint');\n            const filePath = path.join(workspacePath, 'test.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {\n                ...defaultRunConfiguration,\n                workspaceFolderPath: workspacePath,\n            });\n\n            expect(result.lintResult.errorCount).to.equal(1);\n            expect(result.lintResult.warningCount).to.equal(0);\n            expect(result.workspaceFolderPath).to.equal(workspacePath);\n        });\n\n        it.skip('should return warnings for invalid tslint install', () => {\n            const root = path.join(testDataRoot, 'invalid-install');\n            const filePath = path.join(root, 'test.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {\n                ...defaultRunConfiguration,\n                workspaceFolderPath: root,\n            });\n\n            expect(result.warnings.length).to.equal(1);\n        });\n\n        it('should not return errors in js file by default', () => {\n            const root = path.join(testDataRoot, 'with-tslint');\n            const filePath = path.join(root, 'test.js');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);\n\n            expect(result.lintResult.errorCount).to.equal(0);\n        });\n\n        it('should return errors in js file if jsEnable is set', () => {\n            const root = path.join(testDataRoot, 'with-tslint');\n            const filePath = path.join(root, 'test.js');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), { ...defaultRunConfiguration, jsEnable: true });\n\n            expect(result.lintResult.errorCount).to.equal(1);\n        });\n\n        it('should not return errors in excluded file', () => {\n            const root = path.join(testDataRoot, 'with-tslint');\n            const filePath = path.join(root, 'excluded.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);\n\n            expect(result.lintResult.errorCount).to.equal(0);\n        });\n\n        it('should ignore no-unused-varaible rule', () => {\n            const root = path.join(testDataRoot, 'with-tslint');\n            const filePath = path.join(root, 'unused-variable.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);\n\n            expect(result.lintResult.errorCount).to.equal(0);\n            expect(result.warnings.length).to.equal(0);\n        });\n\n        it('should not return errors in js files by default', () => {\n            const root = path.join(testDataRoot, 'js-disabled');\n            {\n                const filePath = path.join(root, 'test.mjs');\n                const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);\n                expect(result.lintResult.errorCount).to.equal(0);\n            }\n            {\n                const filePath = path.join(root, 'test.mjs');\n                const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);\n                expect(result.lintResult.errorCount).to.equal(0);\n            }\n        });\n\n        it('should support using a tslint.js config file', () => {\n            const root = path.join(testDataRoot, 'with-tslint-js-config-file');\n\n            const filePath = path.join(root, 'test.ts');\n            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {\n                configFile: path.join(root, 'tslint.js'),\n                ...defaultRunConfiguration,\n            });\n            expect(result.lintResult.errorCount).to.equal(2);\n            expect(result.lintResult.failures[0].getRuleName()).to.equal('array-type');\n            expect(result.lintResult.failures[1].getRuleName()).to.equal('quotemark');\n        });\n    });\n\n    describe('filterProblemsForFile', () => {\n        it('should filter out all problems not in file', () => {\n            const runner = createTsLintRunner();\n            const filePath = path.join(testDataRoot, 'with-tslint', 'test.ts');\n            const result = runner.runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);\n\n            expect(result.lintResult.failures.length).to.equal(1);\n\n            const filteredFailures = filterProblemsForFile('does-not-exist', result.lintResult.failures);\n            expect(filteredFailures.length).to.equal(0);\n        });\n    });\n\n    describe('getNonOverlappingReplacements', () => {\n        it('should filter out overlapping replacements', () => {\n            const runner = createTsLintRunner();\n            const filePath = path.join(testDataRoot, 'overlapping-errors', 'test.ts');\n            const result = runner.runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);\n\n            expect(result.lintResult.failures.length).to.equal(2);\n\n            const noOverlappingReplacements = getNonOverlappingReplacements(result.lintResult.failures);\n            expect(noOverlappingReplacements.length).to.equal(1);\n        });\n    });\n});\n\nfunction createTsLintRunner() {\n    return new TsLintRunner((_value: string) => { /* noop */ });\n}\n"
  },
  {
    "path": "src/settings.ts",
    "content": "import * as path from 'path';\nimport * as ts_module from 'typescript/lib/tsserverlibrary';\nimport { Logger } from './logger';\nimport { pluginId } from './config';\n\n/**\n * Settings for the plugin section in tsconfig.json\n */\nexport interface Configuration {\n    readonly alwaysShowRuleFailuresAsWarnings: boolean;\n    readonly ignoreDefinitionFiles: boolean;\n    readonly configFile?: string;\n    readonly suppressWhileTypeErrorsPresent: boolean;\n    readonly jsEnable: boolean;\n    readonly exclude?: string | string[];\n    readonly packageManager?: string;\n}\n\nexport class ConfigurationManager {\n\n    private static readonly defaultConfig: Configuration = {\n        alwaysShowRuleFailuresAsWarnings: true,\n        ignoreDefinitionFiles: true,\n        jsEnable: false,\n        suppressWhileTypeErrorsPresent: false,\n    };\n\n    private readonly _configUpdatedListeners = new Set<() => void>();\n\n    private _workingDirectory?: string;\n    private _watcher?: ts_module.FileWatcher;\n\n    public get config(): Configuration { return this._configuration; }\n    private _configuration: Configuration = ConfigurationManager.defaultConfig;\n\n    public constructor(\n        private readonly _ts: typeof ts_module\n    ) { }\n\n    public updateFromPluginConfig(config: Configuration) {\n        const configFile = config.configFile && !path.isAbsolute(config.configFile) && this._workingDirectory\n            ? path.join(this._workingDirectory, config.configFile)\n            : config.configFile;\n\n        this._configuration = {\n            ...ConfigurationManager.defaultConfig,\n            ...config,\n            configFile,\n        };\n\n        for (const listener of this._configUpdatedListeners) {\n            listener();\n        }\n    }\n\n    public setProject(\n        project: ts_module.server.Project,\n        logger: Logger,\n    ) {\n        if (this._watcher) {\n            this._watcher.close();\n            this._watcher = undefined;\n        }\n\n        // Watch config file for changes\n        if (project instanceof this._ts.server.ConfiguredProject && this._ts.sys.watchFile) {\n            const configFile = project.getConfigFilePath();\n            logger.info(`ConfigurationManager: Found configured project: ${configFile}`);\n\n            this._watcher = this._ts.sys.watchFile(configFile, (_fileName: string, eventKind: ts_module.FileWatcherEventKind) => {\n                if (eventKind !== this._ts.FileWatcherEventKind.Changed) {\n                    return;\n                }\n\n                logger.info('ConfigurationManager: file changed');\n\n                const newConfig = loadSettingsFromTsConfig(this._ts, configFile, logger);\n                if (!newConfig) {\n                    logger.info(`ConfigurationManager: Could not read new config`);\n                    return;\n                }\n\n                logger.info(`ConfigurationManager: Updating config settings: ${JSON.stringify(newConfig)}`);\n                this.updateFromPluginConfig(newConfig);\n            });\n        }\n\n        this._workingDirectory = project.getCurrentDirectory();\n        this.updateFromPluginConfig(this.config);\n    }\n\n    public onUpdatedConfig(listener: () => void) {\n        this._configUpdatedListeners.add(listener);\n    }\n}\n\nexport function loadSettingsFromTsConfig(\n    ts: typeof ts_module,\n    configFilePath: string,\n    logger: Logger,\n): Configuration | undefined {\n    const configFileResult = ts.readConfigFile(configFilePath, ts.sys.readFile);\n    if (configFileResult.error || !configFileResult.config) {\n        logger.info(`ConfigurationManager: Could not read new config: ${configFileResult.error}`);\n        return undefined;\n    }\n\n    if (!configFileResult.config.compilerOptions || !Array.isArray(configFileResult.config.compilerOptions.plugins)) {\n        logger.info(`ConfigurationManager: Could not read new config plugins`);\n\n        return undefined;\n    }\n\n    const pluginSettings = (configFileResult.config.compilerOptions.plugins as any[]).find(x => x.name === pluginId);\n    if (!pluginSettings) {\n        logger.info(`ConfigurationManager: Could not read new config tslint-plugin`);\n        return undefined;\n    }\n\n    return pluginSettings;\n}\n"
  },
  {
    "path": "test-data/invalid-install/package.json",
    "content": "{\n  \"name\": \"invalid-install\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"tslint\": \"^5.11.0\"\n  }\n}\n"
  },
  {
    "path": "test-data/invalid-install/test.ts",
    "content": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/invalid-install/tslint.json",
    "content": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ]\n    }\n}"
  },
  {
    "path": "test-data/js-disabled/test.js",
    "content": "console.log(1)\nconsole.log(2)\n"
  },
  {
    "path": "test-data/js-disabled/test.mjs",
    "content": "console.log(1)\nconsole.log(2)\n"
  },
  {
    "path": "test-data/js-disabled/tslint.json",
    "content": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ]\n    },\n    \"defaultSeverity\": \"warning\"\n}"
  },
  {
    "path": "test-data/no-tslint/test.ts",
    "content": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/no-unused-variables/test.ts",
    "content": "export const b = 1;\n\nconst a = 1;"
  },
  {
    "path": "test-data/no-unused-variables/tslint.json",
    "content": "{\n    \"rules\": {\n       \"no-unused-variable\": true\n    }\n}"
  },
  {
    "path": "test-data/overlapping-errors/test.ts",
    "content": "import {\n    isEqual,\n    isEmpty\n} from \"lodash\";\n\nconsole.log(isEmpty, isEqual); "
  },
  {
    "path": "test-data/overlapping-errors/tslint.json",
    "content": "{\n    \"rules\": {\n        \"ordered-imports\": true,\n        \"trailing-comma\": [\n            true,\n            {\n                \"multiline\": \"always\",\n                \"singleline\": \"never\"\n            }\n        ]\n    }\n}"
  },
  {
    "path": "test-data/warnings/test.ts",
    "content": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/warnings/tslint.json",
    "content": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ]\n    },\n    \"defaultSeverity\": \"warning\"\n}"
  },
  {
    "path": "test-data/with-tslint/excluded.ts",
    "content": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/with-tslint/test.js",
    "content": "console.log(1 == 2)"
  },
  {
    "path": "test-data/with-tslint/test.ts",
    "content": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/with-tslint/tslint.json",
    "content": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ],\n        \"no-unused-variable\": true\n    },\n    \"jsRules\": {\n        \"triple-equals\": true\n    },\n    \"linterOptions\": {\n        \"exclude\": [\n            \"excluded.ts\"\n        ]\n    }\n}"
  },
  {
    "path": "test-data/with-tslint/unused-variable.ts",
    "content": "export const _ = 1;\n\nconst unused = 1;"
  },
  {
    "path": "test-data/with-tslint-js-config-file/test.ts",
    "content": "let t: Array<string> = new Array<string>();\n\nconsole.log(t, 'abc');"
  },
  {
    "path": "test-data/with-tslint-js-config-file/tslint.js",
    "content": "module.exports = {\n    \"rules\": {\n        \"array-type\": true,\n        \"quotemark\": 1 === 1\n    }\n}"
  },
  {
    "path": "test-workspace/.vscode/settings.json",
    "content": "{\n    \"typescript.tsdk\": \"node_modules/typescript/lib\"\n}"
  },
  {
    "path": "test-workspace/examples/array-type.ts",
    "content": "let t: Array<string> = new Array<string>();\nlet x: Array<string> = new Array<string>();\n\nconsole.log(t);\n   "
  },
  {
    "path": "test-workspace/examples/arrow-parens.ts",
    "content": "[1, 2 ].map( num => console.log(num) );\n   "
  },
  {
    "path": "test-workspace/examples/eval.ts",
    "content": "// There is no TSLint fix for the \"no-eval\" rule,\n// but the \"disable rule\" fix is still available.\nlet x = eval(\"1 + 1\");\n"
  },
  {
    "path": "test-workspace/examples/no-var-keyword.ts",
    "content": "\nvar anakin: string = \"jedi\";\n\nconsole.log(`variable is used:${anakin}`);"
  },
  {
    "path": "test-workspace/examples/no_unused-variable.ts",
    "content": "// !!! no-unused-variable is currently not supported pls see: https://github.com/palantir/tslint/issues/2649\nimport {  } from \"diff\";\n\nimport { A, B } from \"parse-json\";\n\nconsole.log(`use ${A}`);"
  },
  {
    "path": "test-workspace/examples/ordered-imports.ts",
    "content": "import {B, A, C} from \"diff\";\nimport {D, E} from \"diff\";\n\nconsole.log(`use ${A} ${B} ${C} ${D}, ${E}`);"
  },
  {
    "path": "test-workspace/examples/overlapping-fixes.ts",
    "content": "// overlapping fix ranges are currently not supported (the ordered import range, and the missing comman do overlap)\r\nimport { autorun, computed } from \"mbox\";\r\nimport {\r\n  isEmpty,\r\n  isEqual\r\n} from \"lodash\";\r\n\r\nconsole.log(autorun, computed, isEmpty, isEqual);"
  },
  {
    "path": "test-workspace/examples/quotemark.ts",
    "content": "// VS Code provided fix\nlet s = 'quotemark';\n\nconsole.log(s);"
  },
  {
    "path": "test-workspace/examples/semicolon.ts",
    "content": "let test1: string\nconsole.log(`use ${test1}`)"
  },
  {
    "path": "test-workspace/examples/test-javascript.js",
    "content": "// test a jsRule trippe equals, tripple equals quick fix is vscode-tslint contributed\n   let a = 2;\n\n    if (a == 2) {\n \n    }\n\n    [1, 2 ].map( num => console.log(num) );"
  },
  {
    "path": "test-workspace/examples/test.d.ts",
    "content": "// missing semicolon warning supressed to due ignoreDefinitionFiles setting\r\ninterface F {\r\n    f1()\r\n    f2()\r\n}"
  },
  {
    "path": "test-workspace/examples/trailing-comma.ts",
    "content": "// a comma is missing at the end\n\nlet test = {\n  lastName: \"smith\",\n  missAComma: \"mis\"\n};\n\nlet test2 = {\n  lastName: \"smith\",\n  missAComma: \"mis\"\n};\n\nconsole.log(test, test2);"
  },
  {
    "path": "test-workspace/examples/triple-equals.ts",
    "content": "// VS Code provided fix for === not supported when using the tslint-language-service\nlet a = 3;\n\nif (a == 3) {\n    console.log(a);\n}\n\nif (a != 3) {\n    console.log(a);\n}"
  },
  {
    "path": "test-workspace/package.json",
    "content": "{\n  \"name\": \"project-fixture\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"typescript\": \"3.1.3\",\n    \"typescript-tslint-plugin\": \"file:./..\"\n  }\n}\n"
  },
  {
    "path": "test-workspace/tsconfig.json",
    "content": "{\r\n    \"compilerOptions\": {\r\n        \"plugins\": [\r\n            {\r\n                \"name\": \"typescript-tslint-plugin\",\r\n                \"alwaysShowRuleFailuresAsWarnings\": false,\r\n                \"ignoreDefinitionFiles\": true\r\n                //\"configFile\": \"../tslint.json\",\r\n            }\r\n        ],\r\n        \"module\": \"commonjs\",\r\n        \"target\": \"es6\",\r\n        \"allowJs\": true,\r\n        \"noImplicitAny\": false,\r\n        \"sourceMap\": false,\r\n        \"noEmit\": true\r\n    }\r\n}"
  },
  {
    "path": "test-workspace/tslint.json",
    "content": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ],\n        \"arrow-parens\": true,\n        \"no-var-keyword\": true,\n        \"no-unused-variable\": [\n            true,\n            {\n                \"ignore-pattern\": \"^_\"\n            }\n        ],\n        \"ordered-imports\": [\n            true,\n            {\n                \"import-sources-order\": \"lowercase-last\",\n                \"named-imports-order\": \"lowercase-first\"\n            }\n        ],\n        \"trailing-comma\": [\n            true,\n            {\n                \"multiline\": \"always\",\n                \"singleline\": \"never\"\n            }\n        ],\n        \"class-name\": true,\n        \"comment-format\": [\n            true,\n            \"check-space\"\n        ],\n        \"indent\": [\n            true,\n            \"spaces\"\n        ],\n        \"no-eval\": true,\n        \"no-internal-module\": true,\n        \"no-trailing-whitespace\": true,\n        \"no-unsafe-finally\": true,\n        \"one-line\": [\n            true,\n            \"check-open-brace\",\n            \"check-whitespace\"\n        ],\n        \"quotemark\": [\n            true,\n            \"double\"\n        ],\n        \"semicolon\": [\n            true,\n            \"always\"\n        ],\n        \"triple-equals\": [\n            true,\n            \"allow-null-check\"\n        ],\n        \"typedef-whitespace\": [\n            true,\n            {\n                \"call-signature\": \"nospace\",\n                \"index-signature\": \"nospace\",\n                \"parameter\": \"nospace\",\n                \"property-declaration\": \"nospace\",\n                \"variable-declaration\": \"nospace\"\n            }\n        ],\n        \"variable-name\": [\n            true,\n            \"ban-keywords\"\n        ],\n        \"whitespace\": [\n            true,\n            \"check-branch\",\n            \"check-decl\",\n            \"check-operator\",\n            \"check-separator\",\n            \"check-type\"\n        ]\n    },\n    \"jsRules\": {\n        \"triple-equals\": [\n            true,\n            \"allow-null-check\"\n        ],\n        \"arrow-parens\": true\n    },\n    \"defaultSeverity\": \"warning\"\n}"
  },
  {
    "path": "thirdpartynotices.txt",
    "content": "THIRD-PARTY SOFTWARE NOTICES AND INFORMATION\r\nFor tslint-language-service\r\n\r\nThis project incorporates material from the project(s) listed below (collectively, “Third Party Code”).\r\nThis Third Party Code is licensed to you under their original license terms set forth below.  \r\n\r\n1.       vscode-tslint version 0.1.2 (https://github.com/Microsoft/vscode-tslint)\r\n2.       tslint-language-service (https://github.com/angelozerr/tslint-language-service)\r\n\r\n\r\n1. \r\n\r\nCopyright (c) Microsoft Corporation\r\n\r\nAll rights reserved. \r\n\r\nMIT License\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n\r\n---\r\n\r\n2.\r\n\r\nMIT License\r\n\r\nCopyright (c) 2017 Angelo\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE."
  },
  {
    "path": "tsconfig.json",
    "content": "{\r\n\t\"compilerOptions\": {\r\n\t\t\"target\": \"es6\",\r\n\t\t\"module\": \"commonjs\",\r\n\t\t\"sourceMap\": true,\r\n\t\t\"outDir\": \"out\",\r\n\t\t\"noImplicitAny\": true,\r\n\t\t\"noUnusedParameters\": true,\r\n\t\t\"noUnusedLocals\": true,\r\n\t\t\"forceConsistentCasingInFileNames\": true,\r\n\t\t\"lib\": [\r\n\t\t\t\"es6\"\r\n\t\t],\r\n\t\t\"strict\": true,\r\n\t\t\"baseUrl\": \"./src\"\r\n\t},\r\n\t\"include\": [\r\n\t\t\"./src/**/*.ts\"\r\n\t]\r\n}"
  },
  {
    "path": "tslint.main.json",
    "content": "{\r\n\t\"defaultSeverity\": \"error\",\r\n\t\"extends\": [\r\n\t\t\"tslint:recommended\"\r\n\t],\r\n\t\"rules\": {\r\n\t\t\"indent\": [\r\n\t\t\ttrue,\r\n\t\t\t\"spaces\"\r\n\t\t],\r\n\t\t\"interface-name\": [\r\n\t\t\ttrue,\r\n\t\t\t\"never-prefix\"\r\n\t\t],\r\n\t\t\"variable-name\": [\r\n\t\t\ttrue,\r\n\t\t\t\"check-format\",\r\n\t\t\t\"allow-leading-underscore\"\r\n\t\t],\r\n\t\t\"curly\": [\r\n\t\t\ttrue,\r\n\t\t\t\"ignore-same-line\"\r\n\t\t],\r\n\t\t\"member-access\": [\r\n\t\t\ttrue\r\n\t\t],\r\n\t\t\"max-classes-per-file\": false,\r\n\t\t\"no-empty\": false,\r\n\t\t\"object-literal-sort-keys\": false,\r\n\t\t\"no-unused-expression\": true,\r\n\t\t\"arrow-parens\": [\r\n\t\t\ttrue,\r\n\t\t\t\"ban-single-arg-parens\"\r\n\t\t],\r\n\t\t\"quotemark\": false,\r\n\t\t\"eofline\": false,\r\n\t\t\"semicolon\": [\r\n\t\t\ttrue,\r\n\t\t\t\"always\"\r\n\t\t],\r\n\t\t\"no-console\": false,\r\n\t\t\"class-name\": true,\r\n\t\t\"prefer-const\": true,\r\n\t\t\"import-spacing\": true,\r\n\t\t\"ordered-imports\": false,\r\n\t\t\"trailing-comma\": [\r\n\t\t\ttrue,\r\n\t\t\t{\r\n\t\t\t\t\"multiline\": {\r\n\t\t\t\t\t\"objects\": \"always\",\r\n\t\t\t\t\t\"arrays\": \"always\",\r\n\t\t\t\t\t\"functions\": \"ignore\",\r\n\t\t\t\t\t\"typeLiterals\": \"ignore\"\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t],\r\n\t\t\"max-line-length\": false\r\n\t},\r\n\t\"rulesDirectory\": [],\r\n\t\"linterOptions\": {\r\n\t\t\"exclude\": [\r\n\t\t\t\"e2e/**/*\"\r\n\t\t]\r\n\t}\r\n}"
  }
]