7
7
8
8
import { TextDocument } from 'vscode-languageserver-textdocument' ;
9
9
import {
10
+ CodeAction ,
11
+ CodeActionKind ,
10
12
CodeLens ,
11
13
createConnection ,
12
14
type InitializeParams ,
13
15
type InitializeResult ,
16
+ Position ,
14
17
ProposedFeatures ,
15
18
TextDocuments ,
16
19
TextDocumentSyncKind ,
@@ -29,7 +32,12 @@ import {
29
32
AutoDepsDecorationsRequest ,
30
33
mapCompilerEventToLSPEvent ,
31
34
} from './requests/autodepsdecorations' ;
32
- import { isPositionWithinRange } from './utils/range' ;
35
+ import {
36
+ isPositionWithinRange ,
37
+ isRangeWithinRange ,
38
+ Range ,
39
+ sourceLocationToRange ,
40
+ } from './utils/range' ;
33
41
34
42
const SUPPORTED_LANGUAGE_IDS = new Set ( [
35
43
'javascript' ,
@@ -44,6 +52,15 @@ const documents = new TextDocuments(TextDocument);
44
52
let compilerOptions : PluginOptions | null = null ;
45
53
let compiledFns : Set < CompileSuccessEvent > = new Set ( ) ;
46
54
let autoDepsDecorations : Array < AutoDepsDecorationsLSPEvent > = [ ] ;
55
+ let codeActionEvents : Array < CodeActionLSPEvent > = [ ] ;
56
+
57
+ type CodeActionLSPEvent = {
58
+ title : string ;
59
+ kind : CodeActionKind ;
60
+ newText : string ;
61
+ anchorRange : Range ;
62
+ editRange : { start : Position ; end : Position } ;
63
+ } ;
47
64
48
65
connection . onInitialize ( ( _params : InitializeParams ) => {
49
66
// TODO(@poteto) get config fr
@@ -85,13 +102,24 @@ connection.onInitialize((_params: InitializeParams) => {
85
102
if ( event . kind === 'AutoDepsDecorations' ) {
86
103
autoDepsDecorations . push ( mapCompilerEventToLSPEvent ( event ) ) ;
87
104
}
105
+ if ( event . kind === 'AutoDepsEligible' ) {
106
+ const depArrayLoc = sourceLocationToRange ( event . depArrayLoc ) ;
107
+ codeActionEvents . push ( {
108
+ title : 'Use React Compiler inferred dependency array' ,
109
+ kind : CodeActionKind . QuickFix ,
110
+ newText : '' ,
111
+ anchorRange : sourceLocationToRange ( event . fnLoc ) ,
112
+ editRange : { start : depArrayLoc [ 0 ] , end : depArrayLoc [ 1 ] } ,
113
+ } ) ;
114
+ }
88
115
} ,
89
116
} ,
90
117
} ;
91
118
const result : InitializeResult = {
92
119
capabilities : {
93
120
textDocumentSync : TextDocumentSyncKind . Full ,
94
121
codeLensProvider : { resolveProvider : true } ,
122
+ codeActionProvider : { resolveProvider : true } ,
95
123
} ,
96
124
} ;
97
125
return result ;
@@ -103,8 +131,7 @@ connection.onInitialized(() => {
103
131
104
132
documents . onDidChangeContent ( async event => {
105
133
connection . console . info ( `Changed: ${ event . document . uri } ` ) ;
106
- compiledFns . clear ( ) ;
107
- autoDepsDecorations = [ ] ;
134
+ resetState ( ) ;
108
135
if ( SUPPORTED_LANGUAGE_IDS . has ( event . document . languageId ) ) {
109
136
const text = event . document . getText ( ) ;
110
137
await compile ( {
@@ -116,8 +143,7 @@ documents.onDidChangeContent(async event => {
116
143
} ) ;
117
144
118
145
connection . onDidChangeWatchedFiles ( change => {
119
- compiledFns . clear ( ) ;
120
- autoDepsDecorations = [ ] ;
146
+ resetState ( ) ;
121
147
connection . console . log (
122
148
change . changes . map ( c => `File changed: ${ c . uri } ` ) . join ( '\n' ) ,
123
149
) ;
@@ -157,6 +183,44 @@ connection.onCodeLensResolve(lens => {
157
183
return lens ;
158
184
} ) ;
159
185
186
+ connection . onCodeAction ( params => {
187
+ connection . console . log ( 'onCodeAction' ) ;
188
+ connection . console . log ( JSON . stringify ( params , null , 2 ) ) ;
189
+ const codeActions : Array < CodeAction > = [ ] ;
190
+ for ( const codeActionEvent of codeActionEvents ) {
191
+ if (
192
+ isRangeWithinRange (
193
+ [ params . range . start , params . range . end ] ,
194
+ codeActionEvent . anchorRange ,
195
+ )
196
+ ) {
197
+ codeActions . push (
198
+ CodeAction . create (
199
+ codeActionEvent . title ,
200
+ {
201
+ changes : {
202
+ [ params . textDocument . uri ] : [
203
+ {
204
+ newText : codeActionEvent . newText ,
205
+ range : codeActionEvent . editRange ,
206
+ } ,
207
+ ] ,
208
+ } ,
209
+ } ,
210
+ codeActionEvent . kind ,
211
+ ) ,
212
+ ) ;
213
+ }
214
+ }
215
+ return codeActions ;
216
+ } ) ;
217
+
218
+ connection . onCodeActionResolve ( codeAction => {
219
+ connection . console . log ( 'onCodeActionResolve' ) ;
220
+ connection . console . log ( JSON . stringify ( codeAction , null , 2 ) ) ;
221
+ return codeAction ;
222
+ } ) ;
223
+
160
224
connection . onRequest ( AutoDepsDecorationsRequest . type , async params => {
161
225
const position = params . position ;
162
226
connection . console . debug ( 'Client hovering on: ' + JSON . stringify ( position ) ) ;
@@ -168,6 +232,12 @@ connection.onRequest(AutoDepsDecorationsRequest.type, async params => {
168
232
return null ;
169
233
} ) ;
170
234
235
+ function resetState ( ) {
236
+ compiledFns . clear ( ) ;
237
+ autoDepsDecorations = [ ] ;
238
+ codeActionEvents = [ ] ;
239
+ }
240
+
171
241
documents . listen ( connection ) ;
172
242
connection . listen ( ) ;
173
243
connection . console . info ( `React Analyzer running in node ${ process . version } ` ) ;
0 commit comments