UNPKG

vue-facing-decorator

Version:

Vue typescript class and decorator based component.

131 lines (115 loc) 4.35 kB
import type { IdentityAny } from './identity' import { compatibleMemberDecorator, compatibleClassDecorator } from './deco3/utils'; import { type VueCons, Base } from './class'; import { getSlot, type Slot, type SlotMapNames } from './slot' export function getPrototypeOf(proto: IdentityAny): IdentityAny | null { const p = Object.getPrototypeOf(proto) if (!(p instanceof Base)) { return null } return p } export function toComponentReverse(proto: IdentityAny) { const arr: IdentityAny[] = [] let curr: IdentityAny | null = proto do { arr.unshift(curr) curr = getPrototypeOf(curr) } while (curr !== null && !getSlot(curr)) return arr } export function getSuperSlot(proto: IdentityAny) { let curr = getPrototypeOf(proto) while (curr !== null) { const slot = getSlot(curr) if (slot) { return slot } curr = getPrototypeOf(curr) } return null } /** * Filter decorated names */ export function filterNames(names: string[], slot: Slot, mapNames?: SlotMapNames[]) { return names.filter(name => { let currSlot: Slot | null = slot while (currSlot != null) { for (const mapName of currSlot.names.keys()) { if (mapName === 'customDecorator') { const map = currSlot.obtainMap('customDecorator') if (map.has(name)) { if (map.get(name)!.every(ite => !ite.preserve)) { return false } } } if (mapNames && mapNames.includes(mapName)) { continue } const map = currSlot.names.get(mapName)! if (map.has(name)) { return false } } currSlot = getSuperSlot(currSlot.master) } return true }) } /** * Get own propertie name by a filter */ export function getValidOwnPropertyNames(obj: any, filter: (des: PropertyDescriptor, name: string) => boolean) { const descriptors = Object.getOwnPropertyDescriptors(obj) return Object.keys(descriptors).filter(name => filter(descriptors[name], name)) } /** * Transform provide into function. */ export function getProviderFunction(provide: any): () => {} { if (typeof provide === 'function') return provide return function () { return provide || {} } } export function optionNullableMemberDecorator<T>(handler: { (proto: any, name: string, option?: T): any }) { function decorator(): any function decorator(option: T): any//option function decorator(proto: IdentityAny, name: any): any//deco stage 2 function decorator(value: any, ctx: ClassMemberDecoratorContext): any //deco stage 3 function decorator(optionOrProtoOrValue?: T | IdentityAny | any, nameOrCtx?: string | ClassMemberDecoratorContext): any { if (nameOrCtx) {//no option const protoOrValue = optionOrProtoOrValue as IdentityAny | any compatibleMemberDecorator(function (proto: any, name: any) { handler(proto, name) })(protoOrValue, nameOrCtx) } else {//with option const option = optionOrProtoOrValue as T return compatibleMemberDecorator(function (proto: any, name: any) { handler(proto, name, option as T | undefined) }) } } return decorator } export function optionNullableClassDecorator<T>(handler: { (cons: VueCons, option?: T): any }) { function decorator(): any function decorator(option: T): any//option function decorator(cons: VueCons): any//deco stage 2 function decorator(cons: VueCons, ctx: ClassDecoratorContext): any//deco stage 3 function decorator(optionOrCons?: T | VueCons, ctx?: ClassDecoratorContext) { if (typeof optionOrCons === 'function') { const cons = optionOrCons as VueCons compatibleClassDecorator(function (cons: VueCons) { handler(cons) })(cons, ctx) } else { const option = optionOrCons as T return compatibleClassDecorator(function (cons: VueCons) { handler(cons, option) }) } } return decorator }