@v4fire/client
Version:
V4Fire client core library
264 lines (212 loc) • 5.13 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 { deprecate } from 'core/functools/deprecation';
import { ComponentInterface } from 'core/component/interface';
import { propRgxp, attrRgxp, storeRgxp, hasSeparator } from 'core/component/reflection/const';
import type { PropertyInfo } from 'core/component/reflection/interface';
/**
* Returns an information object of a component property by the specified path
*
* @param path
* @param component - component instance
*
* @example
* ```js
* @component()
* class bButton {
* @system()
* fooStore = {bla: 'bar'};
*
* get foo() {
* return this.fooStore;
* }
*
* created() {
* // {
* // name: 'fooStore',
* // path: 'fooStore.bar',
* // fullPath: '$root.$refs.button.fooStore.bar',
* // topPath: '$root.$refs.button.fooStore',
* // originalPath: '$root.$refs.button.foo.bar',
* // originalTopPath: '$root.$refs.button.foo',
* // type: 'system',
* // accessor: 'foo',
* // accessorType: 'computed'
* // }
* console.log(getPropertyInfo('$root.$refs.button.foo.bar', this));
* }
* }
* ```
*/
export function getPropertyInfo(path: string, component: ComponentInterface): PropertyInfo {
const
originalPath = path;
let
name = path,
fullPath = path,
topPath = path,
originalTopPath = path;
let
chunks,
rootI = 0;
if (hasSeparator.test(path)) {
chunks = path.split('.');
let
obj: Nullable<ComponentInterface> = component;
for (let i = 0; i < chunks.length; i++) {
if (obj == null) {
break;
}
obj = obj[chunks[i]];
if (obj?.instance instanceof ComponentInterface) {
component = obj;
rootI = i === chunks.length - 1 ? i : i + 1;
}
}
path = chunks.slice(rootI).join('.');
topPath = chunks.slice(0, rootI + 1).join('.');
originalTopPath = topPath;
name = chunks[rootI];
}
const
{props, fields, systemFields, computedFields, accessors, params: {deprecatedProps}} = component.unsafe.meta;
const
alternative = deprecatedProps?.[name];
if (alternative != null) {
deprecate({type: 'property', name, renamedTo: alternative});
name = alternative;
if (chunks != null) {
chunks[rootI] = name;
path = chunks.slice(rootI).join('.');
topPath = chunks.slice(0, rootI + 1).join('.');
originalTopPath = topPath;
fullPath = chunks.join('.');
} else {
path = name;
fullPath = name;
topPath = name;
originalTopPath = name;
}
}
const info: PropertyInfo = {
name,
type: 'field',
ctx: resolveCtx(component),
path,
fullPath,
originalPath,
topPath,
originalTopPath
};
if (RegExp.test(propRgxp, name)) {
info.type = 'prop';
return info;
}
if (RegExp.test(attrRgxp, name)) {
info.type = 'attr';
return info;
}
if (RegExp.test(storeRgxp, name)) {
if (fields[name] != null) {
return info;
}
info.type = 'system';
return info;
}
if (fields[name] != null) {
return info;
}
if (props[name] != null) {
info.type = 'prop';
return info;
}
if (systemFields[name] != null) {
info.type = 'system';
return info;
}
const
storeName = `${name}Store`,
hasStoreField = fields[storeName] != null || systemFields[storeName] != null,
propName = hasStoreField ? null : `${name}Prop`;
let
accessorType,
accessor;
if (computedFields[name] != null) {
accessorType = 'computed';
accessor = name;
} else if (accessors[name] != null) {
accessorType = 'accessor';
accessor = name;
}
if (hasStoreField || propName != null && props[propName]) {
name = propName ?? storeName;
if (chunks != null) {
chunks[rootI] = name;
path = chunks.slice(rootI).join('.');
fullPath = chunks.join('.');
topPath = chunks.slice(0, rootI + 1).join('.');
} else {
path = name;
fullPath = name;
topPath = name;
}
let
type: PropertyInfo['type'] = 'field';
if (propName != null) {
type = 'prop';
} else if (systemFields[storeName] != null) {
type = 'system';
}
return {
...info,
name,
type,
path,
fullPath,
topPath,
accessor,
accessorType
};
}
if (accessorType != null) {
if ((computedFields[name] ?? accessors[name])!.watchable) {
let
ctxPath;
if (chunks != null) {
ctxPath = chunks.slice(0, rootI + 1);
path = chunks.slice(rootI + 1).join('.');
topPath = chunks.slice(0, rootI + 2).join('.');
originalTopPath = topPath;
} else {
ctxPath = path;
path = '';
topPath = '';
originalTopPath = '';
}
return {
...info,
type: 'mounted',
ctx: resolveCtx(Object.get(component, ctxPath) ?? {}),
path,
originalPath,
topPath,
originalTopPath
};
}
info.type = accessorType;
return info;
}
info.type = 'system';
return info;
function resolveCtx(component: object): ComponentInterface {
if (Object.cast<Dictionary>(component).$remoteParent != null) {
return Object.getPrototypeOf(component);
}
return Object.cast(component);
}
}