@stacksjs/defaults 0.75.62 → 0.75.64
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/app/Middleware/Throttle.ts +52 -13
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/ide/vscode/build.ts +0 -52
- package/ide/vscode/scripts/package.ts +0 -71
- package/ide/vscode/scripts/stx-contributes.ts +0 -78
- package/ide/vscode/scripts/ts-plugin.ts +0 -72
- package/ide/vscode/src/env-file.ts +0 -103
- package/ide/vscode/src/env.ts +0 -241
- package/ide/vscode/src/extension.ts +0 -163
- package/ide/vscode/src/pickier-protocol.ts +0 -51
- package/ide/vscode/src/pickier-worker.ts +0 -92
- package/ide/vscode/src/pickier.ts +0 -433
- package/ide/vscode/src/project.ts +0 -450
- package/ide/vscode/src/stacks.ts +0 -482
- package/ide/vscode/tests/build.test.ts +0 -82
- package/ide/vscode/tests/env.test.ts +0 -166
- package/ide/vscode/tests/extension.test.ts +0 -428
- package/ide/vscode/tests/fake-vscode.ts +0 -228
- package/ide/vscode/tests/manifest.test.ts +0 -141
- package/ide/vscode/tests/package.test.ts +0 -47
- package/ide/vscode/tests/pickier.test.ts +0 -202
- package/ide/vscode/tests/project.test.ts +0 -268
- package/ide/vscode/tests/ts-plugin-harness.ts +0 -39
- package/ide/vscode/tsconfig.json +0 -19
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pickier, built in: lint diagnostics, a formatter, `source.fixAll.pickier`
|
|
3
|
-
* and quick fixes, all from the project's own pickier and config - the same
|
|
4
|
-
* ones `./buddy lint` and `./buddy format` use.
|
|
5
|
-
*
|
|
6
|
-
* Pickier itself runs in a Bun process per project (./pickier-worker.ts), so
|
|
7
|
-
* this module only manages those processes and turns their answers into
|
|
8
|
-
* editor features. Everything it needs from the machine comes through
|
|
9
|
-
* `PickierHost`, so tests drive it with fakes.
|
|
10
|
-
*/
|
|
11
|
-
import type * as vscode from 'vscode'
|
|
12
|
-
import type { PickierIssue, PickierOperation, PickierReady, PickierRequest, PickierResponse, PickierResult } from './pickier-protocol'
|
|
13
|
-
import { join, relative, sep } from 'node:path'
|
|
14
|
-
import { isLintablePath } from '../../../../core/actions/src/lint/files'
|
|
15
|
-
|
|
16
|
-
type Vscode = typeof vscode
|
|
17
|
-
|
|
18
|
-
export interface PickierProcess {
|
|
19
|
-
write: (line: string) => void
|
|
20
|
-
onLine: (listener: (line: string) => void) => void
|
|
21
|
-
onExit: (listener: () => void) => void
|
|
22
|
-
kill: () => void
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface PickierHost {
|
|
26
|
-
exists: (path: string) => boolean
|
|
27
|
-
/** Start `bun <script>` in `cwd`; stdout is delivered line by line. */
|
|
28
|
-
spawnBun: (bun: string, script: string, cwd: string) => PickierProcess
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface PickierOptions {
|
|
32
|
-
/** Absolute path of dist/pickier-worker.js. */
|
|
33
|
-
workerPath: string
|
|
34
|
-
lintDelayMs?: number
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export const PICKIER_COMMANDS = {
|
|
38
|
-
fixAll: 'stacks.pickier.fixAll',
|
|
39
|
-
restart: 'stacks.pickier.restart',
|
|
40
|
-
} as const
|
|
41
|
-
|
|
42
|
-
/** The language ids of the files `buddy lint` covers (core/actions/src/lint/files.ts). */
|
|
43
|
-
export const PICKIER_LANGUAGES = ['typescript', 'javascript', 'json', 'jsonc', 'markdown', 'yaml'] as const
|
|
44
|
-
|
|
45
|
-
/** Comment syntax for `pickier-disable-next-line`, where the language has line comments. */
|
|
46
|
-
const LINE_COMMENT: Record<string, string> = { typescript: '//', javascript: '//', jsonc: '//' }
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* The Bun that runs pickier: the setting, then the project's pinned Bun
|
|
50
|
-
* (`pantry/.bin/bun`, the one `./buddy` itself runs on), then `bun` on the PATH.
|
|
51
|
-
*/
|
|
52
|
-
export function chooseBun(setting: string, root: string, exists: (path: string) => boolean): string {
|
|
53
|
-
if (setting.trim())
|
|
54
|
-
return setting.trim()
|
|
55
|
-
const pinned = join(root, 'pantry', '.bin', 'bun')
|
|
56
|
-
return exists(pinned) ? pinned : 'bun'
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** Whether saving this file changes the config a running pickier has loaded. */
|
|
60
|
-
export function isPickierConfigPath(path: string): boolean {
|
|
61
|
-
return /(?:^|[/\\])(?:pickier\.config|\.config[/\\]pickier|config[/\\]code-style)\.(?:[cm]?[jt]s|json)$/.test(path)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** The comment that silences `ruleId` on the line below, indented to match it. */
|
|
65
|
-
export function disableNextLineComment(lineText: string, ruleId: string, comment: string): string {
|
|
66
|
-
const indent = lineText.match(/^\s*/)?.[0] ?? ''
|
|
67
|
-
return `${indent}${comment} pickier-disable-next-line ${ruleId}\n`
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** Whether `buddy lint` would lint `file`, given the project it belongs to. */
|
|
71
|
-
export function isLintedFile(root: string, file: string): boolean {
|
|
72
|
-
const rel = relative(root, file)
|
|
73
|
-
if (!rel || rel.startsWith('..'))
|
|
74
|
-
return false
|
|
75
|
-
return isLintablePath(rel.split(sep).join('/'))
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** One pickier worker process, for one project root. */
|
|
79
|
-
export class PickierClient {
|
|
80
|
-
private process: PickierProcess | undefined
|
|
81
|
-
private nextId = 1
|
|
82
|
-
private pending = new Map<number, (response: PickierResponse | undefined) => void>()
|
|
83
|
-
private readyWaiters: Array<(ready: PickierReady | undefined) => void> = []
|
|
84
|
-
/** Set once the worker has said whether it found pickier. */
|
|
85
|
-
status: 'starting' | 'ready' | 'unavailable' = 'starting'
|
|
86
|
-
info: PickierReady | undefined
|
|
87
|
-
unavailableReason = ''
|
|
88
|
-
private exits = 0
|
|
89
|
-
|
|
90
|
-
constructor(
|
|
91
|
-
readonly root: string,
|
|
92
|
-
private readonly start: () => PickierProcess,
|
|
93
|
-
private readonly log: (message: string) => void,
|
|
94
|
-
) {}
|
|
95
|
-
|
|
96
|
-
private ensureProcess(): PickierProcess | undefined {
|
|
97
|
-
if (this.status === 'unavailable')
|
|
98
|
-
return undefined
|
|
99
|
-
if (this.process)
|
|
100
|
-
return this.process
|
|
101
|
-
|
|
102
|
-
const child = this.start()
|
|
103
|
-
this.process = child
|
|
104
|
-
this.status = 'starting'
|
|
105
|
-
|
|
106
|
-
child.onLine((line) => {
|
|
107
|
-
let message: any
|
|
108
|
-
try {
|
|
109
|
-
message = JSON.parse(line)
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if ('ready' in message) {
|
|
116
|
-
if (message.ready) {
|
|
117
|
-
this.status = 'ready'
|
|
118
|
-
this.info = message as PickierReady
|
|
119
|
-
this.log(`pickier ${this.info.version} ready for ${this.root}`)
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
this.status = 'unavailable'
|
|
123
|
-
this.unavailableReason = message.error
|
|
124
|
-
this.log(`pickier is not available in ${this.root}, so it is not linted: ${message.error}`)
|
|
125
|
-
}
|
|
126
|
-
for (const waiter of this.readyWaiters.splice(0))
|
|
127
|
-
waiter(this.info)
|
|
128
|
-
return
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const resolve = this.pending.get(message.id)
|
|
132
|
-
if (resolve) {
|
|
133
|
-
this.pending.delete(message.id)
|
|
134
|
-
resolve(message as PickierResponse)
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
child.onExit(() => {
|
|
139
|
-
if (this.process !== child)
|
|
140
|
-
return
|
|
141
|
-
this.process = undefined
|
|
142
|
-
for (const resolve of this.pending.values())
|
|
143
|
-
resolve(undefined)
|
|
144
|
-
this.pending.clear()
|
|
145
|
-
for (const waiter of this.readyWaiters.splice(0))
|
|
146
|
-
waiter(undefined)
|
|
147
|
-
|
|
148
|
-
// A worker that keeps dying (a broken Bun, a config that throws) would
|
|
149
|
-
// otherwise be restarted on every keystroke.
|
|
150
|
-
if (this.status !== 'unavailable' && ++this.exits >= 3) {
|
|
151
|
-
this.status = 'unavailable'
|
|
152
|
-
this.unavailableReason = 'the pickier process exited three times'
|
|
153
|
-
this.log(`pickier keeps exiting in ${this.root}; run "Stacks: Restart Pickier" after fixing it`)
|
|
154
|
-
}
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
return child
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private whenReady(): Promise<PickierReady | undefined> {
|
|
161
|
-
if (this.status === 'ready')
|
|
162
|
-
return Promise.resolve(this.info)
|
|
163
|
-
if (this.status === 'unavailable')
|
|
164
|
-
return Promise.resolve(undefined)
|
|
165
|
-
return new Promise(resolve => this.readyWaiters.push(resolve))
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
async request(op: PickierOperation, file: string, text: string): Promise<PickierResult | undefined> {
|
|
169
|
-
const child = this.ensureProcess()
|
|
170
|
-
if (!child || !(await this.whenReady()) || !this.process)
|
|
171
|
-
return undefined
|
|
172
|
-
|
|
173
|
-
const id = this.nextId++
|
|
174
|
-
const request: PickierRequest = { id, op, file, text }
|
|
175
|
-
const response = await new Promise<PickierResponse | undefined>((resolve) => {
|
|
176
|
-
this.pending.set(id, resolve)
|
|
177
|
-
this.process!.write(`${JSON.stringify(request)}\n`)
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
if (!response)
|
|
181
|
-
return undefined
|
|
182
|
-
if (!response.ok) {
|
|
183
|
-
this.log(`pickier could not ${op} ${file}: ${response.error}`)
|
|
184
|
-
return undefined
|
|
185
|
-
}
|
|
186
|
-
return response.result
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
dispose(): void {
|
|
190
|
-
const child = this.process
|
|
191
|
-
this.process = undefined
|
|
192
|
-
child?.kill()
|
|
193
|
-
for (const resolve of this.pending.values())
|
|
194
|
-
resolve(undefined)
|
|
195
|
-
this.pending.clear()
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export function createPickierSupport(api: Vscode, host: PickierHost, options: PickierOptions): {
|
|
200
|
-
activate: (context: { subscriptions: Array<{ dispose: () => unknown }> }) => void
|
|
201
|
-
deactivate: () => void
|
|
202
|
-
} {
|
|
203
|
-
const clients = new Map<string, PickierClient>()
|
|
204
|
-
const timers = new Map<string, ReturnType<typeof setTimeout>>()
|
|
205
|
-
const output = api.window.createOutputChannel('Stacks: Pickier')
|
|
206
|
-
const diagnostics = api.languages.createDiagnosticCollection('pickier')
|
|
207
|
-
const fixAllKind = api.CodeActionKind.SourceFixAll.append('pickier')
|
|
208
|
-
const settings = () => api.workspace.getConfiguration('stacks')
|
|
209
|
-
|
|
210
|
-
const enabled = () => settings().get<boolean>('pickier.enable', true)
|
|
211
|
-
|
|
212
|
-
function rootOf(document: vscode.TextDocument): string | undefined {
|
|
213
|
-
if (document.uri.scheme !== 'file')
|
|
214
|
-
return undefined
|
|
215
|
-
const folder = api.workspace.getWorkspaceFolder(document.uri)?.uri.fsPath
|
|
216
|
-
if (!folder || !(host.exists(join(folder, 'buddy')) || host.exists(join(folder, 'config', 'app.ts'))))
|
|
217
|
-
return undefined
|
|
218
|
-
return isLintedFile(folder, document.uri.fsPath) ? folder : undefined
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function client(root: string): PickierClient {
|
|
222
|
-
let existing = clients.get(root)
|
|
223
|
-
if (!existing) {
|
|
224
|
-
existing = new PickierClient(
|
|
225
|
-
root,
|
|
226
|
-
() => host.spawnBun(chooseBun(settings().get<string>('bunPath', ''), root, host.exists), options.workerPath, root),
|
|
227
|
-
message => output.appendLine(message),
|
|
228
|
-
)
|
|
229
|
-
clients.set(root, existing)
|
|
230
|
-
}
|
|
231
|
-
return existing
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async function run(document: vscode.TextDocument, op: PickierOperation): Promise<PickierResult | undefined> {
|
|
235
|
-
const root = enabled() ? rootOf(document) : undefined
|
|
236
|
-
if (!root)
|
|
237
|
-
return undefined
|
|
238
|
-
return client(root).request(op, document.uri.fsPath, document.getText())
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function toDiagnostic(document: vscode.TextDocument, issue: PickierIssue): vscode.Diagnostic {
|
|
242
|
-
const line = Math.min(Math.max(issue.line - 1, 0), Math.max(document.lineCount - 1, 0))
|
|
243
|
-
const start = new api.Position(line, Math.max(issue.column - 1, 0))
|
|
244
|
-
const range = document.getWordRangeAtPosition(start) ?? new api.Range(start, start.translate(0, 1))
|
|
245
|
-
const diagnostic = new api.Diagnostic(
|
|
246
|
-
range,
|
|
247
|
-
issue.help ? `${issue.message}\n${issue.help}` : issue.message,
|
|
248
|
-
issue.severity === 'error' ? api.DiagnosticSeverity.Error : api.DiagnosticSeverity.Warning,
|
|
249
|
-
)
|
|
250
|
-
diagnostic.source = 'pickier'
|
|
251
|
-
diagnostic.code = issue.ruleId
|
|
252
|
-
return diagnostic
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
async function lint(document: vscode.TextDocument): Promise<void> {
|
|
256
|
-
const version = document.version
|
|
257
|
-
const result = await run(document, 'lint')
|
|
258
|
-
if (document.isClosed || document.version !== version)
|
|
259
|
-
return
|
|
260
|
-
if (!result || result.op !== 'lint') {
|
|
261
|
-
diagnostics.delete(document.uri)
|
|
262
|
-
return
|
|
263
|
-
}
|
|
264
|
-
diagnostics.set(document.uri, result.issues.map(issue => toDiagnostic(document, issue)))
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function scheduleLint(document: vscode.TextDocument, delay = options.lintDelayMs ?? 300): void {
|
|
268
|
-
const key = document.uri.toString()
|
|
269
|
-
clearTimeout(timers.get(key))
|
|
270
|
-
timers.set(key, setTimeout(() => {
|
|
271
|
-
timers.delete(key)
|
|
272
|
-
void lint(document)
|
|
273
|
-
}, delay))
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function wholeDocument(document: vscode.TextDocument): vscode.Range {
|
|
277
|
-
return new api.Range(new api.Position(0, 0), document.lineAt(Math.max(document.lineCount - 1, 0)).range.end)
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
async function fixedText(document: vscode.TextDocument): Promise<string | undefined> {
|
|
281
|
-
const result = await run(document, 'fix')
|
|
282
|
-
if (!result || result.op === 'lint' || result.text === null || result.text === document.getText())
|
|
283
|
-
return undefined
|
|
284
|
-
return result.text
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
async function fixAllEdit(document: vscode.TextDocument): Promise<vscode.WorkspaceEdit | undefined> {
|
|
288
|
-
const text = await fixedText(document)
|
|
289
|
-
if (text === undefined)
|
|
290
|
-
return undefined
|
|
291
|
-
const edit = new api.WorkspaceEdit()
|
|
292
|
-
edit.replace(document.uri, wholeDocument(document), text)
|
|
293
|
-
return edit
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function relintOpenDocuments(): void {
|
|
297
|
-
diagnostics.clear()
|
|
298
|
-
for (const document of api.workspace.textDocuments)
|
|
299
|
-
scheduleLint(document, 0)
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function stopClients(root?: string): void {
|
|
303
|
-
for (const [key, existing] of clients) {
|
|
304
|
-
if (root && key !== root)
|
|
305
|
-
continue
|
|
306
|
-
existing.dispose()
|
|
307
|
-
clients.delete(key)
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function restart(root?: string): void {
|
|
312
|
-
stopClients(root)
|
|
313
|
-
relintOpenDocuments()
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function stop(): void {
|
|
317
|
-
for (const timer of timers.values())
|
|
318
|
-
clearTimeout(timer)
|
|
319
|
-
timers.clear()
|
|
320
|
-
stopClients()
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const codeActions: vscode.CodeActionProvider = {
|
|
324
|
-
async provideCodeActions(document, range, context) {
|
|
325
|
-
const actions: vscode.CodeAction[] = []
|
|
326
|
-
const only = context.only
|
|
327
|
-
|
|
328
|
-
if (only && (only.contains(fixAllKind) || fixAllKind.contains(only))) {
|
|
329
|
-
const edit = await fixAllEdit(document)
|
|
330
|
-
if (edit) {
|
|
331
|
-
const action = new api.CodeAction('Fix all pickier problems', fixAllKind)
|
|
332
|
-
action.edit = edit
|
|
333
|
-
actions.push(action)
|
|
334
|
-
}
|
|
335
|
-
return actions
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (only && !only.contains(api.CodeActionKind.QuickFix))
|
|
339
|
-
return actions
|
|
340
|
-
|
|
341
|
-
const ours = context.diagnostics.filter(diagnostic => diagnostic.source === 'pickier')
|
|
342
|
-
if (!ours.length)
|
|
343
|
-
return actions
|
|
344
|
-
|
|
345
|
-
const edit = await fixAllEdit(document)
|
|
346
|
-
if (edit) {
|
|
347
|
-
const action = new api.CodeAction('Fix all pickier problems', api.CodeActionKind.QuickFix)
|
|
348
|
-
action.edit = edit
|
|
349
|
-
action.diagnostics = ours
|
|
350
|
-
actions.push(action)
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
const comment = LINE_COMMENT[document.languageId]
|
|
354
|
-
if (comment) {
|
|
355
|
-
for (const diagnostic of ours) {
|
|
356
|
-
const ruleId = String(diagnostic.code ?? '')
|
|
357
|
-
if (!ruleId)
|
|
358
|
-
continue
|
|
359
|
-
const line = document.lineAt(diagnostic.range.start.line)
|
|
360
|
-
const disable = new api.CodeAction(`Disable ${ruleId} for this line`, api.CodeActionKind.QuickFix)
|
|
361
|
-
disable.edit = new api.WorkspaceEdit()
|
|
362
|
-
disable.edit.insert(document.uri, new api.Position(line.lineNumber, 0), disableNextLineComment(line.text, ruleId, comment))
|
|
363
|
-
disable.diagnostics = [diagnostic]
|
|
364
|
-
actions.push(disable)
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
return actions
|
|
369
|
-
},
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
const formatter: vscode.DocumentFormattingEditProvider = {
|
|
373
|
-
async provideDocumentFormattingEdits(document) {
|
|
374
|
-
const result = await run(document, 'format')
|
|
375
|
-
if (!result || result.op === 'lint' || result.text === null || result.text === document.getText())
|
|
376
|
-
return []
|
|
377
|
-
return [api.TextEdit.replace(wholeDocument(document), result.text)]
|
|
378
|
-
},
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return {
|
|
382
|
-
activate(context) {
|
|
383
|
-
const selector = PICKIER_LANGUAGES.map(language => ({ language, scheme: 'file' }))
|
|
384
|
-
|
|
385
|
-
context.subscriptions.push(
|
|
386
|
-
output,
|
|
387
|
-
diagnostics,
|
|
388
|
-
api.languages.registerCodeActionsProvider(selector, codeActions, {
|
|
389
|
-
providedCodeActionKinds: [fixAllKind, api.CodeActionKind.QuickFix],
|
|
390
|
-
}),
|
|
391
|
-
api.languages.registerDocumentFormattingEditProvider(selector, formatter),
|
|
392
|
-
api.commands.registerCommand(PICKIER_COMMANDS.fixAll, async () => {
|
|
393
|
-
const document = api.window.activeTextEditor?.document
|
|
394
|
-
if (!document)
|
|
395
|
-
return
|
|
396
|
-
const edit = await fixAllEdit(document)
|
|
397
|
-
if (edit)
|
|
398
|
-
await api.workspace.applyEdit(edit)
|
|
399
|
-
else
|
|
400
|
-
void api.window.showInformationMessage('Stacks: pickier has nothing to fix in this file.')
|
|
401
|
-
}),
|
|
402
|
-
api.commands.registerCommand(PICKIER_COMMANDS.restart, () => restart()),
|
|
403
|
-
api.workspace.onDidOpenTextDocument(document => scheduleLint(document, 0)),
|
|
404
|
-
api.workspace.onDidChangeTextDocument((event) => {
|
|
405
|
-
if (settings().get<string>('pickier.run', 'onType') === 'onType')
|
|
406
|
-
scheduleLint(event.document)
|
|
407
|
-
}),
|
|
408
|
-
api.workspace.onDidSaveTextDocument((document) => {
|
|
409
|
-
if (isPickierConfigPath(document.uri.fsPath)) {
|
|
410
|
-
const folder = api.workspace.getWorkspaceFolder(document.uri)?.uri.fsPath
|
|
411
|
-
restart(folder)
|
|
412
|
-
return
|
|
413
|
-
}
|
|
414
|
-
scheduleLint(document, 0)
|
|
415
|
-
}),
|
|
416
|
-
api.workspace.onDidCloseTextDocument((document) => {
|
|
417
|
-
clearTimeout(timers.get(document.uri.toString()))
|
|
418
|
-
diagnostics.delete(document.uri)
|
|
419
|
-
}),
|
|
420
|
-
api.workspace.onDidChangeConfiguration((event) => {
|
|
421
|
-
if (event.affectsConfiguration('stacks.pickier') || event.affectsConfiguration('stacks.bunPath'))
|
|
422
|
-
restart()
|
|
423
|
-
}),
|
|
424
|
-
{ dispose: stop },
|
|
425
|
-
)
|
|
426
|
-
|
|
427
|
-
for (const document of api.workspace.textDocuments)
|
|
428
|
-
scheduleLint(document, 0)
|
|
429
|
-
},
|
|
430
|
-
|
|
431
|
-
deactivate: stop,
|
|
432
|
-
}
|
|
433
|
-
}
|