├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── TypeScriptAnalyzer.sln ├── WebLinter.vsext ├── art ├── context-menu.png ├── errorlist.png ├── options-reset.png ├── options.png └── tools-menu.png ├── build ├── 7z.dll ├── 7z.exe └── build.cmd ├── lib └── community.visualstudio.toolkit.15 │ └── 15.0.445 │ ├── .nupkg.metadata │ ├── .signature.p7s │ ├── Icon.png │ ├── build │ ├── AssemblyInfo.cs │ ├── Community.VisualStudio.Toolkit.15.props │ ├── Community.VisualStudio.Toolkit.15.targets │ └── imports │ │ ├── Constants.props │ │ ├── ExtensibilityEssentialsCheck.targets │ │ ├── MSBuildCapabilities.props │ │ ├── NewtonsoftJsonVersionCheck.targets │ │ └── PublishToMarketplace.targets │ ├── community.visualstudio.toolkit.15.15.0.445.nupkg │ ├── community.visualstudio.toolkit.15.15.0.445.nupkg.sha512 │ ├── community.visualstudio.toolkit.15.nuspec │ └── lib │ └── net46 │ ├── Community.VisualStudio.Toolkit.dll │ └── Community.VisualStudio.Toolkit.xml └── src ├── WebLinter ├── Benchmark.cs ├── Constants.cs ├── Helpers │ ├── AsyncLock.cs │ └── AsyncProcess.cs ├── ISettings.cs ├── Linting │ ├── Linters │ │ ├── Linter.cs │ │ └── LocalNgLintRunner.cs │ ├── LintingError.cs │ └── LintingResult.cs ├── Node │ ├── 7z.dll │ ├── 7z.exe │ ├── node.7z │ ├── package-lock.json │ ├── package.json │ └── server.js ├── NodeServer.cs ├── Properties │ └── AssemblyInfo.cs ├── ServerPostData.cs ├── WebLinter.csproj └── packages.config ├── WebLinterTest ├── AssemblyMethods.cs ├── BadTslintJsonTest.cs ├── BuildSelectedItemsTest.cs ├── EmptyUnloadedProjectsTest.cs ├── LintEndToEndTest.cs ├── LintFileLocationsTest.cs ├── MessageFilter.cs ├── MockSettings.cs ├── Properties │ └── AssemblyInfo.cs ├── TsconfigLocationsTest.cs ├── TslintTest.cs ├── TslintWithTsconfigTest.cs ├── WebLinterTest.csproj ├── app.config ├── artifacts │ ├── bad-tslint-json │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── bad-tslint-json.csproj │ │ ├── bad-tslint-json.sln │ │ ├── badtest.ts │ │ ├── tsconfig.json │ │ └── tslint.json │ ├── empty │ │ └── noprojects.sln │ ├── localinstall │ │ └── multiple │ │ │ ├── a │ │ │ ├── a.csproj │ │ │ ├── fileA.ts │ │ │ └── fileAA.ts │ │ │ ├── b │ │ │ ├── b.csproj │ │ │ ├── fileB.ts │ │ │ ├── node_modules │ │ │ │ └── eslint │ │ │ │ │ └── dummy.txt │ │ │ └── package.json │ │ │ ├── multiple.sln │ │ │ ├── node_modules │ │ │ └── eslint │ │ │ │ └── dummy.txt │ │ │ └── package.json │ ├── tsconfig │ │ ├── Tsconfig.sln │ │ ├── file8.ts │ │ ├── file9.ts │ │ ├── multiple │ │ │ ├── HtmlPage1.html │ │ │ ├── a │ │ │ │ ├── c │ │ │ │ │ ├── file4.ts │ │ │ │ │ └── file6.tsx │ │ │ │ ├── file1.ts │ │ │ │ └── tsconfig.json │ │ │ ├── b │ │ │ │ ├── file2.ts │ │ │ │ ├── file3.ts │ │ │ │ └── tsconfig.json │ │ │ ├── file7.ts │ │ │ ├── react-dom.d.ts │ │ │ ├── react.d.ts │ │ │ ├── test.ts │ │ │ ├── tsconfig.json │ │ │ └── tsconfigTest.csproj │ │ ├── none │ │ │ ├── HtmlPage1.html │ │ │ ├── b │ │ │ │ ├── file5.ts │ │ │ │ └── tsconfig.json │ │ │ ├── tsconfig.json │ │ │ └── tsconfigEmptyTest.csproj │ │ └── tslint.json │ ├── tslint.json │ └── tslint │ │ ├── a.ts │ │ ├── aFixed.ts │ │ ├── b.ts │ │ ├── c.tsx │ │ ├── cFixed.tsx │ │ ├── d.tsx │ │ └── e.ts ├── packages.config └── zzGenerateCsprojEntries.cs └── WebLinterVsix ├── Commands ├── BuildEventsBase.cs ├── CleanErrorsCommand.cs ├── EditConfigFilesCommand.cs ├── FixLintErrorsCommand.cs ├── LintFilesCommand.cs ├── LintFilesCommandBase.cs └── ResetConfigFilesCommand.cs ├── ErrorList ├── ErrorListDataSource.cs ├── ErrorListService.cs ├── SinkManager.cs └── TableEntriesSnapshot.cs ├── FileListeners └── SourceFileCreationListener.cs ├── Helpers ├── BuildSelectedItems.cs ├── LintFileLocations.cs ├── LintableFiles.cs ├── ProjectHelpers.cs └── TsconfigLocations.cs ├── LinterService.cs ├── Logger.cs ├── Properties └── AssemblyInfo.cs ├── Resources ├── icon.png └── preview.png ├── Settings.cs ├── Tagging ├── LintingErrorTag.cs ├── Tagger.cs └── TaggerProvider.cs ├── VSCommandTable.cs ├── VSCommandTable.vsct ├── VSPackage.cs ├── WebLinterVsix.csproj ├── app.config ├── packages.config ├── registry.pkgdef ├── source.extension.cs ├── source.extension.ico ├── source.extension.resx └── source.extension.vsixmanifest /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | packages 2 | node_modules.7z 3 | edge.7z 4 | edge/ 5 | Node/ 6 | 7 | # User files 8 | *.suo 9 | *.user 10 | *.sln.docstates 11 | .vs/ 12 | 13 | # Build results 14 | 15 | [Dd]ebug/ 16 | [Rr]elease/ 17 | x64/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | # NCrunch 26 | *.ncrunchsolution 27 | *.ncrunchproject 28 | _NCrunch_WebCompiler 29 | -------------------------------------------------------------------------------- /TypeScriptAnalyzer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26403.7 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3BDFE0EC-C4AF-422A-BED1-D5EC825FB6B5}" 7 | ProjectSection(SolutionItems) = preProject 8 | build\build.cmd = build\build.cmd 9 | CHANGELOG.md = CHANGELOG.md 10 | README.md = README.md 11 | EndProjectSection 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebLinterVsix", "src\WebLinterVsix\WebLinterVsix.csproj", "{F541D968-0FC8-4AD3-9693-6169F47399F0}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebLinter", "src\WebLinter\WebLinter.csproj", "{9530FD25-EB47-44D8-9F0B-F989B639DEBE}" 16 | EndProject 17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebLinterTest", "src\WebLinterTest\WebLinterTest.csproj", "{4480E2E4-80C1-4DB4-B6CD-000A9B5DA03D}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {F541D968-0FC8-4AD3-9693-6169F47399F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {F541D968-0FC8-4AD3-9693-6169F47399F0}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {F541D968-0FC8-4AD3-9693-6169F47399F0}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {F541D968-0FC8-4AD3-9693-6169F47399F0}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {9530FD25-EB47-44D8-9F0B-F989B639DEBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {9530FD25-EB47-44D8-9F0B-F989B639DEBE}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {9530FD25-EB47-44D8-9F0B-F989B639DEBE}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {9530FD25-EB47-44D8-9F0B-F989B639DEBE}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {4480E2E4-80C1-4DB4-B6CD-000A9B5DA03D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {4480E2E4-80C1-4DB4-B6CD-000A9B5DA03D}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {4480E2E4-80C1-4DB4-B6CD-000A9B5DA03D}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {4480E2E4-80C1-4DB4-B6CD-000A9B5DA03D}.Release|Any CPU.Build.0 = Release|Any CPU 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /WebLinter.vsext: -------------------------------------------------------------------------------- 1 | { 2 | "extensions": { 3 | "mandatory": [ 4 | { 5 | "name": "EditorConfig", 6 | "productId": "EditorConfig..5cd8e6a2-be43-4fcc-a345-40f6cc1e9c9f", 7 | "link": "https://visualstudiogallery.msdn.microsoft.com/c8bccfe2-650c-4b42-bc5c-845e21f96328", 8 | "description": "This makes sure that everyone uses correct spaces and indentation." 9 | }, 10 | { 11 | "name": "Extensibility Tools 2015", 12 | "productId": "f8330d54-0469-43a7-8fc0-7f19febeb897", 13 | "link": "https://visualstudiogallery.msdn.microsoft.com/ab39a092-1343-46e2-b0f1-6a3f91155aa6", 14 | "description": "Used for editing the '.vsct' file in the root of this project." 15 | } 16 | ], 17 | "optional": [ 18 | { 19 | "name": "YAML Editor", 20 | "productId": "YamlDotNetEditor..074a7b74-655b-409c-b5ac-a028f12d6e89", 21 | "link": "https://visualstudiogallery.msdn.microsoft.com/34423c06-f756-4721-8394-bc3d23b91ca7", 22 | "description": "This is handy for editing the 'appveyor.yml' file." 23 | } 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /art/context-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/art/context-menu.png -------------------------------------------------------------------------------- /art/errorlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/art/errorlist.png -------------------------------------------------------------------------------- /art/options-reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/art/options-reset.png -------------------------------------------------------------------------------- /art/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/art/options.png -------------------------------------------------------------------------------- /art/tools-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/art/tools-menu.png -------------------------------------------------------------------------------- /build/7z.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/build/7z.dll -------------------------------------------------------------------------------- /build/7z.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/build/7z.exe -------------------------------------------------------------------------------- /build/build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo Running build.cmd to create folder WebLinterVsix\Node 4 | if exist "%~dp0..\src\WebLinterVsix\Node\log.txt" echo Nothing to do - WebLinterVsix\Node\log.txt already exists & goto:done 5 | 6 | echo Deleting and recreating folder WebLinterVsix\Node... 7 | if exist "%~dp0..\src\WebLinterVsix\Node" rmdir /s /q "%~dp0..\src\WebLinterVsix\Node" 8 | mkdir "%~dp0..\src\WebLinterVsix\Node" 9 | 10 | echo Copying and unzipping core files (node.exe, server.js)... 11 | copy /y "%~dp0..\src\WebLinter\Node\*.*" "%~dp0..\src\WebLinterVsix\Node" 12 | pushd "%~dp0..\src\WebLinterVsix\Node" 13 | 7z.exe x -y node.7z 14 | del /q 7z.dll 15 | del /q 7z.exe 16 | del /q node.7z 17 | 18 | echo Installing packages... 19 | call npm install ^ 20 | --no-optional --quiet > nul 21 | 22 | echo Deleting unneeded files and folders... 23 | del /s /q *.html > nul 24 | del /s /q *.markdown > nul 25 | del /s /q *.md > nul 26 | del /s /q *.npmignore > nul 27 | del /s /q *.txt > nul 28 | del /s /q *.yml > nul 29 | del /s /q .gitattributes > nul 30 | del /s /q CHANGELOG > nul 31 | del /s /q CHANGES > nul 32 | del /s /q CNAME > nul 33 | del /s /q README > nul 34 | del /s /q package-lock.json > nul 35 | del /q package.json > nul 36 | 37 | for /d /r . %%d in (benchmark) do @if exist "%%d" rd /s /q "%%d" > nul 38 | for /d /r . %%d in (bench) do @if exist "%%d" rd /s /q "%%d" > nul 39 | for /d /r . %%d in (doc) do @if exist "%%d" rd /s /q "%%d" > nul 40 | for /d /r . %%d in (docs) do @if exist "%%d" rd /s /q "%%d" > nul 41 | for /d /r . %%d in (example) do @if exist "%%d" rd /s /q "%%d" > nul 42 | for /d /r . %%d in (examples) do @if exist "%%d" rd /s /q "%%d" > nul 43 | for /d /r . %%d in (images) do @if exist "%%d" rd /s /q "%%d" > nul 44 | for /d /r . %%d in (man) do @if exist "%%d" rd /s /q "%%d" > nul 45 | for /d /r . %%d in (media) do @if exist "%%d" rd /s /q "%%d" > nul 46 | for /d /r . %%d in (scripts) do @if exist "%%d" rd /s /q "%%d" > nul 47 | for /d /r . %%d in (tests) do @if exist "%%d" rd /s /q "%%d" > nul 48 | for /d /r . %%d in (testing) do @if exist "%%d" rd /s /q "%%d" > nul 49 | for /d /r . %%d in (tst) do @if exist "%%d" rd /s /q "%%d" > nul 50 | 51 | echo Creating log.txt success file... 52 | type nul > log.txt 53 | :done 54 | echo build.cmd completed 55 | pushd "%~dp0" -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/.nupkg.metadata: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "contentHash": "nXKW0nz77Jy1dMVlPJCxsiNFfIZt4TXrzgXeyyWaromC+gySp8poEA88QMqtes3yteyxn/onF2awLI/B/X5+vw==", 4 | "source": "https://api.nuget.org/v3/index.json" 5 | } -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/.signature.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/lib/community.visualstudio.toolkit.15/15.0.445/.signature.p7s -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/lib/community.visualstudio.toolkit.15/15.0.445/Icon.png -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/build/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // This will add the toolkit assembly to Visual Studio's probing path. 2 | // Without it, Visual Studio is unable to find the assembly and the extension will fail to load. 3 | using Microsoft.VisualStudio.Shell; 4 | 5 | [assembly: ProvideCodeBase(AssemblyName = "Community.VisualStudio.Toolkit")] -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/build/Community.VisualStudio.Toolkit.15.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | Community.VisualStudio.Toolkit.dll 9 | true 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/build/Community.VisualStudio.Toolkit.15.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/build/imports/Constants.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8.0.3 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/build/imports/ExtensibilityEssentialsCheck.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | The 'Extensibility Essentials' extension makes extension development easier. 19 | The 'Extensibility Essentials' extension is recommended for this project. 20 | The 'Extensibility Essentials' extension is required for this project. 21 | 22 | 23 | https://marketplace.visualstudio.com/items?itemName=MadsKristensen.ExtensibilityEssentials 24 | https://marketplace.visualstudio.com/items?itemName=MadsKristensen.ExtensibilityEssentials2019 25 | 26 | 27 | Info 28 | 29 | 30 | CVSTBLD001 31 | 32 | 38 | true 39 | true 40 | 41 | 42 | 46 | 50 | 51 | 55 | 61 | 62 | 63 | 68 | 69 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/build/imports/MSBuildCapabilities.props: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | $([System.Version]::Parse($(MSBuildVersion)).Major) 8 | $([System.Version]::Parse($(MSBuildVersion)).Minor) 9 | 10 | 11 | true 12 | 13 | 14 | true 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/build/imports/NewtonsoftJsonVersionCheck.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | @(CVST_NewtonsoftJsonReferenceVersion) 16 | 17 | 23 | $([MSBuild]::VersionLessThanOrEquals('$(CVST_NewtonsoftJsonVersion)', '$(CVST_NewtonsoftJsonMaxVersion)')) 24 | true 25 | 26 | The version of Newtonsoft.Json cannot be greater than $(CVST_NewtonsoftJsonMaxVersion), but version $(CVST_NewtonsoftJsonVersion) is currently being used. 27 | CVSTBLD002 28 | 29 | 30 | 31 | 36 | 37 | 38 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/build/imports/PublishToMarketplace.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | Rebuild 9 | 10 | 11 | 12 | 17 | 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 30 | 31 | 32 | 36 | $(PkgMicrosoft_VSSDK_BuildTools)\tools\vssdk\bin\VsixPublisher.exe 37 | 38 | 44 | $([MSBuild]::GetPathOfFileAbove('publish.json', '$(ProjectDir)')) 45 | 46 | 47 | $(ProjectDir)$(TargetVsixContainer) 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 62 | 63 | 64 | 68 | 69 | 70 | 74 | 75 | 76 | 77 | "$(VsixPublisher)" publish -personalAccessToken "$(PersonalAccessToken)" -payload "$(PublishExtension)" -publishManifest "$(PublishManifest)" 78 | $(PublishCommand) -ignoreWarnings "$(PublishIgnoreWarnings)" 79 | 80 | 81 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/community.visualstudio.toolkit.15.15.0.445.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/lib/community.visualstudio.toolkit.15/15.0.445/community.visualstudio.toolkit.15.15.0.445.nupkg -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/community.visualstudio.toolkit.15.15.0.445.nupkg.sha512: -------------------------------------------------------------------------------- 1 | QgfIzcgWkwDFIR3dl014PKLYOGO3c6Ag7AbO7ZM8zOXyo1bqZlxQU01TqfOO3fB/dBLc46f9NqFbAM5FVU1p5A== -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/community.visualstudio.toolkit.15.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Community.VisualStudio.Toolkit.15 5 | 15.0.445 6 | VSIX Community 7 | Apache-2.0 8 | https://licenses.nuget.org/Apache-2.0 9 | Icon.png 10 | https://github.com/VsixCommunity/Community.VisualStudio.Toolkit 11 | A community driven effort for a better Visual Studio experience developing extensions. 12 | © Mads Kristensen. All rights reserved. 13 | VisualStudio, VSSDK, SDK 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /lib/community.visualstudio.toolkit.15/15.0.445/lib/net46/Community.VisualStudio.Toolkit.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/lib/community.visualstudio.toolkit.15/15.0.445/lib/net46/Community.VisualStudio.Toolkit.dll -------------------------------------------------------------------------------- /src/WebLinter/Benchmark.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | 5 | namespace WebLinter 6 | { 7 | /// 8 | /// Writes timings for lint runs to the path in variable path. Disabled on conditional compile flags by default. 9 | /// 10 | /// Enable by adding BENCHMARK conditional compile flag to WebLinter AND WebLinterVsix projects 11 | public static class Benchmark 12 | { 13 | private static Stopwatch stopwatch = new Stopwatch(); 14 | private static string log = ""; 15 | private static readonly string path = @"c:\Temp\benchmark.txt"; 16 | 17 | [Conditional("BENCHMARK")] 18 | public static void Start(string message = "Benchmark run started") 19 | { 20 | Reset(); 21 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 22 | AddLogEntry(message); 23 | stopwatch.Start(); 24 | } 25 | 26 | [Conditional("BENCHMARK")] 27 | private static void Reset() 28 | { 29 | log = ""; 30 | stopwatch.Reset(); 31 | } 32 | 33 | [Conditional("BENCHMARK")] 34 | public static void Log(string message) 35 | { 36 | AddLogEntry($"{message} Elapsed: {stopwatch.ElapsedMilliseconds}"); 37 | } 38 | 39 | [Conditional("BENCHMARK")] 40 | public static void End(string message = "Benchmark run ended") 41 | { 42 | stopwatch.Stop(); 43 | AddLogEntry($"{message} Elapsed: {stopwatch.ElapsedMilliseconds}"); 44 | WriteLog(); 45 | } 46 | 47 | [Conditional("BENCHMARK")] 48 | private static void AddLogEntry(string message) 49 | { 50 | log += $"{DateTime.Now.ToLongTimeString()} {DateTime.Now.ToShortDateString()} {message}\n"; 51 | } 52 | 53 | [Conditional("BENCHMARK")] 54 | private static void WriteLog() 55 | { 56 | using (StreamWriter w = File.AppendText(path)) { w.Write(log); } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/WebLinter/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace WebLinter 2 | { 3 | public static class Constants 4 | { 5 | public const string VERSION = "1.23"; 6 | public const string CACHE_NAME = "TypeScriptAnalyzer"; 7 | public const string NODE_FOLDER_NAME = "Node"; // We can blow up in dev with a long Windows user name if this name is too long 8 | } 9 | } -------------------------------------------------------------------------------- /src/WebLinter/Helpers/AsyncLock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace WebLinter 7 | { 8 | // Inspried by Hanselman's post http://www.hanselman.com/blog/ComparingTwoTechniquesInNETAsynchronousCoordinationPrimitives.aspx 9 | // based on Toub's series: http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx 10 | public sealed class AsyncLock : IDisposable 11 | { 12 | private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1); 13 | private readonly Task m_releaser; 14 | 15 | [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] 16 | public AsyncLock() 17 | { 18 | m_releaser = Task.FromResult(new Releaser(this) as IDisposable); 19 | } 20 | 21 | public Task LockAsync() 22 | { 23 | var wait = m_semaphore.WaitAsync(); 24 | return wait.IsCompleted ? 25 | m_releaser : 26 | wait.ContinueWith((_, state) => (IDisposable)state, 27 | m_releaser.Result, CancellationToken.None, 28 | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); 29 | } 30 | 31 | public Task LockSync() 32 | { 33 | var task = m_semaphore.WaitAsync(); 34 | bool completed = task.Wait(60000); 35 | if (!completed) throw new Exception("LockSync timed out. Timeout is 60 seconds."); 36 | return m_releaser; 37 | } 38 | 39 | public Task Lock(bool syncLock) 40 | { 41 | return syncLock ? LockSync() : LockAsync(); 42 | } 43 | 44 | private void Dispose(bool disposing) 45 | { 46 | if (disposing) 47 | m_semaphore.Dispose(); 48 | } 49 | 50 | public void Dispose() 51 | { 52 | Dispose(true); 53 | GC.SuppressFinalize(this); 54 | } 55 | 56 | private sealed class Releaser : IDisposable 57 | { 58 | private readonly AsyncLock m_toRelease; 59 | internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; } 60 | public void Dispose() { m_toRelease.m_semaphore.Release(); } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/WebLinter/Helpers/AsyncProcess.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace WebLinter 6 | { 7 | public static class AsyncProcess 8 | { 9 | // Based on answers from here: http://stackoverflow.com/questions/470256/process-waitforexit-asynchronously 10 | public static Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default(CancellationToken)) 11 | { 12 | var tcs = new TaskCompletionSource(); 13 | process.EnableRaisingEvents = true; 14 | process.Exited += (sender, args) => tcs.TrySetResult(null); 15 | 16 | if (cancellationToken != default(CancellationToken)) 17 | { 18 | cancellationToken.Register(() => 19 | { 20 | tcs.TrySetCanceled(); 21 | }); 22 | } 23 | 24 | return tcs.Task; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/WebLinter/ISettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace WebLinter 4 | { 5 | public interface ISettings 6 | { 7 | bool IgnoreNestedFiles { get; } 8 | bool CleanErrorsOnBuild { get; } 9 | bool RunOnBuild { get; } 10 | bool TSLintEnable { get; } 11 | bool TSLintShowErrors { get; } 12 | bool UseTsConfig { get; } 13 | bool OnlyRunIfRequested { get; } 14 | bool UseProjectNGLint { get; } 15 | bool LintJsFiles { get; } 16 | IEnumerable GetIgnorePatterns(); 17 | void ResetSettings(); 18 | bool ShowUnderlining { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/WebLinter/Linting/Linters/LocalNgLintRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebLinter 9 | { 10 | internal class LocalNgLintRunner 11 | { 12 | private Action _log; 13 | internal LocalNgLintRunner(Action log) {_log = log; } 14 | 15 | internal async Task Run(string name, ServerPostData postData, bool callSync) 16 | { 17 | string output = null; 18 | try 19 | { 20 | output = await RunLocalProcess(callSync, postData); 21 | CallLog("Lint with local 'ng lint' succeeded", showWarning: false); 22 | } 23 | catch (Exception ex) 24 | { 25 | string message = "Attempted to lint with local 'ng lint' and failed. Falling back to regular lint call. "; 26 | message += $"Error message:\n{ex.Message}"; 27 | CallLog(message, showWarning: true); 28 | output = await Linter.Server.CallServer(name, postData, callSync, _log); 29 | } 30 | return output; 31 | } 32 | 33 | private async Task RunLocalProcess(bool callSync, ServerPostData postData) 34 | { 35 | FileInfo configFile = new FileInfo(postData.Config); 36 | ProcessStartInfo startInfo = new ProcessStartInfo() 37 | { 38 | FileName = "cmd.exe", 39 | Arguments = $"/c \"ng lint --type-check {(postData.FixErrors ? "--fix " : "")} --format JSON \"", 40 | RedirectStandardError = true, 41 | RedirectStandardOutput = true, 42 | WindowStyle = ProcessWindowStyle.Hidden, 43 | CreateNoWindow = true, 44 | WorkingDirectory = configFile.DirectoryName, 45 | UseShellExecute = false 46 | }; 47 | string stdOut = ""; 48 | string stdErr = ""; 49 | if (callSync) 50 | { 51 | // Actually I think the old process blocks the UI thread anyway 52 | // so we can use RunLocalProcessSync in the async case as well 53 | stdOut = RunLocalProcessSync(startInfo, out stdErr); 54 | } 55 | else 56 | { 57 | Process localLintProcess = new Process { StartInfo = startInfo, EnableRaisingEvents = true }; 58 | localLintProcess.Start(); 59 | stdOut = await Task.Run(() => { return localLintProcess.StandardOutput.ReadToEnd(); }); 60 | stdErr = await Task.Run(() => { return localLintProcess.StandardError.ReadToEnd(); }); 61 | localLintProcess.WaitForExit(); 62 | } 63 | 64 | if (!string.IsNullOrWhiteSpace(stdErr)) 65 | { 66 | string message = $@"Unable to LOCAL ng lint. : config: { configFile }, dir: { configFile.DirectoryName } 67 | tslint Output: {stdErr} "; 68 | throw new FormatException(message, new InvalidOperationException(stdErr)); 69 | } 70 | 71 | return stdOut; 72 | } 73 | 74 | // https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why 75 | private string RunLocalProcessSync(ProcessStartInfo startInfo, out string stdErr) 76 | { 77 | string stdOut = stdErr = ""; 78 | int timeout = 120000; 79 | using (Process process = new Process()) 80 | { 81 | process.StartInfo = startInfo; 82 | StringBuilder output = new StringBuilder(); 83 | StringBuilder error = new StringBuilder(); 84 | 85 | using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) 86 | using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) 87 | { 88 | process.OutputDataReceived += (sender, e) => { 89 | try 90 | { 91 | if (e.Data == null) 92 | outputWaitHandle.Set(); 93 | else 94 | output.AppendLine(e.Data); 95 | } 96 | catch (Exception) { } 97 | }; 98 | process.ErrorDataReceived += (sender, e) => 99 | { 100 | try 101 | { 102 | if (e.Data == null) 103 | errorWaitHandle.Set(); 104 | else 105 | error.AppendLine(e.Data); 106 | } 107 | catch (Exception) { } 108 | }; 109 | process.Start(); 110 | process.BeginOutputReadLine(); 111 | process.BeginErrorReadLine(); 112 | 113 | if (process.WaitForExit(timeout) && outputWaitHandle.WaitOne(timeout) && errorWaitHandle.WaitOne(timeout)) 114 | { 115 | stdErr = error.ToString(); 116 | stdOut = output.ToString(); 117 | } 118 | else 119 | throw new Exception("Local ng lint call on build timed out. Timeout is 120 seconds."); 120 | } 121 | } 122 | return stdOut; 123 | } 124 | 125 | private void CallLog(string message, bool showWarning) 126 | { 127 | try 128 | { 129 | _log?.Invoke(message, showWarning); 130 | } 131 | catch (Exception) { } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/WebLinter/Linting/LintingError.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WebLinter 8 | { 9 | public class LintingError 10 | { 11 | public LintingError(string fileName, int lineNumber, int columnNumber, bool isError, string errorCode) 12 | { 13 | FileName = fileName; 14 | LineNumber = lineNumber; 15 | ColumnNumber = columnNumber; 16 | IsError = isError; 17 | ErrorCode = errorCode; 18 | } 19 | 20 | public Linter Provider { get; set; } 21 | public string FileName { get; } 22 | public string Message { get; set; } 23 | public int LineNumber { get; } 24 | public int ColumnNumber { get; } 25 | public int? EndLineNumber { get; set; } 26 | public int? EndColumnNumber { get; set; } 27 | public bool IsError { get; } = true; 28 | public string ErrorCode { get; } 29 | public string HelpLink { get; set; } 30 | public bool IsBuildError { get; set; } 31 | 32 | public override string ToString() 33 | { 34 | return Message; 35 | } 36 | 37 | protected bool Equals(LintingError other) 38 | { 39 | return string.Equals(FileName, other.FileName) && LineNumber == other.LineNumber && ColumnNumber == other.ColumnNumber && 40 | IsError == other.IsError && string.Equals(ErrorCode, other.ErrorCode); 41 | } 42 | 43 | public override bool Equals(object obj) 44 | { 45 | if (ReferenceEquals(null, obj)) return false; 46 | if (ReferenceEquals(this, obj)) return true; 47 | if (obj.GetType() != this.GetType()) return false; 48 | return Equals((LintingError)obj); 49 | } 50 | 51 | public override int GetHashCode() 52 | { 53 | unchecked 54 | { 55 | var hashCode = (FileName != null ? FileName.GetHashCode() : 0); 56 | hashCode = (hashCode * 397) ^ LineNumber; 57 | hashCode = (hashCode * 397) ^ ColumnNumber; 58 | hashCode = (hashCode * 397) ^ IsError.GetHashCode(); 59 | hashCode = (hashCode * 397) ^ (ErrorCode != null ? ErrorCode.GetHashCode() : 0); 60 | return hashCode; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/WebLinter/Linting/LintingResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace WebLinter 5 | { 6 | public class LintingResult 7 | { 8 | public LintingResult(params string[] fileNames) 9 | { 10 | FileNames.AddRange(fileNames); 11 | } 12 | 13 | public List FileNames { get; set; } = new List(); 14 | 15 | public bool HasErrors => Errors.Count > 0; 16 | 17 | public HashSet Errors { get; } = new HashSet(); 18 | 19 | // HasVsErrors is true iff there exists a TSLint error that will be 20 | // displayed as a Visual Studio error in the Error Window 21 | public bool HasVsErrors { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /src/WebLinter/Node/7z.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/src/WebLinter/Node/7z.dll -------------------------------------------------------------------------------- /src/WebLinter/Node/7z.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/src/WebLinter/Node/7z.exe -------------------------------------------------------------------------------- /src/WebLinter/Node/node.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/src/WebLinter/Node/node.7z -------------------------------------------------------------------------------- /src/WebLinter/Node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "01", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "tslint": "6.1.3", 13 | "typescript": "4.0.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/WebLinter/Node/server.js: -------------------------------------------------------------------------------- 1 | var http = require("http"), 2 | fs = require("fs"); 3 | 4 | var start = function (port) { 5 | http.createServer(function (req, res) { 6 | 7 | if (!req.url || req.url.length < 2) { 8 | res.writeHead(200, { 'Content-Type': 'text/plain' }); 9 | res.end(); 10 | return; 11 | } 12 | 13 | var path = req.url.substring(1); 14 | var body = ""; 15 | 16 | if (path === "ping") { 17 | res.writeHead(200, { 'Content-Type': 'text/plain' }); 18 | res.end("pong"); 19 | return; 20 | } 21 | 22 | req.on('data', function (data) { 23 | body += data; 24 | }); 25 | 26 | req.on('end', function () { 27 | var debug = false; 28 | try { 29 | if (body === "") 30 | return; 31 | 32 | var linter = linters[path]; 33 | 34 | if (linter) { 35 | var data = JSON.parse(body); 36 | debug = data.debug; 37 | var result = linter(data.config, data.fixerrors, data.files, data.usetsconfig, data.debug); 38 | 39 | res.writeHead(200, { 'Content-Type': 'application/json' }); 40 | res.write(result); 41 | } else { 42 | throw Error("No linter found for " + path); 43 | } 44 | } 45 | catch (e) { 46 | if (debug) { 47 | console.log(e); 48 | } 49 | res.writeHead(500, { 'Content-Type': 'application/json' }); 50 | var response = { 51 | "exception": JSON.stringify(e, Object.getOwnPropertyNames(e)), 52 | "error": true, 53 | "message": e.message, 54 | "path": path 55 | }; 56 | res.write(JSON.stringify(response)); 57 | } 58 | finally { 59 | res.end(); 60 | } 61 | }); 62 | 63 | }).listen(port); 64 | }; 65 | 66 | var linters = { 67 | tslint: function (configFile, fixErrors, files, usetsconfig, debug) { 68 | if (debug) { 69 | console.log(configFile); 70 | files.forEach(f => console.log(f)); 71 | console.log(usetsconfig); 72 | } 73 | var options = { 74 | fix: fixErrors, 75 | formatter: "json" 76 | }; 77 | 78 | if (usetsconfig) { 79 | return linttsconfigs(configFile, files, options, debug); 80 | } else { 81 | return lintFiles(configFile, files, options, debug); 82 | } 83 | } 84 | 85 | }; 86 | 87 | function lintFiles(configFile, files, options, debug) { 88 | var tslint = require("tslint"); 89 | var linter = new tslint.Linter(options); 90 | for (var i = 0; i < files.length; i++) { 91 | var fileName = files[i]; 92 | var fileContents = fs.readFileSync(fileName, "utf8"); 93 | var configuration = tslint.Configuration.findConfiguration(configFile, fileName).results; 94 | linter.lint(fileName, fileContents, configuration); 95 | } 96 | if (debug) console.log(linter.getResult().failures.length + " errors found"); 97 | return linter.getResult().output; 98 | 99 | } 100 | 101 | function linttsconfigs(tslintConfigFile, tsconfigFiles, options, debug) { 102 | var tslint = require("tslint"); 103 | var failures = []; 104 | for (var tsconfigCtr = 0; tsconfigCtr < tsconfigFiles.length; tsconfigCtr++) { 105 | var program = tslint.Linter.createProgram(tsconfigFiles[tsconfigCtr]); 106 | var tsFiles = tslint.Linter.getFileNames(program); 107 | var linter = new tslint.Linter(options, program); 108 | 109 | for (var i = 0; i < tsFiles.length; i++) { 110 | var tsFileContents = program.getSourceFile(tsFiles[i]).getFullText(); 111 | var tslintConfiguration = tslint.Configuration.findConfiguration(tslintConfigFile, tsFiles[i]).results; 112 | linter.lint(tsFiles[i], tsFileContents, tslintConfiguration); 113 | } 114 | failures = failures.concat(linter.getResult().failures); 115 | } 116 | if (debug) console.log(failures.length + " errors found"); 117 | var failuresJson = failures.map(function (failure) { return failure.toJson(); }); 118 | return JSON.stringify(failuresJson); 119 | } 120 | 121 | start(process.argv[2]); 122 | -------------------------------------------------------------------------------- /src/WebLinter/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebLinter")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebLinter")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9530fd25-eb47-44d8-9f0b-f989b639debe")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/WebLinter/ServerPostData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace WebLinter 5 | { 6 | public class ServerPostData 7 | { 8 | [JsonProperty("config")] 9 | public string Config { get; set; } 10 | 11 | [JsonProperty("files")] 12 | public IEnumerable Files { get; set; } 13 | 14 | [JsonProperty("fixerrors")] 15 | public bool FixErrors { get; set; } 16 | 17 | [JsonProperty("usetsconfig")] 18 | public bool UseTSConfig { get; set; } 19 | 20 | [JsonProperty("debug")] 21 | public bool Debug { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/WebLinter/WebLinter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {9530FD25-EB47-44D8-9F0B-F989B639DEBE} 8 | Library 9 | Properties 10 | WebLinter 11 | WebLinter 12 | v4.6.1 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | False 36 | ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 86 | -------------------------------------------------------------------------------- /src/WebLinter/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/WebLinterTest/AssemblyMethods.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using WebLinter; 3 | 4 | namespace WebLinterTest 5 | { 6 | [TestClass] 7 | public class AssemblyMethods 8 | { 9 | [AssemblyCleanup] 10 | public static void Cleanup() 11 | { 12 | Linter.Server.Down(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/WebLinterTest/BadTslintJsonTest.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using WebLinterVsix; 8 | 9 | namespace WebLinterTest 10 | { 11 | 12 | [TestClass] 13 | public class BadTslintJsonTest 14 | { 15 | private static EnvDTE80.DTE2 dte = null; 16 | private static EnvDTE.Solution solution = null; 17 | private static MockSettings settings = null; 18 | 19 | [ClassInitialize] 20 | public static void ClassInitialize(TestContext testContext) 21 | { 22 | // This is the official fix for the unused parameter warning IDE0060. Nice. 23 | // https://github.com/dotnet/roslyn/issues/35063#issuecomment-484616262 24 | _ = testContext; 25 | MessageFilter.Register(); 26 | Type type = Type.GetTypeFromProgID("VisualStudio.DTE.15.0"); 27 | object inst = Activator.CreateInstance(type, true); 28 | dte = (EnvDTE80.DTE2)inst; 29 | dte.Solution.Open(Path.GetFullPath(@"../../artifacts/bad-tslint-json/bad-tslint-json.sln")); 30 | solution = dte.Solution; 31 | 32 | settings = new MockSettings(); 33 | } 34 | 35 | [TestInitialize] 36 | public void TestInitialize() 37 | { 38 | WebLinterPackage.Settings = settings; 39 | WebLinterPackage.Dte = dte; 40 | } 41 | 42 | [TestCleanup] 43 | public void TestCleanup() 44 | { 45 | WebLinterPackage.Settings = null; 46 | WebLinterPackage.Dte = null; 47 | } 48 | 49 | [ClassCleanup] 50 | public static void ClassCleanup() 51 | { 52 | if (solution != null) { solution.Close(); solution = null; } 53 | if (dte != null) dte.Quit(); 54 | WebLinterPackage.Settings = null; 55 | WebLinterPackage.Dte = null; 56 | MessageFilter.Revoke(); 57 | } 58 | 59 | [TestMethod, TestCategory("Lint End to End")] 60 | public async Task LintBadTslintJsonSolution() 61 | { 62 | MockUIHierarchyItem mockSolutionHierarchyItem = new MockUIHierarchyItem() { Object = solution }; 63 | UIHierarchyItem[] selectedItems = new UIHierarchyItem[] { mockSolutionHierarchyItem }; 64 | 65 | MockErrorListDataSource mockErrorListDataSource = new MockErrorListDataSource(); 66 | ErrorListDataSource.InjectMockErrorListDataSource(mockErrorListDataSource); 67 | 68 | settings.UseTsConfig = false; 69 | settings.IgnoreNestedFiles = false; 70 | 71 | try 72 | { 73 | bool hasVSErrors = await LintFilesCommandBase.LintSelectedItems(false, selectedItems); 74 | 75 | Assert.IsTrue(hasVSErrors); 76 | Assert.IsTrue(mockErrorListDataSource.HasErrors()); 77 | Assert.AreEqual(1, mockErrorListDataSource.Snapshots.Count); 78 | 79 | CollectionAssert.AreEquivalent(new string[] { "TSLint" }, mockErrorListDataSource.Snapshots.Keys.ToArray()); 80 | 81 | var actualMsg = mockErrorListDataSource.Snapshots["TSLint"].Select(e => e.Message).First(); 82 | var expectedMsg = "Could not find custom rule directory: ./does-not-exist"; 83 | StringAssert.Contains(actualMsg, expectedMsg); 84 | } 85 | finally 86 | { 87 | ErrorListDataSource.InjectMockErrorListDataSource(null); 88 | settings.UseTsConfig = false; 89 | settings.IgnoreNestedFiles = true; 90 | } 91 | 92 | } 93 | 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/WebLinterTest/EmptyUnloadedProjectsTest.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System; 4 | using System.IO; 5 | using System.Threading.Tasks; 6 | using WebLinterVsix; 7 | namespace WebLinterTest 8 | { 9 | public class ProjectsTestBase 10 | { 11 | protected static EnvDTE80.DTE2 dte; 12 | protected static Solution solution; 13 | protected MockSettings settings; 14 | protected UIHierarchyItem[] selectedItems; 15 | protected MockErrorListDataSource mockErrorListDataSource; 16 | 17 | protected void Initialize(string solutionPath) 18 | { 19 | MessageFilter.Register(); 20 | Type type = Type.GetTypeFromProgID("VisualStudio.DTE.15.0"); 21 | object inst = Activator.CreateInstance(type, true); 22 | dte = (EnvDTE80.DTE2)inst; 23 | var test = (DTE)inst; 24 | //test. 25 | dte.Solution.Open(Path.GetFullPath(solutionPath)); 26 | 27 | solution = dte.Solution; 28 | settings = new MockSettings() { UseTsConfig = false }; 29 | WebLinterPackage.Settings = settings; 30 | WebLinterPackage.Dte = dte; 31 | } 32 | 33 | protected UIHierarchyItem[] Arrange(string solutionPath) 34 | { 35 | Initialize(solutionPath); 36 | MockUIHierarchyItem mockSolutionHierarchyItem = new MockUIHierarchyItem() { Object = solution }; 37 | selectedItems = new UIHierarchyItem[] { mockSolutionHierarchyItem }; 38 | mockErrorListDataSource = new MockErrorListDataSource(); 39 | ErrorListDataSource.InjectMockErrorListDataSource(mockErrorListDataSource); 40 | return selectedItems; 41 | } 42 | 43 | [ClassCleanup] 44 | public static void Cleanup() 45 | { 46 | if (solution != null) { solution.Close(); solution = null; } 47 | if (dte != null) dte.Quit(); 48 | WebLinterPackage.Settings = null; 49 | WebLinterPackage.Dte = null; 50 | MessageFilter.Revoke(); 51 | } 52 | } 53 | 54 | [TestClass] 55 | public class EmptyUnloadedProjectsTest : ProjectsTestBase 56 | { 57 | [TestMethod, TestCategory("Empty/Unloaded Projects")] 58 | public async Task LintEmptySolution() 59 | { 60 | try 61 | { 62 | Arrange(@"../../artifacts/empty/noprojects.sln"); 63 | 64 | bool hasVSErrors = await LintFilesCommandBase.LintSelectedItems(false, selectedItems); 65 | 66 | Assert.IsFalse(hasVSErrors); 67 | Assert.IsFalse(mockErrorListDataSource.HasErrors()); 68 | Assert.AreEqual(0, mockErrorListDataSource.Snapshots.Count); 69 | } 70 | finally 71 | { 72 | ErrorListDataSource.InjectMockErrorListDataSource(null); 73 | } 74 | } 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/WebLinterTest/MessageFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace WebLinterTest 9 | { 10 | public class MessageFilter : IOleMessageFilter 11 | { 12 | // 13 | // Class containing the IOleMessageFilter 14 | // thread error-handling functions. 15 | 16 | // Start the filter. 17 | public static void Register() 18 | { 19 | IOleMessageFilter newFilter = new MessageFilter(); 20 | IOleMessageFilter oldFilter = null; 21 | CoRegisterMessageFilter(newFilter, out oldFilter); 22 | } 23 | 24 | // Done with the filter, close it. 25 | public static void Revoke() 26 | { 27 | IOleMessageFilter oldFilter = null; 28 | CoRegisterMessageFilter(null, out oldFilter); 29 | } 30 | 31 | // 32 | // IOleMessageFilter functions. 33 | // Handle incoming thread requests. 34 | int IOleMessageFilter.HandleInComingCall(int dwCallType, 35 | System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr 36 | lpInterfaceInfo) 37 | { 38 | //Return the flag SERVERCALL_ISHANDLED. 39 | return 0; 40 | } 41 | 42 | // Thread call was rejected, so try again. 43 | int IOleMessageFilter.RetryRejectedCall(System.IntPtr 44 | hTaskCallee, int dwTickCount, int dwRejectType) 45 | { 46 | if (dwRejectType == 2) 47 | // flag = SERVERCALL_RETRYLATER. 48 | { 49 | // Retry the thread call immediately if return >=0 & 50 | // <100. 51 | return 99; 52 | } 53 | // Too busy; cancel call. 54 | return -1; 55 | } 56 | 57 | int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, 58 | int dwTickCount, int dwPendingType) 59 | { 60 | //Return the flag PENDINGMSG_WAITDEFPROCESS. 61 | return 2; 62 | } 63 | 64 | // Implement the IOleMessageFilter interface. 65 | [DllImport("Ole32.dll")] 66 | private static extern int 67 | CoRegisterMessageFilter(IOleMessageFilter newFilter, out 68 | IOleMessageFilter oldFilter); 69 | } 70 | 71 | [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), 72 | InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] 73 | interface IOleMessageFilter 74 | { 75 | [PreserveSig] 76 | int HandleInComingCall( 77 | int dwCallType, 78 | IntPtr hTaskCaller, 79 | int dwTickCount, 80 | IntPtr lpInterfaceInfo); 81 | 82 | [PreserveSig] 83 | int RetryRejectedCall( 84 | IntPtr hTaskCallee, 85 | int dwTickCount, 86 | int dwRejectType); 87 | 88 | [PreserveSig] 89 | int MessagePending( 90 | IntPtr hTaskCallee, 91 | int dwTickCount, 92 | int dwPendingType); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/WebLinterTest/MockSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using WebLinter; 4 | 5 | namespace WebLinterTest 6 | { 7 | public class MockSettings : ISettings 8 | { 9 | private static MockSettings _settings; 10 | 11 | public static MockSettings Instance 12 | { 13 | get 14 | { 15 | if (_settings == null) 16 | _settings = new MockSettings(); 17 | 18 | return _settings; 19 | } 20 | } 21 | 22 | public static string CWD 23 | { 24 | get { return new FileInfo("../../artifacts/").FullName; } 25 | } 26 | 27 | public bool TSLintEnable => true; 28 | public bool TSLintShowErrors => false; 29 | public bool UseTsConfig { get; set; } = false; 30 | public bool UseProjectNGLint => false; 31 | public bool LintJsFiles => false; 32 | public bool OnlyRunIfRequested => true; 33 | public bool RunOnBuild => false; 34 | public bool CleanErrorsOnBuild => false; 35 | public bool IgnoreNestedFiles { get; set; } = true; 36 | public string[] IgnorePatterns { get; set; } = new string[0]; 37 | public bool ShowUnderlining => true; 38 | 39 | public IEnumerable GetIgnorePatterns() { return IgnorePatterns; } 40 | public void ResetSettings() { } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/WebLinterTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebLinterTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebLinterTest")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("4480e2e4-80c1-4db4-b6cd-000a9b5da03d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/WebLinterTest/TslintTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using WebLinter; 5 | using System.IO; 6 | 7 | namespace WebLinterTest 8 | { 9 | /// 10 | /// Tests linting of individual .ts and .tsx files when use tsconfig.json is false 11 | /// 12 | [TestClass] 13 | public class TsLintTest 14 | { 15 | [TestMethod, TestCategory("TSLint")] 16 | public async Task StandardTs() 17 | { 18 | LintingResult result = await new Linter(MockSettings.Instance).Lint(false, "../../artifacts/tslint/a.ts"); 19 | Assert.IsTrue(result.HasErrors); 20 | Assert.IsFalse(string.IsNullOrEmpty(result.Errors.First().FileName), "File name is empty"); 21 | Assert.AreEqual(13, result.Errors.Count); 22 | Assert.AreEqual("if statements must be braced", result.Errors.First().Message); 23 | } 24 | 25 | [TestMethod, TestCategory("TSLint")] 26 | public async Task StandardTsFixErrors() 27 | { 28 | try 29 | { 30 | File.Copy("../../artifacts/tslint/a.ts", "../../artifacts/tslint/aTest.ts", true); 31 | LintingResult result = await new Linter(MockSettings.Instance, true).Lint(false, "../../artifacts/tslint/aTest.ts"); 32 | 33 | // Now, bizarrely, we have to fix twice to fix var -> const with the recommended TSLint rules 34 | // See TSLint issues #2835, #2843, #2625 35 | result = await new Linter(MockSettings.Instance, true).Lint(false, "../../artifacts/tslint/aTest.ts"); 36 | Assert.IsTrue(result.HasErrors); 37 | Assert.IsFalse(string.IsNullOrEmpty(result.Errors.First().FileName), "File name is empty"); 38 | // 2017-10-30: tslint 5.8.0 curly has a fixer #3262, reduces 4 -> 2 below 39 | Assert.AreEqual(2, result.Errors.Count); 40 | Assert.AreEqual("Calls to 'console.log' are not allowed.", result.Errors.First().Message); 41 | string actual = File.ReadAllText("../../artifacts/tslint/aTest.ts"); 42 | string expected = File.ReadAllText("../../artifacts/tslint/aFixed.ts"); 43 | // normalize by removing space indents and using Windows line breaks 44 | actual = System.Text.RegularExpressions.Regex.Replace(actual, "\r?\n\\s+", "\r\n"); 45 | expected = System.Text.RegularExpressions.Regex.Replace(expected, "\r?\n\\s+", "\r\n"); 46 | Assert.AreEqual(expected, actual); 47 | } 48 | finally 49 | { 50 | File.Delete("../../artifacts/tslint/aTest.ts"); 51 | } 52 | } 53 | 54 | [TestMethod, TestCategory("TSLint")] 55 | public async Task StandardTsNoErrors() 56 | { 57 | LintingResult result = await new Linter(MockSettings.Instance).Lint(false, "../../artifacts/tslint/e.ts"); 58 | Assert.IsFalse(result.HasErrors); 59 | Assert.AreEqual(0, result.Errors.Count); 60 | Assert.IsFalse(string.IsNullOrEmpty(result.FileNames.First()), "File name is empty"); 61 | } 62 | 63 | [TestMethod, TestCategory("TSLint")] 64 | public async Task StandardTsx() 65 | { 66 | LintingResult result = await new Linter(MockSettings.Instance).Lint(false, "../../artifacts/tslint/c.tsx"); 67 | Assert.IsTrue(result.HasErrors); 68 | Assert.IsFalse(string.IsNullOrEmpty(result.Errors.First().FileName), "File name is empty"); 69 | Assert.AreEqual(6, result.Errors.Count); 70 | Assert.AreEqual("The class method 'sayHello' must be marked either 'private', 'public', or 'protected'", result.Errors.First().Message); 71 | } 72 | 73 | [TestMethod, TestCategory("TSLint")] 74 | public async Task StandardTsxFixErrors() 75 | { 76 | try 77 | { 78 | File.Copy("../../artifacts/tslint/c.tsx", "../../artifacts/tslint/cTest.tsx", true); 79 | LintingResult result = await new Linter(MockSettings.Instance, true).Lint(false, "../../artifacts/tslint/cTest.tsx"); 80 | Assert.IsFalse(result.HasErrors); 81 | Assert.AreEqual(0, result.Errors.Count); 82 | string actual = File.ReadAllText("../../artifacts/tslint/cTest.tsx"); 83 | string expected = File.ReadAllText("../../artifacts/tslint/cFixed.tsx"); 84 | Assert.AreEqual(expected, actual); 85 | } 86 | finally 87 | { 88 | File.Delete("../../artifacts/tslint/cTest.tsx"); 89 | } 90 | } 91 | 92 | [TestMethod, TestCategory("TSLint")] 93 | public async Task StandardTsxNoErrors() 94 | { 95 | LintingResult result = await new Linter(MockSettings.Instance).Lint(false, "../../artifacts/tslint/d.tsx"); 96 | Assert.IsFalse(result.HasErrors); 97 | Assert.AreEqual(0, result.Errors.Count); 98 | Assert.IsFalse(string.IsNullOrEmpty(result.FileNames.First()), "File name is empty"); 99 | } 100 | 101 | [TestMethod, TestCategory("TSLint")] 102 | public async Task TsFileNotExist() 103 | { 104 | LintingResult result = await new Linter(MockSettings.Instance).Lint(false, "../../artifacts/tslint/doesntexist.ts"); 105 | Assert.IsTrue(result.HasErrors); 106 | } 107 | 108 | [TestMethod, TestCategory("TSLint")] 109 | public async Task TsxFileNotExist() 110 | { 111 | LintingResult result = await new Linter(MockSettings.Instance).Lint(false, "../../artifacts/tslint/doesntexist.tsx"); 112 | Assert.IsTrue(result.HasErrors); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/WebLinterTest/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/bad-tslint-json/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("bad_tslint_json")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("bad_tslint_json")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ee022247-d8c0-43aa-af0d-cd0772b92d22")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/bad-tslint-json/bad-tslint-json.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2035 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bad-tslint-json", "bad-tslint-json.csproj", "{EE022247-D8C0-43AA-AF0D-CD0772B92D22}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {EE022247-D8C0-43AA-AF0D-CD0772B92D22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {EE022247-D8C0-43AA-AF0D-CD0772B92D22}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {EE022247-D8C0-43AA-AF0D-CD0772B92D22}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {EE022247-D8C0-43AA-AF0D-CD0772B92D22}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {B341AE5E-3205-4922-9B76-5C6592FBC68D} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/bad-tslint-json/badtest.ts: -------------------------------------------------------------------------------- 1 | class Undocumented { 2 | mymethod(input: string): string { 3 | return "Hello " + input; 4 | } 5 | } 6 | 7 | function alsoundocumented() { } 8 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/bad-tslint-json/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "target": "es5", 5 | "module": "none", 6 | "outFile": "bundle.js", 7 | "sourceMap": true, 8 | "jsx": "react" 9 | }, 10 | "include": [ 11 | "../src/**/*", 12 | "./**/*" 13 | ], 14 | "exclude": [ 15 | "node.d.ts", 16 | "mocha.d.ts", 17 | "b/file3.ts" 18 | ] 19 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/bad-tslint-json/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": "./does-not-exist" 3 | } 4 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/empty/noprojects.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Global 7 | GlobalSection(SolutionProperties) = preSolution 8 | HideSolutionNode = FALSE 9 | EndGlobalSection 10 | EndGlobal 11 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/a/a.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B0D5B71B-F50C-4C0E-BF3A-BA0C59B82A87} 8 | Exe 9 | a.csproj 10 | a.csproj 11 | v4.6.1 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/a/fileA.ts: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/a/fileAA.ts: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/b/b.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {129B6D29-2D9B-48ED-BE19-9EEB4C99D502} 8 | Exe 9 | a.csproj 10 | a.csproj 11 | v4.6.1 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/b/fileB.ts: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/b/node_modules/eslint/dummy.txt: -------------------------------------------------------------------------------- 1 | Dummy text file to force Git to create the folder on checkout -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/b/package.json: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/multiple.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.1525 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "a", "a\a.csproj", "{B0D5B71B-F50C-4C0E-BF3A-BA0C59B82A87}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "b", "b\b.csproj", "{129B6D29-2D9B-48ED-BE19-9EEB4C99D502}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {B0D5B71B-F50C-4C0E-BF3A-BA0C59B82A87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {B0D5B71B-F50C-4C0E-BF3A-BA0C59B82A87}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {B0D5B71B-F50C-4C0E-BF3A-BA0C59B82A87}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {B0D5B71B-F50C-4C0E-BF3A-BA0C59B82A87}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {129B6D29-2D9B-48ED-BE19-9EEB4C99D502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {129B6D29-2D9B-48ED-BE19-9EEB4C99D502}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {129B6D29-2D9B-48ED-BE19-9EEB4C99D502}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {129B6D29-2D9B-48ED-BE19-9EEB4C99D502}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {2C0D0AB9-450A-49CE-9C9E-C53B8A8D0468} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/node_modules/eslint/dummy.txt: -------------------------------------------------------------------------------- 1 | Dummy text file to force Git to create the folder on checkout -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/localinstall/multiple/package.json: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/Tsconfig.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tsconfigTest", "multiple\tsconfigTest.csproj", "{2574F603-4B6C-4A30-BFDD-E3BC09EEDFDF}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tsconfigEmptyTest", "none\tsconfigEmptyTest.csproj", "{33B15409-8CA5-445F-BFA5-F4BF87B0C419}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionFolder", "SolutionFolder", "{E69AFA62-6B7B-4E73-AA2F-F32E25E080AC}" 11 | ProjectSection(SolutionItems) = preProject 12 | file8.ts = file8.ts 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {2574F603-4B6C-4A30-BFDD-E3BC09EEDFDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {2574F603-4B6C-4A30-BFDD-E3BC09EEDFDF}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {2574F603-4B6C-4A30-BFDD-E3BC09EEDFDF}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {2574F603-4B6C-4A30-BFDD-E3BC09EEDFDF}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {33B15409-8CA5-445F-BFA5-F4BF87B0C419}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {33B15409-8CA5-445F-BFA5-F4BF87B0C419}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {33B15409-8CA5-445F-BFA5-F4BF87B0C419}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {33B15409-8CA5-445F-BFA5-F4BF87B0C419}.Release|Any CPU.Build.0 = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | EndGlobal 34 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/file8.ts: -------------------------------------------------------------------------------- 1 | console.log("Console log in file8.ts"); 2 | 3 | function file8() { } 4 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/file9.ts: -------------------------------------------------------------------------------- 1 | console.log("Console log in file9.ts"); 2 | 3 | function file9() { } 4 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/HtmlPage1.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/a/c/file4.ts: -------------------------------------------------------------------------------- 1 | console.log("Console log in file4.ts"); 2 | 3 | function file4() { } 4 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/a/c/file6.tsx: -------------------------------------------------------------------------------- 1 | // A '.tsx' file enables JSX support in the TypeScript compiler, 2 | // for more information see the following page on the TypeScript wiki: 3 | // https://github.com/Microsoft/TypeScript/wiki/JSX 4 | 5 | //import * as React from 'react'; 6 | //import * as ReactDOM from 'react-dom'; 7 | 8 | /// 9 | /// 10 | 11 | class MyTsx { 12 | sayHello() { 13 | ReactDOM.render( 14 |

