main 585ee21fe900 cached
70 files
109.6 KB
25.9k tokens
102 symbols
1 requests
Download .txt
Repository: Microsoft/typescript-tslint-plugin
Branch: main
Commit: 585ee21fe900
Files: 70
Total size: 109.6 KB

Directory structure:
gitextract_radjmpqj/

├── .gitignore
├── .npmignore
├── .travis.yml
├── .vscode/
│   ├── launch.json
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── e2e/
│   ├── package.json
│   ├── project-fixture/
│   │   ├── .vscode/
│   │   │   └── settings.json
│   │   ├── main.ts
│   │   ├── tsconfig.json
│   │   └── tslint.json
│   ├── server-fixture/
│   │   └── index.js
│   └── tests/
│       ├── assert.js
│       ├── codeFixes.test.js
│       ├── errors.test.js
│       └── helpers.js
├── package.json
├── src/
│   ├── config.ts
│   ├── configFileWatcher.ts
│   ├── index.ts
│   ├── logger.ts
│   ├── plugin.ts
│   ├── runner/
│   │   ├── failures.ts
│   │   ├── index.ts
│   │   ├── mruCache.ts
│   │   └── test/
│   │       ├── mruCache.test.ts
│   │       └── runner.test.ts
│   └── settings.ts
├── test-data/
│   ├── invalid-install/
│   │   ├── package.json
│   │   ├── test.ts
│   │   └── tslint.json
│   ├── js-disabled/
│   │   ├── test.js
│   │   ├── test.mjs
│   │   └── tslint.json
│   ├── no-tslint/
│   │   └── test.ts
│   ├── no-unused-variables/
│   │   ├── test.ts
│   │   └── tslint.json
│   ├── overlapping-errors/
│   │   ├── test.ts
│   │   └── tslint.json
│   ├── warnings/
│   │   ├── test.ts
│   │   └── tslint.json
│   ├── with-tslint/
│   │   ├── excluded.ts
│   │   ├── test.js
│   │   ├── test.ts
│   │   ├── tslint.json
│   │   └── unused-variable.ts
│   └── with-tslint-js-config-file/
│       ├── test.ts
│       └── tslint.js
├── test-workspace/
│   ├── .vscode/
│   │   └── settings.json
│   ├── examples/
│   │   ├── array-type.ts
│   │   ├── arrow-parens.ts
│   │   ├── eval.ts
│   │   ├── no-var-keyword.ts
│   │   ├── no_unused-variable.ts
│   │   ├── ordered-imports.ts
│   │   ├── overlapping-fixes.ts
│   │   ├── quotemark.ts
│   │   ├── semicolon.ts
│   │   ├── test-javascript.js
│   │   ├── test.d.ts
│   │   ├── trailing-comma.ts
│   │   └── triple-equals.ts
│   ├── package.json
│   ├── tsconfig.json
│   └── tslint.json
├── thirdpartynotices.txt
├── tsconfig.json
└── tslint.main.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store
.project
*.log

# Dependencies
node_modules

# Intermediary compilation files
out

# Deployment files
lib


================================================
FILE: .npmignore
================================================
.npmignore
/scripts
/src
/test
/dev
/out/test
/out/**/*.map
/images
/test-data
/test-workspace
/documentation
/e2e

tsconfig.json
tslint.json
.travis.yml
.vscode
.project
node_modules
*.test.js
*.js.map

================================================
FILE: .travis.yml
================================================
branches:
  only:
  - master

language: node_js

node_js:
  - '9'

sudo: false

matrix:
  include:
    - os: linux
    - os: mac
    - os: windows

env:
  - YARN_GPG=no
  
install:
  - npm install 
  - (cd e2e ; npm install)

script:
  - npm run compile
  - npm run test
  - npm run e2e
  - npm run lint

after_failure:
  - cat e2e/server-fixture/server.log


================================================
FILE: .vscode/launch.json
================================================
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "attach",
            "name": "Attach",
            "port": 9999,
            "skipFiles": [
                "<node_internals>/**"
            ]
        }
    ]
}

================================================
FILE: .vscode/settings.json
================================================
{
    "typescript.preferences.quoteStyle": "single",
    "tslint.configFile": "tslint.main.json"
}

================================================
FILE: CHANGELOG.md
================================================
# Changelog

## 1.0.2 - March 31, 2022
- Deprecate package as eslint is now preferred for TypeScript linting.
- Try ignoring in-memory files which can crash tslint.

## 1.0.1 - December 14, 2020
- Catch error when resolving global tslint fails. Thanks @nickjs!

## 1.0.0 - November 30, 2020
- 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).
    - Global TSLint versions can always be loaded.
    - TSLint versions installed next to the plugin can always be loaded.
    - Otherwise, the consumer of the plugin must use `onConfigurationChanged` and explicitly enable `allowWorkspaceLibraryExecution`.
    - You can also force allow workspace versions of TSLint to be loaded by setting a `TS_TSLINT_ENABLE_WORKSPACE_LIBRARY_EXECUTION`  environment variable.

## 0.5.5 - November 11, 2019
- Restore old cwd after linting finishes.

## 0.5.4 - July 10, 2019
- Make sure we pass along packageManager from plugin.

## 0.5.3 - June 28, 2019
- Fixed the disable quick fix not having correct indentation.

## 0.5.2 - June 21, 2019
- Fixes the config file diagnostic not having `tslint` as its source.

## 0.5.1 - June 21, 2019
- Fixes `mjs` files being linted by default.

## 0.5.0 - June 10, 2019
- Add pnpm as `packageManager` option.

## 0.4.0 - May 21, 2019
- 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.

## 0.3.1 - January 31, 2019
- Fix the `fix-all` action show up even on non-autofixable errors.

## 0.3.0 - January 21, 2019
- Set `fixName` on returned actions. Thanks @kondi!
- Fix TS Lint's fix all quick fix showing up on non-tslint errors.
- Use `getCombinedQuickFixes` to compute 'fix all of X' errors. 

## 0.2.1 - December 14, 2018
- Fix `ignoreDefinitionFiles` defaulting to false.

## 0.2.0 - December 12, 2018
- Allowing configuring `excluded` files. Thanks @vemoo!
- Default `alwaysShowRuleFailuresAsWarnings` to true. Set `"alwaysShowRuleFailuresAsWarnings": false` to restore the old behavior.
- Removing logic for older TS lint versions. Only TSlint5 was ever officially supported but there was still some logic for handling older tslint4.
- 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.

## 0.1.2 - November 28, 2018
- Always show a disable rule fix for TSLint errors. Thanks @reduckted!

## 0.1.1 - November 27, 2018
- 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.

## 0.1.0 - November 16, 2018
- Add support for configuring the plugin from an editor.
- Correctly observe changes to the `tsconfig`/`jsconfig`.
- Fix error that could cause duplicate tslint errors to be reported.

## 0.0.7 - November 15, 2018
- Fix potential state corruption error when using TS 3.2.

## 0.0.6 - November 13, 2018
- Add `enableJs` option to enable/disable validating js. Default to `false`.

## 0.0.5 - November 5, 2018
- Use diagnostic as label for quick fixes
- Enable for js files included in tsconfig.

## 0.0.4 - October 23, 2018
- Fix spelling of setting name

## 0.0.3 - October 22, 2018
- Don't call `getProgram` directly since it may corrupt the TS Server state
- Exclude some files from npm package.

## 0.0.2 - October 19, 2018

- Initial release

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 Microsoft

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# TypeScript TSLint Language Service Plugin

