|
1 | | -import semverGt from "semver/functions/gt" |
2 | 1 | import vscode from "vscode" |
3 | | -import { fetchPackage, parsePackage } from "./utils/packages" |
| 2 | +import { fetchPackage } from "./utils/packages" |
| 3 | +import { parseDependency } from "./utils/parseDependency" |
| 4 | +import { DIAGNOSTIC_CODE } from "./utils/vars" |
4 | 5 |
|
5 | 6 | export class PackageJsonCodeActionProvider |
6 | 7 | implements vscode.CodeActionProvider { |
7 | | - public async provideCodeActions( |
8 | | - document: vscode.TextDocument, |
9 | | - range: vscode.Range | vscode.Selection, |
10 | | - context: vscode.CodeActionContext |
11 | | - ): Promise<(vscode.Command | vscode.CodeAction)[]> { |
12 | | - const line = document.lineAt(range.start.line) |
13 | | - const localInfo = parsePackage(line.text) |
14 | | - const registryInfo = localInfo.name |
15 | | - ? await fetchPackage(localInfo.name) |
16 | | - : undefined |
17 | | - |
18 | | - if (localInfo?.version && registryInfo?.version) { |
19 | | - const outdated = semverGt(registryInfo.version, localInfo.version) |
20 | | - console.log(localInfo.name, outdated) |
21 | | - // return vscode.commands.executeCommand("workbench.action") |
| 8 | + provideCodeActions( |
| 9 | + doc: vscode.TextDocument, |
| 10 | + range: vscode.Range, |
| 11 | + ctx: vscode.CodeActionContext |
| 12 | + ): Promise<vscode.CodeAction[]> { |
| 13 | + // TODO: Add a single command to update all the packages |
| 14 | + if (!range.isSingleLine) { |
| 15 | + return Promise.resolve([]) |
22 | 16 | } |
23 | 17 |
|
24 | | - // const actions = context.diagnostics.map((error) => { |
25 | | - // return { |
26 | | - // diagnostics: [error], |
27 | | - // edit: { |
28 | | - // edits: [ |
29 | | - // { |
30 | | - // edits: [ |
31 | | - // { |
32 | | - // range: error, |
33 | | - // text: "This text replaces the text with the error", |
34 | | - // }, |
35 | | - // ], |
36 | | - // resource: document.uri, |
37 | | - // }, |
38 | | - // ], |
39 | | - // }, |
40 | | - // isPreferred: true, |
41 | | - // kind: "quickfix", |
42 | | - // title: `Example quick fix`, |
43 | | - // } |
44 | | - // }) |
45 | | - |
46 | | - // return { |
47 | | - // actions, |
48 | | - // dispose() {}, |
49 | | - // } |
| 18 | + // For each diagnostic entry that has the matching `code`, |
| 19 | + // create a code action command. |
| 20 | + const promises = ctx.diagnostics |
| 21 | + .filter((diagnostic) => diagnostic.code === DIAGNOSTIC_CODE) |
| 22 | + .map((diagnostic) => this.createCommandCodeAction(doc, diagnostic)) |
| 23 | + |
| 24 | + return Promise.all(promises) |
| 25 | + } |
| 26 | + |
| 27 | + private async createCommandCodeAction( |
| 28 | + doc: vscode.TextDocument, |
| 29 | + diagnostic: vscode.Diagnostic |
| 30 | + ) { |
| 31 | + const action = new vscode.CodeAction( |
| 32 | + "Update package to latest version", |
| 33 | + vscode.CodeActionKind.QuickFix |
| 34 | + ) |
| 35 | + |
| 36 | + action.edit = await this.createEdit(doc, diagnostic.range) |
| 37 | + action.diagnostics = [diagnostic] |
| 38 | + action.isPreferred = true |
| 39 | + |
| 40 | + return action |
| 41 | + } |
| 42 | + |
| 43 | + private async createEdit(doc: vscode.TextDocument, range: vscode.Range) { |
| 44 | + const edit = new vscode.WorkspaceEdit() |
| 45 | + |
| 46 | + // Get the latest version from the registry |
| 47 | + const line = doc.lineAt(range.start.line) |
| 48 | + const { name, version } = parseDependency(line.text) |
| 49 | + |
| 50 | + // This check shouldn't be necessary, but the types are overly strong |
| 51 | + // so this is an extra safety check |
| 52 | + if (name && version) { |
| 53 | + // Keep the existing version prefix if it exists. |
| 54 | + const prefix = ["~", "^"].includes(version[0]) ? version[0] : "" |
| 55 | + const info = await fetchPackage(name) |
| 56 | + |
| 57 | + if (info) { |
| 58 | + edit.replace(doc.uri, range, prefix + info.version) |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + return edit |
50 | 63 | } |
51 | 64 | } |
0 commit comments