Hello tsx World!

, 15 | document.getElementById('wrapper') 16 | ); 17 | } 18 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/a/file1.ts: -------------------------------------------------------------------------------- 1 | console.log("Console log in file1.ts"); 2 | 3 | function file1() { } 4 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/a/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "target": "es5", 5 | "module": "none", 6 | "outFile": "testie2.js", 7 | "sourceMap": true, 8 | "jsx": "react" 9 | }, 10 | "include": [ 11 | "./**/*" 12 | ], 13 | "exclude": [ 14 | "node.d.ts", 15 | "mocha.d.ts" 16 | ] 17 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/b/file2.ts: -------------------------------------------------------------------------------- 1 | console.log("Console log in file2.ts"); 2 | 3 | function file2() { } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/b/file3.ts: -------------------------------------------------------------------------------- 1 | console.log("Console log in file3.ts"); 2 | 3 | function file3() { } 4 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/b/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "target": "es5", 5 | "module": "none", 6 | "outFile": "bundle.js", 7 | "sourceMap": true, 8 | "jsx": "react" 9 | }, 10 | "include": [ 11 | "file2.ts", 12 | "file3.ts" 13 | ], 14 | "exclude": [ 15 | "node.d.ts", 16 | "mocha.d.ts" 17 | ] 18 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/file7.ts: -------------------------------------------------------------------------------- 1 | console.log("Console log in file7.ts"); 2 | 3 | function file7() { } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/react-dom.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React (react-dom) 0.14 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 5 | // TypeScript Version: 2.1 6 | 7 | export as namespace ReactDOM; 8 | export = ReactDOM; 9 | 10 | import { ReactInstance, Component, ComponentState, 11 | ReactElement, SFCElement, CElement, 12 | DOMAttributes, DOMElement } from 'react'; 13 | 14 | declare namespace ReactDOM { 15 | function findDOMNode(instance: ReactInstance): E; 16 | function findDOMNode(instance: ReactInstance): Element; 17 | 18 | function render

