import type { Logger } from '@cabloy/logger'; import type { ReactiveMarker } from '@vue/reactivity'; import type { ComputedGetter, DebuggerOptions, MultiWatchSources, RendererNode, WatchCallback, WatchEffect, WatchEffectOptions, WatchHandle, WatchOptions, WatchSource, WritableComputedOptions, } from 'vue'; import { watch, watchEffect, watchPostEffect, watchSyncEffect } from 'vue'; import type { AppEvent } from '../core/component/event.ts'; import type { ILoggerChildRecord, ILoggerClientRecord } from '../core/logger/types.ts'; import type { FunctionAsync } from '../decorator/type/functionable.ts'; import type { MapSources, MaybeUndefined } from '../vueExtra/watch.ts'; import type { IErrorHandlerEventResult, IModuleLocaleText, IZovaComponentRecord } from './resource/index.ts'; import { cast } from '../types/utils/cast.ts'; import { useComputed } from '../vueExtra/computed.ts'; import { BeanBaseSimple, SymbolModuleBelong } from './beanBaseSimple.ts'; import { SymbolErrorInstanceInfo } from './resource/index.ts'; import { getVueDecoratorValue } from './vueDecorators/utils.ts'; const SymbolText = Symbol('SymbolText'); const SymbolLogger = Symbol('SymbolLogger'); const SymbolLoggerChildren = Symbol('SymbolLoggerChildren'); export class BeanBase extends BeanBaseSimple { private [SymbolText]: IModuleLocaleText; private [SymbolLogger]: Record = {} as any; private [SymbolLoggerChildren]: Record> = {} as any; protected get $el(): RendererNode { if (!this.ctx) { throw new Error('$el can not be used inside global bean.'); } return this.ctx.meta.el; } protected get $text(): IModuleLocaleText { if (!this[SymbolText]) { this[SymbolText] = this.app.meta.locale.createLocaleText(this[SymbolModuleBelong]); } return this[SymbolText]; } protected get $logger() { return this.$loggerClient('default'); } protected $loggerClient(clientName: keyof ILoggerClientRecord) { if (!this[SymbolLogger][clientName]) { this[SymbolLogger][clientName] = this.sys.meta.logger.get(clientName).child({ beanFullName: this.$beanFullName }); } return this[SymbolLogger][clientName]; } protected $loggerChild(childName: keyof ILoggerChildRecord, clientName: keyof ILoggerClientRecord = 'default') { if (!this[SymbolLoggerChildren][clientName]) this[SymbolLoggerChildren][clientName] = {} as never; if (!this[SymbolLoggerChildren][clientName][childName]) { this[SymbolLoggerChildren][clientName][childName] = this.sys.meta.logger.get(clientName).child({ beanFullName: this.$beanFullName, name: childName, }); } return this[SymbolLoggerChildren][clientName][childName]; } protected get $event(): AppEvent { return this.app.meta.event; } // need not // protected async __init__() {} // protected __dispose__() {} public get scope(): unknown { return this.bean.scope(this[SymbolModuleBelong] as never); } protected $watchHandle(prop: string | Function, index?: number): WatchHandle { if (typeof prop === 'function') { prop = prop.name; } return getVueDecoratorValue(this, prop, index ?? 0); } protected $renderFreeze(freeze: boolean) { return cast(this.ctx.instance).ctx.renderFreeze(freeze); } protected async $renderFreezeScope(fn: FunctionAsync): Promise { if (this.ctx.disposed) return; return await cast(this.ctx.instance).ctx.renderFreezeScope(fn); } protected $onCreated(fn: any) { this.ctx.meta.hooks.onCreated(fn); } protected $onMounted(fn: any) { this.ctx.meta.hooks.onMounted(fn); } protected $errorHandler(err: unknown, info?: string): IErrorHandlerEventResult { if (err instanceof Error && err[SymbolErrorInstanceInfo]) { delete err[SymbolErrorInstanceInfo]; } return this.app?.vue.config.errorHandler!(err, this.ctx.instance as any, info!) as unknown as IErrorHandlerEventResult; } protected $useComputed(getter: ComputedGetter, debugOptions?: DebuggerOptions): T; protected $useComputed(options: WritableComputedOptions, debugOptions?: DebuggerOptions): T; protected $useComputed(options, debugOptions) { return this.ctx.util.instanceScope(() => { return useComputed(options, debugOptions); }); } protected $watchEffect(effect: WatchEffect, options?: WatchEffectOptions): WatchHandle { return this.ctx.util.instanceScope(() => { return watchEffect(effect, options); }); } protected $watchPostEffect(effect: WatchEffect, options?: DebuggerOptions): WatchHandle { return this.ctx.util.instanceScope(() => { return watchPostEffect(effect, options); }); } protected $watchSyncEffect(effect: WatchEffect, options?: DebuggerOptions): WatchHandle { return this.ctx.util.instanceScope(() => { return watchSyncEffect(effect, options); }); } protected $watch = false>( source: WatchSource, cb: WatchCallback>, options?: WatchOptions, ): WatchHandle; protected $watch, Immediate extends Readonly = false>( sources: readonly [...T] | T, cb: [T] extends [ReactiveMarker] ? WatchCallback> : WatchCallback, MapSources>, options?: WatchOptions, ): WatchHandle; protected $watch = false>( sources: [...T], cb: WatchCallback, MapSources>, options?: WatchOptions, ): WatchHandle; protected $watch = false>( source: T, cb: WatchCallback>, options?: WatchOptions, ): WatchHandle { return this.ctx.util.instanceScope(() => { return watch(source, cb, options); }); } protected $onControllerCreated(fn: any) { return this.ctx.util.instanceScope(() => { return this.ctx.meta.hooks.onCreated(fn); }); } protected $controllerMounted(fn: any) { return this.ctx.util.instanceScope(() => { return this.ctx.meta.hooks.onMounted(fn); }); } protected $zovaComponent(componentName: K): IZovaComponentRecord[K]; protected $zovaComponent(module: string, name: string); protected $zovaComponent(module: string, name?: string) { return this.sys.meta.component.getZovaComponent(module, name!); } // need not // public dispose() { // const self = cast(this); // if (self.__dispose__) { // self.__dispose__(); // } // } }