ivue 1.5.7 → 1.6.1

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.
package/dist/ivue.d.ts CHANGED
@@ -1,25 +1,35 @@
1
- import type { ComputedRef, ExtractPropTypes, Ref, ToRef } from 'vue';
1
+ import type { ExtractPropTypes, Ref, ToRef } from 'vue';
2
2
  import type { Ref as DemiRef } from 'vue-demi';
3
3
  /** Types */
4
4
  /**
5
5
  * IVue core reactive instance type with an extended .toRefs() method added.
6
6
  */
7
- export declare type IVue<T extends AnyClass> = InstanceType<T> & ExtendWithToRefs<T>;
7
+ export declare type IVue<T extends AnyClass> = InstanceType<T> & {
8
+ toRefs: IVueToRefsFn<T>;
9
+ clone: IVueClone<T>;
10
+ };
8
11
  /**
9
- * Extend with .toRefs() method, so that a reactive class can be converted to a composable definition.
12
+ * Type definition for `.clone()` method creates a deep clone of the ivue instance.
10
13
  */
11
- export interface ExtendWithToRefs<T extends AnyClass> {
12
- toRefs: IVueToRefsFn<T>;
13
- }
14
+ export declare type IVueClone<T extends AnyClass> = (...cloneArgs: CloneArgsFor<InstanceType<T>>) => IVue<T>;
14
15
  /**
15
16
  * Type definition for `.toRefs()` method converts reactive class properties to composable .value properties.
16
17
  * But if props = true OR unwrap = true is specified, the refs will be unwrapped refs to be able to be merged with the the root class properties without losing reactivity.
17
18
  */
