UNPKG

vue-facing-decorator

Version:

Vue typescript class and decorator based component.

181 lines (160 loc) 5.59 kB
import { Base } from './index' import type { BaseTypeIdentify } from './index' import type { InjectConfig } from "./option/inject"; import type { EmitConfig } from "./option/emit"; import type { PropsConfig } from "./option/props"; import type { HookConfig } from "./option/methodsAndHooks"; import type { VModelConfig } from "./option/vmodel"; import type { WatchConfig } from "./option/watch"; import type { SetupConfig } from './option/setup' import type { Record as CustomDecoratorRecord } from './custom/custom' import type { RefConfig } from './option/ref'; import type { ProvideConfig } from './option/provide'; import { compatibleMemberDecorator } from './deco3/utils'; const SlotSymbol = Symbol('vue-facing-decorator-slot') export type SlotMapTypes = { vanilla: Map<string, boolean> computed: Map<string, boolean> provide: Map<string, ProvideConfig> inject: Map<string, InjectConfig> emit: Map<string, EmitConfig> emits: Map<string, boolean> props: Map<string, PropsConfig> hooks: Map<string, HookConfig> 'v-model': Map<string, VModelConfig> watch: Map<string, WatchConfig | WatchConfig[]> ref: Map<string, RefConfig> setup: Map<string, SetupConfig> customDecorator: Map<string, CustomDecoratorRecord[]> } class Slot { master: any constructor(master: any) { this.master = master } names: Map<string, SlotMapTypes[keyof SlotMapTypes]> = new Map() obtainMap<T extends keyof SlotMapTypes>(name: T): SlotMapTypes[T] { let map = this.getMap(name) if (!map) { map = new Map() this.names.set(name, map) } return map as SlotMapTypes[T] } getMap<T extends keyof SlotMapTypes>(name: T) { const map = this.names.get(name) return map as SlotMapTypes[T] | undefined } inComponent = false cachedVueComponent: any = null } export function makeSlot(obj: any, defaultSlot?: Slot): Slot { if (getSlot(obj)) { throw '' } if (defaultSlot) { defaultSlot.master = obj } const slot = defaultSlot ?? new Slot(obj) Object.defineProperty(obj, SlotSymbol, { enumerable: false, value: slot }) return slot } export function getSlot(obj: any): Slot | undefined { return Object.getOwnPropertyDescriptor(obj, SlotSymbol)?.value } export function obtainSlot(obj: any, defaultSlot?: Slot): Slot { const slot = getSlot(obj) if (slot) { return slot } return makeSlot(obj, defaultSlot) } export function makeObject(names: string[], obj: any) { return names.reduce<Record<string, any>>((pv, cv) => { pv[cv] = obj[cv] return pv }, {}) } export function toComponentReverse(obj: any) { const arr: any[] = [] let curr = obj do { arr.unshift(curr) curr = Object.getPrototypeOf(curr) } while (curr.constructor !== Base && !getSlot(curr)) return arr } export function getSuperSlot(obj: any) { let curr = Object.getPrototypeOf(obj) while (curr.constructor !== Base) { const slot = getSlot(curr) if (slot) { return slot } curr = Object.getPrototypeOf(curr) } return null } /** * Exclude decorated names by a filter */ export function excludeNames(names: string[], slot: Slot, filter?: (mapName: string) => boolean) { return names.filter(name => { let currSlot: Slot | null = slot while (currSlot != null) { for (const mapName of currSlot.names.keys()) { if (filter && !filter(mapName)) { continue } if (mapName === 'customDecorator') { const map = currSlot.obtainMap('customDecorator') if (map.has(name)) { if (map.get(name)!.every(ite=>!ite.preserve)) { return false } else { continue } } } const map = currSlot.names.get(mapName)! if (map.has(name)) { return false } } currSlot = getSuperSlot(currSlot.master) } return true }) } /** * Get own properties by a filter */ export function getValidNames(obj: any, filter: (des: PropertyDescriptor, name: string) => boolean) { const descriptors = Object.getOwnPropertyDescriptors(obj) return Object.keys(descriptors).filter(name => filter(descriptors[name], name)) } export function optionNullableMemberDecorator<T>(handler: { (proto: any, name: string, option?: T): any }) { function decorator(option?: T): any function decorator(proto: BaseTypeIdentify, name: any): any function decorator(value: any, ctx: ClassMemberDecoratorContext): any //deco stage 3 function decorator(optionOrProto?: T | BaseTypeIdentify | any, name?: string | ClassMemberDecoratorContext): any { if (name) { compatibleMemberDecorator(function (proto: any, name: any) { handler(proto, name) })(optionOrProto, name) } else { return compatibleMemberDecorator(function (proto: any, name: any) { handler(proto, name, optionOrProto as T | undefined) }) } } return decorator } export function getProviderFunction(provide: any): () => {} { if (typeof provide === 'function') return provide return function () { return provide || {} } }