vue-class-component
Version:
ES201X/TypeScript class decorator for Vue components
135 lines (134 loc) • 4.23 kB
JavaScript
function isFunction(value) {
return typeof value === 'function';
}
function getSuperOptions(Ctor) {
const superProto = Object.getPrototypeOf(Ctor.prototype);
if (!superProto) {
return undefined;
}
const Super = superProto.constructor;
return Super.__vccOpts;
}
export class Vue {
constructor(props) {
this.$props = props;
Object.keys(props).forEach(key => {
Object.defineProperty(this, key, {
enumerable: false,
configurable: true,
writable: true,
value: props[key]
});
});
}
/** @internal */
static get __vccOpts() {
// Early return if `this` is base class as it does not have any options
if (this === Vue) {
return {};
}
const cache = this.hasOwnProperty('__vccCache') && this.__vccCache;
if (cache) {
return cache;
}
const Ctor = this;
// If the options are provided via decorator use it as a base
const options = this.__vccCache = this.hasOwnProperty('__vccBase')
? { ...this.__vccBase }
: {};
// Handle super class options
options.extends = getSuperOptions(Ctor);
// Handle mixins
const mixins = this.hasOwnProperty('__vccMixins') && this.__vccMixins;
if (mixins) {
options.mixins = options.mixins ? options.mixins.concat(mixins) : mixins;
}
// Class name -> component name
options.name = options.name || Ctor.name;
options.methods = { ...options.methods };
options.computed = { ...options.computed };
const proto = Ctor.prototype;
Object.getOwnPropertyNames(proto).forEach(key => {
if (key === 'constructor') {
return;
}
// hooks
if (Ctor.__vccHooks.indexOf(key) > -1) {
options[key] = proto[key];
return;
}
const descriptor = Object.getOwnPropertyDescriptor(proto, key);
// methods
if (typeof descriptor.value === 'function') {
options.methods[key] = descriptor.value;
return;
}
// computed properties
if (descriptor.get || descriptor.set) {
options.computed[key] = {
get: descriptor.get,
set: descriptor.set
};
return;
}
});
// Class properties -> reactive data
const hookDataOption = options.data;
options.data = function () {
const hookData = isFunction(hookDataOption)
? hookDataOption.call(this, this)
: hookDataOption;
// should be acquired class property values
const data = new Ctor(this.$props);
// create plain data object
const plainData = {};
Object.keys(data).forEach(key => {
if (data[key] !== undefined && key !== '$props') {
plainData[key] = data[key];
}
});
return {
...hookData,
...plainData
};
};
const decorators = this.hasOwnProperty('__vccDecorators') && this.__vccDecorators;
if (decorators) {
decorators.forEach(fn => fn(options));
}
// from Vue Loader
if (Ctor.render) {
options.render = Ctor.render;
}
if (Ctor.__file) {
options.__file = Ctor.__file;
}
if (Ctor.__cssModules) {
options.__cssModules = Ctor.__cssModules;
}
if (Ctor.__scopeId) {
options.__scopeId = Ctor.__scopeId;
}
return options;
}
static registerHooks(keys) {
this.__vccHooks.push(...keys);
}
}
/** @internal */
Vue.__vccHooks = [
'data',
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUnmount',
'unmounted',
'beforeUpdate',
'updated',
'activated',
'deactivated',
'render',
'errorCaptured',
'serverPrefetch'
];