@@ -6,12 +6,14 @@ import { findHoverMatchesInDoc } from "@src/support/doc";
6
6
import { detectedRange , detectInDoc } from "@src/support/parser" ;
7
7
import { wordMatchRegex } from "@src/support/patterns" ;
8
8
import { facade , relativeMarkdownLink } from "@src/support/util" ;
9
+ import { AutocompleteParsingResult } from "@src/types" ;
9
10
import * as vscode from "vscode" ;
10
11
import {
11
12
CompletionProvider ,
12
13
FeatureTag ,
13
14
HoverProvider ,
14
15
LinkProvider ,
16
+ ValidDetectParamTypes ,
15
17
} from ".." ;
16
18
17
19
const toFind : FeatureTag = [
@@ -40,85 +42,151 @@ const toFind: FeatureTag = [
40
42
} ,
41
43
] ;
42
44
45
+ const analyzeParam = (
46
+ param :
47
+ | AutocompleteParsingResult . StringValue
48
+ | AutocompleteParsingResult . ArrayValue
49
+ | string ,
50
+ item : AutocompleteParsingResult . ContextValue ,
51
+ index : number ,
52
+ ) :
53
+ | { missingReason : "not_found" | "wrong_model" | "ignored" }
54
+ | {
55
+ policies : AuthItem [ ] ;
56
+ values : AutocompleteParsingResult . StringValue [ ] | { value : string } [ ] ;
57
+ missingReason : null ;
58
+ } => {
59
+ if ( item . type !== "methodCall" || ! item . methodName || index !== 0 ) {
60
+ return {
61
+ missingReason : "ignored" ,
62
+ } ;
63
+ }
64
+
65
+ let values = [ ] ;
66
+
67
+ if ( typeof param === "string" ) {
68
+ values . push ( {
69
+ value : param ,
70
+ } ) ;
71
+ } else if ( param . type === "array" ) {
72
+ values . push (
73
+ ...param . children
74
+ . map ( ( child ) => {
75
+ if ( child . value . type === "string" ) {
76
+ return child . value ;
77
+ }
78
+
79
+ return null ;
80
+ } )
81
+ . filter ( ( v ) => v !== null ) ,
82
+ ) ;
83
+ } else {
84
+ values . push ( param ) ;
85
+ }
86
+
87
+ values = values . filter ( ( value ) => value . value !== "" ) ;
88
+
89
+ if ( values . length === 0 ) {
90
+ return {
91
+ missingReason : "not_found" ,
92
+ } ;
93
+ }
94
+
95
+ const policies = values
96
+ . map ( ( value ) => getPolicies ( ) . items [ value . value ] )
97
+ . flat ( ) ;
98
+
99
+ if ( [ "has" ] . includes ( item . methodName ) ) {
100
+ return {
101
+ policies,
102
+ values,
103
+ missingReason : null ,
104
+ } ;
105
+ }
106
+
107
+ if ( item . arguments . children . length < 2 ) {
108
+ // We don't have a second argument, just ignore it for now
109
+ return {
110
+ missingReason : "ignored" ,
111
+ } ;
112
+ }
113
+
114
+ // @ts -ignore
115
+ const nextArg = item . arguments . children [ 1 ] . children [ 0 ] ;
116
+ let classArg : string | null = null ;
117
+
118
+ if ( nextArg . type === "array" ) {
119
+ classArg = nextArg . children [ 0 ] ?. value ?. className ;
120
+ } else {
121
+ classArg = nextArg ?. className ;
122
+ }
123
+
124
+ if ( ! classArg ) {
125
+ // If it's not a class we can even identify, just ignore it
126
+ return {
127
+ missingReason : "ignored" ,
128
+ } ;
129
+ }
130
+
131
+ const found = policies . find ( ( items ) => items . model === classArg ) ;
132
+
133
+ if ( ! found ) {
134
+ return {
135
+ missingReason : "wrong_model" ,
136
+ } ;
137
+ }
138
+
139
+ return {
140
+ policies : [ found ] ,
141
+ values,
142
+ missingReason : null ,
143
+ } ;
144
+ } ;
145
+
43
146
export const linkProvider : LinkProvider = ( doc : vscode . TextDocument ) => {
44
- return detectInDoc < vscode . DocumentLink , "string" > (
147
+ return detectInDoc < vscode . DocumentLink , ValidDetectParamTypes > (
45
148
doc ,
46
149
toFind ,
47
150
getPolicies ,
48
151
( { param, item, index } ) => {
49
- const policy = getPolicies ( ) . items [ param . value ] ;
50
-
51
- if ( ! policy || policy . length === 0 ) {
52
- return null ;
53
- }
54
-
55
- if ( item . type !== "methodCall" || ! item . methodName || index !== 0 ) {
56
- return null ;
57
- }
58
-
59
- if ( [ "has" ] . includes ( item . methodName ) ) {
60
- return formattedLink ( policy , param ) ;
61
- }
62
-
63
- if ( item . arguments . children . length < 2 ) {
64
- // We don't have a second argument, just ignore it for now
65
- return null ;
66
- }
67
-
68
- // @ts -ignore
69
- const nextArg = item . arguments . children [ 1 ] . children [ 0 ] ;
70
- const classArg = nextArg ?. className ;
152
+ const result = analyzeParam ( param , item , index ) ;
71
153
72
- if ( ! classArg ) {
73
- // If it's not a class we can even identify, just ignore it
154
+ if ( result . missingReason ) {
74
155
return null ;
75
156
}
76
157
77
- const found = policy . find ( ( item ) => item . model === classArg ) ;
78
-
79
- if ( ! found ) {
158
+ if ( result . policies . length > 1 ) {
159
+ // We can't link to multiple policies, just ignore it
80
160
return null ;
81
161
}
82
162
83
- return formattedLink ( [ found ] , param ) ;
163
+ return result . policies
164
+ . map ( ( item ) => {
165
+ return result . values
166
+ . map (
167
+ (
168
+ param :
169
+ | AutocompleteParsingResult . StringValue
170
+ | { value : string } ,
171
+ ) => {
172
+ return new vscode . DocumentLink (
173
+ detectedRange (
174
+ param as AutocompleteParsingResult . StringValue ,
175
+ ) ,
176
+ vscode . Uri . file ( item . uri ) . with ( {
177
+ fragment : `L${ item . line } ` ,
178
+ } ) ,
179
+ ) ;
180
+ } ,
181
+ )
182
+ . flat ( ) ;
183
+ } )
184
+ . flat ( ) ;
84
185
} ,
186
+ [ "array" , "string" ] ,
85
187
) ;
86
188
} ;
87
189
88
- const formattedLink = ( items : AuthItem [ ] , param : any ) => {
89
- return items . map ( ( item ) => {
90
- return new vscode . DocumentLink (
91
- detectedRange ( param ) ,
92
- vscode . Uri . file ( item . uri ) . with ( {
93
- fragment : `L${ item . line } ` ,
94
- } ) ,
95
- ) ;
96
- } ) ;
97
- } ;
98
-
99
- const formattedHover = ( items : AuthItem [ ] ) => {
100
- const text = items . map ( ( item ) => {
101
- if ( item . policy ) {
102
- return [
103
- "`" + item . policy + "`" ,
104
- relativeMarkdownLink (
105
- vscode . Uri . file ( item . uri ) . with ( {
106
- fragment : `L${ item . line } ` ,
107
- } ) ,
108
- ) ,
109
- ] . join ( "\n\n" ) ;
110
- }
111
-
112
- return relativeMarkdownLink (
113
- vscode . Uri . file ( item . uri ) . with ( {
114
- fragment : `L${ item . line } ` ,
115
- } ) ,
116
- ) ;
117
- } ) ;
118
-
119
- return new vscode . Hover ( new vscode . MarkdownString ( text . join ( "\n\n" ) ) ) ;
120
- } ;
121
-
122
190
export const hoverProvider : HoverProvider = (
123
191
doc : vscode . TextDocument ,
124
192
pos : vscode . Position ,
@@ -129,42 +197,36 @@ export const hoverProvider: HoverProvider = (
129
197
toFind ,
130
198
getPolicies ,
131
199
( match , { index, item } ) => {
132
- const items = getPolicies ( ) . items [ match ] ;
133
-
134
- if ( ! items || items . length === 0 ) {
135
- return null ;
136
- }
200
+ const result = analyzeParam ( match , item , index ) ;
137
201
138
- if ( item . type !== "methodCall" || ! item . methodName || index !== 0 ) {
202
+ if ( result . missingReason ) {
139
203
return null ;
140
204
}
141
205
142
- if ( [ "has" ] . includes ( item . methodName ) ) {
143
- return formattedHover ( items ) ;
144
- }
145
-
146
- if ( item . arguments . children . length < 2 ) {
147
- // We don't have a second argument, just ignore it for now
148
- return null ;
149
- }
150
-
151
- // @ts -ignore
152
- const nextArg = item . arguments . children [ 1 ] . children [ 0 ] ;
153
- const classArg = nextArg ?. className ;
154
-
155
- if ( ! classArg ) {
156
- // If it's not a class we can even identify, just ignore it
157
- return null ;
158
- }
159
-
160
- const found = items . find ( ( item ) => item . model === classArg ) ;
161
-
162
- if ( ! found ) {
163
- return null ;
164
- }
206
+ const text = result . policies . map ( ( item ) => {
207
+ if ( item . policy ) {
208
+ return [
209
+ "`" + item . policy + "`" ,
210
+ relativeMarkdownLink (
211
+ vscode . Uri . file ( item . uri ) . with ( {
212
+ fragment : `L${ item . line } ` ,
213
+ } ) ,
214
+ ) ,
215
+ ] . join ( "\n\n" ) ;
216
+ }
217
+
218
+ return relativeMarkdownLink (
219
+ vscode . Uri . file ( item . uri ) . with ( {
220
+ fragment : `L${ item . line } ` ,
221
+ } ) ,
222
+ ) ;
223
+ } ) ;
165
224
166
- return formattedHover ( [ found ] ) ;
225
+ return new vscode . Hover (
226
+ new vscode . MarkdownString ( text . join ( "\n\n" ) ) ,
227
+ ) ;
167
228
} ,
229
+ [ "array" , "string" ] ,
168
230
) ;
169
231
} ;
170
232
@@ -176,13 +238,13 @@ export const diagnosticProvider = (
176
238
toFind ,
177
239
getPolicies ,
178
240
( { param, item, index } ) => {
179
- if ( item . type !== "methodCall" || ! item . methodName || index !== 0 ) {
241
+ const result = analyzeParam ( param , item , index ) ;
242
+
243
+ if ( result . missingReason === null || param . value === "" ) {
180
244
return null ;
181
245
}
182
246
183
- const policy = getPolicies ( ) . items [ param . value ] ;
184
-
185
- if ( ! policy ) {
247
+ if ( result . missingReason === "not_found" ) {
186
248
return notFound (
187
249
"Policy" ,
188
250
param . value ,
@@ -191,37 +253,18 @@ export const diagnosticProvider = (
191
253
) ;
192
254
}
193
255
194
- if ( [ "has" ] . includes ( item . methodName ) ) {
195
- return null ;
196
- }
197
-
198
- if ( item . arguments . children . length < 2 ) {
199
- // We don't have a second argument, just ignore it for now
200
- return null ;
201
- }
202
-
203
- // @ts -ignore
204
- const nextArg = item . arguments . children [ 1 ] . children [ 0 ] ;
205
- const classArg = nextArg ?. className ;
206
-
207
- if ( ! classArg ) {
208
- // If it's not a class we can even identify, just ignore it
209
- return null ;
210
- }
211
-
212
- const found = policy . find ( ( item ) => item . model === classArg ) ;
213
-
214
- if ( ! found ) {
256
+ if ( result . missingReason === "wrong_model" ) {
215
257
return notFound (
216
258
"Policy/Model match" ,
217
- classArg ,
259
+ param . value ,
218
260
detectedRange ( param ) ,
219
261
"auth" ,
220
262
) ;
221
263
}
222
264
223
265
return null ;
224
266
} ,
267
+ [ "array" , "string" ] ,
225
268
) ;
226
269
} ;
227
270
@@ -241,7 +284,7 @@ export const completionProvider: CompletionProvider = {
241
284
return [ ] ;
242
285
}
243
286
244
- if ( result . paramCount ( ) > 0 ) {
287
+ if ( result . paramIndex ( ) > 0 ) {
245
288
return [ ] ;
246
289
}
247
290
0 commit comments