JS: Handle .extend called on any component

This commit is contained in:
Asger Feldthaus
2021-08-19 15:38:38 +02:00
parent 2a79817c3b
commit e4901eda91
3 changed files with 44 additions and 11 deletions

View File

@@ -39,17 +39,28 @@ module Vue {
*/
DataFlow::SourceNode vue() { result = vueLibrary().getAnImmediateUse() }
/** An API node referring to a component or `Vue`. */
private API::Node component() {
result = vueLibrary()
or
result = component().getMember("extend").getReturn()
or
result = vueLibrary().getMember("component").getReturn()
or
result = API::root().getASuccessor(any(VueFileImportEntryPoint e))
}
/**
* A call to `vue.extend`.
* A call to `Vue.extend` or `extend` on a component.
*/
private class VueExtend extends API::CallNode {
VueExtend() { this = vueLibrary().getMember("extend").getACall() }
private class VueExtendCall extends API::CallNode {
VueExtendCall() { this = component().getMember("extend").getACall() }
}
private newtype TComponent =
MkVueInstance(API::NewNode def) { def = vueLibrary().getAnInstantiation() } or
MkExtendedVue(VueExtend extend) or
MkExtendedInstance(VueExtend extend, API::NewNode sub) {
MkExtendedVue(VueExtendCall extend) or
MkExtendedInstance(VueExtendCall extend, API::NewNode sub) {
sub = extend.getReturn().getAnInstantiation()
} or
MkComponentRegistration(API::CallNode def) { def = vueLibrary().getMember("component").getACall() } or
@@ -406,7 +417,7 @@ module Vue {
* An extended Vue from `Vue.extend({...})`.
*/
class ExtendedVue extends Component, MkExtendedVue {
VueExtend extend;
VueExtendCall extend;
ExtendedVue() { this = MkExtendedVue(extend) }
@@ -425,13 +436,19 @@ module Vue {
override DataFlow::Node getOwnOptionsObject() { result = extend.getArgument(0) }
override Template::Element getTemplateElement() { none() }
override Component getABaseComponent() {
result = Component.super.getABaseComponent()
or
result.getComponentRef().getMember("extend").getACall() = extend
}
}
/**
* An instance of an extended Vue, for example `instance` of `var Ext = Vue.extend({...}); var instance = new Ext({...})`.
*/
class ExtendedInstance extends Component, MkExtendedInstance {
VueExtend extend;
VueExtendCall extend;
API::NewNode sub;
ExtendedInstance() { this = MkExtendedInstance(extend, sub) }
@@ -457,6 +474,12 @@ module Vue {
}
override Template::Element getTemplateElement() { none() }
override Component getABaseComponent() {
result = Component.super.getABaseComponent()
or
result.getComponentRef().getAnInstantiation() = sub
}
}
/**

View File

@@ -29,8 +29,10 @@ component_getAPropertyValue
| tst.js:85:1:87:2 | new Vue ... e; }\\n}) | created | tst.js:86:38:86:41 | true |
| tst.js:94:2:96:3 | new Vue ... f,\\n\\t}) | dataA | tst.js:89:22:89:23 | 42 |
| tst.js:99:2:104:3 | new Vue ... \\t\\t}\\n\\t}) | dataA | tst.js:100:18:100:19 | 42 |
| tst.js:107:12:109:2 | new Vue ... 23 }\\n}) | fromBase | tst.js:108:20:108:22 | 123 |
| tst.js:107:12:109:2 | Vue.ext ... 23 }\\n}) | fromBase | tst.js:108:20:108:22 | 123 |
| tst.js:110:16:112:2 | new Vue ... base\\n}) | fromBase | tst.js:108:20:108:22 | 123 |
| tst.js:113:17:117:2 | base.ex ... 0\\n\\t}\\n}) | fromBase | tst.js:108:20:108:22 | 123 |
| tst.js:113:17:117:2 | base.ex ... 0\\n\\t}\\n}) | fromSubclass2 | tst.js:115:18:115:20 | 100 |
component_getOption
| compont-with-route.vue:0:0:0:0 | compont-with-route.vue | watch | compont-with-route.vue:10:12:16:5 | {\\n ... }\\n } |
| single-component-file-1.vue:0:0:0:0 | single-component-file-1.vue | data | single-component-file-1.vue:6:11:6:45 | functio ... 42 } } |
@@ -62,9 +64,11 @@ component_getOption
| tst.js:94:2:96:3 | new Vue ... f,\\n\\t}) | data | tst.js:95:9:95:9 | f |
| tst.js:99:2:104:3 | new Vue ... \\t\\t}\\n\\t}) | data | tst.js:100:9:100:21 | { dataA: 42 } |
| tst.js:99:2:104:3 | new Vue ... \\t\\t}\\n\\t}) | methods | tst.js:101:12:103:3 | {\\n\\t\\t\\tm: ... ; }\\n\\t\\t} |
| tst.js:107:12:109:2 | new Vue ... 23 }\\n}) | data | tst.js:108:8:108:24 | { fromBase: 123 } |
| tst.js:107:12:109:2 | Vue.ext ... 23 }\\n}) | data | tst.js:108:8:108:24 | { fromBase: 123 } |
| tst.js:110:16:112:2 | new Vue ... base\\n}) | data | tst.js:108:8:108:24 | { fromBase: 123 } |
| tst.js:110:16:112:2 | new Vue ... base\\n}) | extends | tst.js:111:11:111:14 | base |
| tst.js:113:17:117:2 | base.ex ... 0\\n\\t}\\n}) | data | tst.js:108:8:108:24 | { fromBase: 123 } |
| tst.js:113:17:117:2 | base.ex ... 0\\n\\t}\\n}) | data | tst.js:114:8:116:2 | {\\n\\t\\tfro ... 100\\n\\t} |
component
| compont-with-route.vue:0:0:0:0 | compont-with-route.vue |
| single-component-file-1.vue:0:0:0:0 | single-component-file-1.vue |
@@ -87,8 +91,9 @@ component
| tst.js:85:1:87:2 | new Vue ... e; }\\n}) |
| tst.js:94:2:96:3 | new Vue ... f,\\n\\t}) |
| tst.js:99:2:104:3 | new Vue ... \\t\\t}\\n\\t}) |
| tst.js:107:12:109:2 | new Vue ... 23 }\\n}) |
| tst.js:107:12:109:2 | Vue.ext ... 23 }\\n}) |
| tst.js:110:16:112:2 | new Vue ... base\\n}) |
| tst.js:113:17:117:2 | base.ex ... 0\\n\\t}\\n}) |
instance_heapStep
| Unit | compont-with-route.vue:31:14:31:34 | this.$r ... ery.foo | compont-with-route.vue:2:8:2:21 | v-html=dataA |
| Unit | single-component-file-1.vue:6:40:6:41 | 42 | single-component-file-1.vue:2:8:2:21 | v-html=dataA |

View File

@@ -104,9 +104,14 @@ new Vue({
});
});
let base = new Vue({
let base = Vue.extend({
data: { fromBase: 123 }
});
let subclass = new Vue({
extends: base
});
let subclass2 = base.extend({
data: {
fromSubclass2: 100
}
});