Skip to content

Commit 2fac4fc

Browse files
committed
feat: add a warning when multiple config files found
Closes #299
1 parent 9d9c693 commit 2fac4fc

File tree

5 files changed

+68
-6
lines changed

5 files changed

+68
-6
lines changed

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@
7171
"type": "string",
7272
"scope": "window"
7373
},
74+
"vitest.disableWorkspaceNotification": {
75+
"description": "Disable workspace notification.",
76+
"type": "boolean",
77+
"default": false,
78+
"scope": "window"
79+
},
7480
"vitest.debugExclude": {
7581
"markdownDescription": "Automatically skip files covered by these glob patterns. \nDefault: `[\"<node_internals>/**\", \"**/node_modules/**\"]`",
7682
"type": "array",

src/api.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ChildProcess } from 'node:child_process'
22
import { fork } from 'node:child_process'
33
import { gte } from 'semver'
4-
import { dirname, normalize } from 'pathe'
4+
import { basename, dirname, normalize } from 'pathe'
55
import * as vscode from 'vscode'
66
import { log } from './log'
77
import { configGlob, minimumVersion, workerPath, workspaceGlob } from './constants'
@@ -79,7 +79,10 @@ export class VitestAPI {
7979

8080
async dispose() {
8181
this.forEach(api => api.dispose())
82-
await this.meta.rpc.close()
82+
try {
83+
await this.meta.rpc.close()
84+
}
85+
catch {}
8386
this.meta.process.kill()
8487
}
8588
}
@@ -166,7 +169,7 @@ function nonNullable<T>(value: T | null | undefined): value is T {
166169
return value != null
167170
}
168171

169-
interface VitestMeta {
172+
export interface VitestMeta {
170173
folder: vscode.WorkspaceFolder
171174
vitestNodePath: string
172175
// path to a config file or a workspace config file
@@ -184,7 +187,7 @@ function resolveVitestConfig(showWarning: boolean, configOrWorkspaceFile: vscode
184187

185188
if (!vitest) {
186189
if (showWarning)
187-
vscode.window.showWarningMessage('Vitest not found. Please run `npm i --save-dev vitest` to install Vitest.')
190+
vscode.window.showWarningMessage(`Vitest not found in "${basename(dirname(configOrWorkspaceFile.fsPath))}" folder. Please run \`npm i --save-dev vitest\` to install Vitest.'`)
188191
log.error('[API]', `Vitest not found for ${configOrWorkspaceFile}.`)
189192
return null
190193
}

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@ export function getConfig(workspaceFolder?: WorkspaceFolder | vscode.Uri | strin
3535
debugExclude: get<string[]>('debugExclude', []),
3636
packagePath: get<string | undefined>('packagePath'),
3737
nodeExecutable: get<string | undefined>('nodeExecutable'),
38+
disableWorkspaceNotification: get<boolean>('disableWorkspaceNotification', false),
3839
}
3940
}

src/extension.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { sep } from 'node:path'
22
import * as vscode from 'vscode'
33
import { basename, dirname } from 'pathe'
4-
import { testControllerId } from './config'
4+
import { getConfig, testControllerId } from './config'
55
import type { VitestAPI } from './api'
66
import { resolveVitestAPI, resolveVitestPackages } from './api'
77
import { TestRunner } from './runner/runner'
88
import { TestTree } from './testTree'
99
import { configGlob, workspaceGlob } from './constants'
1010
import { log } from './log'
11+
import { createVitestWorkspaceFile, noop } from './utils'
1112

1213
export async function activate(context: vscode.ExtensionContext) {
1314
const extension = new VitestExtension()
@@ -52,6 +53,26 @@ class VitestExtension {
5253
return
5354
}
5455

56+
const configFiles = vitest.filter(x => x.configFile)
57+
58+
if (configFiles.length > 3 && getConfig().disableWorkspaceNotification !== true) {
59+
vscode.window.showWarningMessage(
60+
`Vitest found ${configFiles.length} config files. For better performance, consider using a workspace configuration.`,
61+
'Create vitest.workspace.js',
62+
'Disable notification',
63+
).then((result) => {
64+
if (!result)
65+
return
66+
if (result === 'Create vitest.workspace.js')
67+
createVitestWorkspaceFile(configFiles).catch(noop)
68+
69+
if (result === 'Disable notification') {
70+
const rootConfig = vscode.workspace.getConfiguration('vitest')
71+
rootConfig.update('disableWorkspaceNotification', true)
72+
}
73+
})
74+
}
75+
5576
const folders = new Set(vitest.map(x => x.folder))
5677
this.testTree.reset(Array.from(folders))
5778

@@ -128,7 +149,7 @@ class VitestExtension {
128149
this.disposables = [
129150
vscode.workspace.onDidChangeWorkspaceFolders(() => this.defineTestProfiles(false)),
130151
vscode.workspace.onDidChangeConfiguration((event) => {
131-
if (event.affectsConfiguration('vitest'))
152+
if (event.affectsConfiguration('vitest.packagePath') || event.affectsConfiguration('vitest.nodeExecutable'))
132153
this.defineTestProfiles(false)
133154
}),
134155
]

src/utils.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import * as vscode from 'vscode'
2+
import { relative } from 'pathe'
3+
import type { VitestMeta } from './api'
4+
5+
export function noop() {}
6+
7+
export async function createVitestWorkspaceFile(vitest: VitestMeta[]) {
8+
const folders = new Set(vitest.map(x => x.folder))
9+
const encoder = new TextEncoder()
10+
const promises = [...folders].map(async (folder) => {
11+
const workspaceFileUri = vscode.Uri.joinPath(folder.uri, 'vitest.workspace.js')
12+
const configFiles = vitest.filter(x => x.folder === folder).map(x => relative(folder.uri.fsPath, x.configFile!))
13+
14+
const workspaceContent = `
15+
import { defineWorkspace } from 'vitest/config'
16+
17+
export default defineWorkspace([
18+
${configFiles.map(file => `"./${file}"`).join(',\n ')}
19+
])
20+
`.trimStart()
21+
22+
await vscode.workspace.fs.writeFile(workspaceFileUri, encoder.encode(workspaceContent))
23+
return await vscode.workspace.openTextDocument(workspaceFileUri)
24+
})
25+
26+
const results = await Promise.all(promises)
27+
if (results[0])
28+
await vscode.window.showTextDocument(results[0])
29+
30+
await vscode.window.showInformationMessage('Created vitest.workspace.js. You might need to run \`npm i --save-dev vitest\` in the root folder to install Vitest.')
31+
}

0 commit comments

Comments
 (0)