Skip to content

Commit b9887ba

Browse files
committed
update
1 parent 711cfb0 commit b9887ba

File tree

4 files changed

+184
-102
lines changed

4 files changed

+184
-102
lines changed

README.md

+15
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ console.log("concat Array", M.concat([1, 2], [2, 3]));
139139

140140
- `deno.unstable` - If Deno's unstable mode is enabled. Default is `false`
141141

142+
- `deno.lint` - If Deno's lint is enabled. `deno.unstable = true` is required. Default is `false`
143+
142144
We recommend that you do not set global configuration. It should be configured in `.vscode/settings.json` in the project directory:
143145

144146
```json5
@@ -164,6 +166,19 @@ This extension also provides Deno's formatting tools, settings are in `.vscode/s
164166
}
165167
```
166168

169+
This extension also provides Deno's lint tools, settings are in `.vscode/settings.json`:
170+
171+
NOTE: Since Lint is still an experimental feature, So you need to set `deno.unstable = true`. And this function may change in the future.
172+
173+
```json5
174+
// .vscode/settings.json
175+
{
176+
"deno.enable": true,
177+
"deno.unstable": true,
178+
"deno.lint": true,
179+
}
180+
```
181+
167182
## Contribute
168183

169184
Follow these steps to contribute, the community needs your strength.

client/src/extension.ts

+53-15
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
TextDocument,
2121
languages,
2222
env,
23+
Position,
2324
} from "vscode";
2425
import {
2526
LanguageClient,
@@ -356,29 +357,39 @@ Executable ${this.denoInfo.executablePath}`;
356357
[command: string]: (
357358
editor: TextEditor,
358359
text: string,
359-
range: Range
360+
range: Range,
361+
...args: unknown[]
360362
) => void | Promise<void>;
361363
}) {
362364
for (const command in map) {
363365
const handler = map[command];
364-
this.registerCommand(command, async (uri: string, range: Range) => {
365-
const textEditor = window.activeTextEditor;
366+
this.registerCommand(
367+
command,
368+
async (uri: string, range: Range, ...args: unknown[]) => {
369+
const textEditor = window.activeTextEditor;
366370

367-
if (!textEditor || textEditor.document.uri.toString() !== uri) {
368-
return;
369-
}
371+
if (!textEditor || textEditor.document.uri.toString() !== uri) {
372+
return;
373+
}
370374

371-
range = new Range(
372-
range.start.line,
373-
range.start.character,
374-
range.end.line,
375-
range.end.character
376-
);
375+
range = new Range(
376+
range.start.line,
377+
range.start.character,
378+
range.end.line,
379+
range.end.character
380+
);
377381

378-
const rangeText = textEditor.document.getText(range);
382+
const rangeText = textEditor.document.getText(range);
379383

380-
return await handler.call(this, textEditor, rangeText, range);
381-
});
384+
return await handler.call(
385+
this,
386+
textEditor,
387+
rangeText,
388+
range,
389+
...args
390+
);
391+
}
392+
);
382393
}
383394
}
384395
// update diagnostic for a Document
@@ -596,6 +607,33 @@ Executable ${this.denoInfo.executablePath}`;
596607

597608
this.updateDiagnostic(editor.document.uri);
598609
},
610+
_ignore_text_line_lint: async (editor, _, range, rule: unknown) => {
611+
editor.edit((edit) => {
612+
const currentLineText = editor.document.lineAt(range.start.line);
613+
const lastLineText = editor.document.lineAt(range.start.line - 1);
614+
615+
const offsetEmpty =
616+
currentLineText.text.length - currentLineText.text.trim().length;
617+
618+
edit.replace(
619+
lastLineText.range,
620+
lastLineText.text +
621+
"\n" +
622+
`${" ".repeat(offsetEmpty)}// deno-lint-ignore-next-line ${rule}`
623+
);
624+
});
625+
return;
626+
},
627+
_ignore_entry_file: async (editor) => {
628+
editor.edit((edit) => {
629+
const firstLineText = editor.document.lineAt(0);
630+
edit.insert(
631+
new Position(0, 0),
632+
"// deno-lint-ignore-file" + (firstLineText.text ? "\n" : "")
633+
);
634+
});
635+
return;
636+
},
599637
});
600638