[![Build Status](https://travis-ci.org/Microsoft/typescript-tslint-plugin.svg?branch=master)](https://travis-ci.org/Microsoft/typescript-tslint-plugin)

> **❗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.
>
> Please look into [migrating your projects to ESLint](https://github.com/typescript-eslint/typescript-eslint#typescript-eslint).

TypeScript [language service plugin](https://blogs.msdn.microsoft.com/typescript/2017/04/27/announcing-typescript-2-3/) for [TSLint][tslint].

To use the plugin:

* Install TSLint 5+ in your workspace or globally (if you are using a local TSLint, see [workspace library execution](#workspace-library-execution))

* Install the plugin with `npm install typescript-tslint-plugin` 

* Enable the plugin in your `tsconfig.json` file:

    ```json
    {
      "compilerOptions": {
        "plugins": [
          { "name": "typescript-tslint-plugin" }
        ]
      }
    }
    ```

See [editor support](#editor-support) for more detailed setup instructions.

## Workspace Library Execution

By 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.

To use enable using a local TSLint install and custom rules from the workspace, you must either:

- Use a workspace version of TypeScript that is installed alongside TSLint.

- Enable workspace library execution in your editor of choice. This must be done through an editor and cannot be configured in a `tsconfig`.

    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.

- 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.

## Configuration options

**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.

 * `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.
 * `jsEnable` - Enable/disable tslint for `.js` files, default is `false`.
 * `ignoreDefinitionFiles` - Control if TypeScript definition files should be ignored. Default is `true`
 * `alwaysShowRuleFailuresAsWarnings` - Always show rule failures as warnings, ignoring the severity configuration in the tslint.json configuration. Default is `true`.
 * `suppressWhileTypeErrorsPresent` - Suppress tslint errors from being reported while other errors are present.
 * `exclude` - List of files to exclude from tslint.
 * `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`.
 
Here is a configuration sample:

```json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-tslint-plugin",
        "alwaysShowRuleFailuresAsWarnings": false,
        "ignoreDefinitionFiles": true,
        "configFile": "../tslint.json",
        "suppressWhileTypeErrorsPresent": false
      }
    ]
  }
}
```

**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. 


# Editor Support
This 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.

## With VS Code
*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.*

The 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.

If you are using a workspace version of TypeScript, you must manually install the plugin alongside the version of TypeScript in your workspace:

```bash
npm install --save-dev typescript-tslint-plugin typescript
```

Then 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)

```json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-tslint-plugin"
      }
    ]
  }
}
```

Finally, 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).

![Usage with VS Code](documentation/example-vscode.png)

The most important differences between the `vscode-tslint` extension and `typescript-tslint-plugin` are:

* The plugin shares the program representation with TypeScript. This is more efficient than the `vscode-tslint` extension which needs 
  to reanalyze the document.
* 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.
* `vscode-tslint` provides additional [features](https://marketplace.visualstudio.com/items?itemName=eg2.tslint), please file issue requests for the features you are missing.


### With Atom
This plugin works with the [Atom TypeScript plugin](https://atom.io/packages/atom-typescript).

First install the plugin and a copy of TypeScript in your workspace:

```bash
npm install --save-dev typescript-tslint-plugin typescript
```

Then 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.

```json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-tslint-plugin"
      }
    ]
  }
}
```

![Usage with atom](documentation/example-atom.png)


### With Sublime
This plugin works with the [Sublime TypeScript plugin](https://github.com/Microsoft/TypeScript-Sublime-Plugin).

First install the plugin and a copy of TypeScript in your workspace:

```bash
npm install --save-dev typescript-tslint-plugin typescript
```

And 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:

```json
{
  "typescript_tsdk": "/Users/me/my-amazing-project/node_modules/typescript/lib"
}
```

Finally 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.

```json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-tslint-plugin"
      }
    ]
  }
}
```

![Usage with Sublime](documentation/example-sublime.png)

### With Visual Studio
This plugin works [Visual Studio 2017](https://www.visualstudio.com) using the TypeScript 2.5+ SDK.

First install the plugin in your project:

```bash
npm install --save-dev typescript-tslint-plugin
```

Then add a `plugins` section to your [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html).

```json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-tslint-plugin"
      }
    ]
  }
}
```

Then reload your project to make sure the plugin has been loaded properly. Note that `jsconfig.json` projects are currently not supported in Visual Studio.

### With vim and neovim

Use [coc-tslint-plugin](https://github.com/neoclide/coc-tslint-plugin) as extension of [coc.nvim](https://github.com/neoclide/coc.nvim).

Run command in your vim after coc.nvim installed:

```
:CocInstall coc-tsserver coc-tslint-plugin
```

Run command `:CocConfig` to open configuration file.

# Contributing
To build the typescript-tslint-plugin, you'll need [Git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/).

First, [fork](https://help.github.com/articles/fork-a-repo/) the typescript-tslint-plugin repo and clone your fork:

```bash
git clone https://github.com/YOUR_GITHUB_ACCOUNT_NAME/typescript-tslint-plugin.git
cd typescript-tslint-plugin
```

Then install dev dependencies:

```bash
npm install
```

The 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:

```bash
npm run compile
```

Please also see our [Code of Conduct](CODE_OF_CONDUCT.md).

## VS Code

To 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).

To 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:

- Use the insider version for development and open it on the typescript-tslint-plugin workspace.
- Use the stable version for debugging opened on the `test-workspace` folder of the tslint-language service.

To setup the stable version for debugging, you need to set the environment variable `TSS_DEBUG` to port 5859. In a command prompt/shell:

- make sure that the stable version isn't running already
- `set TSS_DEBUG=5859`
- cd to the `dev` folder
- `code .`

To debug the plugin press `F5`. The `dev` workspace has a launch configuration that attaches through port 5859 to the language server. 

# Credits

This project was forked from  https://github.com/angelozerr/tslint-language-service which itself is based on https://github.com/Microsoft/vscode-tslint/


[tslint]: https://github.com/palantir/tslint


================================================
FILE: e2e/package.json
================================================
{
  "name": "e2e",
  "private": true,
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "directories": {
    "test": "tests"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "typescript": "3.1.3",
    "typescript-tslint-plugin": "file:./.."
  }
}


================================================
FILE: e2e/project-fixture/.vscode/settings.json
================================================
{
    "typescript.tsdk": "node_modules/typescript/lib"
}

================================================
FILE: e2e/project-fixture/main.ts
================================================


================================================
FILE: e2e/project-fixture/tsconfig.json
================================================
{
    "compilerOptions": {
        "plugins": [
            {
                "name": "typescript-tslint-plugin",
                "alwaysShowRuleFailuresAsWarnings": false,
                "ignoreDefinitionFiles": true
                //"configFile": "../tslint.json",
            }
        ],
        "module": "commonjs",
        "target": "es6",
        "allowJs": true,
        "noImplicitAny": false,
        "sourceMap": false,
        "noEmit": true
    }
}

================================================
FILE: e2e/project-fixture/tslint.json
================================================
{
    "rules": {
        "array-type": [
            true,
            "array-simple"
        ],
        "no-unused-expression": true,
        "arrow-parens": true,
        "no-var-keyword": true,
        "no-unused-variable": [
            true,
            {
                "ignore-pattern": "^_"
            }
        ],
        "ordered-imports": [
            true,
            {
                "import-sources-order": "lowercase-last",
                "named-imports-order": "lowercase-first"
            }
        ],
        "trailing-comma": [
            true,
            {
                "multiline": "always",
                "singleline": "never"
            }
        ],
        "class-name": true,
        "comment-format": [
            true,
            "check-space"
        ],
        "indent": [
            true,
            "spaces"
        ],
        "no-eval": true,
        "no-internal-module": true,
        "no-trailing-whitespace": true,
        "no-unsafe-finally": true,
        "one-line": [
            true,
            "check-open-brace",
            "check-whitespace"
        ],
        "quotemark": [
            true,
            "double"
        ],
        "semicolon": [
            true,
            "always"
        ],
        "triple-equals": [
            true,
            "allow-null-check"
        ],
        "typedef-whitespace": [
            true,
            {
                "call-signature": "nospace",
                "index-signature": "nospace",
                "parameter": "nospace",
                "property-declaration": "nospace",
                "variable-declaration": "nospace"
            }
        ],
        "variable-name": [
            true,
            "ban-keywords"
        ],
        "whitespace": [
            true,
            "check-branch",
            "check-decl",
            "check-operator",
            "check-separator",
            "check-type"
        ]
    },
    "jsRules": {
        "triple-equals": [
            true,
            "allow-null-check"
        ],
        "arrow-parens": true
    },
    "defaultSeverity": "warning"
}

================================================
FILE: e2e/server-fixture/index.js
================================================
const { fork } = require('child_process');
const path = require('path');
const readline = require('readline');

class TSServer {
    constructor(project) {
        const logfile = path.join(__dirname, 'server.log');
        const tsserverPath = path.join(__dirname, '..', 'node_modules', 'typescript', 'lib', 'tsserver');
        const server = fork(tsserverPath, [
            '--logVerbosity', 'verbose',
            '--logFile', logfile,
            '--pluginProbeLocations', path.join(__dirname, '..')
        ], {
                cwd: path.join(__dirname, '..', project),
                stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
            });
        this._exitPromise = new Promise((resolve, reject) => {
            server.on('exit', code => resolve(code));
            server.on('error', reason => reject(reason));
        });
        server.stdout.setEncoding('utf-8');
        readline.createInterface({
            input: server.stdout
        }).on('line', line => {
            if (line[0] !== '{') {
                return;
            }
            try {
                const result = JSON.parse(line);
                if (result.type === 'response') {
                    this.responses.push(result);
                    --this._pendingResponses;

                    if (this._pendingResponses <= 0 && this._isClosed) {
                        this._shutdown();
                    }
                }
            } catch (e) {
                // noop
            }

        });

        this._isClosed = false;
        this._server = server;
        this._seq = 0;
        this.responses = [];
        this._pendingResponses = 0;
    }

    send(command, responseExpected) {
        if (this._isClosed) {
            throw new Error('server is closed');
        }
        if (responseExpected) {
            ++this._pendingResponses;
        }
        const seq = ++this._seq;
        const req = JSON.stringify(Object.assign({ seq: seq, type: 'request' }, command)) + '\n';
        this._server.stdin.write(req);
    }

    sendCommand(name, args) {
        this.send({ command: name, arguments: args }, true);
    }

    close() {
        if (!this._isClosed) {
            this._isClosed = true;
            if (this._pendingResponses <= 0) {
                this._shutdown();
            }
        }
        return this._exitPromise;
    }

    _shutdown() {
        this._server.stdin.end();
    }
}

function createServer(project) {
    return new TSServer(project || 'project-fixture');
}

module.exports = createServer;


================================================
FILE: e2e/tests/assert.js
================================================
// @ts-check

const assert = require('chai').assert;

/**
 * @param {{ start: { line: number, offset: number }, end: { line: number, offset: number }}} span
 * @param {{ line: number, offset: number }} start
 * @param {{ line: number, offset: number }} end
 */
function assertSpan(span, start, end) {
    assertPosition(span.start, start.line, start.offset);
    assertPosition(span.end, end.line, end.offset);
};

/**
 * @param {{ line: number, offset: number }} pos
 * @param {number} line 
 * @param {number} offset
 */
function assertPosition(pos, line, offset) {
    assert.strictEqual(pos.line, line);
    assert.strictEqual(pos.offset, offset);
};

module.exports = {
    assertPosition,
    assertSpan
};

================================================
FILE: e2e/tests/codeFixes.test.js
================================================
// @ts-check
const { assertSpan } = require('./assert');
const assert = require('chai').assert;
const path = require('path');
const createServer = require('../server-fixture');
const { openMockFile, getFirstResponseOfType } = require('./helpers');


const mockFileName = path.join(__dirname, '..', 'project-fixture', 'main.ts').replace(/\\/g, '/');

/**
 * @param {string[]} fileContents 
 */
function createServerForFile(...fileContents) {
    const server = createServer();
    openMockFile(server, mockFileName, fileContents.join('\n'));
    return server;
}

/**
 * @param {*} server 
 * @param {{ startLine: number, startOffset: number, endLine: number, endOffset: number, additionalErrorCodes?: number[] }} data
 */
const getCodeFixes = async (server, data) => {

    // Generate diagnostics 
    server.sendCommand('semanticDiagnosticsSync', { file: mockFileName });

    return server.sendCommand('getCodeFixes', {
        file: mockFileName,
        startLine: data.startLine,
        startOffset: data.startOffset,
        endLine: data.endLine,
        endOffset: data.endOffset,
        errorCodes: [1, ...(data.additionalErrorCodes || [])]
    });
};

const getCombinedCodeFixes = (server, fixId) => {
    return server.sendCommand('getCombinedCodeFix', {
        scope: {
            type: 'file',
            args: { file: mockFileName }
        },
        fixId: fixId,
    });
};

describe('CodeFixes', () => {
    let server = undefined;

    after(() => {
        if (server) {
            server.close();
            server = undefined;
        }
    })

    it('should return fix and disables for single error', async () => {
        server = createServerForFile(
            `let t: Array<string> = new Array<string>(); console.log(t);`
        );
        await getCodeFixes(server, {
            startLine: 1,
            startOffset: 8,
            endLine: 1,
            endOffset: 21,
        });
        await server.close();
        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);

        assert.isTrue(codeFixesResponse.success);
        assert.deepEqual(codeFixesResponse.body, [
            {
                "fixName": "tslint:array-type",
                "description": "Fix: Array type using 'Array<T>' is forbidden for simple types. Use 'T[]' instead.",
                "changes": [
                    {
                        "fileName": mockFileName,
                        "textChanges": [
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 8
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 14
                                },
                                "newText": ""
                            },
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 20
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 21
                                },
                                "newText": "[]"
                            }
                        ]
                    }
                ]
            },
            {
                "fixName": "tslint:fix-all",
                "description": "Fix all auto-fixable tslint failures",
                "changes": [
                    {
                        "fileName": mockFileName,
                        "textChanges": [
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 8
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 14
                                },
                                "newText": ""
                            },
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 20
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 21
                                },
                                "newText": "[]"
                            }
                        ]
                    }
                ]
            },
            {
                "fixName": "tslint:disable:array-type",
                "description": "Disable rule 'array-type'",
                "changes": [
                    {
                        "fileName": mockFileName,
                        "textChanges": [
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 1
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 1
                                },
                                "newText": "// tslint:disable-next-line: array-type\n"
                            }
                        ]
                    }
                ]
            }
        ]);
    });

    it('should return individual fixes and fix all for multiple errors of same type in file', async () => {
        server = createServerForFile(
            `let x: Array<string> = new Array<string>(); console.log(x);\nlet y: Array<string> = new Array<string>(); console.log(y);`,
        );
        await getCodeFixes(server, {
            startLine: 1,
            startOffset: 8,
            endLine: 1,
            endOffset: 21,
        });
        await getCombinedCodeFixes(server, 'tslint:array-type');

        await server.close();

        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);
        const combinedFixesResponse = await getFirstResponseOfType('getCombinedCodeFix', server);

        assert.isTrue(codeFixesResponse.success);
        assert.strictEqual(codeFixesResponse.body.length, 3);

        assert.deepEqual(codeFixesResponse.body, [
            {
                "fixName": "tslint:array-type",
                "description": "Fix: Array type using 'Array<T>' is forbidden for simple types. Use 'T[]' instead.",
                "fixAllDescription": "Fix all 'array-type'",
                "fixId": "tslint:array-type",
                "changes": [
                    {
                        "fileName": mockFileName,
                        "textChanges": [
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 8
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 14
                                },
                                "newText": ""
                            },
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 20
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 21
                                },
                                "newText": "[]"
                            }
                        ]
                    }
                ]
            },
            {
                "fixName": "tslint:fix-all",
                "description": "Fix all auto-fixable tslint failures",
                "changes": [
                    {
                        "fileName": mockFileName,
                        "textChanges": [
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 8
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 14
                                },
                                "newText": ""
                            },
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 20
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 21
                                },
                                "newText": "[]"
                            },
                            {
                                "start": {
                                    "line": 2,
                                    "offset": 8
                                },
                                "end": {
                                    "line": 2,
                                    "offset": 14
                                },
                                "newText": ""
                            },
                            {
                                "start": {
                                    "line": 2,
                                    "offset": 20
                                },
                                "end": {
                                    "line": 2,
                                    "offset": 21
                                },
                                "newText": "[]"
                            }
                        ]
                    }
                ]
            },
            {
                "fixName": "tslint:disable:array-type",
                "description": "Disable rule 'array-type'",
                "changes": [
                    {
                        "fileName": mockFileName,
                        "textChanges": [
                            {
                                "start": {
                                    "line": 1,
                                    "offset": 1
                                },
                                "end": {
                                    "line": 1,
                                    "offset": 1
                                },
                                "newText": "// tslint:disable-next-line: array-type\n"
                            }
                        ]
                    }
                ]
            }
        ]);

        assert.isTrue(combinedFixesResponse.success);
        assert.deepEqual(combinedFixesResponse.body, {
            "changes": [
                {
                    "fileName": mockFileName,
                    "textChanges": [
                        {
                            "start": {
                                "line": 1,
                                "offset": 8
                            },
                            "end": {
                                "line": 1,
                                "offset": 14
                            },
                            "newText": ""
                        },
                        {
                            "start": {
                                "line": 1,
                                "offset": 20
                            },
                            "end": {
                                "line": 1,
                                "offset": 21
                            },
                            "newText": "[]"
                        }
                    ]
                },
                {
                    "fileName": mockFileName,
                    "textChanges": [
                        {
                            "start": {
                                "line": 2,
                                "offset": 8
                            },
                            "end": {
                                "line": 2,
                                "offset": 14
                            },
                            "newText": ""
                        },
                        {
                            "start": {
                                "line": 2,
                                "offset": 20
                            },
                            "end": {
                                "line": 2,
                                "offset": 21
                            },
                            "newText": "[]"
                        }
                    ]
                }
            ]
        });
    });

    it('should not return ts-lint fixes on non-tslint errors', async () => {
        server = createServerForFile(
            `const a = 1; a = 2`
        );
        await getCodeFixes(server, {
            startLine: 1,
            startOffset: 13,
            endLine: 1,
            endOffset: 14,
        });
        await server.close();
        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);

        assert.isTrue(codeFixesResponse.success);
        assert.deepEqual(codeFixesResponse.body, []);
    });

    it('should not return TS Lint fix-all for non-fixable errors', async () => {
        server = createServerForFile(
            `const foo = 123; food`
        );
        await getCodeFixes(server, {
            startLine: 1,
            startOffset: 18,
            endLine: 1,
            endOffset: 22,
            additionalErrorCodes: [2552]
        });
        await server.close();
        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);

        assert.isTrue(codeFixesResponse.success);
        assert.deepEqual(codeFixesResponse.body.length, 2);
        assert.deepEqual(codeFixesResponse.body[0].fixName, 'spelling');
        assert.deepEqual(codeFixesResponse.body[1].fixName, 'tslint:disable:no-unused-expression');
    });

    it('disable comment should be correctly indented', async () => {
        server = createServerForFile(
            '{',
            '    const a = 1',
            '}'
        );
        await getCodeFixes(server, {
            startLine: 2,
            startOffset: 16,
            endLine: 2,
            endOffset: 16,
            additionalErrorCodes: [2552]
        });
        await server.close();
        const codeFixesResponse = await getFirstResponseOfType('getCodeFixes', server);

        assert.isTrue(codeFixesResponse.success);
        assert.deepEqual(codeFixesResponse.body.length, 3);
        const disableFix = codeFixesResponse.body[2];
        const change = disableFix.changes[0].textChanges[0];
        assert.strictEqual(change.start.line, 2);
        assert.strictEqual(change.start.offset, 1);
        assert.strictEqual(change.newText, '    // tslint:disable-next-line: semicolon\n');
    });
});


================================================
FILE: e2e/tests/errors.test.js
================================================
// @ts-check
const { assertSpan } = require('./assert');
const assert = require('chai').assert;
const path = require('path');
const createServer = require('../server-fixture');
const { openMockFile, getFirstResponseOfType } = require('./helpers');

const tslintSource = 'tslint';

const mockFileName = path.join(__dirname, '..', 'project-fixture', 'main.ts');

const getSemanticDiagnosticsForFile = (fileContents) => {
    const server = createServer();
    openMockFile(server, mockFileName, fileContents);
    server.sendCommand('semanticDiagnosticsSync', { file: mockFileName });

    return server.close().then(_ => {
        return getFirstResponseOfType('semanticDiagnosticsSync', server);
    });
}

describe('Errors', () => {
    it('array-type', async () => {
        const errorResponse = await getSemanticDiagnosticsForFile(
            `let t: Array<string> = new Array<string>(); console.log(t);`);

        assert.isTrue(errorResponse.success);
        assert.strictEqual(errorResponse.body.length, 1);

        const [error1] = errorResponse.body;
        assert.strictEqual(error1.source, tslintSource);
        assertSpan(error1, { line: 1, offset: 8 }, { line: 1, offset: 21 });
        assert.strictEqual(error1.text, `Array type using 'Array<T>' is forbidden for simple types. Use 'T[]' instead. (array-type)`);
    });

    it('arrow-parens', async () => {
        const errorResponse = await getSemanticDiagnosticsForFile(
            `[1, 2 ].map( num => console.log(num) );`);

        assert.isTrue(errorResponse.success);
        assert.strictEqual(errorResponse.body.length, 1);

        const [error1] = errorResponse.body;
        assert.strictEqual(error1.source, tslintSource);
        assertSpan(error1, { line: 1, offset: 14 }, { line: 1, offset: 17 });
        assert.strictEqual(error1.text, `Parentheses are required around the parameters of an arrow function definition (arrow-parens)`);
    });
});


================================================
FILE: e2e/tests/helpers.js
================================================
const assert = require('chai').assert;

exports.openMockFile = (server, mockFileName, fileContent) => {
    server.send({
        command: 'open',
        arguments: {
            file: mockFileName,
            fileContent,
            scriptKindName: 'TS'
        }
    });
    return server;
};


exports.getFirstResponseOfType = (command, server) => {
    const response = server.responses.find(response => response.command === command);
    assert.isTrue(response !== undefined);
    return response;
};

exports.getResponsesOfType = (command, server) => {
    return server.responses.filter(response => response.command === command);
};

================================================
FILE: package.json
================================================
{
  "name": "typescript-tslint-plugin",
  "version": "1.0.2",
  "description": "TypeScript tslint language service plugin",
  "main": "out/index.js",
  "author": "Microsoft",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/microsoft/typescript-tslint-plugin.git"
  },
  "scripts": {
    "prepublish": "npm run compile",
    "compile": "tsc",
    "test": "TS_TSLINT_ENABLE_WORKSPACE_LIBRARY_EXECUTION=1 mocha ./out/**/*.test.js --slow 2000 --timeout 10000",
    "lint": "tslint -c tslint.main.json 'src/**/*.ts'",
    "e2e": "TS_TSLINT_ENABLE_WORKSPACE_LIBRARY_EXECUTION=1 mocha ./e2e/tests/**/*.test.js --slow 2000 --timeout 10000"
  },
  "dependencies": {
    "minimatch": "^3.0.4",
    "mock-require": "^3.0.3",
    "vscode-languageserver": "^5.2.1"
  },
  "devDependencies": {
    "@types/chai": "^4.1.6",
    "@types/minimatch": "^3.0.3",
    "@types/mocha": "^8.2.0",
    "@types/mock-require": "^2.0.0",
    "@types/node": "^12.12.0",
    "chai": "^4.2.0",
    "mocha": "^9.2.2",
    "tslint": "^6.1.3",
    "typescript": "^4.0.0"
  }
}


================================================
FILE: src/config.ts
================================================
export const pluginId = 'typescript-tslint-plugin';
export const TSLINT_ERROR_CODE = 1;
export const TSLINT_ERROR_SOURCE = 'tslint';

================================================
FILE: src/configFileWatcher.ts
================================================
import * as ts_module from 'typescript/lib/tsserverlibrary';

export class ConfigFileWatcher {
    private readonly _watchedConfigs = new Set<string>();

    public constructor(
        private readonly ts: typeof ts_module,
        private readonly onChange: (fileName: string) => void
    ) { }

    public ensureWatching(file: string) {
        if (!this.ts.sys.watchFile) {
            return;
        }
        if (this._watchedConfigs.has(file)) {
            return;
        }
        this._watchedConfigs.add(file);
        this.ts.sys.watchFile(file, (fileName: string, eventKind: ts.FileWatcherEventKind) => {
            if (eventKind === this.ts.FileWatcherEventKind.Changed) {
                this.onChange(fileName);
            }
        });
    }
}

================================================
FILE: src/index.ts
================================================
import { TSLintPlugin } from './plugin';
import * as ts_module from 'typescript/lib/tsserverlibrary';
import { Logger } from './logger';
import { ConfigurationManager } from './settings';
import * as mockRequire from 'mock-require';
import { WorkspaceLibraryExecution } from './runner';

const enableWorkspaceLibraryExecutionEnvVar = 'TS_TSLINT_ENABLE_WORKSPACE_LIBRARY_EXECUTION';

export = function init({ typescript }: { typescript: typeof ts_module }) {
    const configManager = new ConfigurationManager(typescript);
    let logger: Logger | undefined;
    let plugin: TSLintPlugin | undefined;

    // Make sure TS Lint imports the correct version of TS
    mockRequire('typescript', typescript);

    return {
        create(info: ts.server.PluginCreateInfo) {
            logger = Logger.forPlugin(info);
            logger.info('Create');

            configManager.setProject(info.project, logger);
            configManager.updateFromPluginConfig(info.config);

            if (!isValidTypeScriptVersion(typescript)) {
                logger.info('Invalid typescript version detected. The TSLint plugin requires TypeScript 3.x');
                return info.languageService;
            }

            plugin = new TSLintPlugin(typescript, info.languageServiceHost, logger, info.project, configManager);

            // Allow clients that don't use onConfigurationChanged to still securely enable
            // workspace library execution with an env var.
            const workspaceLibraryFromEnv = process.env[enableWorkspaceLibraryExecutionEnvVar] ? WorkspaceLibraryExecution.Allow : WorkspaceLibraryExecution.Unknown;
            plugin.updateWorkspaceTrust(workspaceLibraryFromEnv);

            return plugin.decorate(info.languageService);
        },
        onConfigurationChanged(config: any) {
            if (logger) {
                logger.info('onConfigurationChanged');
            }

            if (plugin) {
                if ('allowWorkspaceLibraryExecution' in config) {
                    plugin.updateWorkspaceTrust(config.allowWorkspaceLibraryExecution ? WorkspaceLibraryExecution.Allow : WorkspaceLibraryExecution.Disallow);
                }
            }

            configManager.updateFromPluginConfig(config);
        },
    };
};

function isValidTypeScriptVersion(typescript: typeof ts_module): boolean {
    const [major] = typescript.version.split('.');
    return +major >= 3;
}


================================================
FILE: src/logger.ts
================================================
import * as ts_module from 'typescript/lib/tsserverlibrary';

import { pluginId } from './config';

export class Logger {
    public static forPlugin(info: ts_module.server.PluginCreateInfo) {
        return new Logger(info.project.projectService.logger);
    }

    private constructor(
        private readonly _logger: ts_module.server.Logger
    ) { }

    public info(message: string) {
        this._logger.info(`[${pluginId}] ${JSON.stringify(message)}`);
    }
}

================================================
FILE: src/plugin.ts
================================================
import * as tslint from 'tslint';
import * as path from 'path';
import * as ts_module from 'typescript/lib/tsserverlibrary';
import { TSLINT_ERROR_CODE, TSLINT_ERROR_SOURCE } from './config';
import { ConfigFileWatcher } from './configFileWatcher';
import { Logger } from './logger';
import { RunResult, TsLintRunner, toPackageManager, WorkspaceLibraryExecution } from './runner';
import { ConfigurationManager } from './settings';
import { getNonOverlappingReplacements, filterProblemsForFile, getReplacements } from './runner/failures';

const isTsLintLanguageServiceMarker = Symbol('__isTsLintLanguageServiceMarker__');

interface Problem {
    failure: tslint.RuleFailure;
    fixable: boolean;
}

class TsLintFixId {
    public static fromFailure(failure: tslint.RuleFailure) {
        return `tslint:${failure.getRuleName()}`;
    }

    public static toRuleName(fixId: {}): undefined | string {
        if (typeof fixId !== 'string' || !fixId.startsWith('tslint:')) {
            return undefined;
        }
        return fixId.replace(/^tslint:/, '');
    }
}

class ProblemMap {
    private readonly _map = new Map<string, Problem>();

    public get(start: number, end: number) {
        return this._map.get(this.key(start, end));
    }

    public set(start: number, end: number, problem: Problem): void {
        this._map.set(this.key(start, end), problem);
    }

    public values() {
        return this._map.values();
    }

    // key to identify a rule failure
    private key(start: number, end: number): string {
        return `[${start},${end}]`;
    }
}

export class TSLintPlugin {
    private readonly codeFixActions = new Map<string, ProblemMap>();
    private readonly configFileWatcher: ConfigFileWatcher;

    private runner: TsLintRunner;

    private workspaceTrust = WorkspaceLibraryExecution.Unknown;

    public constructor(
        private readonly ts: typeof ts_module,
        private readonly languageServiceHost: ts_module.LanguageServiceHost,
        private readonly logger: Logger,
        private readonly project: ts_module.server.Project,
        private readonly configurationManager: ConfigurationManager,
    ) {
        this.logger.info('loaded');

        this.runner = new TsLintRunner(message => { this.logger.info(message); });

        this.configFileWatcher = new ConfigFileWatcher(ts, filePath => {
            this.logger.info('TSlint file changed');
            this.runner.onConfigFileChange(filePath);
            this.project.refreshDiagnostics();
        });

        this.configurationManager.onUpdatedConfig(() => {
            this.logger.info('TSConfig configuration changed');
            project.refreshDiagnostics();
        });
    }

    public decorate(languageService: ts.LanguageService) {
        if ((languageService as any)[isTsLintLanguageServiceMarker]) {
            // Already decorated
            return;
        }

        const oldGetSupportedCodeFixes = this.ts.getSupportedCodeFixes.bind(this.ts);
        this.ts.getSupportedCodeFixes = (): string[] => {
            return [
                ...oldGetSupportedCodeFixes(),
                '' + TSLINT_ERROR_CODE,
            ];
        };

        const intercept: Partial<ts.LanguageService> = Object.create(null);

        const oldGetSemanticDiagnostics = languageService.getSemanticDiagnostics.bind(languageService);
        intercept.getSemanticDiagnostics = (...args) => {
            return this.getSemanticDiagnostics(oldGetSemanticDiagnostics, ...args);
        };

        const oldGetCodeFixesAtPosition = languageService.getCodeFixesAtPosition.bind(languageService);
        intercept.getCodeFixesAtPosition = (...args): ReadonlyArray<ts.CodeFixAction> => {
            return this.getCodeFixesAtPosition(oldGetCodeFixesAtPosition, ...args);
        };

        const oldGetCombinedCodeFix = languageService.getCombinedCodeFix.bind(languageService);
        intercept.getCombinedCodeFix = (...args): ts_module.CombinedCodeActions => {
            return this.getCombinedCodeFix(oldGetCombinedCodeFix, ...args);
        };

        return new Proxy(languageService, {
            get: (target: any, property: keyof ts.LanguageService & typeof isTsLintLanguageServiceMarker) => {
                if (property === isTsLintLanguageServiceMarker) {
                    return true;
                }
                return intercept[property] || target[property];
            },
        });
    }

    public updateWorkspaceTrust(workspaceTrust: WorkspaceLibraryExecution) {
        this.workspaceTrust = workspaceTrust;

        // Reset the runner
        this.runner = new TsLintRunner(message => { this.logger.info(message); });
    }

    private getSemanticDiagnostics(
        delegate: (fileName: string) => ts_module.Diagnostic[],
        fileName: string,
    ): ts_module.Diagnostic[] {
        const diagnostics = delegate(fileName);

        if (isInMemoryFile(fileName)) {
            // In-memory file. TS-lint crashes on these so ignore them
            return diagnostics;
        }

        const config = this.configurationManager.config;
        if (diagnostics.length > 0 && config.suppressWhileTypeErrorsPresent) {
            return diagnostics;
        }

        try {
            this.logger.info(`Computing tslint semantic diagnostics for '${fileName}'`);

            if (this.codeFixActions.has(fileName)) {
                this.codeFixActions.delete(fileName);
            }

            if (config.ignoreDefinitionFiles && fileName.endsWith('.d.ts')) {
                return diagnostics;
            }

            let result: RunResult;
            try { // protect against tslint crashes
                result = this.runner.runTsLint(fileName, this.getProgram(), {
                    configFile: config.configFile,
                    ignoreDefinitionFiles: config.ignoreDefinitionFiles,
                    jsEnable: config.jsEnable,
                    exclude: config.exclude
                        ? Array.isArray(config.exclude) ? config.exclude : [config.exclude]
                        : [],
                    packageManager: toPackageManager(config.packageManager),
                    workspaceLibraryExecution: this.workspaceTrust,
                });
                if (result.configFilePath) {
                    this.configFileWatcher.ensureWatching(result.configFilePath);
                }
            } catch (err: any) {
                let errorMessage = `unknown error`;
                if (typeof err.message === 'string' || err.message instanceof String) {
                    errorMessage = err.message as string;
                }
                this.logger.info('tslint error ' + errorMessage);
                return diagnostics;
            }

            const program = this.getProgram();
            const file = program.getSourceFile(fileName)!;
            if (result.warnings) {
                const defaultTsconfigJsonPath = path.join(program.getCurrentDirectory(), 'tslint.json');
                if ((result.configFilePath && this.ts.sys.fileExists(result.configFilePath)) || this.ts.sys.fileExists(defaultTsconfigJsonPath)) {
                    // If we have a config file, the user likely wanted to lint. The fact that linting has a
                    // warning should be reported to them.
                    for (const warning of result.warnings) {
                        diagnostics.unshift({
                            file,
                            start: 0,
                            length: 1,
                            category: this.ts.DiagnosticCategory.Warning,
                            source: TSLINT_ERROR_SOURCE,
                            code: TSLINT_ERROR_CODE,
                            messageText: warning,
                        });
                    }
                } else {
                    // If we have not found a config file, then we don't want to annoy users by generating warnings
                    // about tslint not being installed or misconfigured. In many cases, the user is opening a
                    // file/project that was not intended to be linted.
                    for (const warning of result.warnings) {
                        this.logger.info(`[tslint] ${warning}`);
                    }
                }
            }

            const tslintProblems = filterProblemsForFile(fileName, result.lintResult.failures);
            for (const problem of tslintProblems) {
                diagnostics.push(this.makeDiagnostic(problem, file));
                this.recordCodeAction(problem, file);
            }
        } catch (e: any) {
            this.logger.info(`tslint-language service error: ${e.toString()}`);
            this.logger.info(`Stack trace: ${e.stack}`);
        }

        return diagnostics;
    }

    private getCodeFixesAtPosition(
        delegate: ts.LanguageService['getCodeFixesAtPosition'],
        fileName: string,
        start: number,
        end: number,
        errorCodes: ReadonlyArray<number>,
        formatOptions: ts.FormatCodeSettings,
        userPreferences: ts.UserPreferences
    ): ReadonlyArray<ts.CodeFixAction> {
        const fixes = Array.from(delegate(fileName, start, end, errorCodes, formatOptions, userPreferences));

        if (isInMemoryFile(fileName)) {
            return fixes; // We don't have any tslint errors for these files
        }

        if (this.configurationManager.config.suppressWhileTypeErrorsPresent && fixes.length > 0) {
            return fixes;
        }

        this.logger.info(`getCodeFixes ${errorCodes[0]}`);
        this.logger.info(JSON.stringify(fixes));

        const documentFixes = this.codeFixActions.get(fileName);
        if (documentFixes) {
            const problem = documentFixes.get(start, end);
            if (problem) {
                if (problem.fixable) {
                    const fix = problem.failure.getFix();
                    if (fix) {
                        const codeFixAction = this.getRuleFailureQuickFix(problem.failure, fileName);
                        fixes.push(codeFixAction);

                        const fixAll = this.getRuleFailureFixAllQuickFix(problem.failure.getRuleName(), documentFixes, fileName);
                        if (fixAll) {
                            codeFixAction.fixId = TsLintFixId.fromFailure(problem.failure);
                            codeFixAction.fixAllDescription = `Fix all '${problem.failure.getRuleName()}'`;
                        }

                        fixes.push(this.getFixAllAutoFixableQuickFix(documentFixes, fileName));
                    }
                }

                fixes.push(this.getDisableRuleQuickFix(problem.failure, fileName, this.getProgram().getSourceFile(fileName)!));
            }
        }

        return fixes;
    }

    private getCombinedCodeFix(
        delegate: ts.LanguageService['getCombinedCodeFix'],
        scope: ts_module.CombinedCodeFixScope,
        fixId: {},
        formatOptions: ts_module.FormatCodeSettings,
        preferences: ts_module.UserPreferences
    ): ts_module.CombinedCodeActions {
        const ruleName = TsLintFixId.toRuleName(fixId);
        if (!ruleName) {
            return delegate(scope, fixId, formatOptions, preferences);
        }

        const documentFixes = this.codeFixActions.get(scope.fileName);
        if (documentFixes) {
            const fixAll = this.getRuleFailureFixAllQuickFix(ruleName, documentFixes, scope.fileName);
            if (fixAll) {
                return {
                    changes: fixAll.changes,
                    commands: fixAll.commands,
                };
            }
        }

        return { changes: [] };
    }

    private recordCodeAction(failure: tslint.RuleFailure, file: ts.SourceFile) {
        // tslint can return a fix with an empty replacements array, these fixes are ignored
        const fixable = !!(failure.getFix && failure.getFix() && !replacementsAreEmpty(failure.getFix()));

        let documentAutoFixes = this.codeFixActions.get(file.fileName);
        if (!documentAutoFixes) {
            documentAutoFixes = new ProblemMap();
            this.codeFixActions.set(file.fileName, documentAutoFixes);
        }
        documentAutoFixes.set(failure.getStartPosition().getPosition(), failure.getEndPosition().getPosition(), { failure, fixable });
    }

    private getRuleFailureQuickFix(failure: tslint.RuleFailure, fileName: string): ts_module.CodeFixAction {
        return {
            description: `Fix: ${failure.getFailure()}`,
            fixName: `tslint:${failure.getRuleName()}`,
            changes: [failureToFileTextChange(failure, fileName)],
        };
    }

    /**
     * Generate a code action that fixes all instances of ruleName.
     */
    private getRuleFailureFixAllQuickFix(ruleName: string, problems: ProblemMap, fileName: string): ts_module.CodeFixAction | undefined {
        const changes: ts_module.FileTextChanges[] = [];

        for (const problem of problems.values()) {
            if (problem.fixable) {
                if (problem.failure.getRuleName() === ruleName) {
                    changes.push(failureToFileTextChange(problem.failure, fileName));
                }
            }
        }

        // No need for this action if there's only one instance.
        if (changes.length < 2) {
            return undefined;
        }

        return {
            description: `Fix all '${ruleName}'`,
            fixName: `tslint:fix-all:${ruleName}`,
            changes,
        };
    }

    private getDisableRuleQuickFix(failure: tslint.RuleFailure, fileName: string, file: ts_module.SourceFile): ts_module.CodeFixAction {
        const line = failure.getStartPosition().getLineAndCharacter().line;
        const lineStarts = file.getLineStarts();
        const lineStart = lineStarts[line];
        let prefix = '';
        const snapshot = this.languageServiceHost.getScriptSnapshot(fileName);
        if (snapshot) {
            const lineEnd = line < lineStarts.length - 1 ? lineStarts[line + 1] : file.end;
            const lineText = snapshot.getText(lineStart, lineEnd);
            const leadingSpace = lineText.match(/^([ \t]+)/);
            if (leadingSpace) {
                prefix = leadingSpace[0];
            }
        }

        return {
            description: `Disable rule '${failure.getRuleName()}'`,
            fixName: `tslint:disable:${failure.getRuleName()}`,
            changes: [{
                fileName,
                textChanges: [{
                    newText: `${prefix}// tslint:disable-next-line: ${failure.getRuleName()}\n`,
                    span: { start: lineStart, length: 0 },
                }],
            }],
        };
    }

    private getFixAllAutoFixableQuickFix(documentFixes: ProblemMap, fileName: string): ts_module.CodeFixAction {
        const allReplacements = getNonOverlappingReplacements(Array.from(documentFixes.values()).filter(x => x.fixable).map(x => x.failure));
        return {
            description: `Fix all auto-fixable tslint failures`,
            fixName: `tslint:fix-all`,
            changes: [{
                fileName,
                textChanges: allReplacements.map(convertReplacementToTextChange),
            }],
        };
    }

    private getProgram() {
        return this.project.getLanguageService().getProgram()!;
    }

    private makeDiagnostic(failure: tslint.RuleFailure, file: ts.SourceFile): ts.Diagnostic {
        const message = (failure.getRuleName() !== null)
            ? `${failure.getFailure()} (${failure.getRuleName()})`
            : `${failure.getFailure()}`;

        const category = this.getDiagnosticCategory(failure);
        return {
            file,
            start: failure.getStartPosition().getPosition(),
            length: failure.getEndPosition().getPosition() - failure.getStartPosition().getPosition(),
            messageText: message,
            category,
            source: TSLINT_ERROR_SOURCE,
            code: TSLINT_ERROR_CODE,
        };
    }

    private getDiagnosticCategory(failure: tslint.RuleFailure): ts.DiagnosticCategory {
        if (this.configurationManager.config.alwaysShowRuleFailuresAsWarnings || typeof this.configurationManager.config.alwaysShowRuleFailuresAsWarnings === 'undefined') {
            return this.ts.DiagnosticCategory.Warning;
        }
        if (failure.getRuleSeverity && failure.getRuleSeverity() === 'error') {
            return this.ts.DiagnosticCategory.Error;
        }
        return this.ts.DiagnosticCategory.Warning;
    }
}

