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.
- package/$shared/customMessages.ts +113 -0
- package/$shared/settings.ts +189 -0
- package/.CodeQL.yml +5 -0
- package/.azure-pipelines.yml +27 -0
- package/.github/commands.yml +127 -0
- package/.github/locker.yml +6 -0
- package/.github/needs_more_info.yml +6 -0
- package/.github/workflows/npm-publish.yml +53 -0
- package/.github/workflows/release-please.yml +22 -0
- package/.lsifrc.json +4 -0
- package/.vscode/launch.json +20 -0
- package/.vscode/settings.json +52 -0
- package/.vscode/spellright.dict +8 -0
- package/.vscode/tasks.json +39 -0
- package/.vscodeignore +23 -0
- package/CHANGELOG.md +524 -0
- package/License.txt +17 -0
- package/README.md +517 -0
- package/SECURITY.md +41 -0
- package/agents.md +36 -0
- package/bin/vscode-eslint.js +56 -0
- package/build/azure-pipelines/linux/build.yml +14 -0
- package/build/azure-pipelines/pre-release.yml +42 -0
- package/build/azure-pipelines/release.yml +45 -0
- package/build/azure-pipelines/win32/build.yml +14 -0
- package/build/bin/all.js +29 -0
- package/build/bin/linking.js +102 -0
- package/build/bin/symlink.js +35 -0
- package/client/.mocharc.json +6 -0
- package/client/agents.md +5 -0
- package/client/package-lock.json +176 -0
- package/client/package.json +29 -0
- package/client/src/client.ts +992 -0
- package/client/src/extension.ts +180 -0
- package/client/src/node-utils.ts +393 -0
- package/client/src/settings.ts +379 -0
- package/client/src/tasks.ts +186 -0
- package/client/src/tests/glob.test.ts +31 -0
- package/client/src/vscode-utils.ts +28 -0
- package/client/test/mocha.opts +3 -0
- package/client/tsconfig.json +20 -0
- package/client/webpack.config.js +25 -0
- package/contributing.md +19 -0
- package/esbuild.js +62 -0
- package/eslint.config.js +129 -0
- package/eslint_icon.png +0 -0
- package/history/settings_1_9_x.md +110 -0
- package/images/2_1_10/eslint-dialog.png +0 -0
- package/images/2_1_10/eslint-status.png +0 -0
- package/package-json-schema.json +9 -0
- package/package.json +686 -0
- package/playgrounds/7.0/.eslintignore +1 -0
- package/playgrounds/7.0/.eslintrc.json +71 -0
- package/playgrounds/7.0/.vscode/settings.json +85 -0
- package/playgrounds/7.0/app.js +12 -0
- package/playgrounds/7.0/build/.eslintignore +1 -0
- package/playgrounds/7.0/build/.eslintrc.json +30 -0
- package/playgrounds/7.0/build/build.js +11 -0
- package/playgrounds/7.0/jsconfig.json +5 -0
- package/playgrounds/7.0/package-lock.json +2133 -0
- package/playgrounds/7.0/package.json +10 -0
- package/playgrounds/7.0/readme.md +0 -0
- package/playgrounds/7.0/subDir/sub.js +11 -0
- package/playgrounds/7.0/subDir/test.jsx +10 -0
- package/playgrounds/7.0/test.js +11 -0
- package/playgrounds/7.0/test.sh +1 -0
- package/playgrounds/7.0/test.vue +33 -0
- package/playgrounds/7.0/test2.html +8 -0
- package/playgrounds/8.0/.eslintignore +1 -0
- package/playgrounds/8.0/.eslintrc.json +71 -0
- package/playgrounds/8.0/.vscode/settings.json +91 -0
- package/playgrounds/8.0/app.js +12 -0
- package/playgrounds/8.0/build/.eslintignore +1 -0
- package/playgrounds/8.0/build/.eslintrc.json +30 -0
- package/playgrounds/8.0/build/build.js +11 -0
- package/playgrounds/8.0/jsconfig.json +5 -0
- package/playgrounds/8.0/package-lock.json +2321 -0
- package/playgrounds/8.0/package.json +10 -0
- package/playgrounds/8.0/readme.md +17 -0
- package/playgrounds/8.0/subDir/sub.js +11 -0
- package/playgrounds/8.0/subDir/test.jsx +10 -0
- package/playgrounds/8.0/test.ipynb +49 -0
- package/playgrounds/8.0/test.js +3 -0
- package/playgrounds/8.0/test.sh +1 -0
- package/playgrounds/8.0/test.vue +33 -0
- package/playgrounds/8.0/test2.html +8 -0
- package/playgrounds/9.0/flat/.vscode/settings.json +3 -0
- package/playgrounds/9.0/flat/app.js +12 -0
- package/playgrounds/9.0/flat/dist/ignore.js +12 -0
- package/playgrounds/9.0/flat/eslint.config.js +61 -0
- package/playgrounds/9.0/flat/package-lock.json +1053 -0
- package/playgrounds/9.0/flat/package.json +9 -0
- package/playgrounds/9.0/rc/.eslintrc.json +57 -0
- package/playgrounds/9.0/rc/.vscode/settings.json +3 -0
- package/playgrounds/9.0/rc/app.js +12 -0
- package/playgrounds/9.0/rc/package-lock.json +1345 -0
- package/playgrounds/9.0/rc/package.json +9 -0
- package/playgrounds/flat-config/.vscode/settings.json +22 -0
- package/playgrounds/flat-config/app.js +12 -0
- package/playgrounds/flat-config/eslint.config.js +51 -0
- package/playgrounds/flat-config/package-lock.json +2733 -0
- package/playgrounds/flat-config/package.json +12 -0
- package/playgrounds/flat-config/sub/sub.js +2 -0
- package/playgrounds/flat-config/test.ts +7 -0
- package/playgrounds/flat-config/tsconfig.json +11 -0
- package/playgrounds/flat-config-fail/f1/app.js +12 -0
- package/playgrounds/flat-config-fail/f1/eslint.config.js +51 -0
- package/playgrounds/flat-config-fail/package-lock.json +1683 -0
- package/playgrounds/flat-config-fail/package.json +11 -0
- package/playgrounds/flat-config-mjs/.vscode/settings.json +21 -0
- package/playgrounds/flat-config-mjs/app.js +12 -0
- package/playgrounds/flat-config-mjs/eslint.config.mjs +53 -0
- package/playgrounds/flat-config-mjs/package-lock.json +2860 -0
- package/playgrounds/flat-config-mjs/package.json +11 -0
- package/playgrounds/flat-config-mjs/sub/sub.js +2 -0
- package/playgrounds/flat-config-mjs/test.ts +7 -0
- package/playgrounds/flat-config-mjs/tsconfig.json +11 -0
- package/playgrounds/load-eslint/.vscode/settings.json +21 -0
- package/playgrounds/load-eslint/app.js +12 -0
- package/playgrounds/load-eslint/eslint.config.js +51 -0
- package/playgrounds/load-eslint/package-lock.json +2860 -0
- package/playgrounds/load-eslint/package.json +11 -0
- package/playgrounds/load-eslint/sub/sub.js +2 -0
- package/playgrounds/load-eslint/test.ts +7 -0
- package/playgrounds/load-eslint/tsconfig.json +11 -0
- package/playgrounds/noLib/test.js +22 -0
- package/playgrounds/noWD/.vscode/settings.json +2 -0
- package/playgrounds/noWD/src/.eslintrc.json +18 -0
- package/playgrounds/noWD/src/package-lock.json +2812 -0
- package/playgrounds/noWD/src/package.json +12 -0
- package/playgrounds/noWD/src/test.js +3 -0
- package/playgrounds/notebooks/notebook.ipynb +7072 -0
- package/playgrounds/notebooks/notebook2.ipynb +20 -0
- package/playgrounds/testing.code-workspace +28 -0
- package/playgrounds/ts/.eslintrc.base.json +23 -0
- package/playgrounds/ts/.eslintrc.json +191 -0
- package/playgrounds/ts/.vscode/settings.json +12 -0
- package/playgrounds/ts/package-lock.json +2687 -0
- package/playgrounds/ts/package.json +11 -0
- package/playgrounds/ts/test copy.ts +4 -0
- package/playgrounds/ts/test.ipynb +49 -0
- package/playgrounds/ts/test.ts +4 -0
- package/playgrounds/ts/test.tsx +14 -0
- package/playgrounds/ts/tsconfig.json +100 -0
- package/server/agents.md +9 -0
- package/server/package-lock.json +93 -0
- package/server/package.json +32 -0
- package/server/src/diff.ts +1079 -0
- package/server/src/eslint.ts +1471 -0
- package/server/src/eslintServer.ts +865 -0
- package/server/src/is.ts +18 -0
- package/server/src/languageDefaults.ts +40 -0
- package/server/src/linkedMap.ts +448 -0
- package/server/src/paths.ts +128 -0
- package/server/src/thenable.d.ts +5 -0
- package/server/tsconfig.json +21 -0
- package/server/webpack.config.js +25 -0
- package/shared.webpack.config.js +59 -0
- package/tsconfig.base.json +9 -0
- 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,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
|
+
});
|
package/contributing.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# VSCode ESLint
|
|
2
|
+
|
|
3
|
+
[](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`.
|