601639
this.watchConfiguration(() => {

server/src/deno.ts

+63-46
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Readable } from "stream";
33
import execa from "execa";
44
import which from "which";
55
import * as semver from "semver";
6+
import { Cache } from "../../core/cache";
67

78
type Version = {
89
deno: string;
@@ -15,16 +16,19 @@ type FormatOptions = {
1516
cwd: string;
1617
};
1718

19+
interface LintLocation {
20+
line: number; // one base number
21+
col: number; // zero base number
22+
}
23+
1824
interface LintDiagnostic {
19-
location: {
20-
filename: string;
21-
line: number;
22-
col: number;
23-
};
24-
message: string;
2525
code: string;
26-
line_src: string;
27-
snippet_length: number;
26+
filename: string;
27+
message: string;
28+
range: {
29+
start: LintLocation;
30+
end: LintLocation;
31+
};
2832
}
2933

3034
interface LintError {
@@ -37,6 +41,9 @@ interface LintOutput {
3741
errors: LintError[];
3842
}
3943

44+
// caching Deno lint's rules for 120s or 100 referenced times
45+
const denoLintRulesCache = Cache.create<string[]>(1000 * 120, 100);
46+
4047
class Deno {
4148
public version!: Version | void;
4249
public executablePath!: string | void;
@@ -55,25 +62,23 @@ class Deno {
5562
return;
5663
}
5764

58-
// If the currently used Deno is less than 0.33.0
65+
// If the currently used Deno is less than 1.3.3
5966
// We will give an warning to upgrade.
60-
const minimumDenoVersion = "0.35.0";
67+
const minimumDenoVersion = "1.3.3";
6168
if (!semver.gte(this.version.deno, minimumDenoVersion)) {
6269
throw new Error(`Please upgrade to Deno ${minimumDenoVersion} or above.`);
6370
}
6471
}
6572
public async getTypes(unstable: boolean): Promise<Buffer> {
6673
const { stdout } = await execa(this.executablePath as string, [
6774
"types",
68-
...(unstable && this.version && semver.gte(this.version.deno, "0.43.0")
69-
? ["--unstable"]
70-
: []),
75+
...(unstable ? ["--unstable"] : []),
7176
]);
7277

7378
return Buffer.from(stdout, "utf8");
7479
}
7580
// format code
76-
// echo "console.log(123)" | deno fmt --stdin
81+
// echo "console.log(123)" | deno fmt -
7782
public async format(code: string, options: FormatOptions): Promise<string> {
7883
const reader = Readable.from([code]);
7984

@@ -94,54 +99,66 @@ class Deno {
9499
resolve(stdout);
95100
}
96101
});
97-
subprocess.on("error", (err: Error) => {
98-
reject(err);
99-
});
100-
subprocess.stdout?.on("data", (data: Buffer) => {
101-
stdout += data;
102-
});
103-
104-
subprocess.stderr?.on("data", (data: Buffer) => {
105-
stderr += data;
106-
});
107-
102+
subprocess.on("error", (err: Error) => reject(err));
103+
subprocess.stdout?.on("data", (data: Buffer) => (stdout += data));
104+
subprocess.stderr?.on("data", (data: Buffer) => (stderr += data));
108105
subprocess.stdin && reader.pipe(subprocess.stdin);
109106
})) as string;
110107

111108
return formattedCode;
112109
}
113110

114-
// TODO: We should read the file content from stdin
115-
public async lintFile(filepath: string): Promise<LintOutput> {
111+
public async getLintRules(): Promise<string[]> {
112+
const cachedRules = denoLintRulesCache.get();
113+
if (cachedRules) {
114+
return cachedRules;
115+
}
116116
const subprocess = execa(
117117
this.executablePath as string,
118-
["lint", "--unstable", "--json", filepath],
118+
["lint", "--unstable", "--rules"],
119119
{
120120
stdout: "pipe",
121-
stderr: "pipe",
122121
}
123122
);
124123

125124
const output = await new Promise<string>((resolve, reject) => {
126125
let stdout = "";
127-
let stderr = "";
128-
subprocess.on("exit", (exitCode: number) => {
129-
if (exitCode !== 0) {
130-
resolve(stderr);
131-
} else {
132-
resolve(stdout);
133-
}
134-
});
135-
subprocess.on("error", (err: Error) => {
136-
reject(err);
137-
});
138-
subprocess.stdout?.on("data", (data: Buffer) => {
139-
stdout += data;
140-
});
126+
subprocess.on("exit", () => resolve(stdout));
127+
subprocess.on("error", (err: Error) => reject(err));
128+
subprocess.stdout?.on("data", (data: Buffer) => (stdout += data));
129+
});
141130

142-
subprocess.stderr?.on("data", (data: Buffer) => {
143-
stderr += data;
144-
});
131+
const rules = output
132+
.split("\n")
133+
.map((v) => v.trim())
134+
.filter((v) => v.startsWith("-"))
135+
.map((v) => v.replace(/^-\s+/, ""));
136+
137+
denoLintRulesCache.set(rules);
138+
139+
return rules;
140+
}
141+
142+
// lint code
143+
// echo "console.log(123)" | deno lint --unstable --json -
144+
public async lint(code: string): Promise<LintOutput> {
145+
const reader = Readable.from([code]);
146+
147+
const subprocess = execa(
148+
this.executablePath as string,
149+
["lint", "--unstable", "--json", "-"],
150+
{
151+
stdin: "pipe",
152+
stderr: "pipe",
153+
}
154+
);
155+
156+
const output = await new Promise<string>((resolve, reject) => {
157+
let stderr = "";
158+
subprocess.on("exit", () => resolve(stderr));
159+
subprocess.on("error", (err: Error) => reject(err));
160+
subprocess.stderr?.on("data", (data: Buffer) => (stderr += data));
161+
subprocess.stdin && reader.pipe(subprocess.stdin);
145162
});
146163

147164
return JSON.parse(output) as LintOutput;

0 commit comments

Comments
 (0)