function isInMemoryFile(fileName: string) {
    return fileName.startsWith('^');
}

function convertReplacementToTextChange(repl: tslint.Replacement): ts_module.TextChange {
    return {
        newText: repl.text,
        span: { start: repl.start, length: repl.length },
    };
}

function failureToFileTextChange(failure: tslint.RuleFailure, fileName: string): ts_module.FileTextChanges {
    const fix = failure.getFix();
    const replacements: tslint.Replacement[] = getReplacements(fix);

    return {
        fileName,
        textChanges: replacements.map(convertReplacementToTextChange),
    };
}

function replacementsAreEmpty(fix: tslint.Fix | undefined): boolean {
    if (Array.isArray(fix)) {
        return fix.length === 0;
    }
    return false;
}


================================================
FILE: src/runner/failures.ts
================================================
import { normalize } from 'path';
import * as tslint from 'tslint'; // this is a dev dependency only

/**
 * Filter failures for the given document
 */
export function filterProblemsForFile(
    filePath: string,
    failures: tslint.RuleFailure[],
): tslint.RuleFailure[] {
    const normalizedPath = normalize(filePath);
    // we only show diagnostics targetting this open document, some tslint rule return diagnostics for other documents/files
    const normalizedFiles = new Map<string, string>();
    return failures.filter(each => {
        const fileName = each.getFileName();
        if (!normalizedFiles.has(fileName)) {
            normalizedFiles.set(fileName, normalize(fileName));
        }
        return normalizedFiles.get(fileName) === normalizedPath;
    });
}