, T extends Element>( 19 | element: DOMElement, 20 | container: Element | null, 21 | callback?: (element: T) => any): T; 22 | function render

( 23 | element: SFCElement

, 24 | container: Element | null, 25 | callback?: () => any): void; 26 | function render>( 27 | element: CElement, 28 | container: Element | null, 29 | callback?: (component: T) => any): T; 30 | function render

( 31 | element: ReactElement

, 32 | container: Element | null, 33 | callback?: (component?: Component | Element) => any): Component | Element | void; 34 | 35 | function unmountComponentAtNode(container: Element): boolean; 36 | 37 | var version: string; 38 | 39 | function unstable_batchedUpdates(callback: (a: A, b: B) => any, a: A, b: B): void; 40 | function unstable_batchedUpdates(callback: (a: A) => any, a: A): void; 41 | function unstable_batchedUpdates(callback: () => any): void; 42 | 43 | function unstable_renderSubtreeIntoContainer

, T extends Element>( 44 | parentComponent: Component, 45 | element: DOMElement, 46 | container: Element, 47 | callback?: (element: T) => any): T; 48 | function unstable_renderSubtreeIntoContainer>( 49 | parentComponent: Component, 50 | element: CElement, 51 | container: Element, 52 | callback?: (component: T) => any): T; 53 | function render

