zova-core 5.0.110 → 5.0.113

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/dist/bean/beanBaseSimple.d.ts.map +1 -1
  2. package/dist/bean/beanBaseSimple.js +10 -2
  3. package/dist/bean/beanBaseSimple.js.map +1 -1
  4. package/dist/core/resource.d.ts +6 -6
  5. package/dist/core/resource.d.ts.map +1 -1
  6. package/dist/core/resource.js +2 -6
  7. package/dist/core/resource.js.map +1 -1
  8. package/dist/decorator/class/use.js +8 -5
  9. package/dist/decorator/class/use.js.map +1 -1
  10. package/package.json +4 -3
  11. package/src/bean/beanBase.ts +53 -0
  12. package/src/bean/beanBaseSimple.ts +38 -0
  13. package/src/bean/beanContainer.ts +963 -0
  14. package/src/bean/beanControllerBase.ts +58 -0
  15. package/src/bean/beanControllerLike.ts +29 -0
  16. package/src/bean/beanControllerPageBase.ts +18 -0
  17. package/src/bean/beanRenderBase.ts +7 -0
  18. package/src/bean/beanRenderLike.ts +33 -0
  19. package/src/bean/beanSimple.ts +11 -0
  20. package/src/bean/beanStyleBase.ts +3 -0
  21. package/src/bean/index.ts +13 -0
  22. package/src/bean/resource/component/index.ts +1 -0
  23. package/src/bean/resource/component/type.ts +5 -0
  24. package/src/bean/resource/config/index.ts +1 -0
  25. package/src/bean/resource/config/type.ts +32 -0
  26. package/src/bean/resource/constant/index.ts +1 -0
  27. package/src/bean/resource/constant/type.ts +1 -0
  28. package/src/bean/resource/error/beanScopeError.ts +21 -0
  29. package/src/bean/resource/error/errorClass.ts +57 -0
  30. package/src/bean/resource/error/errorGlobal.ts +7 -0
  31. package/src/bean/resource/error/errorInternal.ts +66 -0
  32. package/src/bean/resource/error/errorObject.ts +4 -0
  33. package/src/bean/resource/error/index.ts +6 -0
  34. package/src/bean/resource/error/type.ts +10 -0
  35. package/src/bean/resource/icon/icon.ts +161 -0
  36. package/src/bean/resource/icon/iconGroup.ts +10 -0
  37. package/src/bean/resource/icon/index.ts +4 -0
  38. package/src/bean/resource/icon/types.ts +21 -0
  39. package/src/bean/resource/icon/useZovaIcon.ts +20 -0
  40. package/src/bean/resource/icon/utils.ts +20 -0
  41. package/src/bean/resource/icon/zovaIcon.ts +52 -0
  42. package/src/bean/resource/index.ts +8 -0
  43. package/src/bean/resource/locale/beanScopeLocale.ts +22 -0
  44. package/src/bean/resource/locale/index.ts +2 -0
  45. package/src/bean/resource/locale/type.ts +21 -0
  46. package/src/bean/resource/page/index.ts +1 -0
  47. package/src/bean/resource/page/type.ts +12 -0
  48. package/src/bean/resource/service/beanScopeService.ts +24 -0
  49. package/src/bean/resource/service/index.ts +2 -0
  50. package/src/bean/resource/service/type.ts +8 -0
  51. package/src/bean/scope/beanScopeBase.ts +74 -0
  52. package/src/bean/scope/index.ts +4 -0
  53. package/src/bean/scope/type.ts +23 -0
  54. package/src/bean/type.ts +31 -0
  55. package/src/composables/index.ts +4 -0
  56. package/src/composables/onControllerMounted.ts +12 -0
  57. package/src/composables/useApp.ts +7 -0
  58. package/src/composables/useContext.ts +7 -0
  59. package/src/composables/useController.ts +125 -0
  60. package/src/core/app/application.ts +76 -0
  61. package/src/core/app/config.ts +68 -0
  62. package/src/core/app/constant.ts +11 -0
  63. package/src/core/app/index.ts +6 -0
  64. package/src/core/app/locale.ts +12 -0
  65. package/src/core/app/meta.ts +44 -0
  66. package/src/core/app/util.ts +31 -0
  67. package/src/core/component/component.ts +44 -0
  68. package/src/core/component/cookie.ts +16 -0
  69. package/src/core/component/error.ts +18 -0
  70. package/src/core/component/event.ts +87 -0
  71. package/src/core/component/index.ts +3 -0
  72. package/src/core/component/locale.ts +97 -0
  73. package/src/core/component/module.ts +281 -0
  74. package/src/core/context/component.ts +34 -0
  75. package/src/core/context/context.ts +38 -0
  76. package/src/core/context/index.ts +4 -0
  77. package/src/core/context/meta.ts +26 -0
  78. package/src/core/context/state.ts +28 -0
  79. package/src/core/context/util.ts +20 -0
  80. package/src/core/index.ts +5 -0
  81. package/src/core/metadata.ts +54 -0
  82. package/src/core/resource.ts +186 -0
  83. package/src/decorator/class/bean.ts +19 -0
  84. package/src/decorator/class/index.ts +12 -0
  85. package/src/decorator/class/local.ts +18 -0
  86. package/src/decorator/class/model.ts +18 -0
  87. package/src/decorator/class/scope.ts +18 -0
  88. package/src/decorator/class/store.ts +18 -0
  89. package/src/decorator/class/style.ts +18 -0
  90. package/src/decorator/class/theme.ts +18 -0
  91. package/src/decorator/class/tool.ts +18 -0
  92. package/src/decorator/class/use.ts +37 -0
  93. package/src/decorator/class/useComposable.ts +16 -0
  94. package/src/decorator/class/useScope.ts +21 -0
  95. package/src/decorator/class/virtual.ts +20 -0
  96. package/src/decorator/index.ts +7 -0
  97. package/src/decorator/interface/beanOptions.ts +80 -0
  98. package/src/decorator/interface/useOptions.ts +37 -0
  99. package/src/decorator/type/constructable.ts +1 -0
  100. package/src/decorator/type/containerScope.ts +1 -0
  101. package/src/decorator/type/functionable.ts +1 -0
  102. package/src/decorator/type/injectionScope.ts +1 -0
  103. package/src/index.ts +9 -0
  104. package/src/plugins/bean.ts +16 -0
  105. package/src/plugins/index.ts +2 -0
  106. package/src/plugins/zova.ts +28 -0
  107. package/src/types/index.ts +2 -0
  108. package/src/types/interface/component.ts +36 -0
  109. package/src/types/interface/event.ts +28 -0
  110. package/src/types/interface/index.ts +6 -0
  111. package/src/types/interface/inject.ts +2 -0
  112. package/src/types/interface/module.ts +38 -0
  113. package/src/types/interface/monkey.ts +38 -0
  114. package/src/types/interface/pluginZova.ts +17 -0
  115. package/src/types/utils/cast.ts +8 -0
  116. package/src/types/utils/env.ts +35 -0
  117. package/src/types/utils/index.ts +3 -0
  118. package/src/types/utils/powerPartial.ts +3 -0
  119. package/src/utils/index.ts +1 -0
  120. package/src/utils/isClass.ts +17 -0
  121. package/src/utils/stateLock.ts +47 -0
  122. package/src/utils/uuid.ts +84 -0
  123. package/src/vue/composable.ts +10 -0
  124. package/src/vue/computed.ts +7 -0
  125. package/src/vue/customRef.ts +5 -0
  126. package/src/vue/index.ts +4 -0
  127. package/src/vue/ref.ts +12 -0
  128. package/src/zod/index.ts +2 -0
  129. package/src/zod/zz.ts +77 -0
  130. package/dist/decorator/class/data.d.ts +0 -3
  131. package/dist/decorator/class/data.d.ts.map +0 -1
  132. package/dist/decorator/class/data.js +0 -18
  133. package/dist/decorator/class/data.js.map +0 -1