export function getReplacements(fix: tslint.Fix | undefined): tslint.Replacement[] {
    if (!fix) {
        return [];
    } else if (Array.isArray(fix)) {
        return fix;
    } else {
        return [fix];
    }
}

function getReplacement(failure: tslint.RuleFailure, at: number): tslint.Replacement {
    return getReplacements(failure.getFix())[at];
}

export function sortFailures(failures: tslint.RuleFailure[]): tslint.RuleFailure[] {
    // The failures.replacements are sorted by position, we sort on the position of the first replacement
    return failures.sort((a, b) => {
        return getReplacement(a, 0).start - getReplacement(b, 0).start;
    });
}

export function getNonOverlappingReplacements(failures: tslint.RuleFailure[]): tslint.Replacement[] {
    function overlaps(a: tslint.Replacement, b: tslint.Replacement): boolean {
        return a.end >= b.start;
    }

    const sortedFailures = sortFailures(failures);
    const nonOverlapping: tslint.Replacement[] = [];
    for (let i = 0; i < sortedFailures.length; i++) {
        const replacements = getReplacements(sortedFailures[i].getFix());
        if (i === 0 || !overlaps(nonOverlapping[nonOverlapping.length - 1], replacements[0])) {
            nonOverlapping.push(...replacements);
        }
    }
    return nonOverlapping;
}


================================================
FILE: src/runner/index.ts
================================================
import * as cp from 'child_process';
import * as minimatch from 'minimatch';
import { dirname, join, normalize, relative, sep } from 'path';
import type * as tslint from 'tslint';
import type { IConfigurationFile } from 'tslint/lib/configuration';
import type * as typescript from 'typescript';
import * as util from 'util';
import * as server from 'vscode-languageserver';
import { MruCache } from './mruCache';

export type PackageManager = 'npm' | 'pnpm' | 'yarn';

export function toPackageManager(manager: string | undefined): PackageManager | undefined {
    switch (manager && manager.toLowerCase()) {
        case 'npm': return 'npm';
        case 'pnpm': return 'pnpm';
        case 'yarn': return 'yarn';
        default: return undefined;
    }
}

export interface RunConfiguration {
    readonly jsEnable: boolean;
    readonly rulesDirectory?: string | string[];
    readonly configFile?: string;
    readonly ignoreDefinitionFiles: boolean;
    readonly exclude: string[];
    readonly validateWithDefaultConfig?: boolean;
    readonly packageManager?: PackageManager;
    readonly traceLevel?: 'verbose' | 'normal';
    readonly workspaceFolderPath?: string;

    /**
     * Controls where TSlint and other scripts can be loaded from.
     */
    readonly workspaceLibraryExecution: WorkspaceLibraryExecution;
}

/**
 * Controls where TSlint and other scripts can be loaded from.
 */
export enum WorkspaceLibraryExecution {
    /**
     * Block executing TSLint, linter rules, and other scripts from the current workspace.
     */
    Disallow = 1,
    /**
     * Enable loading TSLint and rules from the workspace.
     */
    Allow = 2,
    /**
     * The workspace library execution has not yet been configured or cannot be determined.
     */
    Unknown = 3,
}

interface Configuration {
    readonly linterConfiguration: tslint.Configuration.IConfigurationFile | undefined;
    isDefaultLinterConfig: boolean;
    readonly path?: string;
}

class ConfigCache {
    public configuration: Configuration | undefined;

    private filePath: string | undefined;

    constructor() {
        this.filePath = undefined;
        this.configuration = undefined;
    }

    public set(filePath: string, configuration: Configuration) {
        this.filePath = filePath;
        this.configuration = configuration;
    }

    public get(forPath: string): Configuration | undefined {
        return forPath === this.filePath ? this.configuration : undefined;
    }

    public isDefaultLinterConfig(): boolean {
        return !!(this.configuration && this.configuration.isDefaultLinterConfig);
    }

    public flush() {
        this.filePath = undefined;
        this.configuration = undefined;
    }
}

export interface RunResult {
    readonly lintResult: tslint.LintResult;
    readonly warnings: string[];
    readonly workspaceFolderPath?: string;
    readonly configFilePath?: string;
}

const emptyLintResult: tslint.LintResult = {
    errorCount: 0,
    warningCount: 0,
    failures: [],
    fixes: [],
    format: '',
    output: '',
};

const emptyResult: RunResult = {
    lintResult: emptyLintResult,
    warnings: [],
};

export class TsLintRunner {
    private readonly tslintPath2Library = new Map<string, { tslint: typeof tslint, path: string } | undefined>();

    private readonly document2LibraryCache = new MruCache<{
        readonly workspaceTslintPath: string | undefined,
        readonly globalTsLintPath: string | undefined,
        getTSLint(isTrusted: boolean): { tslint: typeof tslint, path: string } | undefined
    }>(100);

    // map stores undefined values to represent failed resolutions
    private readonly globalPackageManagerPath = new Map<PackageManager, string | undefined>();
    private readonly configCache = new ConfigCache();

    constructor(
        private readonly trace: (data: string) => void,
    ) { }

    public runTsLint(
        filePath: string,
        contents: string | typescript.Program,
        configuration: RunConfiguration,
    ): RunResult {
        this.traceMethod('runTsLint', 'start');

        const warnings: string[] = [];
        if (!this.document2LibraryCache.has(filePath)) {
            this.loadLibrary(filePath, configuration);
        }
        this.traceMethod('runTsLint', 'Loaded tslint library');

        if (!this.document2LibraryCache.has(filePath)) {
            return emptyResult;
        }

        const cacheEntry = this.document2LibraryCache.get(filePath)!;

        let library: { tslint: typeof tslint, path: string } | undefined;

        switch (configuration.workspaceLibraryExecution) {
            case WorkspaceLibraryExecution.Disallow:
                library = cacheEntry.getTSLint(false);
                break;

            case WorkspaceLibraryExecution.Allow:
                library = cacheEntry.getTSLint(true);
                break;

            default:
                if (cacheEntry.workspaceTslintPath) {
                    if (this.isWorkspaceImplicitlyTrusted(cacheEntry.workspaceTslintPath)) {
                        configuration = { ...configuration, workspaceLibraryExecution: WorkspaceLibraryExecution.Allow };
                        library = cacheEntry.getTSLint(true);
                        break;
                    }

                    // If the user has not explicitly trusted/not trusted the workspace AND we have a workspace TS version
                    // show a special error that lets the user trust/untrust the workspace
                    return {
                        lintResult: emptyLintResult,
                        warnings: [
                            getWorkspaceNotTrustedMessage(filePath),
                        ],
                    };
                } else if (cacheEntry.globalTsLintPath) {
                    library = cacheEntry.getTSLint(false);
                }
                break;
        }

        if (!library) {
            return {
                lintResult: emptyLintResult,
                warnings: [
                    getInstallFailureMessage(
                        filePath,
                        configuration.packageManager || 'npm'),
                ],
            };
        }

        this.traceMethod('runTsLint', 'About to validate ' + filePath);
        return this.doRun(filePath, contents, library, configuration, warnings);
    }

    public onConfigFileChange(_tsLintFilePath: string) {
        this.configCache.flush();
    }

    private traceMethod(method: string, message: string) {
        this.trace(`(${method}) ${message}`);
    }

