,
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 |
19 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
46 |
54 |
64 |
65 |
66 |
74 |
82 |
83 |
84 |
85 |
86 |
89 |
92 |
95 |
98 |
101 |
104 |
107 |
110 |
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 |
--------------------------------------------------------------------------------