18
- export interface IVueToRefsFn<T extends AnyClass> {
19
- <P extends keyof InstanceType<T>>(props: P[]): Pick<IVueRefs<InstanceType<T>>, P>;
20
- <P extends keyof InstanceType<T>>(props: P[], unwrap: false): Pick<IVueRefs<InstanceType<T>>, P>;
21
- <P extends keyof InstanceType<T>>(props: P[], unwrap: true): Pick<InstanceType<T>, P>;
22
- (props: true): InstanceType<T>;
19
+ /** Extract only non-method keys from a type */
20
+ declare type NonMethodKeys<T> = {
21
+ [K in keyof T]: T[K] extends AnyFn ? never : K;
22
+ }[keyof T];
23
+ /** Create a type with only data properties and accessors */
24
+ declare type DataProperties<T> = Pick<T, NonMethodKeys<T>>;
25
+ /**
26
+ * Simplified IVueToRefsFn that only works with data properties
27
+ */
28
+ interface IVueToRefsFn<T extends AnyClass> {
29
+ <P extends keyof IVueRefs<InstanceType<T>>>(props: P[]): Pick<IVueRefs<InstanceType<T>>, P>;
30
+ <P extends keyof IVueRefs<InstanceType<T>>>(props: P[], unwrap: false): Pick<IVueRefs<InstanceType<T>>, P>;
31
+ <P extends keyof DataProperties<InstanceType<T>>>(props: P[], unwrap: true): Pick<DataProperties<InstanceType<T>>, P>;
32
+ (props: true): DataProperties<InstanceType<T>>;
23
33
  (props: false): IVueRefs<InstanceType<T>>;
24
34
  (): IVueRefs<InstanceType<T>>;
25
35
  }
@@ -28,7 +38,7 @@ export interface IVueToRefsFn<T extends AnyClass> {
28
38
  * also knows NOT to convert functions to .value Refs but to leave them as is.
29
39
  */
30
40
  export declare type IVueRefs<T> = {
31
- [K in keyof T]: T[K] extends Function ? T[K] : ToRef<T[K]>;
41
+ [K in keyof T as T[K] extends AnyFn ? never : K]: ToRef<T[K]>;
32
42
  };
33
43
  /**
34
44
  * Unwraps Ref Recursively, helps resolve fully the bare value types of any type T
@@ -37,19 +47,19 @@ export declare type IVueRefs<T> = {
37
47
  * are difficult to fully resolve to bare values without this utility.
38
48
  * Also support Vue 3 Demi for vue-use library support.
39
49
  */
40
- export declare type UnwrapRefRecursively<T = any> = T extends Ref | DemiRef ? UnwrapRefRecursively<T['value']> : T;
50
+ declare type UnwrapRefRecursively<T = any> = T extends Ref | DemiRef ? UnwrapRefRecursively<T['value']> : T;
41
51
  /**
42
- * Helper type for Use type, unwraps any type of Vue 3 composable down to its bare types.
52
+ * Helper type for Use type, unwraps any type of Vue 3 composable return object down to its bare types.
43
53
  */
44
- export declare type Unwrap<T> = T extends Ref | DemiRef ? UnwrapRefRecursively<T> : {
54
+ declare type UnwrapComposableRefs<T> = T extends Ref | DemiRef ? UnwrapRefRecursively<T> : {
45
55
  [K in keyof T]: T[K] extends Ref | DemiRef ? UnwrapRefRecursively<T[K]> : T[K];
46
56
  };
47
57
  /**
48
58
  * Fully unwraps to bare value types any Vue 3 composable return definition type.
49
59
  */
50
- export declare type Use<T = any> = T extends Ref | DemiRef ? UnwrapRefRecursively<T> : Unwrap<T extends AnyFn ? ReturnType<T> : T>;
60
+ export declare type Use<T = any> = T extends Ref | DemiRef ? UnwrapRefRecursively<T> : UnwrapComposableRefs<T extends AnyFn ? ReturnType<T> : T>;
51
61
  /**
52
- * Extracts object defined emit types by converting them to a plain interface
62
+ * Extracts object defined emit types by converting them to a plain interface.
53
63
  */
54
64
  export declare type ExtractEmitTypes<T extends Record<string, any>> = UnionToIntersection<RecordToUnion<{
55
65
  [K in keyof T]: (evt: K, ...args: Parameters<T[K]>) => void;
@@ -72,15 +82,11 @@ export declare type AnyFn = (...args: any[]) => any;
72
82
  /**
73
83
  * Any JavaScript class of any type.
74
84
  */
75
- export declare type AnyClass = abstract new (...args: any[]) => any;
85
+ export declare type AnyClass = new (...args: any[]) => any;
76
86
  /**
77
- * Descriptors map type.
87
+ * Accessors map type.
78
88
  */
79
- export declare type Descriptors = Map<string, PropertyDescriptor>;
80
- /**
81
- * Computeds hash map type.
82
- */
83
- export declare type Computeds = Record<string, ComputedRef>;
89
+ declare type Accessors = Map<string, PropertyDescriptor>;
84
90
  /**
85
91
  * Infer paramaters of a constructor function of a Class.
86
92
  */
@@ -93,14 +99,6 @@ export declare type InferredArgs<T> = T extends {
93
99
  export declare type PrefixKeys<T, P extends string | undefined = undefined> = {
94
100
  [K in Extract<keyof T, string> as P extends string ? `${P}${K}` : K]: T[K];
95
101
  };
96
- /**
97
- * Get Interface's property's function arguments Parmeters<F>
98
- */
99
- export declare type IFnParameters<T extends Record<any, any>, K extends string> = Parameters<Required<Pick<T, K>>[K]>;
100
- /**
101
- * Get Interface's [T] property's [P] function arguments Parmeters<F> parameter by key [K]
102
- */
103
- export declare type IFnParameter<T extends Record<any, any>, P extends keyof T, K extends number> = FnParameter<ValueOf<T, P>, K>;
104
102
  /**
105
103
  * Get function arguments Parmeters<F> parameter by key K
106
104
  */
@@ -108,34 +106,96 @@ export declare type FnParameter<F extends AnyFn, K extends number> = Parameters<
108
106
  /**
109
107
  * Convert Union Type to Intersection Type.
110
108
  */
111
- export declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
109
+ declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
112
110
  /**
113
111
  * Convert Record to Union Type.
114
112
  */
115
- export declare type RecordToUnion<T extends Record<string, any>> = T[keyof T];
113
+ declare type RecordToUnion<T extends Record<string, any>> = T[keyof T];
116
114
  /**
117
115
  * Gets object T property by key [K].
118
116
  */
119
- export declare type ValueOf<T extends Record<any, any>, K> = T[K];
117
+ declare type ValueOf<T extends Record<any, any>, K> = T[K];
118
+ /**
119
+ * Props Map Value type.
120
+ */
121
+ declare type PropsMapValue = {
122
+ allProps: Map<string, PropKind>;
123
+ onlyProps: Set<string>;
124
+ };
125
+ /**
126
+ * Accessors and Methods map type.
127
+ */
128
+ declare type AccessorsMethodsMap = {
129
+ accessors: Accessors;
130
+ methods: Set<string>;
131
+ };
132
+ export declare type IVueInstanceBase = {
133
+ init?: (...args: any[]) => void;
134
+ };
135
+ /**
136
+ * IVue static configuration interface.
137
+ */
138
+ export interface IVueStaticConfig<T> {
139
+ ivueGlobalStore?: boolean;
140
+ ivueCloneByReference?: Set<keyof T>;
141
+ ivueDisableReactivity?: Set<keyof T>;
142
+ }
143
+ /**
144
+ * IVue constructor type.
145
+ */
146
+ export declare type IVueConstructor<T> = new (...args: any[]) => T;
147
+ /**
148
+ * IVue class type with static configuration.
149
+ */
150
+ export declare type IVueClass<T> = IVueConstructor<T> & IVueStaticConfig<T>;
151
+ /**
152
+ * Get IVue init() method arguments IVueInitArgs<T>
153
+ */
154
+ export declare type IVueInitArgs<T extends IVueInstanceBase> = T['init'] extends (...args: any[]) => any ? Parameters<T['init']> : never;
155
+ /**
156
+ * Get Interface's method keys MethodKeys<T>
157
+ */
158
+ declare type MethodKeys<T> = {
159
+ [P in keyof T]: T[P] extends (...args: any[]) => any ? P : never;
160
+ }[keyof T];
161
+ /**
162
+ * Get Interface's property's function arguments Parameters<F>
163
+ */
164
+ export declare type IFnParameters<T extends Record<any, any> | InstanceType<AnyClass>, K extends MethodKeys<T>> = Parameters<Extract<Required<Pick<T, K>>[K], AnyFn>>;
165
+ /**
166
+ * Get Interface's [T] property's [P] function arguments Parmeters<F> parameter by key [K]
167
+ */
168
+ export declare type IFnParameter<T extends Record<any, any>, P extends keyof T, K extends number> = FnParameter<ValueOf<T, P>, K>;
169
+ export declare type IVueDeepCloneArgsMap = Map<AnyClass, any[]>;
170
+ declare type CloneArgsFor<T> = T extends {
171
+ init: (isClone: boolean, ...rest: infer A) => any;
172
+ } ? A : [];
120
173
  /** Types End. */
174
+ export declare const IVUE_INSTANCE_SYMBOL: unique symbol;
121
175
  /**
122
- * Store all descriptors for each class prototype processed by
123
- * @see {getAllClassDescriptors}
176
+ * Stores accessors for each class prototype processed by
177
+ * @see {getClassAccessorsMethodsMap}. Uses WeakMap to allow garbage collection
178
+ * of unused class accessors, ensuring memory efficiency in long-running applications.
124
179
  */
125
- export declare const descriptorsMap: Map<any, any>;
180
+ export declare let accessorsMethodsMaps: WeakMap<object, AccessorsMethodsMap>;
126
181
  /**
127
- * Get descriptors of an entire class prototype ancestors chain as a Map.
128
- * Completely emulates JavaScript class inheritance chain for getters and setters.
129
- *
130
- * @param className
131
- * @return {Descriptors}
182
+ * Property kind enum for distinguishing between data properties and accessors.
132
183
  */
133
- export declare function getAllClassDescriptors(className: AnyClass): Descriptors;
184
+ declare const enum PropKind {
185
+ Data = 0,
186
+ Accessor = 2
187
+ }
188
+ /**
189
+ * Stores properties for each class prototype processed by
190
+ * @see {getClassPropertiesAccessorsMap}. Uses WeakMap to allow garbage collection
191
+ * of unused class properties, ensuring memory efficiency in long-running applications.
192
+ */
193
+ export declare let propertiesAccessorsMaps: WeakMap<object, PropsMapValue>;
134
194
  /**
135
195
  * Infinite Vue (ivue) class reactive initializer.
136
196
  *
137
197
  * Converts class instance to a reactive object,
138
- * where descriptors are converted to computeds.
198
+ * where accessors are converted to computeds.
139
199
  *
140
200
  * You can turn off computed behaviour by adding static
141
201
  * ivue object and setting the getter props to false.
@@ -151,46 +211,30 @@ export declare function getAllClassDescriptors(className: AnyClass): Descriptors
151
211
  * @param args Class constructor arguments that you would pass to a `new AnyClass(args...)`
152
212
  * @returns {IVue<T>}
153
213
  */
154
- export declare function ivue<T extends AnyClass>(className: T, ...args: InferredArgs<T>): IVue<T>;
155
- /**
156
- * Store all props for each class prototype processed by:
157
- * @see {getAllClassProperties}
158
- */
159
- export declare const propsMap: Map<object, Set<string> | any>;
160
- /**
161
- * Get properties of an entire class prototype ancestors chain as a Map.
162
- */
163
- export declare function getAllClassProperties(obj: object): Set<string>;
214
+ export declare const ivue: <T extends AnyClass>(className: T, ...args: InferredArgs<T>) => IVue<T>;
164
215
  /**
165
216
  * `iref()` is an alias for Vue ref() function but returns an unwrapped type without the .value
166
217
  * `iref()` does not alter the behavior of ref(), but simply transforms the type to an unwrapped raw value.
167
218
  * @param val T
168
- * @returns {T}
219
+ * @returns {T} Ref but with type unwrapped
169
220
  */
170
221
  export declare const iref: <T = any>(value?: T | undefined) => T;
171
222
  /**
172
223
  * `ishallowRef()` is an alias for Vue shallowRef() function but returns an unwrapped type without the .value
173
224
  * `ishallowRef()` does not alter the behavior of shallowRef(), but simply transforms the type to an unwrapped raw value.
174
225
  * @param val T
175
- * @returns {T}
226
+ * @returns {T} ShallowRef but with type unwrapped
176
227
  */
177
228
  export declare const ishallowRef: <T = any>(value?: T | undefined) => T;
178
229
  /**
179
- * Three modes of operation:
180
- * 1. `iuse(useComposable(arg, arg2, arg3, ...))` converts the return types of a Composable / Ref to pure raw unwrapped type definition.
181
- * Returns for all properties of an object an unwrapped raw type definition,
182
- * unwraps direct Refs & ComputedRefs as well down to their raw types.
230
+ * `iuse()` is a helper function that unwraps any Vue 3 composable return type down to its bare types.
183
231
  *
184
- * 2. `iuse(useComposable, arg, arg2, arg3, ...)` for cleaner syntax for #1, it does exactly the same thing but
185
- * here the TypeScript inference works for composable function arguments to assist you with intellisence,
186
- * like they work for constructor arguments in the cause of `ivue()` core function,
187
- * making the API cleaner to look at and make it compatible with how this function operates with classes, see #3.
232
+ * It does not alter the behavior of the composable, but simply transforms the type to an unwrapped raw value.
188
233
  *
189
- * 3. `iuse(AnyClass, ...args)` If AnyClass is supplied and that class's arguments into `iuse(AnyClass, ...args)`,
190
- * it returns an 'ivue(AnyClass, ...args).toRefs()` object for all properties but casts
191
- * their types as raw (no-Ref) types to fit with reactive() structure of the ivue class context.
234
+ * @param obj Any Vue 3 composable return type or any object or any type
235
+ * @returns {Use<T>} Composable with types unwrapped
192
236
  */
193
- export declare function iuse<T extends AnyClass | AnyFn | Object | any>(classFunctionObject?: T, ...args: T extends AnyClass ? InferredArgs<T> : T extends AnyFn ? Parameters<T extends (...args: any[]) => any ? T : any> : any): T extends AnyClass ? InstanceType<T> : Use<T>;
237
+ export declare const iuse: <T extends object>(obj: T) => Use<T>; /** Unwrap any other Object or any type down to its bare types. */
194
238
  /**
195
239
  * Vue props interface in defineComponent() style.
196
240
  */
@@ -216,7 +260,7 @@ export declare type VuePropsWithDefaults<T extends VuePropsObject> = {
216
260
  * @param val Any value
217
261
  * @returns boolean If it's a JavaScript Class returns true
218
262
  */
219
- export declare function isClass(val: any): boolean;
263
+ export declare const isClass: (val: any) => boolean;
220
264
  /**
221
265
  * Creates props with defaults in defineComponent() style.
222
266
  *
@@ -242,6 +286,25 @@ export declare function isClass(val: any): boolean;
242
286
  * @param typedProps Props declared in defineComponent() style with type and possibly required declared, but without default
243
287
  * @returns Props declared in defineComponent() style with all properties having default property declared.
244
288
  */
245
- export declare function propsWithDefaults<T extends VuePropsObject>(defaults: Record<string, any>, typedProps: T): VuePropsWithDefaults<T>;
289
+ export declare const propsWithDefaults: <T extends VuePropsObject>(defaults: Record<string, any>, typedProps: T, deepCloneArgs?: IVueDeepCloneArgsMap | undefined) => VuePropsWithDefaults<T>;
290
+ /**
291
+ * Copies own properties (including symbols and non-enumerable) from source to target.
292
+ * Recursively deep clones values, but preserves getters/setters as-is.
293
+ */
294
+ export declare const copyOwnProps: (source: any, target: any, deepCloneArgs: IVueDeepCloneArgsMap | undefined, seen: WeakMap<object, any>) => void;
295
+ export declare let activeDeepCloneArgsMap: WeakMap<AnyClass, IVueDeepCloneArgsMap>;
296
+ export declare const deepClone: (source: any, deepCloneArgs?: IVueDeepCloneArgsMap, seen?: WeakMap<object, any>) => any;
297
+ /**
298
+ * Clears the accessorsMethodsMaps, and propertiesAccessorsMaps WeakMaps.
299
+ * Useful for SSR scenarios where you want to reset the cache between requests.
300
+ * Also useful for testing purposes to ensure a clean state.
301
+ */
302
+ export declare const clearCache: () => void;
303
+ /** Exported for testing purposes. */
304
+ export declare const __test__: {
305
+ copyOwnProps: (source: any, target: any, deepCloneArgs: IVueDeepCloneArgsMap | undefined, seen: WeakMap<object, any>) => void;
306
+ getClassAccessorsMethodsMap: (className: AnyClass) => AccessorsMethodsMap;
307
+ getClassPropertiesAccessorsMap: (obj: object) => PropsMapValue;
308
+ };
246
309
  /** Necessary ivue.ts to be treated as a module. */
247
310
  export {};
@@ -0,0 +1,338 @@
1
+ import { toRaw, isRef, type Ref } from 'vue';
2
+
3
+ /**
4
+ * Constants & Helpers
5
+ */
6
+ const prototypeHasOwnProperty = Object.prototype.hasOwnProperty.call.bind(
7
+ Object.prototype.hasOwnProperty
8
+ );
9
+ const getPrototypeOf = Object.getPrototypeOf;
10
+ const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
11
+ const defineProperty = Object.defineProperty;
12
+ const getOwnPropertyNames = Object.getOwnPropertyNames;
13
+ const objectPrototype = Object.prototype;
14
+ const getOwnPropertySymbols = Object.getOwnPropertySymbols;
15
+
16
+ const $stopEffects = '$stopEffects';
17
+ const fn = 'function';
18
+ const RAW = Symbol('ivue_raw');
19
+ const SK_MAP = '__ivue_sk'; // Store for cache keys
20
+ const PROCESSED = Symbol('ivue_processed'); // Flag to mark prototype as "Reactified"
21
+
22
+ /**
23
+ * Get unique symbol key for super method/property.
24
+ */
25
+ function getSuperKey(proto: any, key: string): symbol {
26
+ // Ensure the map exists on this specific prototype (shadowing parents)
27
+ if (!prototypeHasOwnProperty(proto, SK_MAP)) {
28
+ defineProperty(proto, SK_MAP, {
29
+ value: {},
30
+ configurable: true,
31
+ enumerable: false,
32
+ writable: true,
33
+ });
34
+ }
35
+ const map = proto[SK_MAP];
36
+ return map[key] || (map[key] = Symbol(key));
37
+ }
38
+
39
+ /**
40
+ * Convert method to a lazy-bound prototype method.
41
+ */
42
+ function convertToLazyBoundMethod(proto: any, key: string, superKey: symbol) {
43
+ const desc = getOwnPropertyDescriptor(proto, key);
44
+ if (!desc || typeof desc.value !== fn) return;
45
+
46
+ const originalFn = desc.value;
47
+
48
+ defineProperty(proto, key, {
49
+ configurable: true,
50
+ enumerable: false,
51
+ get(this: any) {
52
+ const raw = this[RAW] ?? (this[RAW] = toRaw(this));
53
+ return raw[superKey] ?? (raw[superKey] = originalFn.bind(raw));
54
+ },
55
+ set(this: any, newFn: any) {
56
+ toRaw(this)[superKey] = newFn;
57
+ },
58
+ });
59
+ }
60
+
61
+ /**
62
+ * Convert a property to a lazy-computed property.
63
+ */
64
+ function convertToLazyComputed<T extends object>(
65
+ proto: T,
66
+ key: string,
67
+ superKey: symbol
68
+ ) {
69
+ const desc = getOwnPropertyDescriptor(proto, key);
70
+ const originalGetter = desc?.get;
71
+ const originalSetter = desc?.set;
72
+
73
+ // Optimization: Properties starting with $ are assumed singletons
74
+ const cacheWhole = key[0] === '$';
75
+
76
+ // DEV WARNING: Setter/Getter mismatch
77
+ if (import.meta.env.DEV && originalGetter && originalSetter) {
78
+ try {
79
+ const testVal = originalGetter.call({});
80
+ if (isRef(testVal)) {
81
+ console.warn(
82
+ `[ivue] API conflict on "${key}": Getter returns Ref but Setter is standard.`
83
+ );
84
+ }
85
+ } catch (e) {}
86
+ }
87
+
88
+ const newGetter = function (this: any) {
89
+ const raw = toRaw(this);
90
+
91
+ // 1. Check Cache
92
+ if (superKey in raw) return raw[superKey];
93
+
94
+ // 2. Execute Original
95
+ const result = originalGetter!.call(raw);
96
+
97
+ // 3. Handle Result
98
+ if (cacheWhole) {
99
+ // Cache result forever (Singleton pattern)
100
+ raw[superKey] = result;
101
+ return result;
102
+ }
103
+
104
+ if (isRef(result)) {
105
+ // Cache Ref instance (Reactivity pattern)
106
+ raw[superKey] = result;
107
+ } else {
108
+ // DE-OPTIMIZATION: It's just a value. Restore original getter on prototype.
109
+ // This removes overhead for all future calls on this prototype.
110
+ defineProperty(proto, key, {
111
+ configurable: true,
112
+ enumerable: false,
113
+ get: originalGetter
114
+ ? function (this: any) {
115
+ return originalGetter.call(toRaw(this));
116
+ }
117
+ : undefined,
118
+ set: originalSetter
119
+ ? function (this: any, v: any) {
120
+ return originalSetter.call(toRaw(this), v);
121
+ }
122
+ : undefined,
123
+ });
124
+ }
125
+
126
+ return result;
127
+ };
128
+
129
+ defineProperty(proto, key, {
130
+ configurable: true,
131
+ enumerable: false,
132
+ get: originalGetter ? newGetter : undefined,
133
+ set: originalSetter
134
+ ? function (this: any, v: any) {
135
+ return originalSetter.call(toRaw(this), v);
136
+ }
137
+ : undefined,
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Create a reactive class.
143
+ * @param targetClass The class to make reactive.
144
+ * @returns A reactive version of the class.
145
+ */
146
+ export function Reactive<C extends new (...args: any) => any>(
147
+ targetClass: C
148
+ ): ReactiveClass<C> & { Instance: ReactiveInstance<InstanceType<C>> } {
149
+ const chain: any[] = [];
150
+
151
+ let targetPrototype = targetClass.prototype;
152
+ while (targetPrototype && targetPrototype !== objectPrototype) {
153
+ chain.push(targetPrototype);
154
+ targetPrototype = getPrototypeOf(targetPrototype);
155
+ }
156
+
157
+ // Process Base -> Child
158
+ chain.reverse();
159
+
160
+ for (const prototype of chain) {
161
+ // OPTIMIZATION: Skip if this prototype layer is already "Reactified"
162
+ // This handles diamond inheritance and multiple Reactive children safely.
163
+ if (prototypeHasOwnProperty(prototype, PROCESSED)) continue;
164
+
165
+ const names = getOwnPropertyNames(prototype);
166
+
167
+ for (const key of names) {
168
+ if (key === 'constructor') continue;
169
+ const desc = getOwnPropertyDescriptor(prototype, key);
170
+ if (!desc) continue;
171
+
172
+ const superKey = getSuperKey(prototype, key);
173
+
174
+ if (typeof desc.value === fn) {
175
+ convertToLazyBoundMethod(prototype, key, superKey);
176
+ } else if (desc.get) {
177
+ convertToLazyComputed(prototype, key, superKey);
178
+ }
179
+ }
180
+
181
+ // Mark this specific prototype level as processed
182
+ defineProperty(prototype, PROCESSED, {
183
+ configurable: false,
184
+ enumerable: false,
185
+ value: true,
186
+ });
187
+ }
188
+
189
+ // Inject cleanup
190
+ if (!prototypeHasOwnProperty(targetClass.prototype, $stopEffects)) {
191
+ defineProperty(targetClass.prototype, $stopEffects, {
192
+ enumerable: false,
193
+ configurable: true,
194
+ writable: true,
195
+ value: function (this: any) {
196
+ const raw = toRaw(this);
197
+ if (typeof raw.stopEffects === fn) raw.stopEffects();
198
+
199
+ const symbols = getOwnPropertySymbols(raw);
200
+ for (const symbol of symbols) {
201
+ if (symbol === RAW) continue;
202
+ const cached = raw[symbol];
203
+ // Stop computed/effect if present
204
+ if (cached && cached.effect && typeof cached.effect.stop === fn) {
205
+ cached.effect.stop();
206
+ }
207
+ delete raw[symbol];
208
+ }
209
+ },
210
+ });
211
+ }
212
+
213
+ return targetClass as any;
214
+ }
215
+
216
+ /**
217
+ * Vue props interface in defineComponent() style.
218
+ */
219
+ export type VuePropsObject = Record<
220
+ string,
221
+ { type: any; default?: any; required?: boolean }
222
+ >;
223
+
224
+ /**
225
+ * Vue Props with default properties declared as existing and having values.
226
+ */
227
+ export type VuePropsWithDefaults<T extends VuePropsObject> = {
228
+ [K in keyof T]: {
229
+ type: T[K]['type'];
230
+ default: T[K]['default'];
231
+ required?: boolean;
232
+ };
233
+ };
234
+
235
+ /**
236
+ * Determines if the value is a JavaScript Class.
237
+ * Note that class is a class function in JavaScript.
238
+ *
239
+ * @param val Any value
240
+ * @returns boolean If it's a JavaScript Class returns true
241
+ */
242
+ export const isClass = (val: any): boolean => {
243
+ if (typeof val !== 'function') return false; // Not a function, so not a class function either
244
+
245
+ if (!val.prototype) return false; // Arrow function, so not a class
246
+
247
+ // Finally -> distinguish between a normal function and a class function
248
+ if (getOwnPropertyDescriptor(val, 'prototype')?.writable) {
249
+ // Has writable prototype
250
+ return false; // Normal function
251
+ } else {
252
+ return true; // Class -> Not a function
253
+ }
254
+ };
255
+ /**
256
+ * Creates props with defaults in defineComponent() style.
257
+ *
258
+ * Merge defaults regular object with Vue types object
259
+ * declared in defineComponent() style.
260
+ *
261
+ * This is made so that the defaults can be declared "as they are"
262
+ * without requiring objects to be function callbacks returning an object.
263
+ *
264
+ * // You don't need to wrap objects in () => ({ nest: { nest :{} } })
265
+ * // You can just delcare them normally.
266
+ * const defaults = {
267
+ * nest: {
268
+ * nest
269
+ * }
270
+ * }
271
+ *
272
+ * This function will create the Vue expected callbacks for Objects, Arrays & Classes
273
+ * but leave primitive properties and functions intact so that
274
+ * the final object is fully defineComponent() style compatible.
275
+ *
276
+ * @param defaults Regular object of default key -> values
277
+ * @param typedProps Props declared in defineComponent() style with type and possibly required declared, but without default
278
+ * @returns Props declared in defineComponent() style with all properties having default property declared.
279
+ */
280
+ export const propsWithDefaults = <T extends VuePropsObject>(
281
+ defaults: Record<string, any>,
282
+ typedProps: T,
283
+ // Optional: Allows user to pass a custom cloner if structuredClone isn't enough
284
+ customCloner?: (val: any) => any
285
+ ): VuePropsWithDefaults<T> => {
286
+ for (const prop in typedProps) {
287
+ const def = defaults?.[prop];
288
+ const typed = typedProps[prop];
289
+
290
+ if (typed.required || def === undefined) continue;
291
+
292
+ if (typeof def === 'object' && def !== null) {
293
+ typedProps[prop].default = () =>
294
+ customCloner ? customCloner(def) : structuredClone(def);
295
+ } else {
296
+ if (isClass(def)) {
297
+ typedProps[prop].default = () => def;
298
+ } else {
299
+ typedProps[prop].default = def;
300
+ }
301
+ }
302
+ }
303
+ return typedProps as VuePropsWithDefaults<T>;
304
+ };
305
+
306
+ /**
307
+ * Type Utilities
308
+ */
309
+ type GetterKeys<T> = {
310
+ [K in keyof T]: T[K] extends (...args: any[]) => any
311
+ ? never
312
+ : T[K] extends undefined
313
+ ? never
314
+ : K;
315
+ }[keyof T];
316
+
317
+ type GetterReturn<T, K extends keyof T> = T[K] extends (...args: any[]) => any
318
+ ? never
319
+ : T[K];
320
+ type WritableComputedLike = Ref<any> & { set: (...args: any[]) => any };
321
+ type IsWritableGetter<R> = R extends Ref<any>
322
+ ? true
323
+ : R extends WritableComputedLike
324
+ ? true
325
+ : false;
326
+
327
+ type WritableGetters<T> = {
328
+ [K in GetterKeys<T> as IsWritableGetter<GetterReturn<T, K>> extends true
329
+ ? K
330
+ : never]-?: T[K];
331
+ };
332
+
333
+ export type ReactiveInstance<T> = T &
334
+ WritableGetters<T> & { $stopEffects: () => void };
335
+
336
+ export type ReactiveClass<C extends new (...args: any) => any> = new (
337
+ ...args: ConstructorParameters<C>
338
+ ) => ReactiveInstance<InstanceType<C>>;