    private loadLibrary(filePath: string, configuration: RunConfiguration): void {
        this.traceMethod('loadLibrary', `trying to load ${filePath}`);
        const directory = dirname(filePath);

        const tsLintPaths = this.getTsLintPaths(directory, configuration.packageManager);

        this.traceMethod('loadLibrary', `Resolved tslint to workspace: '${tsLintPaths.workspaceTsLintPath}' global: '${tsLintPaths.globalTsLintPath}'`);

        this.document2LibraryCache.set(filePath, {
            workspaceTslintPath: tsLintPaths.workspaceTsLintPath || undefined,
            globalTsLintPath: tsLintPaths.globalTsLintPath || undefined,
            getTSLint: (allowWorkspaceLibraryExecution: boolean) => {
                const tsLintPath = allowWorkspaceLibraryExecution
                    ? tsLintPaths.workspaceTsLintPath || tsLintPaths.globalTsLintPath
                    : tsLintPaths.globalTsLintPath;

                if (!tsLintPath) {
                    return;
                }

                let library;
                if (!this.tslintPath2Library.has(tsLintPath)) {
                    try {
                        library = require(tsLintPath);
                    } catch (e) {
                        this.tslintPath2Library.set(tsLintPath, undefined);
                        return;
                    }
                    this.tslintPath2Library.set(tsLintPath, { tslint: library, path: tsLintPath });
                }
                return this.tslintPath2Library.get(tsLintPath);
            }
        });
    }

    private getTsLintPaths(directory: string, packageManager: PackageManager | undefined) {
        const globalPath = this.getGlobalPackageManagerPath(packageManager);

        let workspaceTsLintPath: string | undefined;
        try {
            workspaceTsLintPath = this.resolveTsLint({ nodePath: undefined, cwd: directory }) || undefined;
        } catch {
            // noop
        }

        let globalTSLintPath: string | undefined;
        try {
            globalTSLintPath = this.resolveTsLint({ nodePath: undefined, cwd: globalPath })
                || this.resolveTsLint({ nodePath: globalPath, cwd: globalPath });
        } catch {
            // noop
        }

        return { workspaceTsLintPath, globalTsLintPath: globalTSLintPath };
    }

    private getGlobalPackageManagerPath(packageManager: PackageManager = 'npm'): string | undefined {
        this.traceMethod('getGlobalPackageManagerPath', `Begin - Resolve Global Package Manager Path for: ${packageManager}`);

        if (!this.globalPackageManagerPath.has(packageManager)) {
            let path: string | undefined;
            if (packageManager === 'npm') {
                path = server.Files.resolveGlobalNodePath(this.trace);
            } else if (packageManager === 'yarn') {
                path = server.Files.resolveGlobalYarnPath(this.trace);
            } else if (packageManager === 'pnpm') {
                path = cp.execSync('pnpm root -g').toString().trim();
            }
            this.globalPackageManagerPath.set(packageManager, path);
        }
        this.traceMethod('getGlobalPackageManagerPath', `Done - Resolve Global Package Manager Path for: ${packageManager}`);
        return this.globalPackageManagerPath.get(packageManager);
    }

    private doRun(
        filePath: string,
        contents: string | typescript.Program,
        library: { tslint: typeof tslint, path: string },
        configuration: RunConfiguration,
        warnings: string[],
    ): RunResult {
        this.traceMethod('doRun', `starting validation for ${filePath}`);

        let cwd = configuration.workspaceFolderPath;
        if (!cwd && typeof contents === "object") {
            cwd = contents.getCurrentDirectory();
        }

        if (this.fileIsExcluded(configuration, filePath, cwd)) {
            this.traceMethod('doRun', `No linting: file ${filePath} is excluded`);
            return emptyResult;
        }

        let cwdToRestore: string | undefined;
        if (cwd && configuration.workspaceLibraryExecution === WorkspaceLibraryExecution.Allow) {
            this.traceMethod('doRun', `Changed directory to ${cwd}`);
            cwdToRestore = process.cwd();
            process.chdir(cwd);
        }

        try {
            const configFile = configuration.configFile || null;
            let linterConfiguration: Configuration | undefined;
            this.traceMethod('doRun', 'About to getConfiguration');
            try {
                linterConfiguration = this.getConfiguration(filePath, filePath, library.tslint, configFile);
            } catch (err) {
                this.traceMethod('doRun', `No linting: exception when getting tslint configuration for ${filePath}, configFile= ${configFile}`);
                warnings.push(getConfigurationFailureMessage(err));
                return {
                    lintResult: emptyLintResult,
                    warnings,
                };
            }

            if (!linterConfiguration) {
                this.traceMethod('doRun', `No linting: no tslint configuration`);
                return emptyResult;
            }
            this.traceMethod('doRun', 'Configuration fetched');

            if (isJsDocument(filePath) && !configuration.jsEnable) {
                this.traceMethod('doRun', `No linting: a JS document, but js linting is disabled`);
                return emptyResult;
            }

            if (configuration.validateWithDefaultConfig === false && this.configCache.configuration!.isDefaultLinterConfig) {
                this.traceMethod('doRun', `No linting: linting with default tslint configuration is disabled`);
                return emptyResult;
            }

            if (isExcludedFromLinterOptions(linterConfiguration.linterConfiguration, filePath)) {
                this.traceMethod('doRun', `No linting: file is excluded using linterOptions.exclude`);
                return emptyResult;
            }

            let result: tslint.LintResult;

            const isTrustedWorkspace = configuration.workspaceLibraryExecution === WorkspaceLibraryExecution.Allow;

            // Only allow using a custom rules directory if the workspace has been trusted by the user
            const rulesDirectory = isTrustedWorkspace ? configuration.rulesDirectory : [];

            const options: tslint.ILinterOptions = {
                formatter: "json",
                fix: false,
                rulesDirectory,
                formattersDirectory: undefined,
            };
            if (configuration.traceLevel && configuration.traceLevel === 'verbose') {
                this.traceConfigurationFile(linterConfiguration.linterConfiguration);
            }

            // tslint writes warnings using console.warn, capture these warnings and send them to the client
            const originalConsoleWarn = console.warn;
            const captureWarnings = (message?: any) => {
                warnings.push(message);
                originalConsoleWarn(message);
            };
            console.warn = captureWarnings;

            const sanitizedLintConfiguration = { ...linterConfiguration.linterConfiguration } as IConfigurationFile;
            // Only allow using a custom rules directory if the workspace has been trusted by the user
            if (!isTrustedWorkspace) {
                sanitizedLintConfiguration.rulesDirectory = [];
            }

            try { // clean up if tslint crashes
                const linter = new library.tslint.Linter(options, typeof contents === 'string' ? undefined : contents);
                this.traceMethod('doRun', `Linting: start linting`);
                linter.lint(filePath, typeof contents === 'string' ? contents : '', sanitizedLintConfiguration);
                result = linter.getResult();
                this.traceMethod('doRun', `Linting: ended linting`);
            } finally {
                console.warn = originalConsoleWarn;
            }

            return {
                lintResult: result,
                warnings,
                workspaceFolderPath: configuration.workspaceFolderPath,
                configFilePath: linterConfiguration.path,
            };
        } finally {
            if (typeof cwdToRestore === 'string') {
                process.chdir(cwdToRestore);
            }
        }
    }

    /**
     * Check if `tslintPath` is next to the running TS version. This indicates that the user has
     * implicitly trusted the workspace since they are already running TS from it.
     */
    private isWorkspaceImplicitlyTrusted(tslintPath: string): boolean {
        const tsPath = process.argv[1];
        const nodeModulesPath = join(tsPath, '..', '..', '..');

        const rel = relative(nodeModulesPath, normalize(tslintPath));
        if (rel === `tslint${sep}lib${sep}index.js`) {
            return true;
        }
        return false;
    }

    private getConfiguration(uri: string, filePath: string, library: typeof tslint, configFileName: string | null): Configuration | undefined {
        this.traceMethod('getConfiguration', `Starting for ${uri}`);

        const config = this.configCache.get(filePath);
        if (config) {
            return config;
        }

        let isDefaultConfig = false;
        let linterConfiguration: tslint.Configuration.IConfigurationFile | undefined;

        const linter = library.Linter;
        if (linter.findConfigurationPath) {
            isDefaultConfig = linter.findConfigurationPath(configFileName, filePath) === undefined;
        }
        const configurationResult = linter.findConfiguration(configFileName, filePath);

        linterConfiguration = configurationResult.results;

        // In tslint version 5 the 'no-unused-variable' rules breaks the TypeScript language service plugin.
        // See https://github.com/Microsoft/TypeScript/issues/15344
        // Therefore we remove the rule from the configuration.
        if (linterConfiguration) {
            if (linterConfiguration.rules) {
                linterConfiguration.rules.delete('no-unused-variable');
            }
            if (linterConfiguration.jsRules) {
                linterConfiguration.jsRules.delete('no-unused-variable');
            }
        }

        const configuration: Configuration = {
            isDefaultLinterConfig: isDefaultConfig,
            linterConfiguration,
            path: configurationResult.path,
        };

        this.configCache.set(filePath, configuration);
        return this.configCache.configuration;
    }

    private fileIsExcluded(settings: RunConfiguration, filePath: string, cwd: string | undefined): boolean {
        if (settings.ignoreDefinitionFiles && filePath.endsWith('.d.ts')) {
            return true;
        }
        return settings.exclude.some(pattern => testForExclusionPattern(filePath, pattern, cwd));
    }

    private traceConfigurationFile(configuration: tslint.Configuration.IConfigurationFile | undefined) {
        if (!configuration) {
            this.trace("no tslint configuration");
            return;
        }
        this.trace("tslint configuration:" + util.inspect(configuration, undefined, 4));
    }

    private resolveTsLint(options: { nodePath: string | undefined; cwd: string | undefined; }): string | undefined {
        const nodePathKey = 'NODE_PATH';
        const app = [
            "console.log(require.resolve('tslint'));",
        ].join('');

        const env = process.env;
        const newEnv = Object.create(null);
        Object.keys(env).forEach(key => newEnv[key] = env[key]);
        if (options.nodePath) {
            newEnv[nodePathKey] = options.nodePath;
        }
        newEnv.ELECTRON_RUN_AS_NODE = '1';

        const spawnResults = cp.spawnSync(process.argv0, ['-e', app], { cwd: options.cwd, env: newEnv });
        return spawnResults.stdout.toString().trim() || undefined;
    }
}

function testForExclusionPattern(filePath: string, pattern: string, cwd: string | undefined): boolean {
    if (cwd) {
        // try first as relative
        const relPath = relative(cwd, filePath);
        if (minimatch(relPath, pattern, { dot: true })) {
            return true;
        }
        if (relPath === filePath) {
            return false;
        }
    }

    return minimatch(filePath, pattern, { dot: true });
}

function getInstallFailureMessage(filePath: string, packageManager: PackageManager): string {
    const localCommands = {
        npm: 'npm install tslint',
        pnpm: 'pnpm install tslint',
        yarn: 'yarn add tslint',
    };
    const globalCommands = {
        npm: 'npm install -g tslint',
        pnpm: 'pnpm install -g tslint',
        yarn: 'yarn global add tslint',
    };

    return [
        `Failed to load the TSLint library for '${filePath}'`,
        `To use TSLint, please install tslint using \'${localCommands[packageManager]}\' or globally using \'${globalCommands[packageManager]}\'.`,
        'Be sure to restart your editor after installing tslint.',
    ].join('\n');
}

function getWorkspaceNotTrustedMessage(filePath: string) {
    return [
        `Not using the local TSLint version found for '${filePath}'`,
        'To enable code execution from the current workspace you must enable workspace library execution.',
    ].join('\n');
}

function isJsDocument(filePath: string): boolean {
    return /\.(jsx?|mjs)$/i.test(filePath);
}

function isExcludedFromLinterOptions(
    config: tslint.Configuration.IConfigurationFile | undefined,
    fileName: string,
): boolean {
    if (config === undefined || config.linterOptions === undefined || config.linterOptions.exclude === undefined) {
        return false;
    }
    return config.linterOptions.exclude.some(pattern => testForExclusionPattern(fileName, pattern, undefined));
}

function getConfigurationFailureMessage(err: any): string {
    let errorMessage = `unknown error`;
    if (typeof err.message === 'string' || err.message instanceof String) {
        errorMessage = err.message;
    }
    return `Cannot read tslint configuration - '${errorMessage}'`;
}


================================================
FILE: src/runner/mruCache.ts
================================================
export class MruCache<T> {

    private readonly _map = new Map<string, T>();
    private readonly _entries = new Set<string>();

    public constructor(
        private readonly _maxSize: number
    ) { }

    public set(filePath: string, entry: T): void {
        this._map.set(filePath, entry);
        this._entries.add(filePath);
        for (const key of this._entries.keys()) {
            if (this._entries.size <= this._maxSize) {
                break;
            }
            this._map.delete(key);
            this._entries.delete(key);
        }
    }

    public has(filePath: string): boolean {
        return this._map.has(filePath);
    }

    public get(filePath: string): (T) | undefined {
        if (this._entries.has(filePath)) {
            this._entries.delete(filePath);
            this._entries.add(filePath);
        }
        return this._map.get(filePath);
    }
}

================================================
FILE: src/runner/test/mruCache.test.ts
================================================
import { expect } from 'chai';
import 'mocha';
import { MruCache } from '../mruCache';

describe('MruCache', () => {
    it('should remove old entries', () => {
        const size = 10;
        const cache = new MruCache<number>(size);

        expect(cache.has('0')).to.equal(false);
        cache.set('0', 0);

        expect(cache.get('0')).to.equal(0);

        for (let i = 1; i < size + 1; ++i) {
            cache.set(i.toString(), i);
        }

        expect(cache.has('0')).to.equal(false);
    });
});


================================================
FILE: src/runner/test/runner.test.ts
================================================
import { expect } from 'chai';
import * as fs from 'fs';
import 'mocha';
import * as path from 'path';
import { RunConfiguration, TsLintRunner, WorkspaceLibraryExecution } from '../index';
import { getNonOverlappingReplacements, filterProblemsForFile } from '../failures';

const testDataRoot = path.join(__dirname, '..', '..', '..', 'test-data');

const defaultRunConfiguration: RunConfiguration = {
    exclude: [],
    jsEnable: false,
    ignoreDefinitionFiles: true,
    workspaceLibraryExecution: WorkspaceLibraryExecution.Unknown
};

