Skip to content

Commit b2ed1ff

Browse files
authored
Eslint improvements. (#18086)
* Adding eslint cache to ignore * Fixing eslint config * Fixing gulp task to use eslint cache * Updating packages and adding stylistic for missing semi rule * linting some files * Making localization and precommit run parallely * fixing code linting
1 parent b60e0df commit b2ed1ff

File tree

11 files changed

+332
-120
lines changed

11 files changed

+332
-120
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ package.nls.*.json
2929
webviews-metafile.json
3030
# Ignore all l10n files except the default one (bundle.l10n.json)
3131
/localization/l10n/bundle.l10n.*.json
32+
.eslintcache

.husky/pre-commit

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
yarn lint
2-
yarn localization
1+
yarn precommit

build/templates/build.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ steps:
3737
env:
3838
BUILDMACHINE: true
3939

40-
- task: gulp@1
40+
- pwsh: |
41+
yarn lint
4142
displayName: Lint code
42-
inputs:
43-
targets: lint
44-
gulpFile: ${{ parameters.gulpfile }}
43+
workingDirectory: "$(Build.SourcesDirectory)"
44+
4545
4646
- task: gulp@1
4747
displayName: Run tests and compute coverage

eslint.config.mjs

+21-11
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,28 @@ import deprecationPlugin from "eslint-plugin-deprecation";
77
import { fixupPluginRules } from "@eslint/compat";
88
import reactRecommended from "eslint-plugin-react/configs/recommended.js";
99
import react from "eslint-plugin-react";
10-
import jsxA11y from "eslint-plugin-jsx-a11y";
1110
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
11+
import { includeIgnoreFile } from "@eslint/compat";
12+
import path from "node:path";
13+
import { fileURLToPath } from "node:url";
14+
15+
const __filename = fileURLToPath(import.meta.url);
16+
const __dirname = path.dirname(__filename);
17+
const gitignorePath = path.resolve(__dirname, ".gitignore");
18+
import stylistic from '@stylistic/eslint-plugin'
1219

1320
export default [
1421
{
15-
files: ["**/*.ts", "**/*.tsx"],
22+
ignores: ["out/**/*"],
23+
},
24+
{
25+
files: ["src/**/*.ts", "src/**/*.tsx", "test/**/*.ts"],
1626
ignores: [
17-
"src/prompts/**/*.ts",
18-
"**/*.d.ts",
19-
"src/reactviews/pages/ExecutionPlan/**/*",
20-
], // Ignore prompts files as they are copied from other repos
27+
...(includeIgnoreFile(gitignorePath).ignores) || [],
28+
"src/views/**/*",
29+
"src/prompts/**/*.ts", // Ignore prompts files as they are copied from other repos
30+
"**/out/**/*",
31+
],
2132
languageOptions: {
2233
...reactRecommended.languageOptions,
2334
ecmaVersion: "latest",
@@ -37,8 +48,8 @@ export default [
3748
// @ts-ignore
3849
["deprecation"]: fixupPluginRules(deprecationPlugin),
3950
react,
40-
"jsx-a11y": jsxA11y,
41-
...eslintPluginPrettierRecommended.plugins
51+
...eslintPluginPrettierRecommended.plugins,
52+
'@stylistic': stylistic
4253
},
4354
settings: {
4455
react: {
@@ -128,10 +139,9 @@ export default [
128139
leadingUnderscore: "require",
129140
},
130141
],
131-
"@typescript-eslint/semi": "warn",
132-
//...jsxA11y.flatConfigs.recommended.rules,
142+
"@stylistic/semi": "warn",
133143
"prettier/prettier": [
134-
"warn",
144+
"error",
135145
{
136146
endOfLine: "auto",
137147
},

gulpfile.js

-20
Original file line numberDiff line numberDiff line change
@@ -70,24 +70,6 @@ const cssLoaderPlugin = {
7070
},
7171
};
7272

73-
gulp.task('ext:lint', () => {
74-
const fix = (argv.fix === undefined) ? false : true;
75-
return gulp.src([
76-
'./src/**/*.ts',
77-
'./src/**/*.tsx',
78-
'./test/**/*.ts',
79-
'!**/*.d.ts',
80-
'!./src/views/htmlcontent/**/*'
81-
])
82-
.pipe(gulpESLintNew({
83-
quiet: true,
84-
fix: fix
85-
}))
86-
.pipe(gulpESLintNew.format()) // Output lint results to the console.
87-
.pipe(gulpESLintNew.failAfterError())
88-
.pipe(gulpESLintNew.fix());
89-
});
90-
9173
// Copy icons for OE
9274
gulp.task('ext:copy-OE-assets', (done) => {
9375
return gulp.src([
@@ -447,6 +429,4 @@ gulp.task('watch-reactviews', function () {
447429
// Do a full build first so we have the latest compiled files before we start watching for more changes
448430
gulp.task('watch', gulp.series('build', gulp.parallel('watch-src', 'watch-tests', 'watch-reactviews')));
449431

450-
gulp.task('lint', gulp.series('ext:lint'));
451-
452432
gulp.task('cover', gulp.series('remap-coverage', 'cover:combine-json'));

package.json

+22-18
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,13 @@
5353
"build": "gulp build",
5454
"compile": "gulp ext:compile",
5555
"watch": "gulp watch",
56-
"lint": "gulp lint",
56+
"lint": "eslint --quiet --cache",
5757
"localization": "gulp ext:extract-localization-strings",
5858
"smoketest": "gulp ext:smoke",
5959
"test": "gulp test:cover --log",
6060
"package": "vsce package",
61-
"prepare": "husky"
61+
"prepare": "husky",
62+
"precommit": "run-p lint localization"
6263
},
6364
"devDependencies": {
6465
"@angular/common": "~2.1.2",
@@ -76,6 +77,7 @@
7677
"@jgoz/esbuild-plugin-typecheck": "^4.0.0",
7778
"@monaco-editor/react": "^4.6.0",
7879
"@playwright/test": "^1.45.0",
80+
"@stylistic/eslint-plugin": "^2.8.0",
7981
"@types/azdata": "^1.46.6",
8082
"@types/ejs": "^3.1.0",
8183
"@types/eslint__js": "^8.42.3",
@@ -94,6 +96,8 @@
9496
"@types/underscore": "1.8.3",
9597
"@types/vscode": "1.83.1",
9698
"@types/vscode-webview": "^1.57.5",
99+
"@typescript-eslint/eslint-plugin": "^8.7.0",
100+
"@typescript-eslint/parser": "^8.7.0",
97101
"@vscode/l10n": "^0.0.18",
98102
"@vscode/l10n-dev": "^0.0.35",
99103
"@vscode/test-electron": "^2.3.9",
@@ -109,7 +113,7 @@
109113
"del": "^2.2.1",
110114
"esbuild": "^0.22.0",
111115
"esbuild-plugin-copy": "^2.1.1",
112-
"eslint": "^9.5.0",
116+
"eslint": "^9.11.1",
113117
"eslint-config-prettier": "^9.1.0",
114118
"eslint-plugin-deprecation": "^3.0.0",
115119
"eslint-plugin-jsdoc": "^50.2.2",
@@ -147,7 +151,7 @@
147151
"systemjs-plugin-json": "^0.2.0",
148152
"typemoq": "^1.7.0",
149153
"typescript": "^5.6.2",
150-
"typescript-eslint": "^7.13.1",
154+
"typescript-eslint": "^8.7.0",
151155
"uglify-js": "mishoo/UglifyJS2#harmony-v2.8.22",
152156
"vscode-nls-dev": "2.0.1",
153157
"xliff": "^6.2.1",
@@ -205,23 +209,23 @@
205209
"icon": "media/server_page_dark.svg"
206210
}
207211
],
208-
"panel": [
209-
{
210-
"id": "queryResult",
211-
"title": "Query Result",
212-
"icon": "media/SignIn.svg"
213-
}
214-
]
212+
"panel": [
213+
{
214+
"id": "queryResult",
215+
"title": "Query Result",
216+
"icon": "media/SignIn.svg"
217+
}
218+
]
215219
},
216220
"views": {
217-
"queryResult": [
218-
{
219-
"type": "webview",
220-
"id": "queryResult",
221-
"name": "%extension.queryResult%",
221+
"queryResult": [
222+
{
223+
"type": "webview",
224+
"id": "queryResult",
225+
"name": "%extension.queryResult%",
222226
"when": "config.mssql.enableNewQueryResultFeature"
223-
}
224-
],
227+
}
228+
],
225229
"objectExplorer": [
226230
{
227231
"id": "objectExplorer",

src/connectionconfig/connectionDialogWebviewController.ts

+54-20
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ import {
2626
import { ConnectionOption } from "azdata";
2727
import { Logger } from "../models/logger";
2828
import VscodeWrapper from "../controllers/vscodeWrapper";
29-
import { ConnectionDialog as Loc, refreshTokenLabel } from "../constants/locConstants";
29+
import {
30+
ConnectionDialog as Loc,
31+
refreshTokenLabel,
32+
} from "../constants/locConstants";
3033
import {
3134
FormItemSpec,
3235
FormItemActionButton,
@@ -38,7 +41,10 @@ import {
3841
AzureSubscription,
3942
VSCodeAzureSubscriptionProvider,
4043
} from "@microsoft/vscode-azext-azureauth";
41-
import { GenericResourceExpanded, ResourceManagementClient } from "@azure/arm-resources";
44+
import {
45+
GenericResourceExpanded,
46+
ResourceManagementClient,
47+
} from "@azure/arm-resources";
4248
import { getErrorMessage, listAllIterator } from "../utils/utils";
4349
import { l10n } from "vscode";
4450

@@ -179,7 +185,10 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
179185
);
180186
this.state.connectionProfile = connection;
181187

182-
this.state.selectedInputMode = (connection.connectionString && connection.server === undefined) ? ConnectionInputMode.ConnectionString : ConnectionInputMode.Parameters;
188+
this.state.selectedInputMode =
189+
connection.connectionString && connection.server === undefined
190+
? ConnectionInputMode.ConnectionString
191+
: ConnectionInputMode.Parameters;
183192
this.state = this.state;
184193
}
185194
}
@@ -442,8 +451,7 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
442451
) {
443452
return {
444453
isValid: false,
445-
validationMessage:
446-
Loc.azureAccountIsRequired,
454+
validationMessage: Loc.azureAccountIsRequired,
447455
};
448456
}
449457
return {
@@ -470,8 +478,7 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
470478
) {
471479
return {
472480
isValid: false,
473-
validationMessage:
474-
Loc.tenantIdIsRequired,
481+
validationMessage: Loc.tenantIdIsRequired,
475482
};
476483
}
477484
return {
@@ -495,8 +502,7 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
495502
) {
496503
return {
497504
isValid: false,
498-
validationMessage:
499-
Loc.connectionStringIsRequired,
505+
validationMessage: Loc.connectionStringIsRequired,
500506
};
501507
}
502508
return {
@@ -947,26 +953,40 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
947953
// getSubscriptions() below checks this config setting if filtering is specified. If the user has this set, then we use it; if not, we get all subscriptions.
948954
// we can't controll which config setting it uses, but the Azure Resources extension (ms-azuretools.vscode-azureresourcegroups) sets this config setting,
949955
// so that's the easiest way for a user to control their subscription filters.
950-
const shouldUseFilter = vscode.workspace.getConfiguration().get<string[] | undefined>('azureResourceGroups.selectedSubscriptions') !== undefined;
956+
const shouldUseFilter =
957+
vscode.workspace
958+
.getConfiguration()
959+
.get<
960+
string[] | undefined
961+
>("azureResourceGroups.selectedSubscriptions") !==
962+
undefined;
951963

952964
const tenantSubMap = this.groupBy(
953965
await auth.getSubscriptions(shouldUseFilter),
954966
"tenantId",
955967
); // TODO: replace with Object.groupBy once ES2024 is supported
956968

957969
if (tenantSubMap.size === 0) {
958-
state.formError = l10n.t("No subscriptions set in VS Code's Azure account filter.");
970+
state.formError = l10n.t(
971+
"No subscriptions set in VS Code's Azure account filter.",
972+
);
959973
} else {
960974
for (const t of tenantSubMap.keys()) {
961975
for (const s of tenantSubMap.get(t)) {
962976
try {
963977
const servers = await this.getAzureServers(s);
964978
state.azureDatabases.push(...servers);
965979
this.state = state; // update state mid-reducer so the UI is more responsive
966-
}
967-
catch (error) {
968-
vscode.window.showErrorMessage(Loc.errorLoadingAzureDatabases(s.name, s.subscriptionId));
969-
console.error(state.formError + "\n" + getErrorMessage(error));
980+
} catch (error) {
981+
vscode.window.showErrorMessage(
982+
Loc.errorLoadingAzureDatabases(
983+
s.name,
984+
s.subscriptionId,
985+
),
986+
);
987+
console.error(
988+
state.formError + "\n" + getErrorMessage(error),
989+
);
970990
}
971991
}
972992
}
@@ -1013,23 +1033,34 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
10131033
server: server.name,
10141034
databases: [],
10151035
location: server.location,
1016-
resourceGroup: this.extractFromResourceId(server.id, "resourceGroups"),
1036+
resourceGroup: this.extractFromResourceId(
1037+
server.id,
1038+
"resourceGroups",
1039+
),
10171040
subscription: `${sub.name} (${sub.subscriptionId})`,
10181041
});
10191042
}
10201043

10211044
for (const database of await databasesPromise) {
1022-
const serverName = this.extractFromResourceId(database.id, "servers");
1045+
const serverName = this.extractFromResourceId(
1046+
database.id,
1047+
"servers",
1048+
);
10231049
const server = result.find((s) => s.server === serverName);
10241050
if (server) {
1025-
server.databases.push(database.name.substring(serverName.length + 1)); // database.name is in the form 'serverName/databaseName', so we need to remove the server name and slash
1051+
server.databases.push(
1052+
database.name.substring(serverName.length + 1),
1053+
); // database.name is in the form 'serverName/databaseName', so we need to remove the server name and slash
10261054
}
10271055
}
10281056

10291057
return result;
10301058
}
10311059

1032-
private extractFromResourceId(resourceId: string, property: string): string | undefined {
1060+
private extractFromResourceId(
1061+
resourceId: string,
1062+
property: string,
1063+
): string | undefined {
10331064
if (!property.endsWith("/")) {
10341065
property += "/";
10351066
}
@@ -1042,6 +1073,9 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
10421073
startIndex += property.length;
10431074
}
10441075

1045-
return resourceId.substring(startIndex, resourceId.indexOf("/", startIndex));
1076+
return resourceId.substring(
1077+
startIndex,
1078+
resourceId.indexOf("/", startIndex),
1079+
);
10461080
}
10471081
}

0 commit comments

Comments
 (0)