@@ -30,6 +30,54 @@ module Vue {
30
30
MkComponent ( DataFlow:: CallNode def ) { def = vue ( ) .getAMemberCall ( "component" ) } or
31
31
MkSingleFileComponent ( VueFile file )
32
32
33
+ /** Gets the name of a lifecycle hook method. */
34
+ private string lifecycleHookName ( ) {
35
+ result =
36
+ [ "beforeCreate" , "created" , "beforeMount" , "mounted" , "beforeUpdate" , "updated" , "activated" ,
37
+ "deactivated" , "beforeDestroy" , "destroyed" , "errorCaptured" ]
38
+ }
39
+
40
+ /** Gets a value that can be used as a `@Component` decorator. */
41
+ private DataFlow:: SourceNode componentDecorator ( ) {
42
+ result = DataFlow:: moduleImport ( "vue-class-component" )
43
+ or
44
+ result = DataFlow:: moduleMember ( "vue-property-decorator" , "Component" )
45
+ }
46
+
47
+ /**
48
+ * A class with a `@Component` decorator, making it usable as an "options" object in Vue.
49
+ */
50
+ private class ClassComponent extends DataFlow:: ClassNode {
51
+ DataFlow:: Node decorator ;
52
+
53
+ ClassComponent ( ) {
54
+ exists ( ClassDefinition cls |
55
+ this = cls .flow ( ) and
56
+ cls .getADecorator ( ) .getExpression ( ) = decorator .asExpr ( ) and
57
+ (
58
+ componentDecorator ( ) .flowsTo ( decorator )
59
+ or
60
+ componentDecorator ( ) .getACall ( ) = decorator
61
+ )
62
+ )
63
+ }
64
+
65
+ /**
66
+ * Gets an option passed to the `@Component` decorator.
67
+ *
68
+ * These options correspond to the options one would pass to `new Vue({...})` or similar.
69
+ */
70
+ DataFlow:: Node getDecoratorOption ( string name ) {
71
+ result = decorator .( DataFlow:: CallNode ) .getOptionArgument ( 0 , name )
72
+ }
73
+ }
74
+
75
+ private string memberKindVerb ( DataFlow:: MemberKind kind ) {
76
+ kind = DataFlow:: MemberKind:: getter ( ) and result = "get"
77
+ or
78
+ kind = DataFlow:: MemberKind:: setter ( ) and result = "set"
79
+ }
80
+
33
81
/**
34
82
* A Vue instance definition.
35
83
*
@@ -65,11 +113,27 @@ module Vue {
65
113
endcolumn = 0
66
114
}
67
115
116
+ /**
117
+ * Gets the options passed to the Vue object, such as the object literal `{...}` in `new Vue{{...})`
118
+ * or the default export of a single-file component.
119
+ */
120
+ abstract DataFlow:: Node getOwnOptionsObject ( ) ;
121
+
122
+ /**
123
+ * Gets the class component implementing this Vue instance, if any.
124
+ *
125
+ * Specifically, this is a class annotated with `@Component` which flows to the options
126
+ * object of this Vue instance.
127
+ */
128
+ ClassComponent getAsClassComponent ( ) { result .flowsTo ( getOwnOptionsObject ( ) ) }
129
+
68
130
/**
69
131
* Gets the node for option `name` for this instance, this does not include
70
132
* those from extended objects and mixins.
71
133
*/
72
- abstract DataFlow:: Node getOwnOption ( string name ) ;
134
+ DataFlow:: Node getOwnOption ( string name ) {
135
+ result = getOwnOptionsObject ( ) .getALocalSource ( ) .getAPropertyWrite ( name ) .getRhs ( )
136
+ }
73
137
74
138
/**
75
139
* Gets the node for option `name` for this instance, including those from
@@ -92,6 +156,8 @@ module Vue {
92
156
mixin .flowsTo ( mixins .getAnElement ( ) ) and
93
157
result = mixin .getAPropertyWrite ( name ) .getRhs ( )
94
158
)
159
+ or
160
+ result = getAsClassComponent ( ) .getDecoratorOption ( name )
95
161
}
96
162
97
163
/**
@@ -112,6 +178,10 @@ module Vue {
112
178
result = f .getAReturn ( )
113
179
)
114
180
)
181
+ or
182
+ result = getAsClassComponent ( ) .getAReceiverNode ( )
183
+ or
184
+ result = getAsClassComponent ( ) .getInstanceMethod ( "data" ) .getAReturn ( )
115
185
}
116
186
117
187
/**
@@ -122,7 +192,11 @@ module Vue {
122
192
/**
123
193
* Gets the node for the `render` option of this instance.
124
194
*/
125
- DataFlow:: Node getRender ( ) { result = getOption ( "render" ) }
195
+ DataFlow:: Node getRender ( ) {
196
+ result = getOption ( "render" )
197
+ or
198
+ result = getAsClassComponent ( ) .getInstanceMethod ( "render" )
199
+ }
126
200
127
201
/**
128
202
* Gets the node for the `methods` option of this instance.
@@ -143,62 +217,63 @@ module Vue {
143
217
methods .flowsTo ( getMethods ( ) ) and
144
218
result = methods .getAPropertyWrite ( ) .getRhs ( )
145
219
)
220
+ or
221
+ result = getAsClassComponent ( ) .getAnInstanceMethod ( ) and
222
+ not result = getAsClassComponent ( ) .getInstanceMethod ( [ lifecycleHookName ( ) , "render" , "data" ] )
146
223
}
147
224
148
225
/**
149
- * Gets a node for a member of the `computed` option of this instance that matches `kind` ("get" or "set") .
226
+ * Gets a node for a member of the `computed` option of this instance that matches `kind`.
150
227
*/
151
228
pragma [ noinline]
152
- private DataFlow:: Node getAnAccessor ( string kind ) {
229
+ private DataFlow:: Node getAnAccessor ( DataFlow :: MemberKind kind ) {
153
230
exists ( DataFlow:: ObjectLiteralNode computedObj , DataFlow:: Node accessorObjOrGetter |
154
231
computedObj .flowsTo ( getComputed ( ) ) and
155
232
computedObj .getAPropertyWrite ( ) .getRhs ( ) = accessorObjOrGetter
156
233
|
157
- result = accessorObjOrGetter and kind = "get"
234
+ result = accessorObjOrGetter and kind = DataFlow :: MemberKind :: getter ( )
158
235
or
159
236
exists ( DataFlow:: ObjectLiteralNode accessorObj |
160
237
accessorObj .flowsTo ( accessorObjOrGetter ) and
161
- result = accessorObj .getAPropertyWrite ( kind ) .getRhs ( )
238
+ result = accessorObj .getAPropertyWrite ( memberKindVerb ( kind ) ) .getRhs ( )
162
239
)
163
240
)
241
+ or
242
+ result = getAsClassComponent ( ) .getAnInstanceMember ( kind ) and
243
+ kind .isAccessor ( )
164
244
}
165
245
166
246
/**
167
- * Gets a node for a member `name` of the `computed` option of this instance that matches `kind` ("get" or "set") .
247
+ * Gets a node for a member `name` of the `computed` option of this instance that matches `kind`.
168
248
*/
169
- private DataFlow:: Node getAccessor ( string name , string kind ) {
249
+ private DataFlow:: Node getAccessor ( string name , DataFlow :: MemberKind kind ) {
170
250
exists ( DataFlow:: ObjectLiteralNode computedObj , DataFlow:: SourceNode accessorObjOrGetter |
171
251
computedObj .flowsTo ( getComputed ( ) ) and
172
252
accessorObjOrGetter .flowsTo ( computedObj .getAPropertyWrite ( name ) .getRhs ( ) )
173
253
|
174
- result = accessorObjOrGetter and kind = "get"
254
+ result = accessorObjOrGetter and kind = DataFlow :: MemberKind :: getter ( )
175
255
or
176
256
exists ( DataFlow:: ObjectLiteralNode accessorObj |
177
257
accessorObj .flowsTo ( accessorObjOrGetter ) and
178
- result = accessorObj .getAPropertyWrite ( kind ) .getRhs ( )
258
+ result = accessorObj .getAPropertyWrite ( memberKindVerb ( kind ) ) .getRhs ( )
179
259
)
180
260
)
261
+ or
262
+ result = getAsClassComponent ( ) .getInstanceMember ( name , kind ) and
263
+ kind .isAccessor ( )
181
264
}
182
265
183
266
/**
184
267
* Gets the node for the life cycle hook of the `hookName` option of this instance.
185
268
*/
186
269
pragma [ noinline]
187
270
private DataFlow:: Node getALifecycleHook ( string hookName ) {
271
+ hookName = lifecycleHookName ( ) and
188
272
(
189
- hookName = "beforeCreate" or
190
- hookName = "created" or
191
- hookName = "beforeMount" or
192
- hookName = "mounted" or
193
- hookName = "beforeUpdate" or
194
- hookName = "updated" or
195
- hookName = "activated" or
196
- hookName = "deactivated" or
197
- hookName = "beforeDestroy" or
198
- hookName = "destroyed" or
199
- hookName = "errorCaptured"
200
- ) and
201
- result = getOption ( hookName )
273
+ result = getOption ( hookName )
274
+ or
275
+ result = getAsClassComponent ( ) .getInstanceMethod ( hookName )
276
+ )
202
277
}
203
278
204
279
/**
@@ -227,7 +302,7 @@ module Vue {
227
302
)
228
303
or
229
304
exists ( DataFlow:: FunctionNode getter |
230
- getter .flowsTo ( getAccessor ( name , "get" ) ) and
305
+ getter .flowsTo ( getAccessor ( name , DataFlow :: MemberKind :: getter ( ) ) ) and
231
306
result = getter .getAReturn ( )
232
307
)
233
308
}
@@ -249,7 +324,7 @@ module Vue {
249
324
def .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
250
325
}
251
326
252
- override DataFlow:: Node getOwnOption ( string name ) { result = def .getOptionArgument ( 0 , name ) }
327
+ override DataFlow:: Node getOwnOptionsObject ( ) { result = def .getArgument ( 0 ) }
253
328
254
329
override Template:: Element getTemplateElement ( ) { none ( ) }
255
330
}
@@ -270,7 +345,7 @@ module Vue {
270
345
extend .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
271
346
}
272
347
273
- override DataFlow:: Node getOwnOption ( string name ) { result = extend .getOptionArgument ( 0 , name ) }
348
+ override DataFlow:: Node getOwnOptionsObject ( ) { result = extend .getArgument ( 0 ) }
274
349
275
350
override Template:: Element getTemplateElement ( ) { none ( ) }
276
351
}
@@ -292,7 +367,7 @@ module Vue {
292
367
sub .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
293
368
}
294
369
295
- override DataFlow:: Node getOwnOption ( string name ) { result = sub .getOptionArgument ( 0 , name ) }
370
+ override DataFlow:: Node getOwnOptionsObject ( ) { result = sub .getArgument ( 0 ) }
296
371
297
372
override DataFlow:: Node getOption ( string name ) {
298
373
result = Instance .super .getOption ( name )
@@ -319,7 +394,7 @@ module Vue {
319
394
def .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
320
395
}
321
396
322
- override DataFlow:: Node getOwnOption ( string name ) { result = def .getOptionArgument ( 1 , name ) }
397
+ override DataFlow:: Node getOwnOptionsObject ( ) { result = def .getArgument ( 1 ) }
323
398
324
399
override Template:: Element getTemplateElement ( ) { none ( ) }
325
400
}
@@ -357,6 +432,13 @@ module Vue {
357
432
)
358
433
}
359
434
435
+ override DataFlow:: Node getOwnOptionsObject ( ) {
436
+ exists ( ExportDefaultDeclaration decl |
437
+ decl .getTopLevel ( ) = getModule ( ) and
438
+ result = DataFlow:: valueNode ( decl .getOperand ( ) )
439
+ )
440
+ }
441
+
360
442
override DataFlow:: Node getOwnOption ( string name ) {
361
443
// The options of a single file component are defined by the exported object of the script element.
362
444
// Our current module model does not support reads on this object very well, so we use custom steps for the common cases for now.
0 commit comments