describe('TSLintRunner', () => {
    describe('runTsLint', () => {
        // Must come first. TS lint only reports warnings once.
        it.skip('should report warnings', () => {
            const filePath = path.join(testDataRoot, 'no-unused-variables', 'test.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);

            expect(result.lintResult.errorCount).to.equal(0);
            expect(result.warnings.length).to.equal(2);
        });

        it('should not return any errors for empty file', () => {
            const result = createTsLintRunner().runTsLint('', '', defaultRunConfiguration);
            expect(result.lintResult.errorCount).to.equal(0);
        });

        it('should return an error for test file', () => {
            const folderPath = path.join(testDataRoot, 'with-tslint');
            const filePath = path.join(folderPath, 'test.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);

            expect(result.lintResult.errorCount).to.equal(1);
            expect(result.lintResult.warningCount).to.equal(0);

            const firstFailure = result.lintResult.failures[0];
            expect(path.normalize(firstFailure.getFileName())).to.equal(filePath);
            expect(firstFailure.getRuleName()).to.equal('array-type');

            const fix = firstFailure.getFix();
            expect(fix).to.not.equal(undefined);
            expect(fix!.length).to.equal(2);

            expect(result.configFilePath).to.equal(path.join(folderPath, 'tslint.json'));
        });

        it('should not validate using if no tslint.json exists and validateWithDefaultConfig is false', () => {
            const filePath = path.join(testDataRoot, 'no-tslint', 'test.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {
                ...defaultRunConfiguration,
                validateWithDefaultConfig: false,
            });

            expect(result.lintResult.errorCount).to.equal(0);
            expect(result.lintResult.warningCount).to.equal(0);
        });

        it('should use correct config for each file', () => {
            const warningFilePath = path.join(testDataRoot, 'warnings', 'test.ts');
            const warnResult = createTsLintRunner().runTsLint(warningFilePath, fs.readFileSync(warningFilePath).toString(), defaultRunConfiguration);

            expect(warnResult.lintResult.errorCount).to.equal(0);
            expect(warnResult.lintResult.warningCount).to.equal(1);

            const errorFilePath = path.join(testDataRoot, 'with-tslint', 'test.ts');
            const errorResult = createTsLintRunner().runTsLint(errorFilePath, fs.readFileSync(warningFilePath).toString(), defaultRunConfiguration);

            expect(errorResult.lintResult.errorCount).to.equal(1);
            expect(errorResult.lintResult.warningCount).to.equal(0);
        });

        it('should not return any errors for excluded file (absolute path)', () => {
            const filePath = path.join(testDataRoot, 'with-tslint', 'test.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {
                ...defaultRunConfiguration,
                exclude: [filePath],
            });

            expect(result.lintResult.errorCount).to.equal(0);
        });

        it('should not return any errors for excluded file (relative path)', () => {
            const root = path.join(testDataRoot, 'with-tslint');
            const filePath = path.join(root, 'test.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {
                ...defaultRunConfiguration,
                workspaceFolderPath: root,
                exclude: ['test.ts'],
            });

            expect(result.lintResult.errorCount).to.equal(0);
        });

        it('should set working directory to workspace path', () => {
            const workspacePath = path.join(testDataRoot, 'with-tslint');
            const filePath = path.join(workspacePath, 'test.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {
                ...defaultRunConfiguration,
                workspaceFolderPath: workspacePath,
            });

            expect(result.lintResult.errorCount).to.equal(1);
            expect(result.lintResult.warningCount).to.equal(0);
            expect(result.workspaceFolderPath).to.equal(workspacePath);
        });

        it.skip('should return warnings for invalid tslint install', () => {
            const root = path.join(testDataRoot, 'invalid-install');
            const filePath = path.join(root, 'test.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {
                ...defaultRunConfiguration,
                workspaceFolderPath: root,
            });

            expect(result.warnings.length).to.equal(1);
        });

        it('should not return errors in js file by default', () => {
            const root = path.join(testDataRoot, 'with-tslint');
            const filePath = path.join(root, 'test.js');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);

            expect(result.lintResult.errorCount).to.equal(0);
        });

        it('should return errors in js file if jsEnable is set', () => {
            const root = path.join(testDataRoot, 'with-tslint');
            const filePath = path.join(root, 'test.js');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), { ...defaultRunConfiguration, jsEnable: true });

            expect(result.lintResult.errorCount).to.equal(1);
        });

        it('should not return errors in excluded file', () => {
            const root = path.join(testDataRoot, 'with-tslint');
            const filePath = path.join(root, 'excluded.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);

            expect(result.lintResult.errorCount).to.equal(0);
        });

        it('should ignore no-unused-varaible rule', () => {
            const root = path.join(testDataRoot, 'with-tslint');
            const filePath = path.join(root, 'unused-variable.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);

            expect(result.lintResult.errorCount).to.equal(0);
            expect(result.warnings.length).to.equal(0);
        });

        it('should not return errors in js files by default', () => {
            const root = path.join(testDataRoot, 'js-disabled');
            {
                const filePath = path.join(root, 'test.mjs');
                const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);
                expect(result.lintResult.errorCount).to.equal(0);
            }
            {
                const filePath = path.join(root, 'test.mjs');
                const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);
                expect(result.lintResult.errorCount).to.equal(0);
            }
        });

        it('should support using a tslint.js config file', () => {
            const root = path.join(testDataRoot, 'with-tslint-js-config-file');

            const filePath = path.join(root, 'test.ts');
            const result = createTsLintRunner().runTsLint(filePath, fs.readFileSync(filePath).toString(), {
                configFile: path.join(root, 'tslint.js'),
                ...defaultRunConfiguration,
            });
            expect(result.lintResult.errorCount).to.equal(2);
            expect(result.lintResult.failures[0].getRuleName()).to.equal('array-type');
            expect(result.lintResult.failures[1].getRuleName()).to.equal('quotemark');
        });
    });

    describe('filterProblemsForFile', () => {
        it('should filter out all problems not in file', () => {
            const runner = createTsLintRunner();
            const filePath = path.join(testDataRoot, 'with-tslint', 'test.ts');
            const result = runner.runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);

            expect(result.lintResult.failures.length).to.equal(1);

            const filteredFailures = filterProblemsForFile('does-not-exist', result.lintResult.failures);
            expect(filteredFailures.length).to.equal(0);
        });
    });

    describe('getNonOverlappingReplacements', () => {
        it('should filter out overlapping replacements', () => {
            const runner = createTsLintRunner();
            const filePath = path.join(testDataRoot, 'overlapping-errors', 'test.ts');
            const result = runner.runTsLint(filePath, fs.readFileSync(filePath).toString(), defaultRunConfiguration);

            expect(result.lintResult.failures.length).to.equal(2);

            const noOverlappingReplacements = getNonOverlappingReplacements(result.lintResult.failures);
            expect(noOverlappingReplacements.length).to.equal(1);
        });
    });
});

function createTsLintRunner() {
    return new TsLintRunner((_value: string) => { /* noop */ });
}


================================================
FILE: src/settings.ts
================================================
import * as path from 'path';
import * as ts_module from 'typescript/lib/tsserverlibrary';
import { Logger } from './logger';
import { pluginId } from './config';

/**
 * Settings for the plugin section in tsconfig.json
 */
export interface Configuration {
    readonly alwaysShowRuleFailuresAsWarnings: boolean;
    readonly ignoreDefinitionFiles: boolean;
    readonly configFile?: string;
    readonly suppressWhileTypeErrorsPresent: boolean;
    readonly jsEnable: boolean;
    readonly exclude?: string | string[];
    readonly packageManager?: string;
}

export class ConfigurationManager {

    private static readonly defaultConfig: Configuration = {
        alwaysShowRuleFailuresAsWarnings: true,
        ignoreDefinitionFiles: true,
        jsEnable: false,
        suppressWhileTypeErrorsPresent: false,
    };

    private readonly _configUpdatedListeners = new Set<() => void>();

    private _workingDirectory?: string;
    private _watcher?: ts_module.FileWatcher;

    public get config(): Configuration { return this._configuration; }
    private _configuration: Configuration = ConfigurationManager.defaultConfig;

    public constructor(
        private readonly _ts: typeof ts_module
    ) { }

    public updateFromPluginConfig(config: Configuration) {
        const configFile = config.configFile && !path.isAbsolute(config.configFile) && this._workingDirectory
            ? path.join(this._workingDirectory, config.configFile)
            : config.configFile;

        this._configuration = {
            ...ConfigurationManager.defaultConfig,
            ...config,
            configFile,
        };

        for (const listener of this._configUpdatedListeners) {
            listener();
        }
    }

    public setProject(
        project: ts_module.server.Project,
        logger: Logger,
    ) {
        if (this._watcher) {
            this._watcher.close();
            this._watcher = undefined;
        }

        // Watch config file for changes
        if (project instanceof this._ts.server.ConfiguredProject && this._ts.sys.watchFile) {
            const configFile = project.getConfigFilePath();
            logger.info(`ConfigurationManager: Found configured project: ${configFile}`);

            this._watcher = this._ts.sys.watchFile(configFile, (_fileName: string, eventKind: ts_module.FileWatcherEventKind) => {
                if (eventKind !== this._ts.FileWatcherEventKind.Changed) {
                    return;
                }

                logger.info('ConfigurationManager: file changed');

                const newConfig = loadSettingsFromTsConfig(this._ts, configFile, logger);
                if (!newConfig) {
                    logger.info(`ConfigurationManager: Could not read new config`);
                    return;
                }

                logger.info(`ConfigurationManager: Updating config settings: ${JSON.stringify(newConfig)}`);
                this.updateFromPluginConfig(newConfig);
            });
        }

        this._workingDirectory = project.getCurrentDirectory();
        this.updateFromPluginConfig(this.config);
    }

    public onUpdatedConfig(listener: () => void) {
        this._configUpdatedListeners.add(listener);
    }
}

export function loadSettingsFromTsConfig(
    ts: typeof ts_module,
    configFilePath: string,
    logger: Logger,
): Configuration | undefined {
    const configFileResult = ts.readConfigFile(configFilePath, ts.sys.readFile);
    if (configFileResult.error || !configFileResult.config) {
        logger.info(`ConfigurationManager: Could not read new config: ${configFileResult.error}`);
        return undefined;
    }

    if (!configFileResult.config.compilerOptions || !Array.isArray(configFileResult.config.compilerOptions.plugins)) {
        logger.info(`ConfigurationManager: Could not read new config plugins`);

        return undefined;
    }

    const pluginSettings = (configFileResult.config.compilerOptions.plugins as any[]).find(x => x.name === pluginId);
    if (!pluginSettings) {
        logger.info(`ConfigurationManager: Could not read new config tslint-plugin`);
        return undefined;
    }

    return pluginSettings;
}


================================================
FILE: test-data/invalid-install/package.json
================================================
{
  "name": "invalid-install",
  "private": true,
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "tslint": "^5.11.0"
  }
}


================================================
FILE: test-data/invalid-install/test.ts
================================================
let t: Array<string> = new Array<string>();

console.log(t);


================================================
FILE: test-data/invalid-install/tslint.json
================================================
{
    "rules": {
        "array-type": [
            true,
            "array-simple"
        ]
    }
}

================================================
FILE: test-data/js-disabled/test.js
================================================
console.log(1)
console.log(2)


================================================
FILE: test-data/js-disabled/test.mjs
================================================
console.log(1)
console.log(2)


================================================
FILE: test-data/js-disabled/tslint.json
================================================
{
    "rules": {
        "array-type": [
            true,
            "array-simple"
        ]
    },
    "defaultSeverity": "warning"
}

================================================
FILE: test-data/no-tslint/test.ts
================================================
let t: Array<string> = new Array<string>();

console.log(t);


================================================
FILE: test-data/no-unused-variables/test.ts
================================================
export const b = 1;

const a = 1;

================================================
FILE: test-data/no-unused-variables/tslint.json
================================================
{
    "rules": {
       "no-unused-variable": true
    }
}

================================================
FILE: test-data/overlapping-errors/test.ts
================================================
import {
    isEqual,
    isEmpty
} from "lodash";

console.log(isEmpty, isEqual); 

================================================
FILE: test-data/overlapping-errors/tslint.json
================================================
{
    "rules": {
        "ordered-imports": true,
        "trailing-comma": [
            true,
            {
                "multiline": "always",
                "singleline": "never"
            }
        ]
    }
}

================================================
FILE: test-data/warnings/test.ts
================================================
let t: Array<string> = new Array<string>();

console.log(t);


================================================
FILE: test-data/warnings/tslint.json
================================================
{
    "rules": {
        "array-type": [
            true,
            "array-simple"
        ]
    },
    "defaultSeverity": "warning"
}

================================================
FILE: test-data/with-tslint/excluded.ts
================================================
let t: Array<string> = new Array<string>();

console.log(t);


================================================
FILE: test-data/with-tslint/test.js
================================================
console.log(1 == 2)

================================================
FILE: test-data/with-tslint/test.ts
================================================
let t: Array<string> = new Array<string>();

console.log(t);


================================================
FILE: test-data/with-tslint/tslint.json
================================================
{
    "rules": {
        "array-type": [
            true,
            "array-simple"
        ],
        "no-unused-variable": true
    },
    "jsRules": {
        "triple-equals": true
    },
    "linterOptions": {
        "exclude": [
            "excluded.ts"
        ]
    }
}

================================================
FILE: test-data/with-tslint/unused-variable.ts
================================================
export const _ = 1;

const unused = 1;

================================================
FILE: test-data/with-tslint-js-config-file/test.ts
================================================
let t: Array<string> = new Array<string>();

console.log(t, 'abc');

================================================
FILE: test-data/with-tslint-js-config-file/tslint.js
================================================
module.exports = {
    "rules": {
        "array-type": true,
        "quotemark": 1 === 1
    }
}

================================================
FILE: test-workspace/.vscode/settings.json
================================================
{
    "typescript.tsdk": "node_modules/typescript/lib"
}

================================================
FILE: test-workspace/examples/array-type.ts
================================================
let t: Array<string> = new Array<string>();
let x: Array<string> = new Array<string>();

console.log(t);
   

================================================
FILE: test-workspace/examples/arrow-parens.ts
================================================
[1, 2 ].map( num => console.log(num) );
   

================================================
FILE: test-workspace/examples/eval.ts
================================================
// There is no TSLint fix for the "no-eval" rule,
// but the "disable rule" fix is still available.
let x = eval("1 + 1");


================================================
FILE: test-workspace/examples/no-var-keyword.ts
================================================

var anakin: string = "jedi";

console.log(`variable is used:${anakin}`);

================================================
FILE: test-workspace/examples/no_unused-variable.ts
================================================
// !!! no-unused-variable is currently not supported pls see: https://github.com/palantir/tslint/issues/2649
import {  } from "diff";

import { A, B } from "parse-json";

console.log(`use ${A}`);

================================================
FILE: test-workspace/examples/ordered-imports.ts
================================================
import {B, A, C} from "diff";
import {D, E} from "diff";

console.log(`use ${A} ${B} ${C} ${D}, ${E}`);

================================================
FILE: test-workspace/examples/overlapping-fixes.ts
================================================
// overlapping fix ranges are currently not supported (the ordered import range, and the missing comman do overlap)
import { autorun, computed } from "mbox";
import {
  isEmpty,
  isEqual
} from "lodash";

console.log(autorun, computed, isEmpty, isEqual);

================================================
FILE: test-workspace/examples/quotemark.ts
================================================
// VS Code provided fix
let s = 'quotemark';

console.log(s);

================================================
FILE: test-workspace/examples/semicolon.ts
================================================
let test1: string
console.log(`use ${test1}`)