( 54 | parentComponent: Component, 55 | element: SFCElement

, 56 | container: Element, 57 | callback?: () => any): void; 58 | function unstable_renderSubtreeIntoContainer

( 59 | parentComponent: Component, 60 | element: ReactElement

, 61 | container: Element, 62 | callback?: (component?: Component | Element) => any): Component | Element | void; 63 | } 64 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/test.ts: -------------------------------------------------------------------------------- 1 | class Undocumented { 2 | mymethod(input: string): string { 3 | return "Hello " + input; 4 | } 5 | } 6 | 7 | function alsoundocumented() { } 8 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "target": "es5", 5 | "module": "none", 6 | "outFile": "bundle.js", 7 | "sourceMap": true, 8 | "jsx": "react" 9 | }, 10 | "include": [ 11 | "../src/**/*", 12 | "./**/*" 13 | ], 14 | "exclude": [ 15 | "node.d.ts", 16 | "mocha.d.ts", 17 | "b/file3.ts" 18 | ] 19 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/multiple/tsconfigTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 7 | 8 | 2.0 9 | {2574F603-4B6C-4A30-BFDD-E3BC09EEDFDF} 10 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 11 | Library 12 | Properties 13 | TypeScriptHTMLApp1 14 | TypeScriptHTMLApp1 15 | v4.5.2 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 2.2 25 | 26 | 27 | true 28 | full 29 | false 30 | bin\ 31 | DEBUG;TRACE 32 | prompt 33 | 4 34 | 35 | 36 | true 37 | pdbonly 38 | true 39 | bin\ 40 | TRACE 41 | prompt 42 | 4 43 | ES5 44 | None 45 | True 46 | False 47 | CommonJS 48 | True 49 | 50 | 51 | False 52 | True 53 | False 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | file9.ts 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Code 72 | HtmlPage1.html 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 10.0 91 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | False 102 | True 103 | 10202 104 | / 105 | http://localhost:10202/ 106 | False 107 | False 108 | 109 | 110 | False 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/none/HtmlPage1.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/none/b/file5.ts: -------------------------------------------------------------------------------- 1 | console.log("Console log in file5.ts"); 2 | 3 | function file5() { } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/none/b/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "target": "es5", 5 | "module": "none", 6 | "outFile": "bundle.js", 7 | "sourceMap": true 8 | }, 9 | "include": [ 10 | "../src/**/*", 11 | "./**/*" 12 | ], 13 | "exclude": [ 14 | "node.d.ts", 15 | "mocha.d.ts", 16 | "b/file2.ts" 17 | ] 18 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/none/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "target": "es5", 5 | "module": "none", 6 | "outFile": "bundle.js", 7 | "sourceMap": true 8 | }, 9 | "include": [ 10 | "../src/**/*", 11 | "./**/*" 12 | ], 13 | "exclude": [ 14 | "node.d.ts", 15 | "mocha.d.ts", 16 | "b/file2.ts" 17 | ] 18 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/none/tsconfigEmptyTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 7 | 8 | 2.0 9 | {33B15409-8CA5-445F-BFA5-F4BF87B0C419} 10 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 11 | Library 12 | Properties 13 | TypeScriptHTMLApp1 14 | TypeScriptHTMLApp1 15 | v4.5.2 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 2.2 25 | 26 | 27 | true 28 | full 29 | false 30 | bin\ 31 | DEBUG;TRACE 32 | prompt 33 | 4 34 | 35 | 36 | true 37 | pdbonly 38 | true 39 | bin\ 40 | TRACE 41 | prompt 42 | 4 43 | ES5 44 | None 45 | True 46 | False 47 | CommonJS 48 | True 49 | 50 | 51 | False 52 | True 53 | False 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | HtmlPage1.html 71 | 72 | 73 | 74 | 10.0 75 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | False 86 | True 87 | 10202 88 | / 89 | http://localhost:10202/ 90 | False 91 | False 92 | 93 | 94 | False 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tsconfig/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "completed-docs": [ true ], 4 | "adjacent-overload-signatures": true, 5 | "align": [ true, "parameters", "statements" ], 6 | "array-type": [ true, "array-simple" ], 7 | "arrow-parens": true, 8 | "arrow-return-shorthand": true, 9 | "ban-types": [ 10 | true, 11 | [ "Object", "Avoid using the `Object` type. Did you mean `object`?" ], 12 | [ "Function", "Avoid using the `Function` type. Prefer a specific function type, like `() => void`." ], 13 | [ "Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?" ], 14 | [ "Number", "Avoid using the `Number` type. Did you mean `number`?" ], 15 | [ "String", "Avoid using the `String` type. Did you mean `string`?" ], 16 | [ "Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?" ] 17 | ], 18 | "callable-types": true, 19 | "class-name": true, 20 | "comment-format": [ true, "check-space" ], 21 | "curly": true, 22 | "cyclomatic-complexity": [ false ], 23 | "eofline": true, 24 | "forin": true, 25 | "import-spacing": true, 26 | "indent": [ true, "spaces" ], 27 | "interface-name": [ true, "always-prefix" ], 28 | "interface-over-type-literal": true, 29 | "jsdoc-format": true, 30 | "label-position": true, 31 | "max-classes-per-file": [ true, 1 ], 32 | "max-line-length": [ true, 120 ], 33 | "member-access": true, 34 | "member-ordering": [ 35 | true, 36 | { "order": "statics-first" } 37 | ], 38 | "new-parens": true, 39 | "no-angle-bracket-type-assertion": true, 40 | "no-any": false, 41 | "no-arg": true, 42 | "no-bitwise": true, 43 | "no-conditional-assignment": true, 44 | "no-consecutive-blank-lines": [ true ], 45 | "no-console": [ true ], 46 | "no-construct": true, 47 | "no-debugger": true, 48 | "no-duplicate-super": true, 49 | "no-empty": true, 50 | "no-empty-interface": true, 51 | "no-eval": true, 52 | "no-internal-module": true, 53 | "no-invalid-this": false, 54 | "no-misused-new": true, 55 | "no-namespace": true, 56 | "no-parameter-properties": false, 57 | "no-reference": true, 58 | "no-reference-import": true, 59 | "no-shadowed-variable": true, 60 | "no-string-literal": true, 61 | "no-string-throw": true, 62 | "no-switch-case-fall-through": false, 63 | "no-trailing-whitespace": true, 64 | "no-unnecessary-initializer": true, 65 | "no-unsafe-finally": true, 66 | "no-unused-expression": true, 67 | // disable this rule as it is very heavy performance-wise and not that useful 68 | "no-use-before-declare": false, 69 | "no-var-keyword": true, 70 | "no-var-requires": true, 71 | "object-literal-key-quotes": [ true, "as-needed" ], 72 | "object-literal-shorthand": true, 73 | "object-literal-sort-keys": true, 74 | "one-line": [ 75 | true, 76 | "check-catch", 77 | "check-else", 78 | "check-finally", 79 | "check-open-brace", 80 | "check-whitespace" 81 | ], 82 | "one-variable-per-declaration": [ true, "ignore-for-loop" ], 83 | "only-arrow-functions": [ true, "allow-declarations", "allow-named-functions" ], 84 | "ordered-imports": [ 85 | true, 86 | { 87 | "import-sources-order": "case-insensitive", 88 | "named-imports-order": "case-insensitive" 89 | } 90 | ], 91 | "prefer-const": true, 92 | "prefer-for-of": true, 93 | "quotemark": [ true, "double", "avoid-escape" ], 94 | "radix": true, 95 | "semicolon": [ true, "always" ], 96 | "space-before-function-paren": [ 97 | true, 98 | { 99 | "anonymous": "never", 100 | "asyncArrow": "always", 101 | "constructor": "never", 102 | "method": "never", 103 | "named": "never" 104 | } 105 | ], 106 | "trailing-comma": [ 107 | true, 108 | { 109 | "multiline": "always", 110 | "singleline": "never" 111 | } 112 | ], 113 | "triple-equals": [ true, "allow-null-check" ], 114 | "typedef": [ false ], 115 | "typedef-whitespace": [ 116 | true, 117 | { 118 | "call-signature": "nospace", 119 | "index-signature": "nospace", 120 | "parameter": "nospace", 121 | "property-declaration": "nospace", 122 | "variable-declaration": "nospace" 123 | }, 124 | { 125 | "call-signature": "onespace", 126 | "index-signature": "onespace", 127 | "parameter": "onespace", 128 | "property-declaration": "onespace", 129 | "variable-declaration": "onespace" 130 | } 131 | ], 132 | "typeof-compare": true, 133 | "unified-signatures": true, 134 | "use-isnan": true, 135 | "variable-name": [ true, "ban-keywords", "check-format", "allow-pascal-case" ], 136 | "whitespace": [ 137 | true, 138 | "check-branch", 139 | "check-decl", 140 | "check-operator", 141 | "check-module", 142 | "check-separator", 143 | "check-type", 144 | "check-typecast" 145 | ] 146 | } 147 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "adjacent-overload-signatures": true, 4 | "align": [ true, "parameters", "statements" ], 5 | "array-type": [ true, "array-simple" ], 6 | "arrow-parens": true, 7 | "arrow-return-shorthand": true, 8 | "ban-types": [ 9 | true, 10 | [ "Object", "Avoid using the `Object` type. Did you mean `object`?" ], 11 | [ "Function", "Avoid using the `Function` type. Prefer a specific function type, like `() => void`." ], 12 | [ "Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?" ], 13 | [ "Number", "Avoid using the `Number` type. Did you mean `number`?" ], 14 | [ "String", "Avoid using the `String` type. Did you mean `string`?" ], 15 | [ "Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?" ] 16 | ], 17 | "callable-types": true, 18 | "class-name": true, 19 | "comment-format": [ true, "check-space" ], 20 | "curly": true, 21 | "cyclomatic-complexity": [ false ], 22 | "eofline": true, 23 | "forin": true, 24 | "import-spacing": true, 25 | "indent": [ true, "spaces" ], 26 | "interface-name": [ true, "always-prefix" ], 27 | "interface-over-type-literal": true, 28 | "jsdoc-format": true, 29 | "label-position": true, 30 | "max-classes-per-file": [ true, 1 ], 31 | "max-line-length": [ true, 120 ], 32 | "member-access": true, 33 | "member-ordering": [ 34 | true, 35 | { "order": "statics-first" } 36 | ], 37 | "new-parens": true, 38 | "no-angle-bracket-type-assertion": true, 39 | "no-any": false, 40 | "no-arg": true, 41 | "no-bitwise": true, 42 | "no-conditional-assignment": true, 43 | "no-consecutive-blank-lines": [ true ], 44 | "no-console": [ true ], 45 | "no-construct": true, 46 | "no-debugger": true, 47 | "no-duplicate-super": true, 48 | "no-empty": true, 49 | "no-empty-interface": true, 50 | "no-eval": true, 51 | "no-internal-module": true, 52 | "no-invalid-this": false, 53 | "no-misused-new": true, 54 | "no-namespace": true, 55 | "no-parameter-properties": false, 56 | "no-reference": true, 57 | "no-reference-import": true, 58 | "no-shadowed-variable": true, 59 | "no-string-literal": true, 60 | "no-string-throw": true, 61 | "no-switch-case-fall-through": false, 62 | "no-trailing-whitespace": true, 63 | "no-unnecessary-initializer": true, 64 | "no-unsafe-finally": true, 65 | "no-unused-expression": true, 66 | // disable this rule as it is very heavy performance-wise and not that useful 67 | "no-use-before-declare": false, 68 | "no-var-keyword": true, 69 | "no-var-requires": true, 70 | "object-literal-key-quotes": [ true, "as-needed" ], 71 | "object-literal-shorthand": true, 72 | "object-literal-sort-keys": true, 73 | "one-line": [ 74 | true, 75 | "check-catch", 76 | "check-else", 77 | "check-finally", 78 | "check-open-brace", 79 | "check-whitespace" 80 | ], 81 | "one-variable-per-declaration": [ true, "ignore-for-loop" ], 82 | "only-arrow-functions": [ true, "allow-declarations", "allow-named-functions" ], 83 | "ordered-imports": [ 84 | true, 85 | { 86 | "import-sources-order": "case-insensitive", 87 | "named-imports-order": "case-insensitive" 88 | } 89 | ], 90 | "prefer-const": true, 91 | "prefer-for-of": true, 92 | "quotemark": [ true, "double", "avoid-escape" ], 93 | "radix": true, 94 | "semicolon": [ true, "always" ], 95 | "space-before-function-paren": [ 96 | true, 97 | { 98 | "anonymous": "never", 99 | "asyncArrow": "always", 100 | "constructor": "never", 101 | "method": "never", 102 | "named": "never" 103 | } 104 | ], 105 | "trailing-comma": [ 106 | true, 107 | { 108 | "multiline": "always", 109 | "singleline": "never" 110 | } 111 | ], 112 | "triple-equals": [ true, "allow-null-check" ], 113 | "typedef": [ false ], 114 | "typedef-whitespace": [ 115 | true, 116 | { 117 | "call-signature": "nospace", 118 | "index-signature": "nospace", 119 | "parameter": "nospace", 120 | "property-declaration": "nospace", 121 | "variable-declaration": "nospace" 122 | }, 123 | { 124 | "call-signature": "onespace", 125 | "index-signature": "onespace", 126 | "parameter": "onespace", 127 | "property-declaration": "onespace", 128 | "variable-declaration": "onespace" 129 | } 130 | ], 131 | "typeof-compare": false, 132 | "unified-signatures": true, 133 | "use-isnan": true, 134 | "variable-name": [ true, "ban-keywords", "check-format", "allow-pascal-case" ], 135 | "whitespace": [ 136 | true, 137 | "check-branch", 138 | "check-decl", 139 | "check-operator", 140 | "check-module", 141 | "check-separator", 142 | "check-type", 143 | "check-typecast" 144 | ] 145 | } 146 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tslint/a.ts: -------------------------------------------------------------------------------- 1 | function foo() { 2 | var i = "test" 3 | var b = "hat" 4 | 5 | if (i == b) 6 | return false 7 | else 8 | return "Hello from foo" 9 | } 10 | 11 | console.log(foo()); -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tslint/aFixed.ts: -------------------------------------------------------------------------------- 1 | function foo() { 2 | const i = "test"; 3 | const b = "hat"; 4 | 5 | if (i == b) { 6 | return false; 7 | } else { 8 | return "Hello from foo"; 9 | } 10 | } 11 | 12 | console.log(foo()); 13 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tslint/b.ts: -------------------------------------------------------------------------------- 1 | function foo() { 2 | var i = "test" 3 | var b = "hat" 4 | 5 | if (i == b) 6 | return false 7 | } -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tslint/c.tsx: -------------------------------------------------------------------------------- 1 | // A '.tsx' file enables JSX support in the TypeScript compiler, 2 | // for more information see the following page on the TypeScript wiki: 3 | // https://github.com/Microsoft/TypeScript/wiki/JSX 4 | 5 | import * as React from 'react'; 6 | import * as ReactDOM from 'react-dom'; 7 | 8 | export class MyTsx { 9 | sayHello() { 10 | ReactDOM.render( 11 |

