vscode-eslint 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/$shared/customMessages.ts +113 -0
  2. package/$shared/settings.ts +189 -0
  3. package/.CodeQL.yml +5 -0
  4. package/.azure-pipelines.yml +27 -0
  5. package/.github/commands.yml +127 -0
  6. package/.github/locker.yml +6 -0
  7. package/.github/needs_more_info.yml +6 -0
  8. package/.github/workflows/npm-publish.yml +53 -0
  9. package/.github/workflows/release-please.yml +22 -0
  10. package/.lsifrc.json +4 -0
  11. package/.vscode/launch.json +20 -0
  12. package/.vscode/settings.json +52 -0
  13. package/.vscode/spellright.dict +8 -0
  14. package/.vscode/tasks.json +39 -0
  15. package/.vscodeignore +23 -0
  16. package/CHANGELOG.md +524 -0
  17. package/License.txt +17 -0
  18. package/README.md +517 -0
  19. package/SECURITY.md +41 -0
  20. package/agents.md +36 -0
  21. package/bin/vscode-eslint.js +56 -0
  22. package/build/azure-pipelines/linux/build.yml +14 -0
  23. package/build/azure-pipelines/pre-release.yml +42 -0
  24. package/build/azure-pipelines/release.yml +45 -0
  25. package/build/azure-pipelines/win32/build.yml +14 -0
  26. package/build/bin/all.js +29 -0
  27. package/build/bin/linking.js +102 -0
  28. package/build/bin/symlink.js +35 -0
  29. package/client/.mocharc.json +6 -0
  30. package/client/agents.md +5 -0
  31. package/client/package-lock.json +176 -0
  32. package/client/package.json +29 -0
  33. package/client/src/client.ts +992 -0
  34. package/client/src/extension.ts +180 -0
  35. package/client/src/node-utils.ts +393 -0
  36. package/client/src/settings.ts +379 -0
  37. package/client/src/tasks.ts +186 -0
  38. package/client/src/tests/glob.test.ts +31 -0
  39. package/client/src/vscode-utils.ts +28 -0
  40. package/client/test/mocha.opts +3 -0
  41. package/client/tsconfig.json +20 -0
  42. package/client/webpack.config.js +25 -0
  43. package/contributing.md +19 -0
  44. package/esbuild.js +62 -0
  45. package/eslint.config.js +129 -0
  46. package/eslint_icon.png +0 -0
  47. package/history/settings_1_9_x.md +110 -0
  48. package/images/2_1_10/eslint-dialog.png +0 -0
  49. package/images/2_1_10/eslint-status.png +0 -0
  50. package/package-json-schema.json +9 -0
  51. package/package.json +686 -0
  52. package/playgrounds/7.0/.eslintignore +1 -0
  53. package/playgrounds/7.0/.eslintrc.json +71 -0
  54. package/playgrounds/7.0/.vscode/settings.json +85 -0
  55. package/playgrounds/7.0/app.js +12 -0
  56. package/playgrounds/7.0/build/.eslintignore +1 -0
  57. package/playgrounds/7.0/build/.eslintrc.json +30 -0
  58. package/playgrounds/7.0/build/build.js +11 -0
  59. package/playgrounds/7.0/jsconfig.json +5 -0
  60. package/playgrounds/7.0/package-lock.json +2133 -0
  61. package/playgrounds/7.0/package.json +10 -0
  62. package/playgrounds/7.0/readme.md +0 -0
  63. package/playgrounds/7.0/subDir/sub.js +11 -0
  64. package/playgrounds/7.0/subDir/test.jsx +10 -0
  65. package/playgrounds/7.0/test.js +11 -0
  66. package/playgrounds/7.0/test.sh +1 -0
  67. package/playgrounds/7.0/test.vue +33 -0
  68. package/playgrounds/7.0/test2.html +8 -0
  69. package/playgrounds/8.0/.eslintignore +1 -0
  70. package/playgrounds/8.0/.eslintrc.json +71 -0
  71. package/playgrounds/8.0/.vscode/settings.json +91 -0
  72. package/playgrounds/8.0/app.js +12 -0
  73. package/playgrounds/8.0/build/.eslintignore +1 -0
  74. package/playgrounds/8.0/build/.eslintrc.json +30 -0
  75. package/playgrounds/8.0/build/build.js +11 -0
  76. package/playgrounds/8.0/jsconfig.json +5 -0
  77. package/playgrounds/8.0/package-lock.json +2321 -0
  78. package/playgrounds/8.0/package.json +10 -0
  79. package/playgrounds/8.0/readme.md +17 -0
  80. package/playgrounds/8.0/subDir/sub.js +11 -0
  81. package/playgrounds/8.0/subDir/test.jsx +10 -0
  82. package/playgrounds/8.0/test.ipynb +49 -0
  83. package/playgrounds/8.0/test.js +3 -0
  84. package/playgrounds/8.0/test.sh +1 -0
  85. package/playgrounds/8.0/test.vue +33 -0
  86. package/playgrounds/8.0/test2.html +8 -0
  87. package/playgrounds/9.0/flat/.vscode/settings.json +3 -0
  88. package/playgrounds/9.0/flat/app.js +12 -0
  89. package/playgrounds/9.0/flat/dist/ignore.js +12 -0
  90. package/playgrounds/9.0/flat/eslint.config.js +61 -0
  91. package/playgrounds/9.0/flat/package-lock.json +1053 -0
  92. package/playgrounds/9.0/flat/package.json +9 -0
  93. package/playgrounds/9.0/rc/.eslintrc.json +57 -0
  94. package/playgrounds/9.0/rc/.vscode/settings.json +3 -0
  95. package/playgrounds/9.0/rc/app.js +12 -0
  96. package/playgrounds/9.0/rc/package-lock.json +1345 -0
  97. package/playgrounds/9.0/rc/package.json +9 -0
  98. package/playgrounds/flat-config/.vscode/settings.json +22 -0
  99. package/playgrounds/flat-config/app.js +12 -0
  100. package/playgrounds/flat-config/eslint.config.js +51 -0
  101. package/playgrounds/flat-config/package-lock.json +2733 -0
  102. package/playgrounds/flat-config/package.json +12 -0
  103. package/playgrounds/flat-config/sub/sub.js +2 -0
  104. package/playgrounds/flat-config/test.ts +7 -0
  105. package/playgrounds/flat-config/tsconfig.json +11 -0
  106. package/playgrounds/flat-config-fail/f1/app.js +12 -0
  107. package/playgrounds/flat-config-fail/f1/eslint.config.js +51 -0
  108. package/playgrounds/flat-config-fail/package-lock.json +1683 -0
  109. package/playgrounds/flat-config-fail/package.json +11 -0
  110. package/playgrounds/flat-config-mjs/.vscode/settings.json +21 -0
  111. package/playgrounds/flat-config-mjs/app.js +12 -0
  112. package/playgrounds/flat-config-mjs/eslint.config.mjs +53 -0
  113. package/playgrounds/flat-config-mjs/package-lock.json +2860 -0
  114. package/playgrounds/flat-config-mjs/package.json +11 -0
  115. package/playgrounds/flat-config-mjs/sub/sub.js +2 -0
  116. package/playgrounds/flat-config-mjs/test.ts +7 -0
  117. package/playgrounds/flat-config-mjs/tsconfig.json +11 -0
  118. package/playgrounds/load-eslint/.vscode/settings.json +21 -0
  119. package/playgrounds/load-eslint/app.js +12 -0
  120. package/playgrounds/load-eslint/eslint.config.js +51 -0
  121. package/playgrounds/load-eslint/package-lock.json +2860 -0
  122. package/playgrounds/load-eslint/package.json +11 -0
  123. package/playgrounds/load-eslint/sub/sub.js +2 -0
  124. package/playgrounds/load-eslint/test.ts +7 -0
  125. package/playgrounds/load-eslint/tsconfig.json +11 -0
  126. package/playgrounds/noLib/test.js +22 -0
  127. package/playgrounds/noWD/.vscode/settings.json +2 -0
  128. package/playgrounds/noWD/src/.eslintrc.json +18 -0
  129. package/playgrounds/noWD/src/package-lock.json +2812 -0
  130. package/playgrounds/noWD/src/package.json +12 -0
  131. package/playgrounds/noWD/src/test.js +3 -0
  132. package/playgrounds/notebooks/notebook.ipynb +7072 -0
  133. package/playgrounds/notebooks/notebook2.ipynb +20 -0
  134. package/playgrounds/testing.code-workspace +28 -0
  135. package/playgrounds/ts/.eslintrc.base.json +23 -0
  136. package/playgrounds/ts/.eslintrc.json +191 -0
  137. package/playgrounds/ts/.vscode/settings.json +12 -0
  138. package/playgrounds/ts/package-lock.json +2687 -0
  139. package/playgrounds/ts/package.json +11 -0
  140. package/playgrounds/ts/test copy.ts +4 -0
  141. package/playgrounds/ts/test.ipynb +49 -0
  142. package/playgrounds/ts/test.ts +4 -0
  143. package/playgrounds/ts/test.tsx +14 -0
  144. package/playgrounds/ts/tsconfig.json +100 -0
  145. package/server/agents.md +9 -0
  146. package/server/package-lock.json +93 -0
  147. package/server/package.json +32 -0
  148. package/server/src/diff.ts +1079 -0
  149. package/server/src/eslint.ts +1471 -0
  150. package/server/src/eslintServer.ts +865 -0
  151. package/server/src/is.ts +18 -0
  152. package/server/src/languageDefaults.ts +40 -0
  153. package/server/src/linkedMap.ts +448 -0
  154. package/server/src/paths.ts +128 -0
  155. package/server/src/thenable.d.ts +5 -0
  156. package/server/tsconfig.json +21 -0
  157. package/server/webpack.config.js +25 -0
  158. package/shared.webpack.config.js +59 -0
  159. package/tsconfig.base.json +9 -0
  160. package/tsconfig.json +21 -0