================================================
FILE: test-workspace/examples/test-javascript.js
================================================
// test a jsRule trippe equals, tripple equals quick fix is vscode-tslint contributed
   let a = 2;

    if (a == 2) {
 
    }

    [1, 2 ].map( num => console.log(num) );

================================================
FILE: test-workspace/examples/test.d.ts
================================================
// missing semicolon warning supressed to due ignoreDefinitionFiles setting
interface F {
    f1()
    f2()
}

================================================
FILE: test-workspace/examples/trailing-comma.ts
================================================
// a comma is missing at the end

let test = {
  lastName: "smith",
  missAComma: "mis"
};

let test2 = {
  lastName: "smith",
  missAComma: "mis"
};

console.log(test, test2);

================================================
FILE: test-workspace/examples/triple-equals.ts
================================================
// VS Code provided fix for === not supported when using the tslint-language-service
let a = 3;

if (a == 3) {
    console.log(a);
}

if (a != 3) {
    console.log(a);
}

================================================
FILE: test-workspace/package.json
================================================
{
  "name": "project-fixture",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "typescript": "3.1.3",
    "typescript-tslint-plugin": "file:./.."
  }
}


================================================
FILE: test-workspace/tsconfig.json
================================================
{
    "compilerOptions": {
        "plugins": [
            {
                "name": "typescript-tslint-plugin",
                "alwaysShowRuleFailuresAsWarnings": false,
                "ignoreDefinitionFiles": true
                //"configFile": "../tslint.json",
            }
        ],
        "module": "commonjs",
        "target": "es6",
        "allowJs": true,
        "noImplicitAny": false,
        "sourceMap": false,
        "noEmit": true
    }
}

================================================
FILE: test-workspace/tslint.json
================================================
{
    "rules": {
        "array-type": [
            true,
            "array-simple"
        ],
        "arrow-parens": true,
        "no-var-keyword": true,
        "no-unused-variable": [
            true,
            {
                "ignore-pattern": "^_"
            }
        ],
        "ordered-imports": [
            true,
            {
                "import-sources-order": "lowercase-last",
                "named-imports-order": "lowercase-first"
            }
        ],
        "trailing-comma": [
            true,
            {
                "multiline": "always",
                "singleline": "never"
            }
        ],
        "class-name": true,
        "comment-format": [
            true,
            "check-space"
        ],
        "indent": [
            true,
            "spaces"
        ],
        "no-eval": true,
        "no-internal-module": true,
        "no-trailing-whitespace": true,
        "no-unsafe-finally": true,
        "one-line": [
            true,
            "check-open-brace",
            "check-whitespace"
        ],
        "quotemark": [
            true,
            "double"
        ],
        "semicolon": [
            true,
            "always"
        ],
        "triple-equals": [
            true,
            "allow-null-check"
        ],
        "typedef-whitespace": [
            true,
            {
                "call-signature": "nospace",
                "index-signature": "nospace",
                "parameter": "nospace",
                "property-declaration": "nospace",
                "variable-declaration": "nospace"
            }
        ],
        "variable-name": [
            true,
            "ban-keywords"
        ],
        "whitespace": [
            true,
            "check-branch",
            "check-decl",
            "check-operator",
            "check-separator",
            "check-type"
        ]
    },
    "jsRules": {
        "triple-equals": [
            true,
            "allow-null-check"
        ],
        "arrow-parens": true
    },
    "defaultSeverity": "warning"
}

================================================
FILE: thirdpartynotices.txt
================================================
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
For tslint-language-service

This project incorporates material from the project(s) listed below (collectively, “Third Party Code”).
This Third Party Code is licensed to you under their original license terms set forth below.  

