UNPKG

8.42 kBJavaScriptView Raw
1/**
2 * vue-class-component v7.2.0
3 * (c) 2015-present Evan You
4 * @license MIT
5 */
6import Vue from 'vue';
7
8// The rational behind the verbose Reflect-feature check below is the fact that there are polyfills
9// which add an implementation for Reflect.defineMetadata but not for Reflect.getOwnMetadataKeys.
10// Without this check consumers will encounter hard to track down runtime errors.
11function reflectionIsSupported() {
12 return typeof Reflect !== 'undefined' && Reflect.defineMetadata && Reflect.getOwnMetadataKeys;
13}
14function copyReflectionMetadata(to, from) {
15 forwardMetadata(to, from);
16 Object.getOwnPropertyNames(from.prototype).forEach(key => {
17 forwardMetadata(to.prototype, from.prototype, key);
18 });
19 Object.getOwnPropertyNames(from).forEach(key => {
20 forwardMetadata(to, from, key);
21 });
22}
23
24function forwardMetadata(to, from, propertyKey) {
25 var metaKeys = propertyKey ? Reflect.getOwnMetadataKeys(from, propertyKey) : Reflect.getOwnMetadataKeys(from);
26 metaKeys.forEach(metaKey => {
27 var metadata = propertyKey ? Reflect.getOwnMetadata(metaKey, from, propertyKey) : Reflect.getOwnMetadata(metaKey, from);
28
29 if (propertyKey) {
30 Reflect.defineMetadata(metaKey, metadata, to, propertyKey);
31 } else {
32 Reflect.defineMetadata(metaKey, metadata, to);
33 }
34 });
35}
36
37var fakeArray = {
38 __proto__: []
39};
40var hasProto = fakeArray instanceof Array;
41function createDecorator(factory) {
42 return (target, key, index) => {
43 var Ctor = typeof target === 'function' ? target : target.constructor;
44
45 if (!Ctor.__decorators__) {
46 Ctor.__decorators__ = [];
47 }
48
49 if (typeof index !== 'number') {
50 index = undefined;
51 }
52
53 Ctor.__decorators__.push(options => factory(options, key, index));
54 };
55}
56function mixins() {
57 for (var _len = arguments.length, Ctors = new Array(_len), _key = 0; _key < _len; _key++) {
58 Ctors[_key] = arguments[_key];
59 }
60
61 return Vue.extend({
62 mixins: Ctors
63 });
64}
65function isPrimitive(value) {
66 var type = typeof value;
67 return value == null || type !== 'object' && type !== 'function';
68}
69function warn(message) {
70 if (typeof console !== 'undefined') {
71 console.warn('[vue-class-component] ' + message);
72 }
73}
74
75function collectDataFromConstructor(vm, Component) {
76 // override _init to prevent to init as Vue instance
77 var originalInit = Component.prototype._init;
78
79 Component.prototype._init = function () {
80 // proxy to actual vm
81 var keys = Object.getOwnPropertyNames(vm); // 2.2.0 compat (props are no longer exposed as self properties)
82
83 if (vm.$options.props) {
84 for (var key in vm.$options.props) {
85 if (!vm.hasOwnProperty(key)) {
86 keys.push(key);
87 }
88 }
89 }
90
91 keys.forEach(key => {
92 if (key.charAt(0) !== '_') {
93 Object.defineProperty(this, key, {
94 get: () => vm[key],
95 set: value => {
96 vm[key] = value;
97 },
98 configurable: true
99 });
100 }
101 });
102 }; // should be acquired class property values
103
104
105 var data = new Component(); // restore original _init to avoid memory leak (#209)
106
107 Component.prototype._init = originalInit; // create plain data object
108
109 var plainData = {};
110 Object.keys(data).forEach(key => {
111 if (data[key] !== undefined) {
112 plainData[key] = data[key];
113 }
114 });
115
116 {
117 if (!(Component.prototype instanceof Vue) && Object.keys(plainData).length > 0) {
118 warn('Component class must inherit Vue or its descendant class ' + 'when class property is used.');
119 }
120 }
121
122 return plainData;
123}
124
125var $internalHooks = ['data', 'beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeDestroy', 'destroyed', 'beforeUpdate', 'updated', 'activated', 'deactivated', 'render', 'errorCaptured', 'serverPrefetch' // 2.6
126];
127function componentFactory(Component) {
128 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
129 options.name = options.name || Component._componentTag || Component.name; // prototype props.
130
131 var proto = Component.prototype;
132 Object.getOwnPropertyNames(proto).forEach(function (key) {
133 if (key === 'constructor') {
134 return;
135 } // hooks
136
137
138 if ($internalHooks.indexOf(key) > -1) {
139 options[key] = proto[key];
140 return;
141 }
142
143 var descriptor = Object.getOwnPropertyDescriptor(proto, key);
144
145 if (descriptor.value !== void 0) {
146 // methods
147 if (typeof descriptor.value === 'function') {
148 (options.methods || (options.methods = {}))[key] = descriptor.value;
149 } else {
150 // typescript decorated data
151 (options.mixins || (options.mixins = [])).push({
152 data() {
153 return {
154 [key]: descriptor.value
155 };
156 }
157
158 });
159 }
160 } else if (descriptor.get || descriptor.set) {
161 // computed properties
162 (options.computed || (options.computed = {}))[key] = {
163 get: descriptor.get,
164 set: descriptor.set
165 };
166 }
167 });
168 (options.mixins || (options.mixins = [])).push({
169 data() {
170 return collectDataFromConstructor(this, Component);
171 }
172
173 }); // decorate options
174
175 var decorators = Component.__decorators__;
176
177 if (decorators) {
178 decorators.forEach(fn => fn(options));
179 delete Component.__decorators__;
180 } // find super
181
182
183 var superProto = Object.getPrototypeOf(Component.prototype);
184 var Super = superProto instanceof Vue ? superProto.constructor : Vue;
185 var Extended = Super.extend(options);
186 forwardStaticMembers(Extended, Component, Super);
187
188 if (reflectionIsSupported()) {
189 copyReflectionMetadata(Extended, Component);
190 }
191
192 return Extended;
193}
194var reservedPropertyNames = [// Unique id
195'cid', // Super Vue constructor
196'super', // Component options that will be used by the component
197'options', 'superOptions', 'extendOptions', 'sealedOptions', // Private assets
198'component', 'directive', 'filter'];
199var shouldIgnore = {
200 prototype: true,
201 arguments: true,
202 callee: true,
203 caller: true
204};
205
206function forwardStaticMembers(Extended, Original, Super) {
207 // We have to use getOwnPropertyNames since Babel registers methods as non-enumerable
208 Object.getOwnPropertyNames(Original).forEach(key => {
209 // Skip the properties that should not be overwritten
210 if (shouldIgnore[key]) {
211 return;
212 } // Some browsers does not allow reconfigure built-in properties
213
214
215 var extendedDescriptor = Object.getOwnPropertyDescriptor(Extended, key);
216
217 if (extendedDescriptor && !extendedDescriptor.configurable) {
218 return;
219 }
220
221 var descriptor = Object.getOwnPropertyDescriptor(Original, key); // If the user agent does not support `__proto__` or its family (IE <= 10),
222 // the sub class properties may be inherited properties from the super class in TypeScript.
223 // We need to exclude such properties to prevent to overwrite
224 // the component options object which stored on the extended constructor (See #192).
225 // If the value is a referenced value (object or function),
226 // we can check equality of them and exclude it if they have the same reference.
227 // If it is a primitive value, it will be forwarded for safety.
228
229 if (!hasProto) {
230 // Only `cid` is explicitly exluded from property forwarding
231 // because we cannot detect whether it is a inherited property or not
232 // on the no `__proto__` environment even though the property is reserved.
233 if (key === 'cid') {
234 return;
235 }
236
237 var superDescriptor = Object.getOwnPropertyDescriptor(Super, key);
238
239 if (!isPrimitive(descriptor.value) && superDescriptor && superDescriptor.value === descriptor.value) {
240 return;
241 }
242 } // Warn if the users manually declare reserved properties
243
244
245 if ( reservedPropertyNames.indexOf(key) >= 0) {
246 warn("Static property name '".concat(key, "' declared on class '").concat(Original.name, "' ") + 'conflicts with reserved property name of Vue internal. ' + 'It may cause unexpected behavior of the component. Consider renaming the property.');
247 }
248
249 Object.defineProperty(Extended, key, descriptor);
250 });
251}
252
253function Component(options) {
254 if (typeof options === 'function') {
255 return componentFactory(options);
256 }
257
258 return function (Component) {
259 return componentFactory(Component, options);
260 };
261}
262
263Component.registerHooks = function registerHooks(keys) {
264 $internalHooks.push(...keys);
265};
266
267export default Component;
268export { createDecorator, mixins };