@@ -0,0 +1,963 @@
1
+ import { isClass } from '../utils/isClass.js';
2
+ import { AppUtil, ZovaApplication, ZovaContext } from '../core/index.js';
3
+ import {
4
+ Constructable,
5
+ Functionable,
6
+ IDecoratorBeanOptionsBase,
7
+ IDecoratorUseOptionsBase,
8
+ } from '../decorator/index.js';
9
+ import { appResource } from '../core/resource.js';
10
+ import { MetadataKey } from '../core/metadata.js';
11
+ import { IBeanRecord, IBeanScopeRecord, IControllerData, TypeBeanScopeRecordKeys } from './type.js';
12
+ import { BeanBase } from './beanBase.js';
13
+ import { BeanSimple } from './beanSimple.js';
14
+ import { compose, composeAsync } from '@cabloy/compose';
15
+ import { markRaw, reactive, shallowReactive, provide as composableProvide, inject as composableInject } from 'vue';
16
+ import { Cast } from '../types/utils/cast.js';
17
+ import { IInjectRecord } from '../types/interface/inject.js';
18
+ import { SymbolBeanFullName, SymbolInited } from './beanBaseSimple.js';
19
+
20
+ const SymbolBeanContainerParent = Symbol('Bean#BeanContainerParent');
21
+ const SymbolProxyMagic = Symbol('Bean#ProxyMagic');
22
+ export const BeanContainerInstances = Symbol('Bean#Instances');
23
+
24
+ export interface BeanContainer extends IBeanRecord {}
25
+
26
+ export class BeanContainer {
27
+ private app: ZovaApplication;
28
+ private ctx: ZovaContext;
29
+ private appUtil: AppUtil;
30
+
31
+ // fullName / uuid / propName
32
+ private [BeanContainerInstances]: Record<MetadataKey, unknown> = shallowReactive({});
33
+
34
+ static create(app: ZovaApplication, ctx: ZovaContext | null) {
35
+ const beanContainer = new BeanContainer(app, ctx);
36
+ const proxy = new Proxy(beanContainer, {
37
+ get(obj, prop) {
38
+ if (typeof prop === 'symbol') return obj[prop];
39
+ if (obj[prop]) return obj[prop];
40
+ return obj._getBeanSyncOnly(prop);
41
+ },
42
+ });
43
+ return markRaw(proxy);
44
+ }
45
+
46
+ protected constructor(app: ZovaApplication, ctx: ZovaContext | null) {
47
+ this.app = app;
48
+ this.ctx = ctx as any;
49
+ this.appUtil = new AppUtil();
50
+ }
51
+
52
+ /** @internal */
53
+ public dispose() {
54
+ const beanInstances = this[BeanContainerInstances];
55
+ for (const prop in beanInstances) {
56
+ if (prop.startsWith('$$')) continue;
57
+ const beanInstance = Cast(beanInstances[prop]);
58
+ if (beanInstance.__dispose__) {
59
+ this.app.meta.module._monkeyModule('beanDispose', undefined, this, beanInstance);
60
+ this.runWithInstanceScopeOrAppContext(() => {
61
+ beanInstance.__dispose__();
62
+ });
63
+ this.app.meta.module._monkeyModule('beanDisposed', undefined, this, beanInstance);
64
+ }
65
+ }
66
+ this[BeanContainerInstances] = shallowReactive({});
67
+ this[SymbolBeanContainerParent] = undefined;
68
+ }
69
+
70
+ get parent(): BeanContainer | null {
71
+ if (this[SymbolBeanContainerParent] === undefined) {
72
+ this[SymbolBeanContainerParent] = this._getParent();
73
+ }
74
+ return this[SymbolBeanContainerParent];
75
+ }
76
+
77
+ private _getParent(): BeanContainer | null {
78
+ let parent = this.ctx?.instance?.parent;
79
+ while (true) {
80
+ if (!parent) return null;
81
+ const beanContainerParent = parent.zova?.bean;
82
+ if (beanContainerParent) return beanContainerParent;
83
+ parent = parent.parent;
84
+ }
85
+ }
86
+
87
+ runWithInstanceScopeOrAppContext(fn, tracking?: boolean) {
88
+ if (this.ctx) {
89
+ return this.ctx.meta.util.instanceScope(fn, tracking);
90
+ } else {
91
+ return this.app.vue.runWithContext(fn);
92
+ }
93
+ }
94
+
95
+ provide<K extends keyof IInjectRecord>(injectKey: K, value: IInjectRecord[K]) {
96
+ return this.ctx.meta.util.instanceScope(() => {
97
+ return composableProvide(injectKey, value as any);
98
+ });
99
+ }
100
+
101
+ inject<K extends keyof IInjectRecord>(injectKey: K): IInjectRecord[K];
102
+ inject<K extends keyof IInjectRecord>(
103
+ injectKey: K,
104
+ defaultValue: IInjectRecord[K],
105
+ treatDefaultAsFactory?: false,
106
+ ): IInjectRecord[K];
107
+ inject<K extends keyof IInjectRecord>(
108
+ injectKey: K,
109
+ defaultValue: IInjectRecord[K] | (() => IInjectRecord[K]),
110
+ treatDefaultAsFactory?: true,
111
+ ): IInjectRecord[K];
112
+ inject(injectKey, defaultValue?, treatDefaultAsFactory?) {
113
+ return this.ctx.meta.util.instanceScope(() => {
114
+ return composableInject(injectKey, defaultValue, treatDefaultAsFactory);
115
+ });
116
+ }
117
+
118
+ defineProperty<T>(obj: T, prop: string, attributes: PropertyDescriptor & ThisType<any>): T {
119
+ const self = this;
120
+ const attrs = { ...attributes };
121
+ if (attributes.get) {
122
+ attrs.get = function () {
123
+ const innerKey = `__innerKey_${prop}`;
124
+ if (!obj[innerKey]) {
125
+ self.runWithInstanceScopeOrAppContext(() => {
126
+ obj[innerKey] = attributes.get!();
127
+ });
128
+ }
129
+ return obj[innerKey];
130
+ };
131
+ }
132
+ return Object.defineProperty(obj, prop, attrs);
133
+ }
134
+
135
+ /** get specific module's scope */
136
+ scope<K extends TypeBeanScopeRecordKeys>(moduleScope: K): IBeanScopeRecord[K];
137
+ scope<T>(moduleScope: string): T;
138
+ scope<T>(moduleScope: string): T {
139
+ if (this !== this.app.bean) {
140
+ return this.app.bean.scope(moduleScope);
141
+ }
142
+ return this._getBeanSyncOnly(`${moduleScope}.scope.module`);
143
+ }
144
+
145
+ async getScope<K extends TypeBeanScopeRecordKeys>(moduleScope: K): Promise<IBeanScopeRecord[K]>;
146
+ async getScope<T>(moduleScope: string): Promise<T>;
147
+ async getScope<T>(moduleScope: string): Promise<T> {
148
+ if (this !== this.app.bean) {
149
+ return await this.app.bean.getScope(moduleScope);
150
+ }
151
+ // module: load
152
+ await this.app.meta.module.use(moduleScope);
153
+ return this.scope(moduleScope);
154
+ }
155
+
156
+ _getBeanSync<K extends keyof IBeanRecord>(
157
+ beanFullName: K,
158
+ markReactive?: boolean,
159
+ forceLoad?: boolean,
160
+ ): IBeanRecord[K] | undefined;
161
+ _getBeanSync<T>(key: string, markReactive?: boolean, forceLoad?: boolean): T | undefined;
162
+ _getBeanSync<T>(key: string, markReactive?: boolean, forceLoad?: boolean): T | undefined {
163
+ const beanInstance: any = this[BeanContainerInstances][key];
164
+ if (!beanInstance) {
165
+ // bean not loaded, so async load to raise the next call
166
+ if (forceLoad !== false) {
167
+ this._getBean(key as any, markReactive);
168
+ }
169
+ return undefined;
170
+ }
171
+ if (beanInstance[SymbolInited] && !beanInstance[SymbolInited].state) {
172
+ return undefined;
173
+ }
174
+ return beanInstance as T;
175
+ }
176
+
177
+ _getBeanSyncOnly<T>(key: MetadataKey): T {
178
+ return this[BeanContainerInstances][key] as T;
179
+ }
180
+
181
+ async _getBean<T>(A: Constructable<T>, markReactive?: boolean): Promise<T>;
182
+ async _getBean<K extends keyof IBeanRecord>(beanFullName: K, markReactive?: boolean): Promise<IBeanRecord[K]>;
183
+ // async _getBean<T>(beanFullName: string, markReactive?: boolean): Promise<T>;
184
+ async _getBean<T>(beanFullName: Constructable<T> | string, markReactive?: boolean): Promise<T> {
185
+ return await this._getBeanSelector(beanFullName as any, markReactive);
186
+ }
187
+
188
+ async _getBeanSelector<T>(A: Constructable<T>, markReactive?: boolean, selector?: string): Promise<T>;
189
+ async _getBeanSelector<K extends keyof IBeanRecord>(
190
+ beanFullName: K,
191
+ markReactive?: boolean,
192
+ selector?: string,
193
+ ): Promise<IBeanRecord[K]>;
194
+ // async _getBeanSelector<T>(beanFullName: string, markReactive?: boolean, selector?: string): Promise<T>;
195
+ async _getBeanSelector<T>(
196
+ beanFullName: Constructable<T> | string,
197
+ markReactive?: boolean,
198
+ selector?: string,
199
+ ): Promise<T> {
200
+ return await this._getBeanSelectorInner(true, null, undefined, beanFullName, markReactive, selector);
201
+ }
202
+
203
+ async _getBeanSelectorInner<T>(
204
+ newBeanForce: boolean,
205
+ recordProp: MetadataKey | null,
206
+ beanComposable: Functionable | undefined,
207
+ beanFullName: Constructable<T> | string | undefined,
208
+ markReactive?: boolean,
209
+ selector?: string,
210
+ ): Promise<T> {
211
+ // fullName
212
+ const fullName = await this._getBeanFullNameByComposableOrClass(beanComposable, beanFullName);
213
+ if (!fullName) {
214
+ // not found
215
+ return null!;
216
+ }
217
+ // same as _getBean if selector is undefined/null/'', as as to get the same bean instance
218
+ // not use !selector which maybe is 0
219
+ const isSelectorValid = !this.app.meta.util.isNullOrEmptyString(selector);
220
+ const key = !isSelectorValid ? fullName : `${fullName}#${selector}`;
221
+ if (this[BeanContainerInstances][key] === undefined && newBeanForce) {
222
+ if (isSelectorValid) {
223
+ await this._newBeanInner(true, recordProp, null, beanComposable, fullName, markReactive, selector);
224
+ } else {
225
+ await this._newBeanInner(true, recordProp, null, beanComposable, fullName, markReactive);
226
+ }
227
+ }
228
+ return this[BeanContainerInstances][key] as T;
229
+ }
230
+
231
+ _newBeanSimple<T>(A: Constructable<T>, markReactive: boolean, ...args): T {
232
+ // prepare
233
+ const beanInstance = this._prepareBeanInstance(undefined, A, A, args, false, markReactive);
234
+ // init
235
+ if (beanInstance.__init__) {
236
+ beanInstance.__init__(...args);
237
+ }
238
+ // ok
239
+ return beanInstance;
240
+ }
241
+
242
+ async _newBean<T>(A: Constructable<T>, markReactive?: boolean, ...args): Promise<T>;
243
+ async _newBean<K extends keyof IBeanRecord>(
244
+ beanFullName: K,
245
+ markReactive?: boolean,
246
+ ...args
247
+ ): Promise<IBeanRecord[K]>;
248
+ // async _newBean<T>(beanFullName: string, markReactive?: boolean, ...args): Promise<T>;
249
+ async _newBean<T>(beanFullName: Constructable<T> | string, markReactive?: boolean, ...args): Promise<T> {
250
+ return await this._newBeanInner(false, null, null, undefined, beanFullName, markReactive, ...args);
251
+ }
252
+
253
+ async _newBeanSelector<T>(A: Constructable<T>, markReactive?: boolean, selector?: string, ...args): Promise<T>;
254
+ async _newBeanSelector<K extends keyof IBeanRecord>(
255
+ beanFullName: K,
256
+ markReactive?: boolean,
257
+ selector?: string,
258
+ ...args
259
+ ): Promise<IBeanRecord[K]>;
260
+ // async _newBeanSelector<T>(beanFullName: string, markReactive?: boolean, selector?: string, ...args): Promise<T>;
261
+ async _newBeanSelector<T>(
262
+ beanFullName: Constructable<T> | string,
263
+ markReactive?: boolean,
264
+ selector?: string,
265
+ ...args
266
+ ): Promise<T> {
267
+ return await this._newBean(beanFullName as any, markReactive, selector, ...args);
268
+ }
269
+
270
+ /** @internal */
271
+ public async _newBeanInner<T>(
272
+ record: boolean,
273
+ recordProp: MetadataKey | null,
274
+ controllerData: any,
275
+ beanComposable: Functionable | undefined,
276
+ beanFullName: Constructable<T> | string | undefined,
277
+ markReactive?: boolean,
278
+ ...args
279
+ ): Promise<T> {
280
+ // bean composable
281
+ if (beanComposable) {
282
+ return await this._createBeanInstance<T>(
283
+ record,
284
+ recordProp,
285
+ controllerData,
286
+ beanComposable,
287
+ undefined,
288
+ undefined,
289
+ args,
290
+ false,
291
+ markReactive,
292
+ );
293
+ }
294
+ // bean options
295
+ const beanOptions = await this._getBeanOptionsForce(beanFullName);
296
+ if (!beanOptions) {
297
+ // class
298
+ if (typeof beanFullName === 'function' && isClass(beanFullName)) {
299
+ return await this._createBeanInstance<T>(
300
+ record,
301
+ recordProp,
302
+ controllerData,
303
+ undefined,
304
+ undefined,
305
+ beanFullName,
306
+ args,
307
+ false,
308
+ markReactive,
309
+ );
310
+ }
311
+ // throw new Error(`bean not found: ${beanFullName}`);
312
+ return null!;
313
+ }
314
+ // beanFullName
315
+ return await this._createBeanInstance<T>(
316
+ record,
317
+ recordProp,
318
+ controllerData,
319
+ undefined,
320
+ beanOptions.beanFullName,
321
+ beanOptions.beanClass as Constructable<T>,
322
+ args,
323
+ beanOptions.aop,
324
+ // default is true: same as inject prop
325
+ markReactive ?? beanOptions.markReactive ?? true,
326
+ );
327
+ }
328
+
329
+ private async _getBeanFullNameByComposableOrClass(beanComposable: Functionable | undefined, beanFullName: any) {
330
+ // bean composable
331
+ if (beanComposable) {
332
+ return appResource.getBeanFullNameOfComposable(beanComposable);
333
+ }
334
+ // bean options
335
+ const beanOptions = await this._getBeanOptionsForce(beanFullName);
336
+ if (!beanOptions) {
337
+ // not found
338
+ return undefined;
339
+ }
340
+ return beanOptions.beanFullName;
341
+ }
342
+
343
+ private async _getBeanOptionsForce(beanFullName: any) {
344
+ // class
345
+ if (typeof beanFullName === 'function' && isClass(beanFullName)) {
346
+ return appResource.getBean(beanFullName);
347
+ }
348
+ // check if uuid
349
+ if (!this.appUtil.isUuid(beanFullName)) {
350
+ // module: name
351
+ const moduleName = beanFullName.split('.')[0];
352
+ // module: load
353
+ await this.app.meta.module.use(moduleName);
354
+ }
355
+ // get
356
+ return appResource.getBean(beanFullName);
357
+ }
358
+
359
+ private async _createBeanInstance<T>(
360
+ record: boolean,
361
+ recordProp: MetadataKey | null,
362
+ controllerData: IControllerData,
363
+ beanComposable: Functionable | undefined,
364
+ beanFullName: string | undefined,
365
+ beanClass: Constructable<T> | undefined,
366
+ args: any[],
367
+ aop: boolean | undefined,
368
+ markReactive: boolean | undefined,
369
+ ): Promise<T> {
370
+ // prepare
371
+ const beanInstance = this._prepareBeanInstance(beanComposable, beanFullName, beanClass, args, aop, markReactive);
372
+ // special for controller
373
+ if (controllerData) {
374
+ beanInstance.__initControllerData(controllerData);
375
+ }
376
+ // record
377
+ if (record) {
378
+ // fullName
379
+ const fullName = await this._getBeanFullNameByComposableOrClass(beanComposable, beanFullName);
380
+ if (fullName) {
381
+ this[BeanContainerInstances][fullName] = beanInstance;
382
+ }
383
+ // always record for app/ctx bean
384
+ if (recordProp) {
385
+ this.__recordProp(recordProp, fullName, beanInstance, true);
386
+ }
387
+ }
388
+ // init
389
+ if (!beanComposable) {
390
+ await this._initBeanInstance(beanFullName, beanInstance, args);
391
+ }
392
+ // ok
393
+ return beanInstance;
394
+ }
395
+
396
+ private _prepareBeanInstance(
397
+ beanComposable: Functionable | undefined,
398
+ beanFullName,
399
+ beanClass,
400
+ args,
401
+ aop,
402
+ markReactive,
403
+ ) {
404
+ // create
405
+ let beanInstance;
406
+ if (beanComposable) {
407
+ beanInstance = this._createBeanComposableInstance(beanComposable, args);
408
+ } else {
409
+ if (beanClass.prototype.__init__) {
410
+ beanInstance = new beanClass();
411
+ } else {
412
+ beanInstance = new beanClass(...args);
413
+ }
414
+ }
415
+ // app/ctx
416
+ if (beanInstance instanceof BeanSimple) {
417
+ // app
418
+ (<any>beanInstance).app = this.app;
419
+ // ctx: always set even if is null, so as to prevent magic method __get__ take effect.
420
+ (<any>beanInstance).ctx = this.ctx;
421
+ }
422
+ // beanFullName
423
+ if (typeof beanFullName === 'string') {
424
+ __setPropertyValue(beanInstance, SymbolBeanFullName, beanFullName);
425
+ }
426
+ // reactive
427
+ if (markReactive) {
428
+ beanInstance = reactive(beanInstance);
429
+ } else {
430
+ beanInstance = markRaw(beanInstance);
431
+ }
432
+ // aop: proxy
433
+ const beanInstanceProxy = this._patchBeanInstance(beanFullName || beanClass, beanInstance, aop);
434
+ if (beanInstanceProxy) {
435
+ // reactive
436
+ if (markReactive) {
437
+ beanInstance = reactive(beanInstanceProxy);
438
+ } else {
439
+ beanInstance = markRaw(beanInstanceProxy);
440
+ }
441
+ }
442
+ // ok
443
+ return beanInstance;
444
+ }
445
+
446
+ private _createBeanComposableInstance(beanComposable, args) {
447
+ return this.runWithInstanceScopeOrAppContext(function () {
448
+ return beanComposable(...args);
449
+ });
450
+ }
451
+
452
+ private async _initBeanInstance(beanFullName, beanInstance, args) {
453
+ // inject
454
+ await this._injectBeanInstance(beanInstance, beanFullName);
455
+ // init
456
+ if (this.app) {
457
+ await this.app.meta.module._monkeyModule('beanInit', undefined, this, beanInstance);
458
+ }
459
+ if (beanInstance.__init__) {
460
+ await this.runWithInstanceScopeOrAppContext(async () => {
461
+ await beanInstance.__init__(...args);
462
+ });
463
+ }
464
+ if (this.app) {
465
+ await this.app.meta.module._monkeyModule('beanInited', undefined, this, beanInstance);
466
+ }
467
+ if (beanInstance[SymbolInited]) {
468
+ beanInstance[SymbolInited].touch();
469
+ }
470
+ // ok
471
+ return beanInstance;
472
+ }
473
+
474
+ private async _injectBeanInstance(beanInstance, beanFullName) {
475
+ const beanOptions = appResource.getBean(beanFullName);
476
+ if (!beanOptions) return;
477
+ const uses = appResource.getUses(beanOptions.beanClass.prototype);
478
+ if (!uses) return;
479
+ for (const key in uses) {
480
+ const useOptions = uses[key];
481
+ // beanComposable
482
+ const targetBeanComposable = useOptions.beanComposable;
483
+ // beanClass
484
+ let targetBeanFullName = useOptions.beanFullName;
485
+ if (!targetBeanFullName && useOptions.beanClass) {
486
+ targetBeanFullName = appResource.getBeanFullName(useOptions.beanClass);
487
+ }
488
+ const targetBeanInstance = await this._injectBeanInstanceProp(
489
+ targetBeanComposable,
490
+ targetBeanFullName,
491
+ useOptions,
492
+ );
493
+ if (targetBeanInstance) {
494
+ targetBeanInstance.__v_isShallow_patch = true;
495
+ beanInstance[key] = targetBeanInstance;
496
+ delete targetBeanInstance.__v_isShallow_patch;
497
+ } else {
498
+ beanInstance[key] = targetBeanInstance;
499
+ }
500
+ }
501
+ }
502
+
503
+ private async _injectBeanInstanceProp(
504
+ targetBeanComposable: Functionable | undefined,
505
+ targetBeanFullName: string | undefined,
506
+ useOptions: IDecoratorUseOptionsBase,
507
+ ) {
508
+ // 0. host/skipSelf
509
+ if (useOptions.injectionScope === 'host') {
510
+ return await this._getBeanFromHost(true, this, targetBeanComposable, targetBeanFullName, useOptions);
511
+ } else if (useOptions.injectionScope === 'skipSelf') {
512
+ return await this._getBeanFromHost(true, this.parent, targetBeanComposable, targetBeanFullName, useOptions);
513
+ }
514
+ // 1. use name
515
+ if (useOptions.name) {
516
+ return this[BeanContainerInstances][useOptions.name];
517
+ }
518
+ // 2. use prop
519
+ if (!targetBeanComposable && !targetBeanFullName) {
520
+ return this[BeanContainerInstances][useOptions.prop];
521
+ }
522
+ // 3. targetBeanFullName
523
+ let targetOptions: Pick<IDecoratorBeanOptionsBase, 'containerScope' | 'markReactive'> | undefined;
524
+ if (targetBeanComposable) {
525
+ targetOptions = {
526
+ containerScope: undefined,
527
+ markReactive: undefined,
528
+ };
529
+ } else if (targetBeanFullName) {
530
+ targetOptions = await this._getBeanOptionsForce(targetBeanFullName);
531
+ if (!targetOptions) {
532
+ throw new Error(`not found bean class: ${targetBeanFullName}`);
533
+ }
534
+ }
535
+ // options: injectionScope
536
+ const injectionScope = useOptions.injectionScope ?? targetOptions!.containerScope ?? 'ctx';
537
+ // options: markReactive: default is true
538
+ const markReactive = useOptions.markReactive ?? targetOptions!.markReactive ?? true;
539
+ // options: selector: maybe empty string
540
+ const selector = useOptions.selector;
541
+ // recordProp
542
+ //const recordProp = useOptions.name || useOptions.prop;
543
+ const recordProp = useOptions.prop;
544
+ // targetInstance
545
+ let targetInstance;
546
+ if (injectionScope === 'app') {
547
+ targetInstance = await this.app.bean._getBeanSelectorInner(
548
+ true,
549
+ null,
550
+ targetBeanComposable,
551
+ targetBeanFullName,
552
+ markReactive,
553
+ selector,
554
+ );
555
+ await this._injectBeanInstanceProp_appBean(recordProp, targetBeanComposable, targetBeanFullName, targetInstance);
556
+ } else if (injectionScope === 'ctx') {
557
+ targetInstance = await this._getBeanSelectorInner(
558
+ true,
559
+ recordProp,
560
+ targetBeanComposable,
561
+ targetBeanFullName,
562
+ markReactive,
563
+ selector,
564
+ );
565
+ } else if (injectionScope === 'new') {
566
+ // not record prop
567
+ targetInstance = await this._newBeanInner(
568
+ false,
569
+ null,
570
+ null,
571
+ targetBeanComposable,
572
+ targetBeanFullName,
573
+ markReactive,
574
+ selector,
575
+ );
576
+ }
577
+ return targetInstance;
578
+ }
579
+
580
+ private async _getBeanFromHost(
581
+ recordProp: boolean,
582
+ beanContainerStart: BeanContainer | null,
583
+ targetBeanComposable: Functionable | undefined,
584
+ targetBeanFullName: string | undefined,
585
+ useOptions: IDecoratorUseOptionsBase,
586
+ ) {
587
+ let beanContainerParent = beanContainerStart;
588
+ while (true) {
589
+ if (!beanContainerParent) return null;
590
+ const beanInstance = await this._getBeanFromHostInner(
591
+ beanContainerParent,
592
+ targetBeanComposable,
593
+ targetBeanFullName,
594
+ useOptions,
595
+ );
596
+ // null is valid value
597
+ if (beanInstance !== undefined) {
598
+ // record prop
599
+ if (recordProp) {
600
+ this.__recordProp(useOptions.prop, undefined, beanInstance, false);
601
+ }
602
+ return beanInstance;
603
+ }
604
+ beanContainerParent = beanContainerParent.parent;
605
+ }
606
+ }
607
+
608
+ private async _getBeanFromHostInner(
609
+ beanContainerParent: BeanContainer,
610
+ targetBeanComposable: Functionable | undefined,
611
+ targetBeanFullName: string | undefined,
612
+ useOptions: IDecoratorUseOptionsBase,
613
+ ) {
614
+ // 1. use name
615
+ if (useOptions.name) {
616
+ return beanContainerParent[BeanContainerInstances][useOptions.name];
617
+ }
618
+ // 2. use prop
619
+ if (!targetBeanComposable && !targetBeanFullName) {
620
+ return beanContainerParent[BeanContainerInstances][useOptions.prop];
621
+ }
622
+ // 3. targetBeanFullName
623
+ return await beanContainerParent._getBeanSelectorInner(
624
+ false,
625
+ null,
626
+ targetBeanComposable,
627
+ targetBeanFullName,
628
+ undefined,
629
+ useOptions.selector,
630
+ );
631
+ }
632
+
633
+ private async _injectBeanInstanceProp_appBean(recordProp, targetBeanComposable, _targetBeanFullName, targetInstance) {
634
+ if (targetInstance === undefined) return;
635
+ // only when ctx bean
636
+ if (!this.ctx) return;
637
+ // record prop
638
+ this.__recordProp(recordProp, undefined, targetInstance, false);
639
+ // force init
640
+ if (!targetBeanComposable && targetInstance) {
641
+ await targetInstance[SymbolInited].wait();
642
+ }
643
+ }
644
+
645
+ private _patchBeanInstance(beanFullNameOrBeanClass, beanInstance, aop) {
646
+ if (!beanFullNameOrBeanClass) return undefined;
647
+ // not aop on aop
648
+ if (aop) return undefined;
649
+ // aop chains
650
+ const _aopChains = this._prepareAopChains(beanFullNameOrBeanClass, beanInstance);
651
+ // no aop
652
+ if (_aopChains.length === 0) return undefined;
653
+ // aop
654
+ return this._newBeanProxy(beanFullNameOrBeanClass, beanInstance);
655
+ }
656
+
657
+ private _newBeanProxy(beanFullName, beanInstance) {
658
+ const self = this;
659
+ const proxy = new Proxy(beanInstance, {
660
+ get(target, prop, receiver) {
661
+ if (typeof prop === 'symbol') {
662
+ return target[prop];
663
+ }
664
+ if (__isInnerMethod(prop)) {
665
+ if (prop === '__v_isShallow' && target.__v_isShallow_patch) return target.__v_isShallow_patch;
666
+ return target[prop];
667
+ }
668
+ // descriptorInfo
669
+ const descriptorInfo = __getPropertyDescriptor(target, prop);
670
+ if (!__checkAopOfDescriptorInfo(descriptorInfo)) return target[prop];
671
+ const methodType = __methodTypeOfDescriptor(descriptorInfo);
672
+ // get prop
673
+ if (!methodType) {
674
+ const methodName = `__get_${prop}__`;
675
+ const methodNameMagic = '__get__';
676
+ const _aopChainsProp = self._getAopChainsProp(beanFullName, methodName, methodNameMagic);
677
+ if (_aopChainsProp.length === 0) return target[prop];
678
+ // context
679
+ const context = {
680
+ target,
681
+ receiver,
682
+ prop,
683
+ value: undefined,
684
+ };
685
+ // aop
686
+ self.__composeForProp(_aopChainsProp)(context, (context, next) => {
687
+ if (context.value === undefined) {
688
+ if (!descriptorInfo && target.__get__) {
689
+ context.value = target.__get__(prop);
690
+ } else {
691
+ context.value = target[prop];
692
+ }
693
+ }
694
+ next();
695
+ });
696
+ // ok
697
+ return context.value;
698
+ }
699
+ // method
700
+ return self._getInstanceMethodProxy(beanFullName, target, prop, methodType);
701
+ },
702
+ set(target, prop, value, receiver) {
703
+ if (typeof prop === 'symbol') {
704
+ target[prop] = value;
705
+ return true;
706
+ }
707
+ if (__isInnerMethod(prop)) {
708
+ target[prop] = value;
709
+ return true;
710
+ }
711
+ // descriptorInfo
712
+ const descriptorInfo = __getPropertyDescriptor(target, prop);
713
+ if (!__checkAopOfDescriptorInfo(descriptorInfo)) {
714
+ target[prop] = value;
715
+ return true;
716
+ }
717
+ const methodName = `__set_${prop}__`;
718
+ const methodNameMagic = '__set__';
719
+ const _aopChainsProp = self._getAopChainsProp(beanFullName, methodName, methodNameMagic);
720
+ if (_aopChainsProp.length === 0) {
721
+ target[prop] = value;
722
+ return true;
723
+ }
724
+ // context
725
+ const context = {
726
+ target,
727
+ receiver,
728
+ prop,
729
+ value,
730
+ };
731
+ // aop
732
+ self.__composeForProp(_aopChainsProp)(context, (context, next) => {
733
+ if (!descriptorInfo && target.__set__) {
734
+ const res = target.__set__(prop, context.value);
735
+ if (res === undefined) throw new Error('__set__ must return true/false');
736
+ if (!res) {
737
+ target[prop] = context.value;
738
+ }
739
+ } else {
740
+ target[prop] = context.value;
741
+ }
742
+ next();
743
+ });
744
+ // ok
745
+ return true;
746
+ },
747
+ });
748
+ return proxy;
749
+ }
750
+
751
+ private _getInstanceMethodProxy(beanFullName, beanInstance, prop, methodType) {
752
+ const self = this;
753
+ // not aop magic methods
754
+ if (__isInnerMethod(prop)) {
755
+ return beanInstance[prop];
756
+ }
757
+ // aop chains
758
+ const _aopChainsProp = this._getAopChainsProp(beanFullName, prop, null);
759
+ if (_aopChainsProp.length === 0) return beanInstance[prop];
760
+ // proxy
761
+ const methodProxyKey = `__aopproxy_method_${prop}__`;
762
+ if (beanInstance[methodProxyKey]) return beanInstance[methodProxyKey];
763
+ const methodProxy = new Proxy(beanInstance[prop], {
764
+ apply(target, thisArg, args) {
765
+ // context
766
+ const context = {
767
+ target: beanInstance,
768
+ receiver: thisArg,
769
+ prop,
770
+ arguments: args,
771
+ result: undefined,
772
+ };
773
+ // aop
774
+ if (methodType === 'Function') {
775
+ self.__composeForProp(_aopChainsProp)(context, (context, next) => {
776
+ if (context.result === undefined) {
777
+ context.result = target.apply(thisArg, args);
778
+ }
779
+ next();
780
+ });
781
+ // ok
782
+ return context.result;
783
+ }
784
+ if (methodType === 'AsyncFunction') {
785
+ return new Promise((resolve, reject) => {
786
+ self
787
+ .__composeForPropAsync(_aopChainsProp)(context, async (context, next) => {
788
+ if (context.result === undefined) {
789
+ context.result = await target.apply(thisArg, args);
790
+ }
791
+ await next();
792
+ })
793
+ .then(() => {
794
+ resolve(context.result);
795
+ })
796
+ .catch(err => {
797
+ reject(err);
798
+ });
799
+ });
800
+ }
801
+ },
802
+ });
803
+ __setPropertyValue(beanInstance, methodProxyKey, methodProxy);
804
+ return methodProxy;
805
+ }
806
+
807
+ private _prepareAopChains(beanFullNameOrBeanClass, beanInstance) {
808
+ if (!beanFullNameOrBeanClass) return [];
809
+ // beanFullName maybe class
810
+ const beanOptions = appResource.getBean(beanFullNameOrBeanClass);
811
+ const host = beanOptions || beanFullNameOrBeanClass;
812
+ if (host.__aopChains__) return host.__aopChains__;
813
+ // chains
814
+ let chains: MetadataKey[] = [];
815
+ if (beanOptions && !beanOptions.aop) {
816
+ const aops = appResource.findAopsMatched(beanOptions.beanFullName);
817
+ if (aops) {
818
+ chains = chains.concat(aops);
819
+ }
820
+ }
821
+ // magic self
822
+ if (__hasMagicMothod(beanInstance)) {
823
+ chains.push(SymbolProxyMagic);
824
+ }
825
+ // hold
826
+ host.__aopChains__ = chains;
827
+ return chains;
828
+ }
829
+
830
+ private _getAopChains(beanFullName) {
831
+ // beanFullName maybe class
832
+ const beanOptions = appResource.getBean(beanFullName);
833
+ const host = beanOptions || beanFullName;
834
+ return host.__aopChains__;
835
+ }
836
+
837
+ private _getAopChainsProp(beanFullName, methodName, methodNameMagic) {
838
+ const chainsKey = `__aopChains_${methodName}__`;
839
+ const beanOptions = appResource.getBean(beanFullName);
840
+ const host = beanOptions || beanFullName;
841
+ if (!host.__aopChainsKey__) host.__aopChainsKey__ = {};
842
+ if (host.__aopChainsKey__[chainsKey]) return host.__aopChainsKey__[chainsKey];
843
+ const _aopChains = this._getAopChains(beanFullName);
844
+ const chains: [MetadataKey, string][] = [];
845
+ for (const aopKey of _aopChains) {
846
+ if (aopKey === SymbolProxyMagic) {
847
+ chains.push([aopKey, methodName]);
848
+ } else {
849
+ const aop: any = this._getBeanSyncOnly(aopKey as string);
850
+ if (aop[methodName]) {
851
+ chains.push([aopKey, methodName]);
852
+ } else if (methodNameMagic && aop[methodNameMagic]) {
853
+ chains.push([aopKey, methodNameMagic]);
854
+ }
855
+ }
856
+ }
857
+ host.__aopChainsKey__[chainsKey] = chains;
858
+ return chains;
859
+ }
860
+
861
+ private __composeForPropAdapter = (_context, chain) => {
862
+ const [aopKey, methodName] = chain;
863
+ // SymbolProxyMagic
864
+ if (aopKey === SymbolProxyMagic) return null;
865
+ // chain
866
+ const aop = this._getBeanSyncOnly(aopKey);
867
+ if (!aop) throw new Error(`aop not found: ${chain}`);
868
+ if (!aop[methodName]) return null;
869
+ return {
870
+ receiver: aop,
871
+ fn: aop[methodName],
872
+ };
873
+ };
874
+
875
+ private __composeForProp(chains) {
876
+ return compose(chains, this.__composeForPropAdapter);
877
+ }
878
+
879
+ private __composeForPropAsync(chains) {
880
+ return composeAsync(chains, this.__composeForPropAdapter);
881
+ }
882
+
883
+ private __recordProp(recordProp, fullName: string | undefined, beanInstance, throwError: boolean) {
884
+ if (this[BeanContainerInstances][recordProp] !== undefined && throwError) {
885
+ throw new Error(`prop exsits: ${recordProp.toString()}, ${fullName}`);
886
+ }
887
+ if (this[BeanContainerInstances][recordProp] === undefined) {
888
+ this[BeanContainerInstances][recordProp] = beanInstance;
889
+ }
890
+ }
891
+ }
892
+
893
+ function __checkAopOfDescriptorInfo(descriptorInfo) {
894
+ if (!descriptorInfo) return true;
895
+ return !descriptorInfo.dynamic && !descriptorInfo.ofBeanBase;
896
+ }
897
+
898
+ function __getPropertyDescriptor(obj, prop) {
899
+ // dynamic
900
+ const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
901
+ if (descriptor) return { descriptor, dynamic: true };
902
+ // static
903
+ return __getPropertyDescriptorStatic(obj, prop);
904
+ }
905
+
906
+ function __getPropertyDescriptorStatic(obj, prop) {
907
+ let proto = Object.getPrototypeOf(obj);
908
+ let ofBeanBase = false;
909
+ while (proto) {
910
+ if (proto.constructor.name === BeanBase.name) {
911
+ ofBeanBase = true;
912
+ }
913
+ const descriptor = Object.getOwnPropertyDescriptor(proto, prop);
914
+ if (descriptor) return { descriptor, dynamic: false, ofBeanBase };
915
+ proto = Object.getPrototypeOf(proto);
916
+ }
917
+ return null;
918
+ }
919
+
920
+ function __setPropertyValue(obj, prop, value) {
921
+ Object.defineProperty(obj, prop, {
922
+ enumerable: false,
923
+ configurable: true,
924
+ get() {
925
+ return value;
926
+ },
927
+ });
928
+ }
929
+
930
+ function __hasMagicMothod(instance) {
931
+ return !!instance.__get__ || !!instance.__set__;
932
+ }
933
+
934
+ function __isInnerMethod(prop) {
935
+ return [
936
+ '__get__',
937
+ '__set__',
938
+ '__init__',
939
+ '__dispose__',
940
+ 'then',
941
+ '__v_skip',
942
+ '__v_isReactive',
943
+ '__v_isReadonly',
944
+ '__v_isShallow',
945
+ '__v_raw',
946
+ '__v_isRef',
947
+ '__v_isVNode',
948
+ '__v_cache',
949
+ '__v_isShallow_patch',
950
+ ].includes(prop);
951
+ }
952
+
953
+ function __methodTypeOfDescriptor(descriptorInfo) {
954
+ if (!descriptorInfo) return null;
955
+ const { descriptor, dynamic } = descriptorInfo;
956
+ if (dynamic) return null;
957
+ if (descriptor.get) return null;
958
+ const methodType = descriptor.value?.constructor?.name;
959
+ if (['Function', 'AsyncFunction'].includes(methodType)) {
960
+ return methodType;
961
+ }
962
+ return null;
963
+ }