1.       vscode-tslint version 0.1.2 (https://github.com/Microsoft/vscode-tslint)
2.       tslint-language-service (https://github.com/angelozerr/tslint-language-service)


1. 

Copyright (c) Microsoft Corporation

All rights reserved. 

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

---

2.

MIT License

Copyright (c) 2017 Angelo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: tsconfig.json
================================================
{
	"compilerOptions": {
		"target": "es6",
		"module": "commonjs",
		"sourceMap": true,
		"outDir": "out",
		"noImplicitAny": true,
		"noUnusedParameters": true,
		"noUnusedLocals": true,
		"forceConsistentCasingInFileNames": true,
		"lib": [
			"es6"
		],
		"strict": true,
		"baseUrl": "./src"
	},
	"include": [
		"./src/**/*.ts"
	]
}

================================================
FILE: tslint.main.json
================================================
{
	"defaultSeverity": "error",
	"extends": [
		"tslint:recommended"
	],
	"rules": {
		"indent": [
			true,
			"spaces"
		],
		"interface-name": [
			true,
			"never-prefix"
		],
		"variable-name": [
			true,
			"check-format",
			"allow-leading-underscore"
		],
		"curly": [
			true,
			"ignore-same-line"
		],
		"member-access": [
			true
		],
		"max-classes-per-file": false,
		"no-empty": false,
		"object-literal-sort-keys": false,
		"no-unused-expression": true,
		"arrow-parens": [
			true,
			"ban-single-arg-parens"
		],
		"quotemark": false,
		"eofline": false,
		"semicolon": [
			true,
			"always"
		],
		"no-console": false,
		"class-name": true,
		"prefer-const": true,
		"import-spacing": true,
		"ordered-imports": false,
		"trailing-comma": [
			true,
			{
				"multiline": {
					"objects": "always",
					"arrays": "always",
					"functions": "ignore",
					"typeLiterals": "ignore"
				}
			}
		],
		"max-line-length": false
	},
	"rulesDirectory": [],
	"linterOptions": {
		"exclude": [
			"e2e/**/*"
		]
	}
}
Download .txt
gitextract_radjmpqj/

├── .gitignore
├── .npmignore
├── .travis.yml
├── .vscode/
│   ├── launch.json
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── e2e/
│   ├── package.json
│   ├── project-fixture/
│   │   ├── .vscode/
│   │   │   └── settings.json
│   │   ├── main.ts
│   │   ├── tsconfig.json
│   │   └── tslint.json
│   ├── server-fixture/
│   │   └── index.js
│   └── tests/
│       ├── assert.js
│       ├── codeFixes.test.js
│       ├── errors.test.js
│       └── helpers.js
├── package.json
├── src/
│   ├── config.ts
│   ├── configFileWatcher.ts
│   ├── index.ts
│   ├── logger.ts
│   ├── plugin.ts
│   ├── runner/
│   │   ├── failures.ts
│   │   ├── index.ts
│   │   ├── mruCache.ts
│   │   └── test/
│   │       ├── mruCache.test.ts
│   │       └── runner.test.ts
│   └── settings.ts
├── test-data/
│   ├── invalid-install/
│   │   ├── package.json
│   │   ├── test.ts
│   │   └── tslint.json
│   ├── js-disabled/
│   │   ├── test.js
│   │   ├── test.mjs
│   │   └── tslint.json
│   ├── no-tslint/
│   │   └── test.ts
│   ├── no-unused-variables/
│   │   ├── test.ts
│   │   └── tslint.json
│   ├── overlapping-errors/
│   │   ├── test.ts
│   │   └── tslint.json
│   ├── warnings/
│   │   ├── test.ts
│   │   └── tslint.json
│   ├── with-tslint/
│   │   ├── excluded.ts
│   │   ├── test.js
│   │   ├── test.ts
│   │   ├── tslint.json
│   │   └── unused-variable.ts
│   └── with-tslint-js-config-file/
│       ├── test.ts
│       └── tslint.js
├── test-workspace/
│   ├── .vscode/
│   │   └── settings.json
│   ├── examples/
│   │   ├── array-type.ts
│   │   ├── arrow-parens.ts
│   │   ├── eval.ts
│   │   ├── no-var-keyword.ts
│   │   ├── no_unused-variable.ts
│   │   ├── ordered-imports.ts
│   │   ├── overlapping-fixes.ts
│   │   ├── quotemark.ts
│   │   ├── semicolon.ts
│   │   ├── test-javascript.js
│   │   ├── test.d.ts
│   │   ├── trailing-comma.ts
│   │   └── triple-equals.ts
│   ├── package.json
│   ├── tsconfig.json
│   └── tslint.json
├── thirdpartynotices.txt
├── tsconfig.json
└── tslint.main.json
Download .txt
SYMBOL INDEX (102 symbols across 14 files)

FILE: e2e/server-fixture/index.js
  class TSServer (line 5) | class TSServer {
    method constructor (line 6) | constructor(project) {
    method send (line 51) | send(command, responseExpected) {
    method sendCommand (line 63) | sendCommand(name, args) {
    method close (line 67) | close() {
    method _shutdown (line 77) | _shutdown() {
  function createServer (line 82) | function createServer(project) {

FILE: e2e/tests/assert.js
  function assertSpan (line 10) | function assertSpan(span, start, end) {
  function assertPosition (line 20) | function assertPosition(pos, line, offset) {

FILE: e2e/tests/codeFixes.test.js
  function createServerForFile (line 14) | function createServerForFile(...fileContents) {

FILE: src/config.ts
  constant TSLINT_ERROR_CODE (line 2) | const TSLINT_ERROR_CODE = 1;
  constant TSLINT_ERROR_SOURCE (line 3) | const TSLINT_ERROR_SOURCE = 'tslint';

FILE: src/configFileWatcher.ts
  class ConfigFileWatcher (line 3) | class ConfigFileWatcher {
    method constructor (line 6) | public constructor(
    method ensureWatching (line 11) | public ensureWatching(file: string) {

FILE: src/index.ts
  method create (line 19) | create(info: ts.server.PluginCreateInfo) {
  method onConfigurationChanged (line 40) | onConfigurationChanged(config: any) {
  function isValidTypeScriptVersion (line 56) | function isValidTypeScriptVersion(typescript: typeof ts_module): boolean {

FILE: src/logger.ts
  class Logger (line 5) | class Logger {
    method forPlugin (line 6) | public static forPlugin(info: ts_module.server.PluginCreateInfo) {
    method constructor (line 10) | private constructor(
    method info (line 14) | public info(message: string) {

FILE: src/plugin.ts
  type Problem (line 13) | interface Problem {
  class TsLintFixId (line 18) | class TsLintFixId {
    method fromFailure (line 19) | public static fromFailure(failure: tslint.RuleFailure) {
    method toRuleName (line 23) | public static toRuleName(fixId: {}): undefined | string {
  class ProblemMap (line 31) | class ProblemMap {
    method get (line 34) | public get(start: number, end: number) {
    method set (line 38) | public set(start: number, end: number, problem: Problem): void {
    method values (line 42) | public values() {
    method key (line 47) | private key(start: number, end: number): string {
  class TSLintPlugin (line 52) | class TSLintPlugin {
    method constructor (line 60) | public constructor(
    method decorate (line 83) | public decorate(languageService: ts.LanguageService) {
    method updateWorkspaceTrust (line 124) | public updateWorkspaceTrust(workspaceTrust: WorkspaceLibraryExecution) {
    method getSemanticDiagnostics (line 131) | private getSemanticDiagnostics(
    method getCodeFixesAtPosition (line 223) | private getCodeFixesAtPosition(
    method getCombinedCodeFix (line 272) | private getCombinedCodeFix(
    method recordCodeAction (line 298) | private recordCodeAction(failure: tslint.RuleFailure, file: ts.SourceF...
    method getRuleFailureQuickFix (line 310) | private getRuleFailureQuickFix(failure: tslint.RuleFailure, fileName: ...
    method getRuleFailureFixAllQuickFix (line 321) | private getRuleFailureFixAllQuickFix(ruleName: string, problems: Probl...
    method getDisableRuleQuickFix (line 344) | private getDisableRuleQuickFix(failure: tslint.RuleFailure, fileName: ...
    method getFixAllAutoFixableQuickFix (line 372) | private getFixAllAutoFixableQuickFix(documentFixes: ProblemMap, fileNa...
    method getProgram (line 384) | private getProgram() {
    method makeDiagnostic (line 388) | private makeDiagnostic(failure: tslint.RuleFailure, file: ts.SourceFil...
    method getDiagnosticCategory (line 405) | private getDiagnosticCategory(failure: tslint.RuleFailure): ts.Diagnos...
  function isInMemoryFile (line 416) | function isInMemoryFile(fileName: string) {
  function convertReplacementToTextChange (line 420) | function convertReplacementToTextChange(repl: tslint.Replacement): ts_mo...
  function failureToFileTextChange (line 427) | function failureToFileTextChange(failure: tslint.RuleFailure, fileName: ...
  function replacementsAreEmpty (line 437) | function replacementsAreEmpty(fix: tslint.Fix | undefined): boolean {

FILE: src/runner/failures.ts
  function filterProblemsForFile (line 7) | function filterProblemsForFile(
  function getReplacements (line 23) | function getReplacements(fix: tslint.Fix | undefined): tslint.Replacemen...
  function getReplacement (line 33) | function getReplacement(failure: tslint.RuleFailure, at: number): tslint...
  function sortFailures (line 37) | function sortFailures(failures: tslint.RuleFailure[]): tslint.RuleFailur...
  function getNonOverlappingReplacements (line 44) | function getNonOverlappingReplacements(failures: tslint.RuleFailure[]): ...

FILE: src/runner/index.ts
  type PackageManager (line 11) | type PackageManager = 'npm' | 'pnpm' | 'yarn';
  function toPackageManager (line 13) | function toPackageManager(manager: string | undefined): PackageManager |...
  type RunConfiguration (line 22) | interface RunConfiguration {
  type WorkspaceLibraryExecution (line 42) | enum WorkspaceLibraryExecution {
  type Configuration (line 57) | interface Configuration {
  class ConfigCache (line 63) | class ConfigCache {
    method constructor (line 68) | constructor() {
    method set (line 73) | public set(filePath: string, configuration: Configuration) {
    method get (line 78) | public get(forPath: string): Configuration | undefined {
    method isDefaultLinterConfig (line 82) | public isDefaultLinterConfig(): boolean {
    method flush (line 86) | public flush() {
  type RunResult (line 92) | interface RunResult {
  class TsLintRunner (line 113) | class TsLintRunner {
    method constructor (line 126) | constructor(
    method runTsLint (line 130) | public runTsLint(
    method onConfigFileChange (line 197) | public onConfigFileChange(_tsLintFilePath: string) {
    method traceMethod (line 201) | private traceMethod(method: string, message: string) {
    method loadLibrary (line 205) | private loadLibrary(filePath: string, configuration: RunConfiguration)...
    method getTsLintPaths (line 240) | private getTsLintPaths(directory: string, packageManager: PackageManag...
    method getGlobalPackageManagerPath (line 261) | private getGlobalPackageManagerPath(packageManager: PackageManager = '...
    method doRun (line 279) | private doRun(
    method isWorkspaceImplicitlyTrusted (line 399) | private isWorkspaceImplicitlyTrusted(tslintPath: string): boolean {
    method getConfiguration (line 410) | private getConfiguration(uri: string, filePath: string, library: typeo...
    method fileIsExcluded (line 451) | private fileIsExcluded(settings: RunConfiguration, filePath: string, c...
    method traceConfigurationFile (line 458) | private traceConfigurationFile(configuration: tslint.Configuration.ICo...
    method resolveTsLint (line 466) | private resolveTsLint(options: { nodePath: string | undefined; cwd: st...
  function testForExclusionPattern (line 485) | function testForExclusionPattern(filePath: string, pattern: string, cwd:...
  function getInstallFailureMessage (line 500) | function getInstallFailureMessage(filePath: string, packageManager: Pack...
  function getWorkspaceNotTrustedMessage (line 519) | function getWorkspaceNotTrustedMessage(filePath: string) {
  function isJsDocument (line 526) | function isJsDocument(filePath: string): boolean {
  function isExcludedFromLinterOptions (line 530) | function isExcludedFromLinterOptions(
  function getConfigurationFailureMessage (line 540) | function getConfigurationFailureMessage(err: any): string {

FILE: src/runner/mruCache.ts
  class MruCache (line 1) | class MruCache<T> {
    method constructor (line 6) | public constructor(
    method set (line 10) | public set(filePath: string, entry: T): void {
    method has (line 22) | public has(filePath: string): boolean {
    method get (line 26) | public get(filePath: string): (T) | undefined {

FILE: src/runner/test/runner.test.ts
  function createTsLintRunner (line 211) | function createTsLintRunner() {

FILE: src/settings.ts
  type Configuration (line 9) | interface Configuration {
  class ConfigurationManager (line 19) | class ConfigurationManager {
    method config (line 33) | public get config(): Configuration { return this._configuration; }
    method constructor (line 36) | public constructor(
    method updateFromPluginConfig (line 40) | public updateFromPluginConfig(config: Configuration) {
    method setProject (line 56) | public setProject(
    method onUpdatedConfig (line 92) | public onUpdatedConfig(listener: () => void) {
  function loadSettingsFromTsConfig (line 97) | function loadSettingsFromTsConfig(

FILE: test-workspace/examples/test.d.ts
  type F (line 2) | interface F {
Condensed preview — 70 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (121K chars).
[
  {
    "path": ".gitignore",
    "chars": 116,
    "preview": ".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",
    "chars": 202,
    "preview": ".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\ntsco"
  },
  {
    "path": ".travis.yml",
    "chars": 390,
    "preview": "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"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 474,
    "preview": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 98,
    "preview": "{\n    \"typescript.preferences.quoteStyle\": \"single\",\n    \"tslint.configFile\": \"tslint.main.json\"\n}"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 3510,
    "preview": "# Changelog\n\n## 1.0.2 - March 31, 2022\n- Deprecate package as eslint is now preferred for TypeScript linting.\n- Try igno"
  },
  {
    "path": "LICENSE",
    "chars": 1066,
    "preview": "MIT License\n\nCopyright (c) 2018 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
  },
  {
    "path": "README.md",
    "chars": 10781,
    "preview": "# TypeScript TSLint Language Service Plugin\n\n[![Build Status](https://travis-ci.org/Microsoft/typescript-tslint-plugin.s"
  },
  {
    "path": "e2e/package.json",
    "chars": 376,
    "preview": "{\n  \"name\": \"e2e\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"directories\": "
  },
  {
    "path": "e2e/project-fixture/.vscode/settings.json",
    "chars": 56,
    "preview": "{\n    \"typescript.tsdk\": \"node_modules/typescript/lib\"\n}"
  },
  {
    "path": "e2e/project-fixture/main.ts",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "e2e/project-fixture/tsconfig.json",
    "chars": 481,
    "preview": "{\r\n    \"compilerOptions\": {\r\n        \"plugins\": [\r\n            {\r\n                \"name\": \"typescript-tslint-plugin\",\r\n "
  },
  {
    "path": "e2e/project-fixture/tslint.json",
    "chars": 2129,
    "preview": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ],\n        \"no-unused-expr"
  },
  {
    "path": "e2e/server-fixture/index.js",
    "chars": 2548,
    "preview": "const { fork } = require('child_process');\nconst path = require('path');\nconst readline = require('readline');\n\nclass TS"
  },
  {
    "path": "e2e/tests/assert.js",
    "chars": 712,
    "preview": "// @ts-check\n\nconst assert = require('chai').assert;\n\n/**\n * @param {{ start: { line: number, offset: number }, end: { l"
  },
  {
    "path": "e2e/tests/codeFixes.test.js",
    "chars": 15242,
    "preview": "// @ts-check\nconst { assertSpan } = require('./assert');\nconst assert = require('chai').assert;\nconst path = require('pa"
  },
  {
    "path": "e2e/tests/errors.test.js",
    "chars": 1937,
    "preview": "// @ts-check\nconst { assertSpan } = require('./assert');\nconst assert = require('chai').assert;\nconst path = require('pa"
  },
  {
    "path": "e2e/tests/helpers.js",
    "chars": 642,
    "preview": "const assert = require('chai').assert;\n\nexports.openMockFile = (server, mockFileName, fileContent) => {\n    server.send("
  },
  {
    "path": "package.json",
    "chars": 1083,
    "preview": "{\n  \"name\": \"typescript-tslint-plugin\",\n  \"version\": \"1.0.2\",\n  \"description\": \"TypeScript tslint language service plugi"
  },
  {
    "path": "src/config.ts",
    "chars": 132,
    "preview": "export const pluginId = 'typescript-tslint-plugin';\nexport const TSLINT_ERROR_CODE = 1;\nexport const TSLINT_ERROR_SOURCE"
  },
  {
    "path": "src/configFileWatcher.ts",
    "chars": 764,
    "preview": "import * as ts_module from 'typescript/lib/tsserverlibrary';\n\nexport class ConfigFileWatcher {\n    private readonly _wat"
  },
  {
    "path": "src/index.ts",
    "chars": 2428,
    "preview": "import { TSLintPlugin } from './plugin';\nimport * as ts_module from 'typescript/lib/tsserverlibrary';\nimport { Logger } "
  },
  {
    "path": "src/logger.ts",
    "chars": 470,
    "preview": "import * as ts_module from 'typescript/lib/tsserverlibrary';\n\nimport { pluginId } from './config';\n\nexport class Logger "
  },
  {
    "path": "src/plugin.ts",
    "chars": 17365,
    "preview": "import * as tslint from 'tslint';\nimport * as path from 'path';\nimport * as ts_module from 'typescript/lib/tsserverlibra"
  },
  {
    "path": "src/runner/failures.ts",
    "chars": 2097,
    "preview": "import { normalize } from 'path';\nimport * as tslint from 'tslint'; // this is a dev dependency only\n\n/**\n * Filter fail"
  },
  {
    "path": "src/runner/index.ts",
    "chars": 20700,
    "preview": "import * as cp from 'child_process';\nimport * as minimatch from 'minimatch';\nimport { dirname, join, normalize, relative"
  },
  {
    "path": "src/runner/mruCache.ts",
    "chars": 896,
    "preview": "export class MruCache<T> {\n\n    private readonly _map = new Map<string, T>();\n    private readonly _entries = new Set<st"
  },
  {
    "path": "src/runner/test/mruCache.test.ts",
    "chars": 514,
    "preview": "import { expect } from 'chai';\nimport 'mocha';\nimport { MruCache } from '../mruCache';\n\ndescribe('MruCache', () => {\n   "
  },
  {
    "path": "src/runner/test/runner.test.ts",
    "chars": 10140,
    "preview": "import { expect } from 'chai';\nimport * as fs from 'fs';\nimport 'mocha';\nimport * as path from 'path';\nimport { RunConfi"
  },
  {
    "path": "src/settings.ts",
    "chars": 4179,
    "preview": "import * as path from 'path';\nimport * as ts_module from 'typescript/lib/tsserverlibrary';\nimport { Logger } from './log"
  },
  {
    "path": "test-data/invalid-install/package.json",
    "chars": 297,
    "preview": "{\n  \"name\": \"invalid-install\",\n  \"private\": true,\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"sc"
  },
  {
    "path": "test-data/invalid-install/test.ts",
    "chars": 61,
    "preview": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/invalid-install/tslint.json",
    "chars": 103,
    "preview": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ]\n    }\n}"
  },
  {
    "path": "test-data/js-disabled/test.js",
    "chars": 30,
    "preview": "console.log(1)\nconsole.log(2)\n"
  },
  {
    "path": "test-data/js-disabled/test.mjs",
    "chars": 30,
    "preview": "console.log(1)\nconsole.log(2)\n"
  },
  {
    "path": "test-data/js-disabled/tslint.json",
    "chars": 137,
    "preview": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ]\n    },\n    \"defaultSever"
  },
  {
    "path": "test-data/no-tslint/test.ts",
    "chars": 61,
    "preview": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/no-unused-variables/test.ts",
    "chars": 33,
    "preview": "export const b = 1;\n\nconst a = 1;"
  },
  {
    "path": "test-data/no-unused-variables/tslint.json",
    "chars": 58,
    "preview": "{\n    \"rules\": {\n       \"no-unused-variable\": true\n    }\n}"
  },
  {
    "path": "test-data/overlapping-errors/test.ts",
    "chars": 83,
    "preview": "import {\n    isEqual,\n    isEmpty\n} from \"lodash\";\n\nconsole.log(isEmpty, isEqual); "
  },
  {
    "path": "test-data/overlapping-errors/tslint.json",
    "chars": 218,
    "preview": "{\n    \"rules\": {\n        \"ordered-imports\": true,\n        \"trailing-comma\": [\n            true,\n            {\n          "
  },
  {
    "path": "test-data/warnings/test.ts",
    "chars": 61,
    "preview": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/warnings/tslint.json",
    "chars": 137,
    "preview": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ]\n    },\n    \"defaultSever"
  },
  {
    "path": "test-data/with-tslint/excluded.ts",
    "chars": 61,
    "preview": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/with-tslint/test.js",
    "chars": 19,
    "preview": "console.log(1 == 2)"
  },
  {
    "path": "test-data/with-tslint/test.ts",
    "chars": 61,
    "preview": "let t: Array<string> = new Array<string>();\n\nconsole.log(t);\n"
  },
  {
    "path": "test-data/with-tslint/tslint.json",
    "chars": 280,
    "preview": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ],\n        \"no-unused-vari"
  },
  {
    "path": "test-data/with-tslint/unused-variable.ts",
    "chars": 38,
    "preview": "export const _ = 1;\n\nconst unused = 1;"
  },
  {
    "path": "test-data/with-tslint-js-config-file/test.ts",
    "chars": 67,
    "preview": "let t: Array<string> = new Array<string>();\n\nconsole.log(t, 'abc');"
  },
  {
    "path": "test-data/with-tslint-js-config-file/tslint.js",
    "chars": 98,
    "preview": "module.exports = {\n    \"rules\": {\n        \"array-type\": true,\n        \"quotemark\": 1 === 1\n    }\n}"
  },
  {
    "path": "test-workspace/.vscode/settings.json",
    "chars": 56,
    "preview": "{\n    \"typescript.tsdk\": \"node_modules/typescript/lib\"\n}"
  },
  {
    "path": "test-workspace/examples/array-type.ts",
    "chars": 108,
    "preview": "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",
    "chars": 43,
    "preview": "[1, 2 ].map( num => console.log(num) );\n   "
  },
  {
    "path": "test-workspace/examples/eval.ts",
    "chars": 123,
    "preview": "// There is no TSLint fix for the \"no-eval\" rule,\n// but the \"disable rule\" fix is still available.\nlet x = eval(\"1 + 1\""
  },
  {
    "path": "test-workspace/examples/no-var-keyword.ts",
    "chars": 73,
    "preview": "\nvar anakin: string = \"jedi\";\n\nconsole.log(`variable is used:${anakin}`);"
  },
  {
    "path": "test-workspace/examples/no_unused-variable.ts",
    "chars": 195,
    "preview": "// !!! no-unused-variable is currently not supported pls see: https://github.com/palantir/tslint/issues/2649\nimport {  }"
  },
  {
    "path": "test-workspace/examples/ordered-imports.ts",
    "chars": 103,
    "preview": "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",
    "chars": 262,
    "preview": "// overlapping fix ranges are currently not supported (the ordered import range, and the missing comman do overlap)\r\nimp"
  },
  {
    "path": "test-workspace/examples/quotemark.ts",
    "chars": 61,
    "preview": "// VS Code provided fix\nlet s = 'quotemark';\n\nconsole.log(s);"
  },
  {
    "path": "test-workspace/examples/semicolon.ts",
    "chars": 45,
    "preview": "let test1: string\nconsole.log(`use ${test1}`)"
  },
  {
    "path": "test-workspace/examples/test-javascript.js",
    "chars": 171,
    "preview": "// test a jsRule trippe equals, tripple equals quick fix is vscode-tslint contributed\n   let a = 2;\n\n    if (a == 2) {\n "
  },
  {
    "path": "test-workspace/examples/test.d.ts",
    "chars": 113,
    "preview": "// 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",
    "chars": 176,
    "preview": "// a comma is missing at the end\n\nlet test = {\n  lastName: \"smith\",\n  missAComma: \"mis\"\n};\n\nlet test2 = {\n  lastName: \"s"
  },
  {
    "path": "test-workspace/examples/triple-equals.ts",
    "chars": 169,
    "preview": "// VS Code provided fix for === not supported when using the tslint-language-service\nlet a = 3;\n\nif (a == 3) {\n    conso"
  },
  {
    "path": "test-workspace/package.json",
    "chars": 325,
    "preview": "{\n  \"name\": \"project-fixture\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test"
  },
  {
    "path": "test-workspace/tsconfig.json",
    "chars": 481,
    "preview": "{\r\n    \"compilerOptions\": {\r\n        \"plugins\": [\r\n            {\r\n                \"name\": \"typescript-tslint-plugin\",\r\n "
  },
  {
    "path": "test-workspace/tslint.json",
    "chars": 2091,
    "preview": "{\n    \"rules\": {\n        \"array-type\": [\n            true,\n            \"array-simple\"\n        ],\n        \"arrow-parens\":"
  },
  {
    "path": "thirdpartynotices.txt",
    "chars": 2680,
    "preview": "THIRD-PARTY SOFTWARE NOTICES AND INFORMATION\r\nFor tslint-language-service\r\n\r\nThis project incorporates material from the"
  },
  {
    "path": "tsconfig.json",
    "chars": 355,
    "preview": "{\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\"noIm"
  },
  {
    "path": "tslint.main.json",
    "chars": 1092,
    "preview": "{\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\"s"
  }
]

About this extraction

This page contains the full source code of the Microsoft/typescript-tslint-plugin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 70 files (109.6 KB), approximately 25.9k tokens, and a symbol index with 102 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!