Hello tsx World!

, 12 | document.getElementById('wrapper') 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tslint/cFixed.tsx: -------------------------------------------------------------------------------- 1 | // A '.tsx' file enables JSX support in the TypeScript compiler, 2 | // for more information see the following page on the TypeScript wiki: 3 | // https://github.com/Microsoft/TypeScript/wiki/JSX 4 | 5 | import * as React from "react"; 6 | import * as ReactDOM from "react-dom"; 7 | 8 | export class MyTsx { 9 | public sayHello() { 10 | ReactDOM.render( 11 |

Hello tsx World!

, 12 | document.getElementById("wrapper"), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tslint/d.tsx: -------------------------------------------------------------------------------- 1 | // a '.tsx' file enables JSX support in the TypeScript compiler, 2 | // for more information see the following page on the TypeScript wiki: 3 | // https://github.com/Microsoft/TypeScript/wiki/JSX 4 | 5 | // import * as React from "react"; 6 | import * as ReactDOM from "react-dom"; 7 | 8 | export class MyTsx { 9 | public sayHello() { 10 | ReactDOM.render( 11 |

Hello tsx World!

, 12 | document.getElementById("wrapper")); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/WebLinterTest/artifacts/tslint/e.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function foo() { 4 | "use strict"; 5 | const i = "test"; 6 | const b = "hat"; 7 | 8 | if (i === b) { 9 | return false; 10 | } 11 | } 12 | 13 | foo(); 14 | -------------------------------------------------------------------------------- /src/WebLinterTest/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/WebLinterTest/zzGenerateCsprojEntries.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace WebLinterTest 10 | { 11 | [TestClass] 12 | public class zzGenerateCsprojEntries 13 | { 14 | private string result; 15 | private int pathLocation; 16 | [TestMethod] 17 | public void GenerateEntriesTest() 18 | { 19 | // Results are in typescript-analyzer\src\WebLinterVsix\Node\temp.txt 20 | // and need to be used to update WebLinterVsix.csproj 21 | result = ""; 22 | string assemblyDirectory = WebLinter.NodeServer.ExecutionPath; 23 | assemblyDirectory = assemblyDirectory.Replace("WebLinterTest\\bin\\Debug", "WebLinterVsix"); 24 | Assert.IsTrue(Directory.Exists(assemblyDirectory), $"Source folder for node files ({assemblyDirectory}) doesn't exist"); 25 | pathLocation = assemblyDirectory.LastIndexOf($"\\{WebLinter.Constants.NODE_FOLDER_NAME}") + 1; 26 | ProcessDirectory(assemblyDirectory); 27 | File.WriteAllText(assemblyDirectory + "\\temp.txt", result); 28 | } 29 | 30 | private void ProcessDirectory(string targetDirectory) 31 | { 32 | string[] fileEntries = Directory.GetFiles(targetDirectory); 33 | foreach (string fileName in fileEntries) 34 | ProcessFile(fileName); 35 | string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory); 36 | foreach (string subdirectory in subdirectoryEntries) 37 | ProcessDirectory(subdirectory); 38 | } 39 | 40 | private readonly string template = @" 41 | true 42 | PreserveNewest 43 | 44 | "; 45 | private void ProcessFile(string path) 46 | { 47 | string pathForCsproj = path.Substring(pathLocation, path.Length - pathLocation); 48 | string entry = template.Replace("REPLACE", pathForCsproj); 49 | result += entry; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Commands/BuildEventsBase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio; 2 | using Microsoft.VisualStudio.Shell.Interop; 3 | using System; 4 | 5 | namespace WebLinterVsix 6 | { 7 | public class BuildEventsBase : IVsUpdateSolutionEvents2 8 | { 9 | private readonly IVsSolution _solution; 10 | private readonly IVsSolutionBuildManager3 _buildManager; 11 | //private uint _cookie1 = VSConstants.VSCOOKIE_NIL; 12 | private uint _cookie2 = VSConstants.VSCOOKIE_NIL; 13 | //private uint _cookie3 = VSConstants.VSCOOKIE_NIL; 14 | 15 | public BuildEventsBase(IServiceProvider serviceProvider) 16 | { 17 | if (serviceProvider == null) 18 | { 19 | throw new ArgumentNullException("serviceProvider"); 20 | } 21 | 22 | this._solution = serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution; 23 | if (this._solution == null) 24 | { 25 | throw new InvalidOperationException("Cannot get solution service"); 26 | } 27 | this._buildManager = serviceProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager3; 28 | } 29 | 30 | public void StartListeningForChanges() 31 | { 32 | //ErrorHandler.ThrowOnFailure(this._solution.AdviseSolutionEvents(this, out this._cookie1)); 33 | if (this._buildManager != null) 34 | { 35 | var bm2 = this._buildManager as IVsSolutionBuildManager2; 36 | if (bm2 != null) 37 | { 38 | ErrorHandler.ThrowOnFailure(bm2.AdviseUpdateSolutionEvents(this, out this._cookie2)); 39 | } 40 | //ErrorHandler.ThrowOnFailure(this._buildManager.AdviseUpdateSolutionEvents3(this, out this._cookie3)); 41 | } 42 | } 43 | 44 | public void Dispose() 45 | { 46 | // Ignore failures in UnadviseSolutionEvents 47 | //if (this._cookie1 != VSConstants.VSCOOKIE_NIL) 48 | //{ 49 | // this._solution.UnadviseSolutionEvents(this._cookie1); 50 | // this._cookie1 = VSConstants.VSCOOKIE_NIL; 51 | //} 52 | if (this._cookie2 != VSConstants.VSCOOKIE_NIL) 53 | { 54 | ((IVsSolutionBuildManager2)this._buildManager).UnadviseUpdateSolutionEvents(this._cookie2); 55 | this._cookie2 = VSConstants.VSCOOKIE_NIL; 56 | } 57 | //if (this._cookie3 != VSConstants.VSCOOKIE_NIL) 58 | //{ 59 | // this._buildManager.UnadviseUpdateSolutionEvents3(this._cookie3); 60 | // this._cookie3 = VSConstants.VSCOOKIE_NIL; 61 | //} 62 | } 63 | 64 | public virtual int UpdateSolution_Begin(ref int pfCancelUpdate) 65 | { 66 | return VSConstants.E_NOTIMPL; 67 | } 68 | 69 | public virtual int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) 70 | { 71 | return VSConstants.E_NOTIMPL; 72 | } 73 | 74 | public virtual int UpdateSolution_StartUpdate(ref int pfCancelUpdate) 75 | { 76 | return VSConstants.E_NOTIMPL; 77 | } 78 | 79 | public virtual int UpdateSolution_Cancel() 80 | { 81 | return VSConstants.E_NOTIMPL; 82 | } 83 | 84 | public virtual int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy) 85 | { 86 | return VSConstants.E_NOTIMPL; 87 | } 88 | 89 | public virtual int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) 90 | { 91 | return VSConstants.E_NOTIMPL; 92 | } 93 | 94 | public virtual int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) 95 | { 96 | return VSConstants.E_NOTIMPL; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Commands/CleanErrorsCommand.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using Microsoft.VisualStudio.Shell; 3 | using System; 4 | using System.ComponentModel.Design; 5 | 6 | namespace WebLinterVsix 7 | { 8 | internal sealed class CleanErrorsCommand 9 | { 10 | private readonly Package _package; 11 | private readonly BuildEvents _events; 12 | 13 | private CleanErrorsCommand(Package package) 14 | { 15 | _package = package; 16 | _events = WebLinterPackage.Dte.Events.BuildEvents; 17 | _events.OnBuildBegin += OnBuildBegin; 18 | 19 | OleMenuCommandService commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService; 20 | var menuCommandID = new CommandID(PackageGuids.WebLinterCmdSet, PackageIds.CleanErrorsCommand); 21 | var menuItem = new OleMenuCommand(CleanErrors, menuCommandID); 22 | menuItem.BeforeQueryStatus += BeforeQueryStatus; 23 | commandService.AddCommand(menuItem); 24 | } 25 | 26 | private void OnBuildBegin(vsBuildScope Scope, vsBuildAction Action) 27 | { 28 | // Called on UI thread 29 | if (WebLinterPackage.Settings.CleanErrorsOnBuild && 30 | (Action == vsBuildAction.vsBuildActionClean || 31 | (Action == vsBuildAction.vsBuildActionRebuildAll && !WebLinterPackage.Settings.RunOnBuild))) 32 | { 33 | ErrorListDataSource.Instance.CleanAllErrors(); 34 | } 35 | } 36 | 37 | public static CleanErrorsCommand Instance { get; private set; } 38 | 39 | private IServiceProvider ServiceProvider 40 | { 41 | get { return _package; } 42 | } 43 | 44 | public static void Initialize(Package package) 45 | { 46 | Instance = new CleanErrorsCommand(package); 47 | } 48 | 49 | private void BeforeQueryStatus(object sender, EventArgs e) 50 | { 51 | // Called on UI thread 52 | var button = (OleMenuCommand)sender; 53 | 54 | button.Visible = ErrorListDataSource.Instance.HasErrors(); 55 | } 56 | 57 | private void CleanErrors(object sender, EventArgs e) 58 | { 59 | // Called on UI thread 60 | ErrorListDataSource.Instance.CleanAllErrors(); 61 | WebLinterPackage.TaggerProvider?.RefreshTags(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Commands/EditConfigFilesCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Design; 4 | using System.IO; 5 | using Microsoft.VisualStudio.Shell; 6 | using WebLinter; 7 | 8 | namespace WebLinterVsix 9 | { 10 | internal sealed class EditConfigFilesCommand 11 | { 12 | private readonly Package _package; 13 | 14 | private EditConfigFilesCommand(Package package) 15 | { 16 | _package = package; 17 | 18 | List list = new List 19 | { 20 | new CommandID(PackageGuids.ConfigFileCmdSet, PackageIds.EditTSLint), 21 | }; 22 | 23 | OleMenuCommandService commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService; 24 | 25 | foreach (var id in list) 26 | { 27 | var menuItem = new MenuCommand(EditConfig, id); 28 | commandService.AddCommand(menuItem); 29 | } 30 | } 31 | 32 | public static EditConfigFilesCommand Instance { get; private set; } 33 | 34 | private IServiceProvider ServiceProvider 35 | { 36 | get { return _package; } 37 | } 38 | 39 | public static void Initialize(Package package) 40 | { 41 | Instance = new EditConfigFilesCommand(package); 42 | } 43 | 44 | private void EditConfig(object sender, EventArgs e) 45 | { 46 | try 47 | { 48 | var button = (MenuCommand)sender; 49 | 50 | string folder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); 51 | string fileName = GetFileName(button.CommandID.ID); 52 | string configFile = Path.Combine(folder, fileName); 53 | 54 | if (!string.IsNullOrEmpty(configFile) && File.Exists(configFile)) 55 | WebLinterPackage.Dte.ExecuteCommand("File.OpenFile", "\"" + configFile + "\""); 56 | else 57 | WebLinterPackage.Dte.StatusBar.Text = $"Configuration file not found: {configFile}"; 58 | } 59 | catch (Exception ex) { Logger.LogAndWarn(ex); } 60 | } 61 | 62 | private string GetFileName(int commandId) 63 | { 64 | switch (commandId) 65 | { 66 | case PackageIds.EditTSLint: 67 | return "tslint.json"; 68 | } 69 | 70 | return null; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Commands/FixLintErrorsCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Design; 4 | using System.IO; 5 | using System.Linq; 6 | using Microsoft.VisualStudio.Shell; 7 | using WebLinter; 8 | 9 | namespace WebLinterVsix 10 | { 11 | internal sealed class FixLintErrorsCommand : LintFilesCommandBase 12 | { 13 | private readonly Package _package; 14 | 15 | private FixLintErrorsCommand(Package package) : base(package) 16 | { 17 | _package = package ?? throw new ArgumentNullException("package"); 18 | if (ServiceProvider.GetService(typeof(IMenuCommandService)) is OleMenuCommandService commandService) 19 | { 20 | var menuCommandID = new CommandID(PackageGuids.WebLinterCmdSet, PackageIds.FixLintErrorsCommand); 21 | var menuItem = new OleMenuCommand(async (s, e) => { await LintSelectedFiles(true); }, menuCommandID); 22 | menuItem.BeforeQueryStatus += BeforeQueryStatus; 23 | commandService.AddCommand(menuItem); 24 | } 25 | } 26 | 27 | public static FixLintErrorsCommand Instance { get; private set; } 28 | private IServiceProvider ServiceProvider => _package; 29 | public static void Initialize(Package package) => Instance = new FixLintErrorsCommand(package); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Commands/LintFilesCommand.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using Microsoft.VisualStudio; 3 | using Microsoft.VisualStudio.Shell; 4 | using Microsoft.VisualStudio.Shell.Interop; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.ComponentModel.Design; 8 | using I = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; 9 | 10 | namespace WebLinterVsix 11 | { 12 | enum BuildType 13 | { 14 | 15 | } 16 | internal sealed class LintFilesCommand : LintFilesCommandBase 17 | { 18 | private readonly Package _package; 19 | private readonly CommandEvents _commandEvents; 20 | 21 | private LintFilesCommand(Package package): base(package) 22 | { 23 | _package = package ?? throw new ArgumentNullException("package"); 24 | _commandEvents = WebLinterPackage.Dte.Events.CommandEvents; 25 | _commandEvents.BeforeExecute += CommandEvents_BeforeExecute; 26 | 27 | if (ServiceProvider.GetService(typeof(IMenuCommandService)) is OleMenuCommandService commandService) 28 | { 29 | var menuCommandID = new CommandID(PackageGuids.WebLinterCmdSet, PackageIds.LintFilesCommand); 30 | var menuItem = new OleMenuCommand(async (s, e) => { await LintSelectedFiles(false); }, menuCommandID); 31 | menuItem.BeforeQueryStatus += BeforeQueryStatus; 32 | commandService.AddCommand(menuItem); 33 | } 34 | base.StartListeningForChanges(); 35 | } 36 | 37 | private bool _isBuilding = false; 38 | private bool _isBuildingSolution = true; 39 | private readonly HashSet _buildIds = new HashSet { (int)I.BuildSln, (int)I.RebuildSln, (int)I.BuildCtx, (int)I.RebuildCtx, 40 | (int)I.BuildSel, (int)I.RebuildSel, (int)I.BatchBuildDlg, (int)I.Start, 41 | (int)I.StartNoDebug }; 42 | private readonly HashSet _buildSolutionIds = new HashSet { (int)I.BuildSln, (int)I.RebuildSln, (int)I.BatchBuildDlg, 43 | (int)I.Start, (int)I.StartNoDebug }; 44 | private void CommandEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault) 45 | { 46 | // TODO There's also Build1-9, Rebuild1-9 and BuildLast/RebuildLast. 47 | // 1-9 can be called from the build menu if on an item outside a project. 48 | // These are really edge cases and a bit of work to implement as we need to map them to projects and tell the linter 49 | // TODO Batch build lints everything, not just the built projects 50 | if (!WebLinterPackage.Settings.RunOnBuild || !Guid.StartsWith("{5E") || Guid != "{5EFC7975-14BC-11CF-9B2B-00AA00573819}") return; 51 | if (!_buildIds.Contains(ID)) return; 52 | _isBuilding = true; 53 | _isBuildingSolution = _buildSolutionIds.Contains(ID); 54 | } 55 | 56 | public override int UpdateSolution_Begin(ref int pfCancelUpdate) 57 | { 58 | try 59 | { 60 | if (!_isBuilding || !WebLinterPackage.Settings.RunOnBuild) return VSConstants.S_OK; 61 | bool cancelBuild = false; 62 | System.Threading.Tasks.Task task = LintBuildSelection(_isBuildingSolution); 63 | // If we've called sync correctly task should be completed here, if not we may not have results anyway 64 | // Exceptions are in general swallowed and logged by the linter, which will return false here 65 | bool completed = task.IsCompleted; //task.Wait(10); 66 | if (!completed) throw new Exception("Linting on build failed to complete correctly"); 67 | cancelBuild = task.Result; 68 | pfCancelUpdate = cancelBuild ? 1 : 0; 69 | if (cancelBuild) WebLinterPackage.Dte.StatusBar.Text = "Build failed because of TSLint Errors"; 70 | } 71 | catch (Exception ex) 72 | { 73 | Logger.Log(ex); 74 | } 75 | finally 76 | { 77 | _isBuilding = false; 78 | } 79 | return VSConstants.S_OK; 80 | } 81 | 82 | public static LintFilesCommand Instance { get; private set; } 83 | private IServiceProvider ServiceProvider => _package; 84 | public static void Initialize(Package package) => Instance = new LintFilesCommand(package); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Commands/LintFilesCommandBase.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using Microsoft.VisualStudio.Shell; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using WebLinter; 7 | using WebLinterVsix.Helpers; 8 | 9 | namespace WebLinterVsix 10 | { 11 | internal class LintFilesCommandBase: BuildEventsBase 12 | { 13 | internal LintFilesCommandBase(Package package) : base(package) { } 14 | 15 | protected void BeforeQueryStatus(object sender, EventArgs e) 16 | { 17 | try 18 | { 19 | ((OleMenuCommand)sender).Visible = LintableFiles.AreAllSelectedItemsLintable(); 20 | } 21 | catch (Exception ex) 22 | { 23 | Logger.LogAndWarn(ex); 24 | } 25 | } 26 | 27 | protected async System.Threading.Tasks.Task LintSelectedFiles(bool fixErrors) 28 | { 29 | try 30 | { 31 | Benchmark.Start(); 32 | if (!LinterService.IsLinterEnabled) 33 | { 34 | WebLinterPackage.Dte.StatusBar.Text = "TSLint is not enabled in Tools/Options"; 35 | return false; 36 | } 37 | UIHierarchyItem[] selectedItems = WebLinterPackage.Dte.ToolWindows.SolutionExplorer.SelectedItems as UIHierarchyItem[]; 38 | return await LintSelectedItems(fixErrors, selectedItems); 39 | } 40 | catch (Exception ex) 41 | { 42 | Logger.LogAndWarn(ex); 43 | Linter.Server.Down(); 44 | return false; 45 | } 46 | finally { Benchmark.End(); } 47 | } 48 | 49 | internal static async System.Threading.Tasks.Task LintSelectedItems(bool fixErrors, UIHierarchyItem[] selectedItems) 50 | { 51 | Dictionary fileToProjectMap; 52 | IEnumerable files = WebLinterPackage.Settings.UseTsConfig ? 53 | TsconfigLocations.FindPathsFromSelectedItems(selectedItems, out fileToProjectMap) : 54 | LintFileLocations.FindPathsFromSelectedItems(selectedItems, out fileToProjectMap); 55 | if (files.Any()) 56 | { 57 | bool clearAllErrors = AnyItemNotLintableSingleFile(selectedItems); 58 | return await LinterService.Lint(showErrorList: true, fixErrors: fixErrors, callSync: false, fileNames: files.ToArray(), 59 | clearAllErrors, fileToProjectMap); 60 | } 61 | else 62 | { 63 | WebLinterPackage.Dte.StatusBar.Text = $"No {(WebLinterPackage.Settings.UseTsConfig ? "tsconfig.json" : "ts or tsx")}" + 64 | $" files found to {(fixErrors ? "fix" : "lint")}"; 65 | return false; 66 | } 67 | } 68 | 69 | private static bool AnyItemNotLintableSingleFile(UIHierarchyItem[] items) 70 | { 71 | foreach (UIHierarchyItem selItem in items) 72 | { 73 | if (!(selItem.Object is ProjectItem item && 74 | item.GetFullPath() is string projectItemPath && 75 | LintableFiles.IsLintableTsTsxJsJsxFile(projectItemPath))) 76 | return true; 77 | } 78 | return false; 79 | } 80 | 81 | protected async System.Threading.Tasks.Task LintBuildSelection(bool isBuildingSolution) 82 | { 83 | try 84 | { 85 | Benchmark.Start(); 86 | if (!LinterService.IsLinterEnabled) return false; 87 | UIHierarchyItem[] selectedItems = BuildSelectedItems.Get(isBuildingSolution); 88 | Dictionary fileToProjectMap; 89 | string[] files = WebLinterPackage.Settings.UseTsConfig ? 90 | TsconfigLocations.FindPathsFromSelectedItems(selectedItems, out fileToProjectMap) : 91 | LintFileLocations.FindPathsFromSelectedItems(selectedItems, out fileToProjectMap); 92 | if (!files.Any()) return false; 93 | return await LinterService.Lint(showErrorList: true, fixErrors: false, callSync: true, 94 | fileNames: files, clearAllErrors: true, fileToProjectMap); 95 | } 96 | catch (Exception ex) 97 | { 98 | Logger.LogAndWarn(ex); 99 | Linter.Server.Down(); 100 | return true; // Return value is true if we have VS errors 101 | } 102 | finally { Benchmark.End(); } 103 | } 104 | 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /src/WebLinterVsix/Commands/ResetConfigFilesCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Design; 3 | using System.Windows.Forms; 4 | using Microsoft.VisualStudio.Shell; 5 | using WebLinter; 6 | 7 | namespace WebLinterVsix 8 | { 9 | internal sealed class ResetConfigFilesCommand 10 | { 11 | private readonly Package _package; 12 | 13 | private ResetConfigFilesCommand(Package package) 14 | { 15 | _package = package; 16 | 17 | OleMenuCommandService commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService; 18 | 19 | var menuCommandID = new CommandID(PackageGuids.ConfigFileCmdSet, PackageIds.ResetConfigFiles); 20 | var menuItem = new OleMenuCommand(ResetConfigurationFiles, menuCommandID); 21 | commandService.AddCommand(menuItem); 22 | } 23 | 24 | public static ResetConfigFilesCommand Instance { get; private set; } 25 | 26 | private IServiceProvider ServiceProvider 27 | { 28 | get { return _package; } 29 | } 30 | 31 | public static void Initialize(Package package) 32 | { 33 | Instance = new ResetConfigFilesCommand(package); 34 | } 35 | 36 | private async void ResetConfigurationFiles(object sender, EventArgs e) 37 | { 38 | try 39 | { 40 | string msg = "This will reset the configuration for the TypeScript Analyzer to its defaults.\n\nDo you wish to continue?"; 41 | var result = MessageBox.Show(msg, Vsix.Name, MessageBoxButtons.YesNo, MessageBoxIcon.Question); 42 | 43 | if (result == DialogResult.Yes) 44 | { 45 | await LinterService.CopyResourceFilesToUserProfile(true); 46 | WebLinterPackage.Settings.ResetSettings(); 47 | WebLinterPackage.Dte.StatusBar.Text = "TypeScript Analyzer (tslint) configuration files have been reset"; 48 | } 49 | } 50 | catch (Exception ex) 51 | { 52 | Logger.LogAndWarn(ex); 53 | } 54 | 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/WebLinterVsix/ErrorList/ErrorListService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using WebLinter; 5 | using System.Windows; 6 | 7 | namespace WebLinterVsix 8 | { 9 | class ErrorListService 10 | { 11 | public static void ProcessLintingResults(LintingResult result, string[] fileNames, 12 | bool clearAllErrors, bool showErrorList, bool isFixing, Dictionary fileToProjectMap) 13 | { 14 | // Called on worker thread unless we're running on a build when we are on the UI thread 15 | // We have several possibilities re files and filters: 16 | // 1. We're not using tsconfig. In this case fileNames is the list of files we're linting, clearAllErrors is true unless 17 | // we're linting an individual file or files, in which case we want to clear errors for those files only. In this case 18 | // fileToProjectMap contains the list of files we are linting. 19 | // 2. We're using tsconfig but have selected an individual file or files to lint in Solution Explorer or are saving/opening an 20 | // individual file. In this case fileNames contains the relevant tsconfig(s) to pass to ESLint, clearAllErrors is false and 21 | // fileToProjectMap contains the names of the files we are linting. These are the only errors we want to update. 22 | // 3. We're using tsconfig and have selected a folder/project/solution to lint in Solution Explorer. In this case fileNames 23 | // again contains the tsconfig file names we will pass to ESLint. clearAllErrors is true. We want to update all errors 24 | // for the project/solution. 25 | //bool useFilter = WebLinterPackage.Settings.UseTsConfig && !clearAllErrors; // Case 2 26 | //bool tsConfigNoFilter = WebLinterPackage.Settings.UseTsConfig && clearAllErrors; // Case 3 27 | IEnumerable allErrors = clearAllErrors ? result.Errors : 28 | result.Errors.Where(e => fileToProjectMap.ContainsKey(e.FileName)); 29 | // lintedFilesWithNoErrors is used to clear previous errors for files with no errors remaining in cases 1 and 2 30 | IEnumerable lintedFilesWithNoErrors = clearAllErrors ? Enumerable.Empty() : 31 | fileToProjectMap.Keys.Where(f => !allErrors.Select(e => e.FileName).Contains(f, StringComparer.OrdinalIgnoreCase)); 32 | UpdateErrorListDataSource(allErrors, showErrorList, lintedFilesWithNoErrors, isFixing, clearAllErrors, fileToProjectMap); 33 | } 34 | 35 | private static void UpdateErrorListDataSource(IEnumerable allErrors, bool showErrorList, 36 | IEnumerable lintedFilesWithNoErrors, bool isFixing, bool clearAllErrors, 37 | Dictionary fileToProjectMap) 38 | { 39 | if (Application.Current?.Dispatcher == null || Application.Current.Dispatcher.CheckAccess()) 40 | { 41 | if (clearAllErrors) 42 | { 43 | Benchmark.Log("Before CleanAllErrors"); 44 | ErrorListDataSource.Instance.CleanAllErrors(); 45 | Benchmark.Log("After CleanAllErrors"); 46 | } 47 | else 48 | { 49 | Benchmark.Log($"Before CleanErrors, using linted files with no errors"); 50 | ErrorListDataSource.Instance.CleanErrors(lintedFilesWithNoErrors); 51 | Benchmark.Log("After CleanErrors"); 52 | } 53 | if (allErrors.Any()) 54 | { 55 | ErrorListDataSource.Instance.AddErrors(allErrors, fileToProjectMap); 56 | if (showErrorList) 57 | { 58 | Benchmark.Log("Before BringToFront"); 59 | ErrorListDataSource.Instance.BringToFront(); 60 | Benchmark.Log("After BringToFront"); 61 | } 62 | } 63 | 64 | Benchmark.Log("Before RefreshTags"); 65 | WebLinterPackage.TaggerProvider?.RefreshTags(isFixing); 66 | Benchmark.Log("After RefreshTags"); 67 | } 68 | else 69 | { 70 | Application.Current.Dispatcher.BeginInvoke( 71 | (Action)(() => UpdateErrorListDataSource(allErrors, showErrorList, lintedFilesWithNoErrors, 72 | isFixing, clearAllErrors, fileToProjectMap))); 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/WebLinterVsix/ErrorList/SinkManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell.TableManager; 2 | using System.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | using WebLinter; 6 | 7 | namespace WebLinterVsix 8 | { 9 | class SinkManager : IDisposable 10 | { 11 | private readonly ITableDataSink _sink; 12 | private ErrorListDataSource _errorList; 13 | private List _snapshots = new List(); 14 | 15 | internal SinkManager(ErrorListDataSource errorList, ITableDataSink sink) 16 | { 17 | _sink = sink; 18 | _errorList = errorList; 19 | 20 | errorList.AddSinkManager(this); 21 | } 22 | 23 | internal void Clear() 24 | { 25 | _sink.RemoveAllSnapshots(); 26 | } 27 | 28 | internal void UpdateSink(IEnumerable snapshots) 29 | { 30 | try 31 | { 32 | foreach (var snapshot in snapshots) 33 | { 34 | var existing = _snapshots.FirstOrDefault(s => snapshot.FilePath.Equals(s.FilePath, StringComparison.OrdinalIgnoreCase)); 35 | 36 | if (existing != null) 37 | { 38 | _snapshots.Remove(existing); 39 | _sink.ReplaceSnapshot(existing, snapshot); 40 | } 41 | else 42 | { 43 | _sink.AddSnapshot(snapshot); 44 | } 45 | 46 | _snapshots.Add(snapshot); 47 | } 48 | 49 | } 50 | catch (Exception ex) { Logger.Log(ex); } 51 | } 52 | 53 | internal void RemoveSnapshots(IEnumerable files) 54 | { 55 | try 56 | { 57 | foreach (string file in files) 58 | { 59 | var existing = _snapshots.FirstOrDefault(s => file.Equals(s.FilePath, StringComparison.OrdinalIgnoreCase)); 60 | 61 | if (existing != null) 62 | { 63 | _snapshots.Remove(existing); 64 | _sink.RemoveSnapshot(existing); 65 | } 66 | } 67 | } 68 | catch (Exception ex) { Logger.Log(ex); } 69 | } 70 | 71 | public void Dispose() 72 | { 73 | // Called when the person who subscribed to the data source disposes of the cookie (== this object) they were given. 74 | _errorList.RemoveSinkManager(this); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/WebLinterVsix/ErrorList/TableEntriesSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using EnvDTE; 4 | using Microsoft.VisualStudio.Shell.Interop; 5 | using Microsoft.VisualStudio.Shell.TableManager; 6 | using WebLinter; 7 | 8 | namespace WebLinterVsix 9 | { 10 | class TableEntriesSnapshot : TableEntriesSnapshotBase 11 | { 12 | private readonly List _errors = new List(); 13 | 14 | internal TableEntriesSnapshot(string filePath, string projectName, IEnumerable errors) 15 | { 16 | FilePath = filePath; 17 | ProjectName = projectName; 18 | _errors.AddRange(errors); 19 | } 20 | 21 | public override int Count 22 | { 23 | get { return _errors.Count; } 24 | } 25 | 26 | public string FilePath { get; } 27 | public string ProjectName { get; set; } 28 | public List Errors => _errors; 29 | 30 | public override int VersionNumber { get; } = 1; 31 | 32 | public override bool TryGetValue(int index, string columnName, out object content) 33 | { 34 | content = null; 35 | 36 | if ((index >= 0) && (index < _errors.Count)) 37 | { 38 | if (columnName == StandardTableKeyNames.DocumentName) 39 | { 40 | content = FilePath; 41 | } 42 | else if (columnName == StandardTableKeyNames.ErrorCategory) 43 | { 44 | content = Vsix.Name; 45 | } 46 | else if (columnName == StandardTableKeyNames.Line) 47 | { 48 | content = _errors[index].LineNumber; 49 | } 50 | else if (columnName == StandardTableKeyNames.Column) 51 | { 52 | content = _errors[index].ColumnNumber; 53 | } 54 | else if (columnName == StandardTableKeyNames.Text) 55 | { 56 | content = $"({_errors[index].Provider.Name}) {_errors[index].Message}"; 57 | } 58 | else if (columnName == StandardTableKeyNames.ErrorSeverity) 59 | { 60 | content = _errors[index].IsError ? __VSERRORCATEGORY.EC_ERROR : __VSERRORCATEGORY.EC_WARNING; 61 | } 62 | else if (columnName == StandardTableKeyNames.Priority) 63 | { 64 | content = _errors[index].IsError ? vsTaskPriority.vsTaskPriorityHigh : vsTaskPriority.vsTaskPriorityMedium; 65 | } 66 | else if (columnName == StandardTableKeyNames.ErrorSource) 67 | { 68 | content = _errors[index].IsBuildError ? ErrorSource.Build : ErrorSource.Other; 69 | } 70 | else if (columnName == StandardTableKeyNames.BuildTool) 71 | { 72 | content = _errors[index].Provider.Name; 73 | } 74 | else if (columnName == StandardTableKeyNames.ErrorCode) 75 | { 76 | content = _errors[index].ErrorCode; 77 | } 78 | else if (columnName == StandardTableKeyNames.ProjectName) 79 | { 80 | // The pre-lint work will normally create a file to project map that allows us to set the project name when this class 81 | // is instantiated. However, there are certain edge cases where this won't happen. For example, we lint directly with 82 | // a tsconfig. In that case the project name will be null here and we retrieve it from the filename on the error. 83 | if (ProjectName == null) 84 | { 85 | var _item = WebLinterPackage.Dte.Solution.FindProjectItem(_errors[index].FileName); 86 | 87 | if (_item != null && _item.Properties != null && _item.ContainingProject != null) 88 | ProjectName = _item.ContainingProject.Name; 89 | else 90 | ProjectName = ""; 91 | } 92 | content = ProjectName; 93 | } 94 | else if ((columnName == StandardTableKeyNames.ErrorCodeToolTip) || (columnName == StandardTableKeyNames.HelpLink)) 95 | { 96 | var error = _errors[index]; 97 | string url; 98 | if (!string.IsNullOrEmpty(error.HelpLink)) 99 | { 100 | url = error.HelpLink; 101 | } 102 | else 103 | { 104 | url = string.Format("http://www.bing.com/search?q={0} {1}", _errors[index].Provider.Name, _errors[index].ErrorCode); 105 | } 106 | 107 | content = Uri.EscapeUriString(url); 108 | } 109 | } 110 | 111 | return content != null; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Helpers/BuildSelectedItems.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace WebLinterVsix.Helpers 6 | { 7 | /// 8 | /// Works out what we're building in terms of UIHierarchyItems in the Solution Explorer window, however we invoke the build 9 | /// 10 | public class BuildSelectedItems 11 | { 12 | public static UIHierarchyItem[] Get(bool isBuildingSolution) => 13 | isBuildingSolution ? 14 | new UIHierarchyItem[] { GetUIHierarchySolutionItem() } : 15 | MapToProjects(WebLinterPackage.Dte.ToolWindows.SolutionExplorer.SelectedItems as UIHierarchyItem[]).ToArray(); 16 | 17 | private static UIHierarchyItem GetUIHierarchySolutionItem() 18 | { 19 | UIHierarchyItems uiHierarchyItems = WebLinterPackage.Dte.ToolWindows.SolutionExplorer.UIHierarchyItems; 20 | foreach (UIHierarchyItem item in uiHierarchyItems) 21 | { 22 | if (item.Object is Solution) return item; 23 | } 24 | return null; 25 | } 26 | 27 | internal static IEnumerable MapToProjects(UIHierarchyItem[] selectedItems) 28 | { 29 | if (selectedItems == null) yield break; 30 | // Note that you can build a single project from the build menu, but your options are limited 31 | // to the project you have selected in Solution Explorer. Here 'project you have selected' can 32 | // mean the project a selected item is in. If you ctrl-click items in two projects the menu option 33 | // changes to 'Build Selection', meaning build both. This logic replicates that. 34 | HashSet seenPaths = new HashSet(); 35 | 36 | foreach (UIHierarchyItem selectedItem in selectedItems) 37 | { 38 | if (selectedItem.Object is ProjectItem projectItem && 39 | projectItem.ContainingProject?.GetRootFolder() is string projectItemRootFolder && 40 | !seenPaths.Contains(projectItemRootFolder)) 41 | { 42 | seenPaths.Add(projectItemRootFolder); 43 | UIHierarchyItems uiHierarchyItems = WebLinterPackage.Dte.ToolWindows.SolutionExplorer.UIHierarchyItems; 44 | UIHierarchyItem containingProjectHierarchyItem = GetHierarchyItemForProject(projectItemRootFolder, uiHierarchyItems); 45 | if (containingProjectHierarchyItem != null) yield return containingProjectHierarchyItem; 46 | } 47 | else if (selectedItem.Object is Project project && 48 | project?.GetRootFolder() is string projectRootFolder && 49 | !seenPaths.Contains(projectRootFolder)) 50 | { 51 | seenPaths.Add(projectRootFolder); 52 | yield return selectedItem; 53 | } 54 | else if (selectedItem.Object is Solution solution) 55 | yield return selectedItem; 56 | } 57 | } 58 | 59 | private static UIHierarchyItem GetHierarchyItemForProject(string projectRootFolder, UIHierarchyItems uiHierarchyItems) 60 | { 61 | foreach (UIHierarchyItem item in uiHierarchyItems) 62 | { 63 | if (item.Object is Project project && projectRootFolder == project.GetRootFolder()) return item; 64 | if (item.UIHierarchyItems != null) 65 | { 66 | UIHierarchyItem uiHierarchyItem = GetHierarchyItemForProject(projectRootFolder, item.UIHierarchyItems); 67 | if (uiHierarchyItem != null) return uiHierarchyItem; 68 | } 69 | } 70 | return null; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Helpers/LintFileLocations.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace WebLinterVsix.Helpers 7 | { 8 | public static class LintFileLocations 9 | { 10 | private static void FindInSolution(Solution solution, Dictionary fileToProjectMap) 11 | { 12 | if (solution.Projects == null) return; 13 | foreach (Project project in solution.Projects) 14 | FindInProject(project, fileToProjectMap); 15 | } 16 | 17 | private static void FindInProject(Project project, Dictionary fileToProjectMap) 18 | { 19 | if (project.ProjectItems == null) return; 20 | foreach (ProjectItem projectItem in project.ProjectItems) 21 | FindInProjectItem(projectItem, fileToProjectMap); 22 | } 23 | 24 | private static void FindInProjectItem(ProjectItem projectItem, Dictionary fileToProjectMap) 25 | { 26 | string itemPath = projectItem.GetFullPath(); 27 | if (LintableFiles.IsLintableTsTsxJsJsxFile(itemPath) && !fileToProjectMap.ContainsKey(itemPath)) 28 | fileToProjectMap.Add(itemPath, projectItem.ContainingProject.Name); 29 | if (projectItem.ProjectItems == null) return; 30 | foreach (ProjectItem subProjectItem in projectItem.ProjectItems) 31 | FindInProjectItem(subProjectItem, fileToProjectMap); 32 | } 33 | 34 | public static string[] FindPathsFromSelectedItems(UIHierarchyItem[] items, out Dictionary fileToProjectMap) 35 | { 36 | fileToProjectMap = new Dictionary(StringComparer.OrdinalIgnoreCase); 37 | foreach (UIHierarchyItem selItem in items) 38 | { 39 | if (!LintableFiles.IsLintable(selItem)) continue; 40 | if (selItem.Object is Solution solution) 41 | FindInSolution(solution, fileToProjectMap); 42 | else if (selItem.Object is Project project) 43 | FindInProject(project, fileToProjectMap); 44 | else if (selItem.Object is ProjectItem item) 45 | FindInProjectItem(item, fileToProjectMap); 46 | } 47 | return fileToProjectMap.Keys.ToArray(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Helpers/LintableFiles.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using WebLinter; 7 | 8 | namespace WebLinterVsix.Helpers 9 | { 10 | /// 11 | /// Methods to test whether various items can be linted 12 | /// 13 | /// 14 | /// I don't think 'lintable' is a valid adjective either. But then neither is 'lint' as a verb. http://www.dictionary.com/browse/lint 15 | /// 16 | public static class LintableFiles 17 | { 18 | public static bool AreAllSelectedItemsLintable() 19 | { 20 | UIHierarchyItem[] selectedItems = WebLinterPackage.Dte.ToolWindows.SolutionExplorer.SelectedItems as UIHierarchyItem[]; 21 | // In this test we check whether what's clicked on is lintable, meaning it's an item that might contain 22 | // files that can be linted. We don't actually check whether there ARE any files that can be linted associated 23 | // with the item. For example, if you rightclick a solution file we check it's a solution file, but we don't 24 | // check for valid .ts or .tsx files in the solution. This applies to the ignore options as well (ignore patterns, 25 | // ignore nested). 26 | // TODO: make the right-click check if lintable files associated with the clicked item exist 27 | foreach (UIHierarchyItem selectedItem in selectedItems) 28 | { 29 | if (!IsLintable(selectedItem)) return false; 30 | } 31 | return true; 32 | } 33 | 34 | public static bool IsLintable(UIHierarchyItem selectedItem) 35 | { 36 | return selectedItem.Object is Solution || 37 | selectedItem.Object is Project || 38 | (selectedItem.Object is ProjectItem item && 39 | item.GetFullPath() is string projectItemPath && 40 | IsLintableProjectItem(projectItemPath)); 41 | } 42 | 43 | 44 | public static bool IsLintableProjectItem(string projectItemPath) 45 | { 46 | return IsLintableDirectory(projectItemPath) || 47 | (!WebLinterPackage.Settings.UseTsConfig && IsLintableTsTsxJsJsxFile(projectItemPath)) || 48 | (WebLinterPackage.Settings.UseTsConfig && 49 | (IsLintableTsconfig(projectItemPath) || 50 | IsLintableTsTsxJsJsxFile(projectItemPath, checkIgnoreOptions: false))); 51 | } 52 | 53 | public static bool IsLintableDirectory(string path) 54 | { 55 | if (!Directory.Exists(path)) return false; 56 | if (!WebLinterPackage.Settings.UseTsConfig) 57 | { 58 | // Optimization (I think): We only use this to check if contained files are lintable and we use ignore strings 59 | // like '\node_modules\'. That won't match the folder without the line below, but will match every file and folder in it. 60 | if (!path.EndsWith("\\")) path += "\\"; 61 | if(WebLinterPackage.Settings.GetIgnorePatterns().Any(p => path.Contains(p))) return false; 62 | } 63 | 64 | // TODO Folder is not in project?? Below always returns null, so how do we check? 65 | //ProjectItem item = WebLinterPackage.Dte.Solution.FindProjectItem(path); 66 | return true; 67 | } 68 | 69 | public static bool IsValidFile(string fileName) 70 | => !string.IsNullOrEmpty(fileName) && Path.IsPathRooted(fileName) && File.Exists(fileName); 71 | 72 | public static bool IsLintableTsTsxJsJsxFile(string fileName, bool checkIgnoreOptions = true) 73 | { 74 | // Check if filename is absolute because when debugging, script files are sometimes dynamically created. 75 | if (!IsValidFile(fileName)) return false; 76 | if (!Linter.IsLintableFileExtension(fileName, WebLinterPackage.Settings.LintJsFiles)) return false; 77 | return IsLintableFile(fileName, checkIgnoreOptions); 78 | } 79 | 80 | public static bool IsLintableTsconfig(string fileName) 81 | { 82 | if (string.IsNullOrEmpty(fileName) || !Path.IsPathRooted(fileName) || !File.Exists(fileName)) return false; 83 | if (!fileName.EndsWith("tsconfig.json", ignoreCase: true, culture: null)) return false; 84 | return IsLintableFile(fileName); 85 | } 86 | 87 | private static bool IsLintableFile(string fileName, bool checkIgnoreOptions = true) 88 | { 89 | ProjectItem item = WebLinterPackage.Dte.Solution.FindProjectItem(fileName); 90 | bool isInProject = item?.GetFullPath() is string; 91 | if (!isInProject) return false; 92 | 93 | if (checkIgnoreOptions) 94 | { 95 | if (ContainsIgnorePattern(fileName)) return false; 96 | 97 | // Ignore nested files 98 | if (WebLinterPackage.Settings.IgnoreNestedFiles) 99 | { 100 | // item.Collection is not supported in Node.js projects 101 | if (item.ContainingProject.Kind.Equals("{9092aa53-fb77-4645-b42d-1ccca6bd08bd}", StringComparison.OrdinalIgnoreCase)) 102 | return true; 103 | 104 | if (item.Collection?.Parent is ProjectItem parent && 105 | parent.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFile) 106 | return false; 107 | } 108 | } 109 | 110 | return true; 111 | } 112 | 113 | public static bool ContainsIgnorePattern(string path) 114 | { 115 | return WebLinterPackage.Settings == null || WebLinterPackage.Settings.GetIgnorePatterns().Any(p => path.Contains(p)); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Helpers/ProjectHelpers.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using System; 3 | using System.IO; 4 | 5 | namespace WebLinterVsix 6 | { 7 | public static class ProjectHelpers 8 | { 9 | public static string GetRootFolder(this Project project) 10 | { 11 | if (string.IsNullOrEmpty(project.FullName)) 12 | return null; 13 | 14 | string fullPath; 15 | 16 | try 17 | { 18 | fullPath = project.Properties.Item("FullPath").Value as string; 19 | } 20 | catch (ArgumentException) 21 | { 22 | try 23 | { 24 | // MFC projects don't have FullPath, and there seems to be no way to query existence 25 | fullPath = project.Properties.Item("ProjectDirectory").Value as string; 26 | } 27 | catch (ArgumentException) 28 | { 29 | // Installer projects have a ProjectPath. 30 | fullPath = project.Properties.Item("ProjectPath").Value as string; 31 | } 32 | } 33 | 34 | if (string.IsNullOrEmpty(fullPath)) 35 | return File.Exists(project.FullName) ? Path.GetDirectoryName(project.FullName) : null; 36 | 37 | if (Directory.Exists(fullPath)) 38 | return fullPath; 39 | 40 | if (File.Exists(fullPath)) 41 | return Path.GetDirectoryName(fullPath); 42 | 43 | return null; 44 | } 45 | 46 | public static string GetFullPath(this ProjectItem projectItem) 47 | { 48 | string objectTypeName = projectItem.Object?.GetType().FullName; 49 | if (objectTypeName == "Microsoft.NodejsTools.Project.NodeModulesNode") return null; 50 | try 51 | { 52 | return projectItem.Properties?.Item("FullPath")?.Value?.ToString(); 53 | } 54 | // If FullPath doesn't exist then .Item throws. Which is a damn shame because we wouldn't need this method. 55 | catch (ArgumentException) 56 | { 57 | Logger.Log("GetFullPath throws for " + objectTypeName); 58 | return null; 59 | } 60 | } 61 | 62 | public static string GetProjectNameFromFilePath(string filePath) 63 | { 64 | ProjectItem projectItem = WebLinterPackage.Dte.Solution.FindProjectItem(filePath); 65 | return projectItem?.ContainingProject?.Name != null ? projectItem.ContainingProject.Name : ""; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Helpers/TsconfigLocations.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | 7 | namespace WebLinterVsix.Helpers 8 | { 9 | // Currently finding tsconfigs can get confusing, because there are broadly two scenarios: 10 | // 1. We open/save/request a lint on a single .ts file 11 | // 2. We request a lint on a project or solution from Solution Explorer 12 | // In case 1 we have to try to find an associated tsconfig.json to use for type rules: we search the folder and parent folders. 13 | // We lint with the first tsconfig.json we find and filter the results to the individual file requested. 14 | // In case 2 we find all tsconfig.jsons in the project or solution, lint with them, and show all results. 15 | // Case 1 means there's no real link between VS projects and tsconfig.json projects, except we do insist any tsconfigs we want to 16 | // lint with are included in a project somewhere in the solution. 17 | // Other possibilities include requesting a lint with a tsconfig.json, where we do just that and show all results, and requesting a 18 | // lint on a folder in Solution Explorer. Here again we should find all tsconfigs in the folder or below and lint. 19 | public static class TsconfigLocations 20 | { 21 | // Given a path to a file finds any lintable tsconfig.json in the folder of the path, or any parent folder 22 | // 'lintable' means 'exists and is in a VS project in this solution' 23 | public static string FindParentTsconfig(string projectItemFullPath) 24 | { 25 | if (LintableFiles.IsLintableTsconfig(projectItemFullPath)) return projectItemFullPath; 26 | DirectoryInfo folder = Directory.GetParent(projectItemFullPath); 27 | while (folder != null) 28 | { 29 | foreach (FileInfo fileInfo in folder.EnumerateFiles()) 30 | { 31 | if (LintableFiles.IsLintableTsconfig(fileInfo.FullName)) 32 | return fileInfo.FullName; 33 | } 34 | folder = folder.Parent; 35 | } 36 | return null; 37 | } 38 | 39 | public static string[] FindPathsFromSelectedItems(UIHierarchyItem[] items, out Dictionary fileToProjectMap) 40 | { 41 | fileToProjectMap = new Dictionary(StringComparer.OrdinalIgnoreCase); 42 | HashSet tsconfigFiles = new HashSet(StringComparer.OrdinalIgnoreCase); 43 | foreach (UIHierarchyItem selItem in items) 44 | { 45 | if (!LintableFiles.IsLintable(selItem)) continue; 46 | if (selItem.Object is Solution solution) 47 | FindTsconfigsInSolution(solution, tsconfigFiles); 48 | else if (selItem.Object is Project project) 49 | FindTsconfigsInProject(project, tsconfigFiles); 50 | else if (selItem.Object is ProjectItem item && item.GetFullPath() is string projectItemPath) 51 | FindTsconfigsFromSelectedProjectItem(projectItemPath, item, tsconfigFiles, fileToProjectMap); 52 | } 53 | return tsconfigFiles.ToArray(); 54 | } 55 | 56 | private static void FindTsconfigsFromSelectedProjectItem(string projectItemPath, ProjectItem item, HashSet result, 57 | Dictionary fileToProjectMap) 58 | { 59 | if (LintableFiles.IsLintableTsTsxJsJsxFile(projectItemPath)) 60 | { 61 | if (!fileToProjectMap.ContainsKey(projectItemPath)) fileToProjectMap.Add(projectItemPath, item.ContainingProject.Name); 62 | string tsconfig = FindParentTsconfig(projectItemPath); 63 | if (tsconfig != null && !result.Contains(tsconfig)) result.Add(tsconfig); 64 | } 65 | else if (item.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder || LintableFiles.IsLintableTsconfig(projectItemPath)) 66 | { 67 | FindTsConfigsInProjectItem(item, result); 68 | } 69 | } 70 | 71 | internal static void FindTsconfigsInSolution(Solution solution, HashSet result) 72 | { 73 | if (solution.Projects == null) return; 74 | foreach (Project project in solution.Projects) 75 | FindTsconfigsInProject(project, result); 76 | } 77 | 78 | internal static void FindTsconfigsInProject(Project project, HashSet result) 79 | { 80 | if (project.ProjectItems == null) return; 81 | foreach (ProjectItem projectItem in project.ProjectItems) 82 | FindTsConfigsInProjectItem(projectItem, result); 83 | } 84 | 85 | private static void FindTsConfigsInProjectItem(ProjectItem projectItem, HashSet result) 86 | { 87 | string itemPath = projectItem.GetFullPath(); 88 | if (LintableFiles.IsLintableTsconfig(itemPath) && !result.Contains(itemPath)) result.Add(itemPath); 89 | // A project item can be a folder or a nested file, so we may need to continue searching down the tree 90 | if (projectItem.ProjectItems == null || LintableFiles.ContainsIgnorePattern(itemPath)) return; 91 | foreach (ProjectItem subProjectItem in projectItem.ProjectItems) 92 | FindTsConfigsInProjectItem(subProjectItem, result); 93 | } 94 | 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/WebLinterVsix/LinterService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Reflection; 5 | using System.Threading.Tasks; 6 | using EnvDTE; 7 | using WebLinter; 8 | 9 | namespace WebLinterVsix 10 | { 11 | internal static class LinterService 12 | { 13 | private static bool _defaultsCreated; 14 | 15 | public static bool IsLinterEnabled => WebLinterPackage.Settings.TSLintEnable; 16 | 17 | public static async Task Lint(bool showErrorList, bool fixErrors, bool callSync, 18 | string[] fileNames, bool clearAllErrors, Dictionary fileToProjectMap) 19 | { 20 | #if DEBUG 21 | if (fileNames.Length == 0) throw new Exception("LinterService/Lint called with empty fileNames list"); 22 | #endif 23 | bool hasVSErrors = false; 24 | try 25 | { 26 | WebLinterPackage.Dte.StatusBar.Text = "Analyzing..."; 27 | WebLinterPackage.Dte.StatusBar.Animate(true, vsStatusAnimation.vsStatusAnimationGeneral); 28 | 29 | await CopyResourceFilesToUserProfile(false, callSync); 30 | Linter linter = new Linter(WebLinterPackage.Settings, fixErrors, Logger.LogAndWarn); 31 | LintingResult result = await linter.Lint(callSync, fileNames); 32 | 33 | if (result != null) 34 | { 35 | ErrorListService.ProcessLintingResults(result, fileNames, clearAllErrors, 36 | showErrorList, fixErrors, fileToProjectMap); 37 | hasVSErrors = result.HasVsErrors; 38 | } 39 | } 40 | catch (Exception ex) 41 | { 42 | Logger.Log(ex); 43 | } 44 | finally 45 | { 46 | WebLinterPackage.Dte.StatusBar.Clear(); 47 | WebLinterPackage.Dte.StatusBar.Animate(false, vsStatusAnimation.vsStatusAnimationGeneral); 48 | } 49 | return hasVSErrors; 50 | } 51 | 52 | public static async Task CopyResourceFilesToUserProfile(bool force = false, bool callSync = false) 53 | { 54 | // Not sure about the defaultsCreated flag here: if you delete your own tslint.json whilst 55 | // VS is running we're going to fail until you restart 56 | if (!_defaultsCreated || force) 57 | { 58 | string sourceFolder = GetVsixFolder(); 59 | string destFolder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); 60 | 61 | try 62 | { 63 | foreach (string sourceFile in Directory.EnumerateFiles(sourceFolder)) 64 | { 65 | string fileName = Path.GetFileName(sourceFile); 66 | string destFile = Path.Combine(destFolder, fileName); 67 | 68 | if (force || !File.Exists(destFile)) 69 | { 70 | using (var source = File.Open(sourceFile, FileMode.Open)) 71 | using (var dest = File.Create(destFile)) 72 | { 73 | if (callSync) 74 | source.CopyTo(dest); 75 | else 76 | await source.CopyToAsync(dest); 77 | } 78 | } 79 | } 80 | } 81 | catch (Exception ex) 82 | { 83 | Logger.Log(ex); 84 | } 85 | 86 | _defaultsCreated = true; 87 | } 88 | } 89 | 90 | private static string GetVsixFolder() 91 | { 92 | string assembly = Assembly.GetExecutingAssembly().Location; 93 | string root = Path.GetDirectoryName(assembly); 94 | return Path.Combine(root, "Resources\\Defaults"); 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /src/WebLinterVsix/Logger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell.Interop; 2 | using System; 3 | using System.Diagnostics.CodeAnalysis; 4 | 5 | namespace WebLinterVsix 6 | { 7 | public static class Logger 8 | { 9 | private static IVsOutputWindowPane pane; 10 | private static WebLinterPackage _provider; 11 | private static string _name; 12 | 13 | public static void Initialize(WebLinterPackage provider, string name) 14 | { 15 | _provider = provider; 16 | _name = name; 17 | } 18 | 19 | [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "Microsoft.VisualStudio.Shell.Interop.IVsOutputWindowPane.OutputString(System.String)")] 20 | public static void Log(string message) 21 | { 22 | if (string.IsNullOrEmpty(message)) return; 23 | try 24 | { 25 | if (EnsurePane()) 26 | pane.OutputString(DateTime.Now.ToString() + ": " + message + Environment.NewLine); 27 | } 28 | catch { } 29 | } 30 | 31 | public static void Log(Exception ex) 32 | { 33 | try 34 | { 35 | if (ex != null) Log(ex.ToString()); 36 | } 37 | catch { } 38 | } 39 | 40 | public static void LogAndWarn(Exception ex) 41 | { 42 | if (ex != null) LogAndWarn(ex.Message); 43 | } 44 | 45 | public static void LogAndWarn(string message, bool showWarning = true) 46 | { 47 | try 48 | { 49 | Log(message); 50 | if (showWarning) 51 | WebLinterPackage.Dte.StatusBar.Text = "A TypeScript Analyzer error occurred. See Output window for more details."; 52 | } 53 | catch { } 54 | } 55 | 56 | private static bool EnsurePane() 57 | { 58 | // during unit tests, _provider is not set. Do not try to get pane then. 59 | if (pane == null && _provider != null) 60 | { 61 | Guid guid = Guid.NewGuid(); 62 | IVsOutputWindow output = _provider.GetIVsOutputWindow(); 63 | output.CreatePane(ref guid, _name, 1, 1); 64 | output.GetPane(ref guid, out pane); 65 | } 66 | 67 | return pane != null; 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/WebLinterVsix/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("WebLinterVsix")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("Rich Newman")] 9 | [assembly: AssemblyProduct("TypeScript Analyzer")] 10 | [assembly: AssemblyCopyright("")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: AssemblyVersion(WebLinter.Constants.VERSION)] 17 | [assembly: AssemblyFileVersion(WebLinter.Constants.VERSION)] 18 | 19 | [assembly: InternalsVisibleTo("WebLinterTest")] -------------------------------------------------------------------------------- /src/WebLinterVsix/Resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/src/WebLinterVsix/Resources/icon.png -------------------------------------------------------------------------------- /src/WebLinterVsix/Resources/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/src/WebLinterVsix/Resources/preview.png -------------------------------------------------------------------------------- /src/WebLinterVsix/Settings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using Microsoft.VisualStudio.Shell; 5 | using WebLinter; 6 | 7 | namespace WebLinterVsix 8 | { 9 | public class Settings : DialogPage, ISettings 10 | { 11 | public Settings() 12 | { 13 | SetDefaults(); 14 | } 15 | 16 | private void SetDefaults() 17 | { 18 | // General 19 | IgnoreFolderNames = @"\node_modules\,\bower_components\,\typings\,\lib\,\vendor\,.min.,.d.ts"; 20 | IgnoreNestedFiles = true; 21 | CleanErrorsOnBuild = true; 22 | RunOnBuild = false; 23 | TSLintEnable = true; 24 | TSLintShowErrors = false; 25 | UseTsConfig = false; 26 | OnlyRunIfRequested = false; 27 | UseProjectNGLint = false; 28 | ShowUnderlining = true; 29 | LintJsFiles = false; 30 | } 31 | 32 | public override void ResetSettings() 33 | { 34 | SetDefaults(); 35 | base.ResetSettings(); 36 | base.SaveSettingsToStorage(); 37 | } 38 | 39 | // Advanced 40 | [Category("Ignore")] 41 | [DisplayName("Ignore patterns")] 42 | [Description("A comma-separated list of strings without quotes. Any file containing one of the strings in the path will be ignored.")] 43 | [DefaultValue(@"\node_modules\,\bower_components\,\typings\,\lib\,\vendor\,.min.,.d.ts")] 44 | public string IgnoreFolderNames { get; set; } 45 | 46 | [Category("Ignore")] 47 | [DisplayName("Ignore nested files")] 48 | [Description("Nested files are files that are nested under other files in Solution Explorer.")] 49 | [DefaultValue(true)] 50 | public bool IgnoreNestedFiles { get; set; } 51 | 52 | [Category("Build")] 53 | [DisplayName("Clean errors on build")] 54 | [Description("Clean the analyzer errors from the Error List when 'Rebuild Solution' or 'Clean' is executed.")] 55 | [DefaultValue(true)] 56 | public bool CleanErrorsOnBuild { get; set; } 57 | 58 | [Category("Build")] 59 | [DisplayName("Run on build")] 60 | [Description("Runs the analyzer before a build. Will cause build to fail if there are any TSLint errors in the Visual Studio Error List. This can only happen if 'Show errors' (above) is true.")] 61 | [DefaultValue(false)] 62 | public bool RunOnBuild { get; set; } 63 | 64 | [Category("Basic")] 65 | [DisplayName("Enable TypeScript Analyzer")] 66 | [Description("TypeScript Analyzer uses tslint to analyze TypeScript files (.ts or .tsx)")] 67 | [DefaultValue(true)] 68 | public bool TSLintEnable { get; set; } 69 | 70 | [Category("Basic")] 71 | [DisplayName("Show errors")] 72 | [Description("Shows TSLint errors as errors in the Error List. If false TSLint errors are shown as warnings. TSLint warnings are always shown as warnings in the Error List.")] 73 | [DefaultValue(false)] 74 | public bool TSLintShowErrors { get; set; } 75 | 76 | [Category("Basic")] 77 | [DisplayName("Use tsconfig.json files")] 78 | [Description("Searches for tsconfig.json files included in the Visual Studio project file, and lints using the configuration in those.")] 79 | [DefaultValue(false)] 80 | public bool UseTsConfig { get; set; } 81 | 82 | [Category("Basic")] 83 | [DisplayName("Only run if requested")] 84 | [Description("Only runs the analyzer if it is explicitly requested via the Solution Explorer context menu. If false the analyzer will additionally run for a file when it is opened or saved.")] 85 | [DefaultValue(false)] 86 | public bool OnlyRunIfRequested { get; set; } 87 | 88 | [Category("Basic")] 89 | [DisplayName("Use local ng lint")] 90 | [Description("If True, will attempt to use the projects own ng lint and tslint configuration. Useful if your project uses older versions for example codelyzer < 3.0. Falls back to the plugin built-in ts lint")] 91 | [DefaultValue(false)] 92 | public bool UseProjectNGLint { get; set; } 93 | 94 | [Category("Basic")] 95 | [DisplayName("Lint .js and .jsx files")] 96 | [Description("If True, will lint .js and .jsx files in addition to .ts and .tsx files. This option uses rules in the the jsRules section of tslint.json. This section is empty by default.")] 97 | [DefaultValue(false)] 98 | public bool LintJsFiles { get; set; } 99 | 100 | [Category("Basic")] 101 | [DisplayName("Show red/green underlining")] 102 | [Description("If True, shows red/green underlining in code files for errors/warnings, and gives details on a hover.")] 103 | [DefaultValue(true)] 104 | public bool ShowUnderlining { get; set; } 105 | 106 | protected override void OnApply(PageApplyEventArgs e) 107 | { 108 | base.OnApply(e); 109 | if (!TSLintEnable && ErrorListDataSource.Instance.HasErrors()) ErrorListDataSource.Instance.CleanAllErrors(); 110 | if (!LintJsFiles && ErrorListDataSource.Instance.HasJsJsxErrors()) ErrorListDataSource.Instance.CleanJsJsxErrors(); 111 | WebLinterPackage.TaggerProvider?.RefreshTags(); 112 | } 113 | 114 | public IEnumerable GetIgnorePatterns() 115 | { 116 | var raw = IgnoreFolderNames.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); 117 | 118 | foreach (string pattern in raw) 119 | { 120 | yield return pattern; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Tagging/LintingErrorTag.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text.Adornments; 2 | using Microsoft.VisualStudio.Text.Tagging; 3 | using WebLinter; 4 | 5 | namespace WebLinterVsix.Tagging 6 | { 7 | /// 8 | /// Wrapper for a LintingError that provides additional information that 9 | /// allows underlining ('tagging') in the code window 10 | /// 11 | public class LintingErrorTag : IErrorTag 12 | { 13 | public string ErrorType { get; } 14 | public object ToolTipContent { get; } 15 | 16 | internal LintingErrorTag(LintingError lintingError) 17 | { 18 | ErrorType = lintingError.IsError ? PredefinedErrorTypeNames.SyntaxError : PredefinedErrorTypeNames.Warning; 19 | ToolTipContent = $"({lintingError.Provider.Name}) {lintingError.Message} ({lintingError.ErrorCode})"; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/WebLinterVsix/Tagging/TaggerProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | using Microsoft.VisualStudio.Text.Editor; 3 | using Microsoft.VisualStudio.Text.Tagging; 4 | using Microsoft.VisualStudio.Utilities; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.ComponentModel.Composition; 8 | using System.Diagnostics; 9 | using System.Threading; 10 | 11 | namespace WebLinterVsix.Tagging 12 | { 13 | [Export(typeof(IViewTaggerProvider))] 14 | [ContentType("text")] 15 | [ContentType("projection")] 16 | [TagType(typeof(IErrorTag))] 17 | [TextViewRole(PredefinedTextViewRoles.Document)] 18 | [TextViewRole(PredefinedTextViewRoles.Analyzable)] 19 | public class TaggerProvider : IViewTaggerProvider 20 | { 21 | private readonly ITextDocumentFactoryService _textDocumentFactoryService; 22 | 23 | [ImportingConstructor] 24 | public TaggerProvider([Import] ITextDocumentFactoryService textDocumentFactoryService) 25 | { 26 | _textDocumentFactoryService = textDocumentFactoryService; 27 | WebLinterPackage.TaggerProvider = this; 28 | } 29 | 30 | public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag 31 | { 32 | CheckThread(); 33 | if (buffer != textView.TextBuffer || typeof(IErrorTag) != typeof(T) || 34 | !_textDocumentFactoryService.TryGetTextDocument(buffer, out ITextDocument document)) return null; 35 | // For .js/.jsx files we need to create a tagger in case we turn the option on 36 | if (!WebLinter.Linter.IsLintableFileExtension(document.FilePath)) return null; 37 | if (!_taggerCache.ContainsKey(textView)) 38 | { 39 | _taggerCache.Add(textView, new Tagger(buffer, document)); 40 | textView.Closed += (s, e) => _taggerCache.Remove(textView); 41 | } 42 | return _taggerCache[textView] as ITagger; 43 | } 44 | 45 | // We key on ITextView (rather than filenames) because of renames with open files, when the text view remains 46 | // the same but the file name changes (and blows up the code) 47 | private readonly Dictionary _taggerCache = new Dictionary(); 48 | 49 | public void RefreshTags(bool isFixing = false) 50 | { 51 | foreach (KeyValuePair tagger in _taggerCache) 52 | tagger.Value.RefreshTags(isFixing); 53 | } 54 | 55 | [Conditional("DEBUG")] 56 | private void CheckThread() 57 | { 58 | if (Thread.CurrentThread.ManagedThreadId != 1) throw new Exception("TaggerProvider not running on UI thread"); 59 | } 60 | 61 | //[Conditional("DEBUG")] 62 | //private void DebugDumpTaggers() 63 | //{ 64 | // Debug.WriteLine("CURRENT TAGGERS:"); 65 | // foreach (KeyValuePair tagger in _taggerCache) 66 | // { 67 | // Debug.WriteLine(tagger.Value.FilePath); 68 | // } 69 | //} 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/WebLinterVsix/VSCommandTable.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // This file was generated by Extensibility Tools v1.10.188 4 | // 5 | // ------------------------------------------------------------------------------ 6 | namespace WebLinterVsix 7 | { 8 | using System; 9 | 10 | /// 11 | /// Helper class that exposes all GUIDs used across VS Package. 12 | /// 13 | internal sealed partial class PackageGuids 14 | { 15 | public const string guidVSPackageString = "4e737333-d498-4553-8096-b2f6fff930a2"; 16 | public const string WebLinterCmdSetString = "214001ac-2bd3-474a-a56c-b45dcb785e96"; 17 | public const string ConfigFileCmdSetString = "03997e40-2a1e-4241-ad40-e9296c0a58a0"; 18 | public static Guid guidVSPackage = new Guid(guidVSPackageString); 19 | public static Guid WebLinterCmdSet = new Guid(WebLinterCmdSetString); 20 | public static Guid ConfigFileCmdSet = new Guid(ConfigFileCmdSetString); 21 | } 22 | /// 23 | /// Helper class that encapsulates all CommandIDs uses across VS Package. 24 | /// 25 | internal sealed partial class PackageIds 26 | { 27 | public const int ContextMenuGroup = 0x1020; 28 | public const int LintFilesCommand = 0x0100; 29 | public const int FixLintErrorsCommand = 0x0150; 30 | public const int CleanErrorsCommand = 0x0200; 31 | public const int ToolsGroup = 0x1010; 32 | public const int ToolsMenu = 0x1020; 33 | public const int ToolsMenuGroup = 0x1030; 34 | public const int ToolsMenuResetGroup = 0x1040; 35 | public const int ResetConfigFiles = 0x0010; 36 | public const int EditTSLint = 0x0400; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/WebLinterVsix/VSCommandTable.vsct: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | TypeScript Analyzer 30 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 54 | 64 | 65 | 66 | 74 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/WebLinterVsix/VSPackage.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using EnvDTE80; 3 | using Microsoft.VisualStudio; 4 | using Microsoft.VisualStudio.Shell; 5 | using Microsoft.VisualStudio.Shell.Interop; 6 | using Microsoft.VisualStudio.Text; 7 | using Microsoft.VisualStudio.Text.Editor; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Runtime.InteropServices; 11 | using System.Threading; 12 | using WebLinter; 13 | using WebLinterVsix.Tagging; 14 | 15 | namespace WebLinterVsix 16 | { 17 | [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] 18 | [InstalledProductRegistration("#110", "#112", WebLinter.Constants.VERSION, IconResourceID = 400)] 19 | [ProvideOptionPage(typeof(Settings), "TypeScript Analyzer", "TSLint", 101, 111, true, new[] { "tslint" }, ProvidesLocalizedCategoryName = false)] 20 | [ProvideAutoLoad(UIContextGuids80.SolutionExists, PackageAutoLoadFlags.BackgroundLoad)] 21 | [Guid(PackageGuids.guidVSPackageString)] 22 | [ProvideMenuResource("Menus.ctmenu", 1)] 23 | public sealed class WebLinterPackage : AsyncPackage 24 | { 25 | public static DTE2 Dte; 26 | public static ISettings Settings; 27 | public static TaggerProvider TaggerProvider; 28 | private SolutionEvents _events; 29 | public static List> UnhandledStartUpFiles = new List>(); 30 | 31 | protected override async System.Threading.Tasks.Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) 32 | { 33 | await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); 34 | Dte = GetService(typeof(DTE)) as DTE2; 35 | Settings = (Settings)GetDialogPage(typeof(Settings)); 36 | 37 | _events = Dte.Events.SolutionEvents; 38 | _events.AfterClosing += delegate { ErrorListDataSource.Instance.CleanAllErrors(); }; // Called on UI thread 39 | 40 | Logger.Initialize(this, Vsix.Name); 41 | 42 | bool isSolutionLoaded = await IsSolutionLoadedAsync(); 43 | if (isSolutionLoaded) HandleOpenSolution(); 44 | 45 | LintFilesCommand.Initialize(this); 46 | FixLintErrorsCommand.Initialize(this); 47 | CleanErrorsCommand.Initialize(this); 48 | EditConfigFilesCommand.Initialize(this); 49 | ResetConfigFilesCommand.Initialize(this); 50 | 51 | base.Initialize(); 52 | } 53 | 54 | private async System.Threading.Tasks.Task IsSolutionLoadedAsync() 55 | { 56 | await JoinableTaskFactory.SwitchToMainThreadAsync(); 57 | IVsSolution solService = await GetServiceAsync(typeof(SVsSolution)) as IVsSolution; 58 | ErrorHandler.ThrowOnFailure(solService.GetProperty((int)__VSPROPID.VSPROPID_IsSolutionOpen, out object value)); 59 | return value is bool isSolOpen && isSolOpen; 60 | } 61 | 62 | private void HandleOpenSolution(object sender = null, EventArgs e = null) 63 | { 64 | foreach (Tuple tuple in UnhandledStartUpFiles) 65 | { 66 | WebLinterVsix.FileListeners.SourceFileCreationListener.OnFileOpened(tuple.Item1, tuple.Item2); 67 | } 68 | UnhandledStartUpFiles.Clear(); 69 | } 70 | 71 | public IVsOutputWindow GetIVsOutputWindow() => (IVsOutputWindow)GetService(typeof(SVsOutputWindow)); 72 | 73 | protected override void Dispose(bool disposing) 74 | { 75 | if (disposing) Linter.Server.Down(); 76 | base.Dispose(true); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/WebLinterVsix/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/WebLinterVsix/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/WebLinterVsix/registry.pkgdef: -------------------------------------------------------------------------------- 1 | // Icons 2 | [$RootKey$\ShellFileAssociations\.tsx] 3 | "DefaultIconMoniker"="KnownMonikers.JSXScript" -------------------------------------------------------------------------------- /src/WebLinterVsix/source.extension.cs: -------------------------------------------------------------------------------- 1 | namespace WebLinterVsix 2 | { 3 | static class Vsix 4 | { 5 | public const string Id = "A95BEECA-9D08-48C5-882B-BAB22D5723BC"; 6 | public const string Name = "TypeScript Analyzer"; 7 | public const string Description = @"Provides static analysis directly in Visual Studio for TypeScript files (.ts and .tsx) using TSLint"; 8 | public const string Language = "en-US"; 9 | public const string Version = "1.0"; 10 | public const string Author = "Rich Newman"; 11 | public const string Tags = "TSLint"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/WebLinterVsix/source.extension.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rich-newman/typescript-analyzer/92862f90ff082447b690903e3c8455a842c5d38c/src/WebLinterVsix/source.extension.ico -------------------------------------------------------------------------------- /src/WebLinterVsix/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | TypeScript Analyzer 6 | Provides static analysis directly in Visual Studio for TypeScript files (.ts and .tsx) using TSLint 7 | https://github.com/rich-newman/typescript-analyzer 8 | Resources\LICENSE 9 | Resources\icon.png 10 | Resources\preview.png 11 | TSLint 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------