@@ -0,0 +1,379 @@
1
+ /* --------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ * ------------------------------------------------------------------------------------------ */
5
+
6
+ import { workspace as Workspace, Uri, WorkspaceConfiguration, ConfigurationTarget } from 'vscode';
7
+
8
+ import { Is } from './node-utils';
9
+ import { DirectoryItem, ModeItem } from './shared/settings';
10
+
11
+ // Defines settings locally to the client or deprecated settings that are converted to
12
+ // shared settings
13
+
14
+ export type ValidateItem = {
15
+ language: string;
16
+ autoFix?: boolean;
17
+ };
18
+
19
+ export namespace ValidateItem {
20
+ export function is(item: any): item is ValidateItem {
21
+ const candidate = item as ValidateItem;
22
+ return candidate && Is.string(candidate.language) && (Is.boolean(candidate.autoFix) || candidate.autoFix === void 0);
23
+ }
24
+ }
25
+
26
+ export type LegacyDirectoryItem = {
27
+ directory: string;
28
+ changeProcessCWD: boolean;
29
+ };
30
+
31
+ export namespace LegacyDirectoryItem {
32
+ export function is(item: any): item is LegacyDirectoryItem {
33
+ const candidate = item as LegacyDirectoryItem;
34
+ return candidate && Is.string(candidate.directory) && Is.boolean(candidate.changeProcessCWD);
35
+ }
36
+ }
37
+
38
+ export type PatternItem = {
39
+ pattern: string;
40
+ '!cwd'?: boolean;
41
+ };
42
+
43
+ export namespace PatternItem {
44
+ export function is(item: any): item is PatternItem {
45
+ const candidate = item as PatternItem;
46
+ return candidate && Is.string(candidate.pattern) && (Is.boolean(candidate['!cwd']) || candidate['!cwd'] === undefined);
47
+ }
48
+ }
49
+
50
+ // ----- Settings migration code
51
+
52
+ type InspectData<T> = {
53
+ globalValue?: T;
54
+ workspaceValue?: T;
55
+ workspaceFolderValue?: T;
56
+ };
57
+
58
+ type MigrationElement<T> = {
59
+ changed: boolean;
60
+ value: T | undefined;
61
+ };
62
+
63
+ type MigrationData<T> = {
64
+ global: MigrationElement<T>;
65
+ workspace: MigrationElement<T>;
66
+ workspaceFolder: MigrationElement<T>;
67
+ };
68
+
69
+ interface CodeActionsOnSaveMap {
70
+ 'source.fixAll'?: boolean;
71
+ 'source.fixAll.eslint'?: boolean;
72
+ [key: string]: boolean | undefined;
73
+ }
74
+
75
+ type CodeActionsOnSave = CodeActionsOnSaveMap | string[] | null;
76
+
77
+ namespace CodeActionsOnSave {
78
+ export function isExplicitlyDisabled(setting: CodeActionsOnSave | undefined): boolean {
79
+ if (setting === undefined || setting === null || Array.isArray(setting)) {
80
+ return false;
81
+ }
82
+ return setting['source.fixAll.eslint'] === false;
83
+ }
84
+
85
+ export function getSourceFixAll(setting: CodeActionsOnSave): boolean | undefined {
86
+ if (setting === null) {
87
+ return undefined;
88
+ } if (Array.isArray(setting)) {
89
+ return setting.includes('source.fixAll') ? true : undefined;
90
+ } else {
91
+ return setting['source.fixAll'];
92
+ }
93
+ }
94
+
95
+ export function getSourceFixAllESLint(setting: CodeActionsOnSave): boolean | undefined {
96
+ if (setting === null) {
97
+ return undefined;
98
+ } else if (Array.isArray(setting)) {
99
+ return setting.includes('source.fixAll.eslint') ? true : undefined;
100
+ } else {
101
+ return setting['source.fixAll.eslint'];
102
+ }
103
+ }
104
+
105
+ export function setSourceFixAllESLint(setting: CodeActionsOnSave, value: boolean | undefined): void {
106
+ // If the setting is mistyped do nothing.
107
+ if (setting === null) {
108
+ return;
109
+ } else if (Array.isArray(setting)) {
110
+ const index = setting.indexOf('source.fixAll.eslint');
111
+ if (value === true) {
112
+ if (index === -1) {
113
+ setting.push('source.fixAll.eslint');
114
+ }
115
+ } else {
116
+ if (index >= 0) {
117
+ setting.splice(index, 1);
118
+ }
119
+ }
120
+ } else {
121
+ setting['source.fixAll.eslint'] = value;
122
+ }
123
+ }
124
+ }
125
+
126
+ type LanguageSettings = {
127
+ 'editor.codeActionsOnSave'?: CodeActionsOnSave;
128
+ };
129
+
130
+ namespace MigrationData {
131
+ export function create<T>(inspect: InspectData<T> | undefined): MigrationData<T> {
132
+ return inspect === undefined
133
+ ? {
134
+ global: { value: undefined, changed: false },
135
+ workspace: { value: undefined, changed: false },
136
+ workspaceFolder: { value: undefined, changed: false }
137
+ }
138
+ : {
139
+ global: { value: inspect.globalValue, changed: false },
140
+ workspace: { value: inspect.workspaceValue, changed: false },
141
+ workspaceFolder: { value: inspect.workspaceFolderValue, changed: false }
142
+ };
143
+ }
144
+ export function needsUpdate(data: MigrationData<any>): boolean {
145
+ return data.global.changed || data.workspace.changed || data.workspaceFolder.changed;
146
+ }
147
+ }
148
+
149
+ export class Migration {
150
+ private workspaceConfig: WorkspaceConfiguration;
151
+ private eslintConfig: WorkspaceConfiguration;
152
+ private editorConfig: WorkspaceConfiguration;
153
+
154
+ private codeActionOnSave: MigrationData<CodeActionsOnSave>;
155
+ private languageSpecificSettings: Map<string, MigrationData<CodeActionsOnSave>>;
156
+
157
+ private autoFixOnSave: MigrationData<boolean>;
158
+ private validate: MigrationData<(ValidateItem | string)[]>;
159
+
160
+ private workingDirectories: MigrationData<(string | DirectoryItem)[]>;
161
+
162
+ private didChangeConfiguration: (() => void) | undefined;
163
+
164
+ constructor(resource: Uri) {
165
+ this.workspaceConfig = Workspace.getConfiguration(undefined, resource);
166
+ this.eslintConfig = Workspace.getConfiguration('eslint', resource);
167
+ this.editorConfig = Workspace.getConfiguration('editor', resource);
168
+ this.codeActionOnSave = MigrationData.create(this.editorConfig.inspect<CodeActionsOnSave>('codeActionsOnSave'));
169
+ this.autoFixOnSave = MigrationData.create(this.eslintConfig.inspect<boolean>('autoFixOnSave'));
170
+ this.validate = MigrationData.create(this.eslintConfig.inspect<(ValidateItem | string)[]>('validate'));
171
+ this.workingDirectories = MigrationData.create(this.eslintConfig.inspect<(string | DirectoryItem)[]>('workingDirectories'));
172
+ this.languageSpecificSettings = new Map();
173
+ }
174
+
175
+ public record(): void {
176
+ const fixAll = this.recordAutoFixOnSave();
177
+ this.recordValidate(fixAll);
178
+ this.recordWorkingDirectories();
179
+ }
180
+
181
+ public captureDidChangeSetting(func: () => void): void {
182
+ this.didChangeConfiguration = func;
183
+ }
184
+
185
+ private recordAutoFixOnSave(): [boolean, boolean, boolean] {
186
+ function record(this: void, elem: MigrationElement<boolean>, setting: MigrationElement<CodeActionsOnSave>): boolean {
187
+ // if it is explicitly set to false don't convert anything anymore
188
+ if (CodeActionsOnSave.isExplicitlyDisabled(setting.value)) {
189
+ return false;
190
+ }
191
+ if (!Is.objectLiteral(setting.value) && !Array.isArray(setting.value)) {
192
+ setting.value = Object.create(null) as {};
193
+ }
194
+ const autoFix: boolean = !!elem.value;
195
+ const sourceFixAll: boolean = !!CodeActionsOnSave.getSourceFixAll(setting.value);
196
+ let result: boolean;
197
+ if (autoFix !== sourceFixAll && autoFix && CodeActionsOnSave.getSourceFixAllESLint(setting.value) === undefined) {
198
+ CodeActionsOnSave.setSourceFixAllESLint(setting.value, elem.value);
199
+ setting.changed = true;
200
+ result = !!CodeActionsOnSave.getSourceFixAllESLint(setting.value);
201
+ } else {
202
+ result = !!CodeActionsOnSave.getSourceFixAll(setting.value);
203
+ }
204
+ /* For now we don't rewrite the settings to allow users to go back to an older version
205
+ elem.value = undefined;
206
+ elem.changed = true;
207
+ */
208
+ return result;
209
+ }
210
+
211
+ return [
212
+ record(this.autoFixOnSave.global, this.codeActionOnSave.global),
213
+ record(this.autoFixOnSave.workspace, this.codeActionOnSave.workspace),
214
+ record(this.autoFixOnSave.workspaceFolder, this.codeActionOnSave.workspaceFolder)
215
+ ];
216
+ }
217
+
218
+ private recordValidate(fixAll: [boolean, boolean, boolean]): void {
219
+ function record(this: void, elem: MigrationElement<(ValidateItem | string)[]>, settingAccessor: (language: string) => MigrationElement<CodeActionsOnSave>, fixAll: boolean): void {
220
+ if (elem.value === undefined) {
221
+ return;
222
+ }
223
+ for (let i = 0; i < elem.value.length; i++) {
224
+ const item = elem.value[i];
225
+ if (typeof item === 'string') {
226
+ continue;
227
+ }
228
+ if (fixAll && item.autoFix === false && typeof item.language === 'string') {
229
+ const setting = settingAccessor(item.language);
230
+ if (!Is.objectLiteral(setting.value) && !Array.isArray(setting.value)) {
231
+ setting.value = Object.create(null) as {};
232
+ }
233
+ if (CodeActionsOnSave.getSourceFixAllESLint(setting.value!) !== false) {
234
+ CodeActionsOnSave.setSourceFixAllESLint(setting.value!, false);
235
+ setting.changed = true;
236
+ }
237
+ }
238
+ /* For now we don't rewrite the settings to allow users to go back to an older version
239
+ if (item.language !== undefined) {
240
+ elem.value[i] = item.language;
241
+ elem.changed = true;
242
+ }
243
+ */
244
+ }
245
+ }
246
+
247
+ const languageSpecificSettings = this.languageSpecificSettings;
248
+ const workspaceConfig = this.workspaceConfig;
249
+ function getCodeActionsOnSave(language: string): MigrationData<CodeActionsOnSave> {
250
+ let result: MigrationData<CodeActionsOnSave> | undefined = languageSpecificSettings.get(language);
251
+ if (result !== undefined) {
252
+ return result;
253
+ }
254
+ const value: InspectData<LanguageSettings> | undefined = workspaceConfig.inspect(`[${language}]`);
255
+ if (value === undefined) {
256
+ return MigrationData.create(undefined);
257
+ }
258
+
259
+ const globalValue = value.globalValue?.['editor.codeActionsOnSave'];
260
+ const workspaceFolderValue = value.workspaceFolderValue?.['editor.codeActionsOnSave'];
261
+ const workspaceValue = value.workspaceValue?.['editor.codeActionsOnSave'];
262
+ result = MigrationData.create<CodeActionsOnSave>({ globalValue, workspaceFolderValue, workspaceValue });
263
+ languageSpecificSettings.set(language, result);
264
+ return result;
265
+ }
266
+
267
+ record(this.validate.global, (language) => getCodeActionsOnSave(language).global, fixAll[0]);
268
+ record(this.validate.workspace, (language) => getCodeActionsOnSave(language).workspace, fixAll[1] ? fixAll[1] : fixAll[0]);
269
+ record(this.validate.workspaceFolder, (language) => getCodeActionsOnSave(language).workspaceFolder, fixAll[2] ? fixAll[2] : (fixAll[1] ? fixAll[1] : fixAll[0]));
270
+ }
271
+
272
+ private recordWorkingDirectories(): void {
273
+ function record(this: void, elem: MigrationElement<(string | DirectoryItem | LegacyDirectoryItem | PatternItem | ModeItem)[]>): void {
274
+ if (elem.value === undefined || !Array.isArray(elem.value)) {
275
+ return;
276
+ }
277
+ for (let i = 0; i < elem.value.length; i++) {
278
+ const item = elem.value[i];
279
+ if (typeof item === 'string' || ModeItem.is(item) || PatternItem.is(item)) {
280
+ continue;
281
+ }
282
+ if (DirectoryItem.is(item) && item['!cwd'] !== undefined) {
283
+ continue;
284
+ }
285
+ /* For now we don't rewrite the settings to allow users to go back to an older version
286
+ if (LegacyDirectoryItem.is(item)) {
287
+ const legacy: LegacyDirectoryItem = item;
288
+ if (legacy.changeProcessCWD === false) {
289
+ (item as DirectoryItem)['!cwd'] = true;
290
+ elem.changed = true;
291
+ }
292
+ }
293
+ if (DirectoryItem.is(item) && item['!cwd'] === undefined) {
294
+ elem.value[i] = item.directory;
295
+ elem.changed = true;
296
+ }
297
+ */
298
+ }
299
+ }
300
+
301
+ record(this.workingDirectories.global);
302
+ record(this.workingDirectories.workspace);
303
+ record(this.workingDirectories.workspaceFolder);
304
+ }
305
+
306
+ public needsUpdate(): boolean {
307
+ if (MigrationData.needsUpdate(this.autoFixOnSave) ||
308
+ MigrationData.needsUpdate(this.validate) ||
309
+ MigrationData.needsUpdate(this.codeActionOnSave) ||
310
+ MigrationData.needsUpdate(this.workingDirectories)
311
+ ) {
312
+ return true;
313
+ }
314
+ for (const value of this.languageSpecificSettings.values()) {
315
+ if (MigrationData.needsUpdate(value)) {
316
+ return true;
317
+ }
318
+ }
319
+ return false;
320
+ }
321
+
322
+ public async update(): Promise<void> {
323
+ async function _update<T>(config: WorkspaceConfiguration, section: string, newValue: MigrationElement<T>, target: ConfigurationTarget): Promise<void> {
324
+ if (!newValue.changed) {
325
+ return;
326
+ }
327
+ await config.update(section, newValue.value, target);
328
+ }
329
+
330
+ async function _updateLanguageSetting(config: WorkspaceConfiguration, section: string, settings: LanguageSettings | undefined, newValue: MigrationElement<CodeActionsOnSave>, target: ConfigurationTarget): Promise<void> {
331
+ if (!newValue.changed) {
332
+ return;
333
+ }
334
+
335
+ if (settings === undefined) {
336
+ settings = Object.create(null) as object;
337
+ }
338
+ if (settings['editor.codeActionsOnSave'] === undefined) {
339
+ settings['editor.codeActionsOnSave'] = {};
340
+ }
341
+ settings['editor.codeActionsOnSave'] = newValue.value;
342
+ await config.update(section, settings, target);
343
+ }
344
+
345
+ try {
346
+ await _update(this.editorConfig, 'codeActionsOnSave', this.codeActionOnSave.global, ConfigurationTarget.Global);
347
+ await _update(this.editorConfig, 'codeActionsOnSave', this.codeActionOnSave.workspace, ConfigurationTarget.Workspace);
348
+ await _update(this.editorConfig, 'codeActionsOnSave', this.codeActionOnSave.workspaceFolder, ConfigurationTarget.WorkspaceFolder);
349
+
350
+ await _update(this.eslintConfig, 'autoFixOnSave', this.autoFixOnSave.global, ConfigurationTarget.Global);
351
+ await _update(this.eslintConfig, 'autoFixOnSave', this.autoFixOnSave.workspace, ConfigurationTarget.Workspace);
352
+ await _update(this.eslintConfig, 'autoFixOnSave', this.autoFixOnSave.workspaceFolder, ConfigurationTarget.WorkspaceFolder);
353
+
354
+ await _update(this.eslintConfig, 'validate', this.validate.global, ConfigurationTarget.Global);
355
+ await _update(this.eslintConfig, 'validate', this.validate.workspace, ConfigurationTarget.Workspace);
356
+ await _update(this.eslintConfig, 'validate', this.validate.workspaceFolder, ConfigurationTarget.WorkspaceFolder);
357
+
358
+ await _update(this.eslintConfig, 'workingDirectories', this.workingDirectories.global, ConfigurationTarget.Global);
359
+ await _update(this.eslintConfig, 'workingDirectories', this.workingDirectories.workspace, ConfigurationTarget.Workspace);
360
+ await _update(this.eslintConfig, 'workingDirectories', this.workingDirectories.workspaceFolder, ConfigurationTarget.WorkspaceFolder);
361
+
362
+ for (const language of this.languageSpecificSettings.keys()) {
363
+ const value = this.languageSpecificSettings.get(language)!;
364
+ if (MigrationData.needsUpdate(value)) {
365
+ const section = `[${language}]`;
366
+ const current = this.workspaceConfig.inspect<LanguageSettings>(section);
367
+ await _updateLanguageSetting(this.workspaceConfig, section, current?.globalValue, value.global, ConfigurationTarget.Global);
368
+ await _updateLanguageSetting(this.workspaceConfig, section, current?.workspaceValue, value.workspace, ConfigurationTarget.Workspace);
369
+ await _updateLanguageSetting(this.workspaceConfig, section, current?.workspaceFolderValue, value.workspaceFolder, ConfigurationTarget.WorkspaceFolder);
370
+ }
371
+ }
372
+ } finally {
373
+ if (this.didChangeConfiguration) {
374
+ this.didChangeConfiguration();
375
+ this.didChangeConfiguration = undefined;
376
+ }
377
+ }
378
+ }
379
+ }
@@ -0,0 +1,186 @@
1
+ /* --------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ * ------------------------------------------------------------------------------------------ */
5
+
6
+ import * as vscode from 'vscode';
7
+ import { Disposable } from 'vscode-languageclient';
8
+
9
+ import { findEslint } from './node-utils';
10
+
11
+ /**
12
+ * A special task definition for ESLint tasks
13
+ */
14
+ interface EslintTaskDefinition extends vscode.TaskDefinition {
15
+ }
16
+
17
+
18
+ class FolderTaskProvider {
19
+ constructor(private _workspaceFolder: vscode.WorkspaceFolder) {
20
+ }
21
+
22
+ public get workspaceFolder(): vscode.WorkspaceFolder {
23
+ return this._workspaceFolder;
24
+ }
25
+
26
+ public isEnabled(): boolean {
27
+ const config = vscode.workspace.getConfiguration('eslint', this._workspaceFolder.uri);
28
+ return config.get<boolean>('lintTask.enable', false) ?? config.get<boolean>('provideLintTask', false);
29
+ }
30
+
31
+ public start(): void {
32
+ }
33
+
34
+ public dispose(): void {
35
+ }
36
+
37
+ public async getTask(): Promise<vscode.Task | undefined> {
38
+ const rootPath = this._workspaceFolder.uri.scheme === 'file' ? this._workspaceFolder.uri.fsPath : undefined;
39
+ if (!rootPath) {
40
+ return undefined;
41
+ }
42
+ try {
43
+
44
+ const kind: EslintTaskDefinition = {
45
+ type: 'eslint'
46
+ };
47
+
48
+ const options: vscode.ShellExecutionOptions = { cwd: this.workspaceFolder.uri.fsPath };
49
+ const config = vscode.workspace.getConfiguration('eslint', this._workspaceFolder.uri);
50
+ const command = config.get<string>('lintTask.command', await findEslint(rootPath));
51
+ const lintTaskOptions = config.get<string>('lintTask.options', '.');
52
+ return new vscode.Task(
53
+ kind, this.workspaceFolder,
54
+ 'lint whole folder', 'eslint', new vscode.ShellExecution(`${command} ${lintTaskOptions}`, options),
55
+ '$eslint-stylish'
56
+ );
57
+ } catch {
58
+ return undefined;
59
+ }
60
+ }
61
+ }
62
+
63
+ /**
64
+ * A task provider that adds ESLint checking tasks.
65
+ */
66
+ export class TaskProvider {
67
+
68
+ /**
69
+ * A Disposable to unregister the task provider inside
70
+ * VS Code.
71
+ */
72
+ private taskProvider: vscode.Disposable | undefined;
73
+
74
+ /**
75
+ * The actual providers per workspace folder.
76
+ */
77
+ private readonly providers: Map<string, FolderTaskProvider>;
78
+
79
+ /**
80
+ * A disposable to unregister event listeners
81
+ */
82
+ private disposable: Disposable | undefined;
83
+
84
+ constructor() {
85
+ this.providers = new Map();
86
+ }
87
+
88
+ public start(): void {
89
+ const folders = vscode.workspace.workspaceFolders;
90
+ if (folders !== undefined) {
91
+ this.updateWorkspaceFolders(folders, []);
92
+ }
93
+
94
+ const disposables: vscode.Disposable[] = [];
95
+ disposables.push(vscode.workspace.onDidChangeWorkspaceFolders((event) => this.updateWorkspaceFolders(event.added, event.removed)));
96
+ disposables.push(vscode.workspace.onDidChangeConfiguration(this.updateConfiguration, this));
97
+ this.disposable = vscode.Disposable.from(...disposables);
98
+ }
99
+
100
+ public dispose(): void {
101
+ if (this.taskProvider !== undefined) {
102
+ this.taskProvider.dispose();
103
+ this.taskProvider = undefined;
104
+ }
105
+ if (this.disposable !== undefined) {
106
+ this.disposable.dispose();
107
+ this.disposable = undefined;
108
+ }
109
+ this.providers.clear();
110
+ }
111
+
112
+ /**
113
+ * The workspace folders have changed.
114
+ */
115
+ private updateWorkspaceFolders(added: ReadonlyArray<vscode.WorkspaceFolder>, removed: ReadonlyArray<vscode.WorkspaceFolder>): void {
116
+ for (const remove of removed) {
117
+ const provider = this.providers.get(remove.uri.toString());
118
+ if (provider) {
119
+ provider.dispose();
120
+ this.providers.delete(remove.uri.toString());
121
+ }
122
+ }
123
+ for (const add of added) {
124
+ const provider = new FolderTaskProvider(add);
125
+ if (provider.isEnabled()) {
126
+ this.providers.set(add.uri.toString(), provider);
127
+ provider.start();
128
+ }
129
+ }
130
+ this.updateProvider();
131
+ }
132
+
133
+ /**
134
+ * The configuration has changed.
135
+ */
136
+ private updateConfiguration(): void {
137
+ for (const detector of this.providers.values()) {
138
+ if (!detector.isEnabled()) {
139
+ detector.dispose();
140
+ this.providers.delete(detector.workspaceFolder.uri.toString());
141
+ }
142
+ }
143
+ const folders = vscode.workspace.workspaceFolders;
144
+ if (folders) {
145
+ for (const folder of folders) {
146
+ if (!this.providers.has(folder.uri.toString())) {
147
+ const provider = new FolderTaskProvider(folder);
148
+ if (provider.isEnabled()) {
149
+ this.providers.set(folder.uri.toString(), provider);
150
+ provider.start();
151
+ }
152
+ }
153
+ }
154
+ }
155
+ this.updateProvider();
156
+ }
157
+
158
+ private updateProvider(): void {
159
+ if (!this.taskProvider && this.providers.size > 0) {
160
+ this.taskProvider = vscode.tasks.registerTaskProvider('eslint', {
161
+ provideTasks: () => {
162
+ return this.getTasks();
163
+ },
164
+ resolveTask(_task: vscode.Task): vscode.Task | undefined {
165
+ return undefined;
166
+ }
167
+ });
168
+ } else if (this.taskProvider && this.providers.size === 0) {
169
+ this.taskProvider.dispose();
170
+ this.taskProvider = undefined;
171
+ }
172
+ }
173
+
174
+ private async getTasks(): Promise<vscode.Task[]> {
175
+ if (this.providers.size === 0) {
176
+ return [];
177
+ } else {
178
+ const promises: Promise<vscode.Task | undefined>[] = [];
179
+ for (const provider of this.providers.values()) {
180
+ promises.push(provider.getTask());
181
+ }
182
+ const values = await Promise.all(promises);
183
+ return values.filter<vscode.Task>((value): value is vscode.Task => { return value !== undefined; });
184
+ }
185
+ }
186
+ }
@@ -0,0 +1,31 @@
1
+ /* --------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ * ------------------------------------------------------------------------------------------ */
5
+
6
+ import * as assert from 'assert';
7
+ import { convert2RegExp } from '../node-utils';
8
+
9
+ function isDefined<T>(value: T | undefined | null): asserts value is Exclude<T, undefined | null> {
10
+ if (value === undefined || value === null) {
11
+ throw new Error(`Value is null or undefined`);
12
+ }
13
+ }
14
+
15
+ function toOSPath(path: string): string {
16
+ if (process.platform !== 'win32') {
17
+ return path;
18
+ }
19
+ return path.replace(/\//g, '\\');
20
+ }
21
+
22
+ suite('Glob', () => {
23
+ test('Simple', () => {
24
+ const regExp = convert2RegExp('/test/*/');
25
+ isDefined(regExp);
26
+ const matches = regExp.exec(toOSPath('/test/foo/bar/file.txt'));
27
+ isDefined(matches);
28
+ assert.strictEqual(matches.length, 1);
29
+ assert.strictEqual(matches[0], toOSPath('/test/foo/'));
30
+ });
31
+ });
@@ -0,0 +1,28 @@
1
+ /* --------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ * ------------------------------------------------------------------------------------------ */
5
+
6
+ import { QuickPickItem, window, WorkspaceFolder } from 'vscode';
7
+
8
+ interface WorkspaceFolderItem extends QuickPickItem {
9
+ folder: WorkspaceFolder;
10
+ }
11
+
12
+ /**
13
+ * Picks a folder from a list of workspace folders.
14
+ */
15
+ export async function pickFolder(folders: ReadonlyArray<WorkspaceFolder>, placeHolder: string): Promise<WorkspaceFolder | undefined> {
16
+ if (folders.length === 1) {
17
+ return Promise.resolve(folders[0]);
18
+ }
19
+
20
+ const selected = await window.showQuickPick(
21
+ folders.map<WorkspaceFolderItem>((folder) => { return { label: folder.name, description: folder.uri.fsPath, folder: folder }; }),
22
+ { placeHolder: placeHolder }
23
+ );
24
+ if (selected === undefined) {
25
+ return undefined;
26
+ }
27
+ return selected.folder;
28
+ }
@@ -0,0 +1,3 @@
1
+ out/tests
2
+ --recursive
3
+ --ui tdd
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "Node16",
5
+ "target": "ES2022",
6
+ "outDir": "out",
7
+ "rootDir": "src",
8
+ "lib": [ "ES2023" ],
9
+ "sourceMap": true,
10
+ "tsBuildInfoFile": "out/compile.tsbuildinfo",
11
+ "incremental": true,
12
+ "composite": true
13
+ },
14
+ "include": [
15
+ "src"
16
+ ],
17
+ "exclude": [
18
+ "node_modules"
19
+ ]
20
+ }
@@ -0,0 +1,25 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License. See License.txt in the project root for license information.
4
+ *--------------------------------------------------------------------------------------------*/
5
+
6
+ //@ts-check
7
+
8
+ 'use strict';
9
+
10
+ const withDefaults = require('../shared.webpack.config');
11
+ const path = require('path');
12
+
13
+ module.exports = withDefaults({
14
+ context: path.join(__dirname),
15
+ entry: {
16
+ extension: './src/extension.ts',
17
+ },
18
+ resolve: {
19
+ symlinks: false
20
+ },
21
+ output: {
22
+ filename: 'extension.js',
23
+ path: path.join(__dirname, 'out')
24
+ }
25
+ });
@@ -0,0 +1,19 @@
1
+ # VSCode ESLint
2
+
3
+ [![Build Status](https://travis-ci.org/Microsoft/vscode-eslint.svg?branch=master)](https://travis-ci.org/Microsoft/vscode-eslint)
4
+
5
+ Extension to integrate [ESLint](http://eslint.org/) into VS Code.
6
+
7
+ ## Development setup
8
+ - Use git with symbolic link support enabled. You can enable this with `git config core.symlinks true`.
9
+ - Run `npm ci`
10
+ - Open VS Code
11
+ - Run the `watch` task to compile the client and server
12
+ - To run/debug the extension use the `Launch Extension` launch configuration
13
+
14
+ ## Release and npm publish automation
15
+ - Add a repository secret named `NPM_TOKEN` (npm automation token).
16
+ - Push regular changes to the default branch.
17
+ - `Release Please` opens/updates a release PR with version and changelog changes.
18
+ - Merge the release PR to create a GitHub release and tag.
19
+ - The `Publish to npm` workflow runs `npm ci`, `npm run compile --if-present`, tests (if present), build (if present), and then `npm publish`.