@v4fire/client
Version:
V4Fire client core library
145 lines (119 loc) • 2.99 kB
text/typescript
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
import { defProp } from 'core/const/props';
import type { ComponentMeta } from 'core/component/interface';
/**
* Iterates over a prototype of a component constructor and adds methods/accessors to the specified meta object
*
* @param meta
* @param [constructor]
*/
export function addMethodsToMeta(meta: ComponentMeta, constructor: Function = meta.constructor): void {
const
proto = constructor.prototype,
ownProps = Object.getOwnPropertyNames(proto),
replace = !meta.params.flyweight;
const {
componentName: src,
props,
fields,
computedFields,
systemFields,
accessors,
methods
} = meta;
for (let i = 0; i < ownProps.length; i++) {
const
key = ownProps[i];
if (key === 'constructor') {
continue;
}
const
desc = <PropertyDescriptor>Object.getOwnPropertyDescriptor(proto, key);
// Methods
if ('value' in desc) {
const
fn = desc.value;
if (!Object.isFunction(fn)) {
continue;
}
methods[key] = Object.assign(methods[key] ?? {replace, watchers: {}, hooks: {}}, {src, fn});
// Accessors
} else {
const
propKey = `${key}Prop`,
storeKey = `${key}Store`;
let
metaKey;
// Computed fields are cached by default
if (
key in computedFields ||
!(key in accessors) && (props[propKey] || fields[storeKey] || systemFields[storeKey])
) {
metaKey = 'computedFields';
} else {
metaKey = 'accessors';
}
let
field;
if (props[key] != null) {
field = props;
} else if (fields[key] != null) {
field = fields;
} else {
field = systemFields;
}
const
obj = meta[metaKey];
// If we already have a property by this key, like a prop or a field,
// we need to delete it to correct override
if (field[key] != null) {
Object.defineProperty(proto, key, defProp);
delete field[key];
}
const
old = obj[key],
// eslint-disable-next-line @typescript-eslint/unbound-method
set = desc.set ?? old?.set,
// eslint-disable-next-line @typescript-eslint/unbound-method
get = desc.get ?? old?.get;
// For using "super" within a setter we also create a method with a name of form `${key}Setter`
if (set != null) {
const
k = `${key}Setter`;
proto[k] = set;
meta.methods[k] = {
src,
replace,
fn: set,
watchers: {},
hooks: {}
};
}
// For using "super" within a getter we also create a method with a name of form `${key}Getter`
if (get != null) {
const
k = `${key}Getter`;
proto[k] = get;
meta.methods[k] = {
src,
replace,
fn: get,
watchers: {},
hooks: {}
};
}
obj[key] = Object.assign(obj[key] ?? {replace}, {
src,
// eslint-disable-next-line @typescript-eslint/unbound-method
get: desc.get ?? old?.get,
set
});
}
}
}