@@ -3,6 +3,7 @@ import { Readable } from "stream";
3
3
import execa from "execa" ;
4
4
import which from "which" ;
5
5
import * as semver from "semver" ;
6
+ import { Cache } from "../../core/cache" ;
6
7
7
8
type Version = {
8
9
deno : string ;
@@ -15,16 +16,19 @@ type FormatOptions = {
15
16
cwd : string ;
16
17
} ;
17
18
19
+ interface LintLocation {
20
+ line : number ; // one base number
21
+ col : number ; // zero base number
22
+ }
23
+
18
24
interface LintDiagnostic {
19
- location : {
20
- filename : string ;
21
- line : number ;
22
- col : number ;
23
- } ;
24
- message : string ;
25
25
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
+ } ;
28
32
}
29
33
30
34
interface LintError {
@@ -37,6 +41,9 @@ interface LintOutput {
37
41
errors : LintError [ ] ;
38
42
}
39
43
44
+ // caching Deno lint's rules for 120s or 100 referenced times
45
+ const denoLintRulesCache = Cache . create < string [ ] > ( 1000 * 120 , 100 ) ;
46
+
40
47
class Deno {
41
48
public version ! : Version | void ;
42
49
public executablePath ! : string | void ;
@@ -55,25 +62,23 @@ class Deno {
55
62
return ;
56
63
}
57
64
58
- // If the currently used Deno is less than 0.33.0
65
+ // If the currently used Deno is less than 1.3.3
59
66
// We will give an warning to upgrade.
60
- const minimumDenoVersion = "0.35.0 " ;
67
+ const minimumDenoVersion = "1.3.3 " ;
61
68
if ( ! semver . gte ( this . version . deno , minimumDenoVersion ) ) {
62
69
throw new Error ( `Please upgrade to Deno ${ minimumDenoVersion } or above.` ) ;
63
70
}
64
71
}
65
72
public async getTypes ( unstable : boolean ) : Promise < Buffer > {
66
73
const { stdout } = await execa ( this . executablePath as string , [
67
74
"types" ,
68
- ...( unstable && this . version && semver . gte ( this . version . deno , "0.43.0" )
69
- ? [ "--unstable" ]
70
- : [ ] ) ,
75
+ ...( unstable ? [ "--unstable" ] : [ ] ) ,
71
76
] ) ;
72
77
73
78
return Buffer . from ( stdout , "utf8" ) ;
74
79
}
75
80
// format code
76
- // echo "console.log(123)" | deno fmt --stdin
81
+ // echo "console.log(123)" | deno fmt -
77
82
public async format ( code : string , options : FormatOptions ) : Promise < string > {
78
83
const reader = Readable . from ( [ code ] ) ;
79
84
@@ -94,54 +99,66 @@ class Deno {
94
99
resolve ( stdout ) ;
95
100
}
96
101
} ) ;
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 ) ) ;
108
105
subprocess . stdin && reader . pipe ( subprocess . stdin ) ;
109
106
} ) ) as string ;
110
107
111
108
return formattedCode ;
112
109
}
113
110
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
+ }
116
116
const subprocess = execa (
117
117
this . executablePath as string ,
118
- [ "lint" , "--unstable" , "--json" , filepath ] ,
118
+ [ "lint" , "--unstable" , "--rules" ] ,
119
119
{
120
120
stdout : "pipe" ,
121
- stderr : "pipe" ,
122
121
}
123
122
) ;
124
123
125
124
const output = await new Promise < string > ( ( resolve , reject ) => {
126
125
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
+ } ) ;
141
130
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 ) ;
145
162
} ) ;
146
163
147
164
return JSON . parse ( output ) as LintOutput ;
0 commit comments