ivue 2.5.0 → 2.6.0

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/README.md CHANGED
@@ -189,7 +189,7 @@ export namespace TextSegmentation {
189
189
  [**Invar**](https://ivue.dev/examples/invar) is ivue at full scale: a
190
190
  complete terminal IDE — editor, workspace search, git, terminals, LSP,
191
191
  agents — running on ivue classes under Bun, with no DOM and no Vue
192
- components. **94,000 source lines, 345 classes, 35 invariant contracts,
192
+ components. **108,000 source lines, 384 classes, 39 invariant contracts,
193
193
  zero import cycles**, built almost entirely by AI agents holding the
194
194
  [Standard](https://ivue.dev/guide/standard) as their base discipline.
195
195
 
@@ -35,11 +35,11 @@
35
35
  * entry stays minimal.
36
36
  */
37
37
  export declare class LazyShared<T> {
38
- private readonly make;
38
+ protected readonly make: () => T;
39
39
  constructor(make: () => T);
40
- private constructed;
41
- private constructing;
42
- private stored;
40
+ protected constructed: boolean;
41
+ protected constructing: boolean;
42
+ protected stored: T | null;
43
43
  get value(): T;
44
44
  /**
45
45
  * Drop the constructed value; the next read constructs again. For
@@ -1,4 +1,5 @@
1
1
  import { watch, watchEffect, type ExtractPropTypes, type Ref } from 'vue';
2
+ export { clone } from './clone';
2
3
  /**
3
4
  * Create a reactive class.
4
5
  * @param targetClass The class to make reactive.
@@ -54,14 +55,14 @@ export declare function isClass(val: any): boolean;
54
55
  * but leave primitive properties and functions intact so that
55
56
  * the final object is fully defineComponent() style compatible.
56
57
  *
57
- * The default cloner is the native `structuredClone` (zero-dependency, handles
58
- * plain data, Map/Set/Date/typed arrays, circular refs). For defaults that
59
- * contain class instances or functions which `structuredClone` cannot clone —
60
- * pass a `customCloner` such as lodash `cloneDeep`.
58
+ * The default cloner copies acyclic plain-object and array trees while
59
+ * retaining callbacks, class constructors and opaque objects by reference.
60
+ * For independent Map/Set/Date values or cyclic data, pass a `customCloner`
61
+ * such as `structuredClone` when the values support it.
61
62
  *
62
63
  * @param defaults Regular object of default key -> values
63
64
  * @param typedProps Props declared in defineComponent() style with type and possibly required declared, but without default
64
- * @param customCloner Optional cloner used for object/array defaults (defaults to structuredClone)
65
+ * @param customCloner Optional cloner used for object/array defaults (defaults to clone)
65
66
  * @returns Props declared in defineComponent() style with all properties having default property declared.
66
67
  */
67
68
  export declare function propsWithDefaults<T extends VuePropsObject>(defaults: Record<string, any>, typedProps: T, customCloner?: (val: any) => any): VuePropsWithDefaults<T>;
@@ -79,7 +80,16 @@ declare type IsWritableGetter<R> = R extends Ref<any> ? true : R extends Writabl
79
80
  declare type WritableGetters<T> = {
80
81
  [K in GetterKeys<T> as IsWritableGetter<GetterReturn<T, K>> extends true ? K : never]-?: T[K];
81
82
  };
82
- export declare type ReactiveInstance<T> = T & WritableGetters<T> & {
83
+ /**
84
+ * The members `Reactive()` installs on every instance's prototype. A raw
85
+ * class body cannot see them (the transform runs after the class is typed),
86
+ * so a class that calls them merges this interface into its own instance
87
+ * type — one declaration beside the class, zero runtime:
88
+ *
89
+ * class $Session { constructor() { this.$watch(…) } }
90
+ * interface $Session extends ReactiveHelpers {}
91
+ */
92
+ export interface ReactiveHelpers {
83
93
  /** Register a watcher in the instance's lazy effect scope (same signature as Vue `watch`). */
84
94
  $watch: typeof watch;
85
95
  /** Register a watchEffect in the instance's lazy effect scope (same signature as Vue `watchEffect`). */
@@ -90,7 +100,8 @@ export declare type ReactiveInstance<T> = T & WritableGetters<T> & {
90
100
  $stopEffects: (options?: {
91
101
  reset?: boolean;
92
102
  }) => void;
93
- };
103
+ }
104
+ export declare type ReactiveInstance<T> = T & WritableGetters<T> & ReactiveHelpers;
94
105
  export declare type ReactiveClass<C extends new (...args: any) => any> = {
95
106
  [Key in keyof C]: C[Key];
96
107
  } & (new (...args: ConstructorParameters<C>) => ReactiveInstance<InstanceType<C>>);
@@ -151,4 +162,3 @@ export declare type FnParameter<F extends AnyFn, K extends number> = Parameters<
151
162
  export declare type IFnParameters<T extends Record<any, any>, K extends string> = Parameters<Required<Pick<T, K>>[K]>;
152
163
  /** Get interface T property P's function parameter by index K. */
153
164
  export declare type IFnParameter<T extends Record<any, any>, P extends keyof T, K extends number> = FnParameter<NonNullable<T[P]> extends AnyFn ? NonNullable<T[P]> : never, K>;
154
- export {};
@@ -0,0 +1,3 @@
1
+ /** Copy plain configuration containers; retain callbacks, constructors and
2
+ * opaque objects by reference. Container trees must be acyclic. */
3
+ export declare function clone<T>(value: T): T;
package/dist/extras.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=Object.hasOwn,c=new Set;exports.LazyShared=class{constructor(s){this.make=s,this.constructed=!1,this.constructing=!1,this.stored=null}get value(){if(!this.constructed){if(this.constructing)throw new Error("LazyShared thunk cycle: this cell is read inside its own construction. Break the dependency between the two thunks.");this.constructing=!0;try{this.stored=this.make(),this.constructed=!0}finally{this.constructing=!1}}return this.stored}reset(){this.constructed=!1,this.stored=null}},exports.Static=function(s){var a;const o=class extends s{},u=new Set;for(let n=s;n!==Function.prototype;n=Object.getPrototypeOf(n))for(const t of Reflect.ownKeys(n)){if(u.has(t)||(u.add(t),typeof t=="symbol"&&((a=Symbol.keyFor(t))==null?void 0:a.startsWith("ivue.static")))||c.has(t))continue;const i=Object.getOwnPropertyDescriptor(n,t);if(typeof i.value=="function"){const r=i.value,e=typeof t=="string"?Symbol.for(`ivue.staticBound.${t}`):Symbol("ivue.staticBound");c.add(e),Object.defineProperty(o,t,{configurable:!0,enumerable:i.enumerable,get(){return l(this,e)||Object.defineProperty(this,e,{configurable:!0,value:r.bind(this)}),this[e]}})}else if(i.get&&!i.set&&typeof t=="string"&&t.startsWith("$")){const r=i.get,e=Symbol.for(`ivue.staticCache.${t}`);c.add(e),Object.defineProperty(o,t,{configurable:!0,enumerable:i.enumerable,get(){return l(this,e)||Object.defineProperty(this,e,{configurable:!0,value:r.call(this)}),this[e]}})}}return o};
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=Object.hasOwn,e=new Set;function o(t){if(Array.isArray(t)){const e=new Array(t.length);for(let n=0;n<t.length;n++)n in t&&(e[n]=o(t[n]));return e}if(null===t||"object"!=typeof t||t.constructor!==Object&&void 0!==t.constructor)return t;const e={__proto__:Object.getPrototypeOf(t),...t};for(const t in e)e[t]=o(e[t]);return e}function n(t){return null!==t&&"object"==typeof t&&(t.constructor===Object||void 0===t.constructor)}function r(t,e,o){for(const s in e){const c=t[s],i=e[s];void 0===c?t[s]=o(i):n(c)&&n(i)&&r(c,i,o)}}exports.LazyShared=class{constructor(t){this.make=t,this.constructed=!1,this.constructing=!1,this.stored=null}get value(){if(!this.constructed){if(this.constructing)throw new Error("LazyShared thunk cycle: this cell is read inside its own construction. Break the dependency between the two thunks.");this.constructing=!0;try{this.stored=this.make(),this.constructed=!0}finally{this.constructing=!1}}return this.stored}reset(){this.constructed=!1,this.stored=null}},exports.Static=function(o){var n;const r=class extends o{},s=new Set;for(let c=o;c!==Function.prototype;c=Object.getPrototypeOf(c))for(const o of Reflect.ownKeys(c)){if(s.has(o)||(s.add(o),"symbol"==typeof o&&null!=(n=Symbol.keyFor(o))&&n.startsWith("ivue.static"))||e.has(o))continue;const i=Object.getOwnPropertyDescriptor(c,o);if("function"==typeof i.value){const n=i.value,s="string"==typeof o?Symbol.for(`ivue.staticBound.${o}`):Symbol("ivue.staticBound");e.add(s),Object.defineProperty(r,o,{configurable:!0,enumerable:i.enumerable,get(){return t(this,s)||Object.defineProperty(this,s,{configurable:!0,value:n.bind(this)}),this[s]}})}else if(i.get&&!i.set&&"string"==typeof o&&o.startsWith("$")){const n=i.get,s=Symbol.for(`ivue.staticCache.${o}`);e.add(s),Object.defineProperty(r,o,{configurable:!0,enumerable:i.enumerable,get(){return t(this,s)||Object.defineProperty(this,s,{configurable:!0,value:n.call(this)}),this[s]}})}}return r},exports.nestedProps=function(t,e,s=o){for(const o in e){const c=t[o],i=e[o];n(c)&&n(i)&&r(c,i,s)}return t};
package/dist/extras.d.ts CHANGED
@@ -8,3 +8,4 @@
8
8
  */
9
9
  export { Static, type ClassConstructor } from './Static';
10
10
  export { LazyShared } from './LazyShared';
11
+ export { nestedProps, type NestedPartial, type NestedProps } from './nestedProps';
package/dist/extras.es.js CHANGED
@@ -1,49 +1 @@
1
- const h = Object.hasOwn, c = /* @__PURE__ */ new Set();
2
- function l(o) {
3
- var a;
4
- const i = class extends o {
5
- }, u = /* @__PURE__ */ new Set();
6
- for (let n = o; n !== Function.prototype; n = Object.getPrototypeOf(n))
7
- for (const t of Reflect.ownKeys(n)) {
8
- if (u.has(t) || (u.add(t), typeof t == "symbol" && ((a = Symbol.keyFor(t)) == null ? void 0 : a.startsWith("ivue.static"))) || c.has(t))
9
- continue;
10
- const s = Object.getOwnPropertyDescriptor(n, t);
11
- if (typeof s.value == "function") {
12
- const r = s.value, e = typeof t == "string" ? Symbol.for(`ivue.staticBound.${t}`) : Symbol("ivue.staticBound");
13
- c.add(e), Object.defineProperty(i, t, { configurable: !0, enumerable: s.enumerable, get() {
14
- return h(this, e) || Object.defineProperty(this, e, { configurable: !0, value: r.bind(this) }), this[e];
15
- } });
16
- } else if (s.get && !s.set && typeof t == "string" && t.startsWith("$")) {
17
- const r = s.get, e = Symbol.for(`ivue.staticCache.${t}`);
18
- c.add(e), Object.defineProperty(i, t, { configurable: !0, enumerable: s.enumerable, get() {
19
- return h(this, e) || Object.defineProperty(this, e, { configurable: !0, value: r.call(this) }), this[e];
20
- } });
21
- }
22
- }
23
- return i;
24
- }
25
- class f {
26
- constructor(i) {
27
- this.make = i, this.constructed = !1, this.constructing = !1, this.stored = null;
28
- }
29
- get value() {
30
- if (!this.constructed) {
31
- if (this.constructing)
32
- throw new Error("LazyShared thunk cycle: this cell is read inside its own construction. Break the dependency between the two thunks.");
33
- this.constructing = !0;
34
- try {
35
- this.stored = this.make(), this.constructed = !0;
36
- } finally {
37
- this.constructing = !1;
38
- }
39
- }
40
- return this.stored;
41
- }
42
- reset() {
43
- this.constructed = !1, this.stored = null;
44
- }
45
- }
46
- export {
47
- f as LazyShared,
48
- l as Static
49
- };
1
+ const t=Object.hasOwn,e=/* @__PURE__ */new Set;function n(n){var o;const r=class extends n{},s=/* @__PURE__ */new Set;for(let c=n;c!==Function.prototype;c=Object.getPrototypeOf(c))for(const n of Reflect.ownKeys(c)){if(s.has(n)||(s.add(n),"symbol"==typeof n&&null!=(o=Symbol.keyFor(n))&&o.startsWith("ivue.static"))||e.has(n))continue;const i=Object.getOwnPropertyDescriptor(c,n);if("function"==typeof i.value){const o=i.value,s="string"==typeof n?Symbol.for(`ivue.staticBound.${n}`):Symbol("ivue.staticBound");e.add(s),Object.defineProperty(r,n,{configurable:!0,enumerable:i.enumerable,get(){return t(this,s)||Object.defineProperty(this,s,{configurable:!0,value:o.bind(this)}),this[s]}})}else if(i.get&&!i.set&&"string"==typeof n&&n.startsWith("$")){const o=i.get,s=Symbol.for(`ivue.staticCache.${n}`);e.add(s),Object.defineProperty(r,n,{configurable:!0,enumerable:i.enumerable,get(){return t(this,s)||Object.defineProperty(this,s,{configurable:!0,value:o.call(this)}),this[s]}})}}return r}class o{constructor(t){this.make=t,this.constructed=!1,this.constructing=!1,this.stored=null}get value(){if(!this.constructed){if(this.constructing)throw new Error("LazyShared thunk cycle: this cell is read inside its own construction. Break the dependency between the two thunks.");this.constructing=!0;try{this.stored=this.make(),this.constructed=!0}finally{this.constructing=!1}}return this.stored}reset(){this.constructed=!1,this.stored=null}}function r(t){if(Array.isArray(t)){const e=new Array(t.length);for(let n=0;n<t.length;n++)n in t&&(e[n]=r(t[n]));return e}if(null===t||"object"!=typeof t||t.constructor!==Object&&void 0!==t.constructor)return t;const e={__proto__:Object.getPrototypeOf(t),...t};for(const t in e)e[t]=r(e[t]);return e}function s(t){return null!==t&&"object"==typeof t&&(t.constructor===Object||void 0===t.constructor)}function c(t,e,n){for(const o in e){const r=t[o],i=e[o];void 0===r?t[o]=n(i):s(r)&&s(i)&&c(r,i,n)}}function i(t,e,n=r){for(const o in e){const r=t[o],i=e[o];s(r)&&s(i)&&c(r,i,n)}return t}export{o as LazyShared,n as Static,i as nestedProps};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("vue"),d=Object.hasOwn,y=Object.getPrototypeOf,w=Object.getOwnPropertyDescriptor,m=Object.getOwnPropertyNames,a=Object.defineProperty,g=Object.prototype,b=Symbol.for("ivue.raw"),p=Symbol.for("ivue.scope"),h=Symbol.for("ivue.processed");function i(e){const c=l.toRaw(e);if(c!==e)return c[b]??(c[b]=c);const r=e[b];return r?r===e?r:l.toRaw(r):e[b]=e}function O(e,c,r,o){a(e,c,{configurable:!0,enumerable:!1,get(){const t=i(this);return t[r]??(t[r]=o.bind(t))},set(t){i(this)[r]=t}})}function S(e,c,r,o,t){const n=c[0]==="$";a(e,c,{configurable:!0,enumerable:!1,get:function(){const u=i(this);if(r in u)return u[r];const f=o.call(u);return n?(u[r]=f,f):(l.isRef(f)?u[r]=f:a(e,c,{configurable:!0,enumerable:!1,get(){return o.call(i(this))},set:t?function(s){return t.call(i(this),s)}:void 0}),f)},set:t?function(u){return t.call(i(this),u)}:void 0})}function v(e){var c;return typeof e=="function"&&!!e.prototype&&!((c=w(e,"prototype"))!=null&&c.writable)}exports.Reactive=function(e){const c=[];let r=e.prototype;for(;r&&r!==g;)c.push(r),r=y(r);c.reverse();for(const o of c){if(d(o,h))continue;const t=m(o),n=[];for(const u of t){if(u==="constructor")continue;const f=w(o,u);if(typeof f.value=="function"){const s=Symbol(u);n.push(s),O(o,u,s,f.value)}else if(f.get){const s=Symbol(u);n.push(s),S(o,u,s,f.get,f.set)}}a(o,h,{value:n})}return d(e.prototype,"$stopEffects")||(a(e.prototype,"$watch",{enumerable:!1,configurable:!0,writable:!0,value:function(...o){const t=i(this);return(t[p]??(t[p]=l.effectScope(!0))).run(()=>l.watch(...o))}}),a(e.prototype,"$watchEffect",{enumerable:!1,configurable:!0,writable:!0,value:function(...o){const t=i(this);return(t[p]??(t[p]=l.effectScope(!0))).run(()=>l.watchEffect(...o))}}),a(e.prototype,"$stopEffects",{enumerable:!1,configurable:!0,writable:!0,value:function(o){const t=i(this);try{const n=t[p];n&&n.stop()}finally{if(delete t[p],(o==null?void 0:o.reset)!==!1){let n=y(t);for(;n&&n!==g;){const u=n[h];if(u)for(const f of u)delete t[f];n=y(n)}}}}})),e},exports.definePropTypes=function(e){return e},exports.isClass=v,exports.propsWithDefaults=function(e,c,r){const o={};for(const t in c){const n=e==null?void 0:e[t],u=c[t];o[t]={...u},u.required||n===void 0||(typeof n=="object"&&n!==null?o[t].default=()=>r?r(n):structuredClone(n):v(n)?o[t].default=()=>n:o[t].default=n)}return o};
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("vue");function e(t){if(Array.isArray(t)){const o=new Array(t.length);for(let n=0;n<t.length;n++)n in t&&(o[n]=e(t[n]));return o}if(null===t||"object"!=typeof t||t.constructor!==Object&&void 0!==t.constructor)return t;const o={__proto__:Object.getPrototypeOf(t),...t};for(const t in o)o[t]=e(o[t]);return o}const o=Object.hasOwn,n=Object.getPrototypeOf,r=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,u=Object.defineProperty,s=Object.prototype,i=Symbol.for("ivue.raw"),f=Symbol.for("ivue.scope"),l=Symbol.for("ivue.processed");function a(e){const o=t.toRaw(e);if(o!==e)return o[i]??(o[i]=o);const n=e[i];return n?n===e?n:t.toRaw(n):e[i]=e}function p(t,e,o,n){u(t,e,{configurable:!0,enumerable:!1,get(){const t=a(this);return t[o]??(t[o]=n.bind(t))},set(t){a(this)[o]=t}})}function b(e,o,n,r,c){const s="$"===o[0];u(e,o,{configurable:!0,enumerable:!1,get:function(){const i=a(this);if(n in i)return i[n];const f=r.call(i);return s?(i[n]=f,f):(t.isRef(f)?i[n]=f:u(e,o,{configurable:!0,enumerable:!1,get(){return r.call(a(this))},set:c?function(t){return c.call(a(this),t)}:void 0}),f)},set:c?function(t){return c.call(a(this),t)}:void 0})}function y(t){var e;return!("function"!=typeof t||!t.prototype||null!=(e=r(t,"prototype"))&&e.writable)}exports.Reactive=function(e){const i=[];let y=e.prototype;for(;y&&y!==s;)i.push(y),y=n(y);i.reverse();for(const t of i){if(o(t,l))continue;const e=c(t),n=[];for(const o of e){if("constructor"===o)continue;const e=r(t,o);if("function"==typeof e.value){const r=Symbol(o);n.push(r),p(t,o,r,e.value)}else if(e.get){const r=Symbol(o);n.push(r),b(t,o,r,e.get,e.set)}}u(t,l,{value:n})}return o(e.prototype,"$stopEffects")||(u(e.prototype,"$watch",{enumerable:!1,configurable:!0,writable:!0,value:function(...e){const o=a(this);return(o[f]??(o[f]=t.effectScope(!0))).run((()=>t.watch(...e)))}}),u(e.prototype,"$watchEffect",{enumerable:!1,configurable:!0,writable:!0,value:function(...e){const o=a(this);return(o[f]??(o[f]=t.effectScope(!0))).run((()=>t.watchEffect(...e)))}}),u(e.prototype,"$stopEffects",{enumerable:!1,configurable:!0,writable:!0,value:function(t){const e=a(this);try{const t=e[f];t&&t.stop()}finally{if(delete e[f],!1!==(null==t?void 0:t.reset)){let t=n(e);for(;t&&t!==s;){const o=t[l];if(o)for(const t of o)delete e[t];t=n(t)}}}}})),e},exports.clone=e,exports.definePropTypes=function(t){return t},exports.isClass=y,exports.propsWithDefaults=function(t,o,n){const r={};for(const c in o){const u=null==t?void 0:t[c],s=o[c];r[c]={...s},!s.required&&void 0!==u&&("object"==typeof u&&null!==u?r[c].default=()=>n?n(u):e(u):y(u)?r[c].default=()=>u:r[c].default=u)}return r};
package/dist/index.es.js CHANGED
@@ -1,103 +1 @@
1
- import { effectScope as h, watch as w, watchEffect as O, toRaw as d, isRef as j } from "vue";
2
- const g = Object.hasOwn, b = Object.getPrototypeOf, v = Object.getOwnPropertyDescriptor, S = Object.getOwnPropertyNames, a = Object.defineProperty, m = Object.prototype, p = Symbol.for("ivue.raw"), l = Symbol.for("ivue.scope"), y = Symbol.for("ivue.processed");
3
- function f(t) {
4
- const c = d(t);
5
- if (c !== t)
6
- return c[p] ?? (c[p] = c);
7
- const r = t[p];
8
- return r ? r === t ? r : d(r) : t[p] = t;
9
- }
10
- function P(t, c, r, o) {
11
- a(t, c, { configurable: !0, enumerable: !1, get() {
12
- const e = f(this);
13
- return e[r] ?? (e[r] = o.bind(e));
14
- }, set(e) {
15
- f(this)[r] = e;
16
- } });
17
- }
18
- function $(t, c, r, o, e) {
19
- const n = c[0] === "$";
20
- a(t, c, { configurable: !0, enumerable: !1, get: function() {
21
- const s = f(this);
22
- if (r in s)
23
- return s[r];
24
- const u = o.call(s);
25
- return n ? (s[r] = u, u) : (j(u) ? s[r] = u : a(t, c, { configurable: !0, enumerable: !1, get() {
26
- return o.call(f(this));
27
- }, set: e ? function(i) {
28
- return e.call(f(this), i);
29
- } : void 0 }), u);
30
- }, set: e ? function(s) {
31
- return e.call(f(this), s);
32
- } : void 0 });
33
- }
34
- function C(t) {
35
- const c = [];
36
- let r = t.prototype;
37
- for (; r && r !== m; )
38
- c.push(r), r = b(r);
39
- c.reverse();
40
- for (const o of c) {
41
- if (g(o, y))
42
- continue;
43
- const e = S(o), n = [];
44
- for (const s of e) {
45
- if (s === "constructor")
46
- continue;
47
- const u = v(o, s);
48
- if (typeof u.value == "function") {
49
- const i = Symbol(s);
50
- n.push(i), P(o, s, i, u.value);
51
- } else if (u.get) {
52
- const i = Symbol(s);
53
- n.push(i), $(o, s, i, u.get, u.set);
54
- }
55
- }
56
- a(o, y, { value: n });
57
- }
58
- return g(t.prototype, "$stopEffects") || (a(t.prototype, "$watch", { enumerable: !1, configurable: !0, writable: !0, value: function(...o) {
59
- const e = f(this);
60
- return (e[l] ?? (e[l] = h(!0))).run(() => w(...o));
61
- } }), a(t.prototype, "$watchEffect", { enumerable: !1, configurable: !0, writable: !0, value: function(...o) {
62
- const e = f(this);
63
- return (e[l] ?? (e[l] = h(!0))).run(() => O(...o));
64
- } }), a(t.prototype, "$stopEffects", { enumerable: !1, configurable: !0, writable: !0, value: function(o) {
65
- const e = f(this);
66
- try {
67
- const n = e[l];
68
- n && n.stop();
69
- } finally {
70
- if (delete e[l], (o == null ? void 0 : o.reset) !== !1) {
71
- let n = b(e);
72
- for (; n && n !== m; ) {
73
- const s = n[y];
74
- if (s)
75
- for (const u of s)
76
- delete e[u];
77
- n = b(n);
78
- }
79
- }
80
- }
81
- } })), t;
82
- }
83
- function E(t) {
84
- var c;
85
- return typeof t == "function" && !!t.prototype && !((c = v(t, "prototype")) != null && c.writable);
86
- }
87
- function D(t, c, r) {
88
- const o = {};
89
- for (const e in c) {
90
- const n = t == null ? void 0 : t[e], s = c[e];
91
- o[e] = { ...s }, s.required || n === void 0 || (typeof n == "object" && n !== null ? o[e].default = () => r ? r(n) : structuredClone(n) : E(n) ? o[e].default = () => n : o[e].default = n);
92
- }
93
- return o;
94
- }
95
- function q(t) {
96
- return t;
97
- }
98
- export {
99
- C as Reactive,
100
- q as definePropTypes,
101
- E as isClass,
102
- D as propsWithDefaults
103
- };
1
+ import{effectScope as t,watch as e,watchEffect as o,toRaw as n,isRef as r}from"vue";function c(t){if(Array.isArray(t)){const e=new Array(t.length);for(let o=0;o<t.length;o++)o in t&&(e[o]=c(t[o]));return e}if(null===t||"object"!=typeof t||t.constructor!==Object&&void 0!==t.constructor)return t;const e={__proto__:Object.getPrototypeOf(t),...t};for(const t in e)e[t]=c(e[t]);return e}const s=Object.hasOwn,u=Object.getPrototypeOf,i=Object.getOwnPropertyDescriptor,f=Object.getOwnPropertyNames,l=Object.defineProperty,a=Object.prototype,p=Symbol.for("ivue.raw"),b=Symbol.for("ivue.scope"),y=Symbol.for("ivue.processed");function h(t){const e=n(t);if(e!==t)return e[p]??(e[p]=e);const o=t[p];return o?o===t?o:n(o):t[p]=t}function v(t,e,o,n){l(t,e,{configurable:!0,enumerable:!1,get(){const t=h(this);return t[o]??(t[o]=n.bind(t))},set(t){h(this)[o]=t}})}function g(t,e,o,n,c){const s="$"===e[0];l(t,e,{configurable:!0,enumerable:!1,get:function(){const u=h(this);if(o in u)return u[o];const i=n.call(u);return s?(u[o]=i,i):(r(i)?u[o]=i:l(t,e,{configurable:!0,enumerable:!1,get(){return n.call(h(this))},set:c?function(t){return c.call(h(this),t)}:void 0}),i)},set:c?function(t){return c.call(h(this),t)}:void 0})}function d(n){const r=[];let c=n.prototype;for(;c&&c!==a;)r.push(c),c=u(c);r.reverse();for(const t of r){if(s(t,y))continue;const e=f(t),o=[];for(const n of e){if("constructor"===n)continue;const e=i(t,n);if("function"==typeof e.value){const r=Symbol(n);o.push(r),v(t,n,r,e.value)}else if(e.get){const r=Symbol(n);o.push(r),g(t,n,r,e.get,e.set)}}l(t,y,{value:o})}return s(n.prototype,"$stopEffects")||(l(n.prototype,"$watch",{enumerable:!1,configurable:!0,writable:!0,value:function(...o){const n=h(this);return(n[b]??(n[b]=t(!0))).run((()=>e(...o)))}}),l(n.prototype,"$watchEffect",{enumerable:!1,configurable:!0,writable:!0,value:function(...e){const n=h(this);return(n[b]??(n[b]=t(!0))).run((()=>o(...e)))}}),l(n.prototype,"$stopEffects",{enumerable:!1,configurable:!0,writable:!0,value:function(t){const e=h(this);try{const t=e[b];t&&t.stop()}finally{if(delete e[b],!1!==(null==t?void 0:t.reset)){let t=u(e);for(;t&&t!==a;){const o=t[y];if(o)for(const t of o)delete e[t];t=u(t)}}}}})),n}function m(t){var e;return!("function"!=typeof t||!t.prototype||null!=(e=i(t,"prototype"))&&e.writable)}function w(t,e,o){const n={};for(const r in e){const s=null==t?void 0:t[r],u=e[r];n[r]={...u},!u.required&&void 0!==s&&("object"==typeof s&&null!==s?n[r].default=()=>o?o(s):c(s):m(s)?n[r].default=()=>s:n[r].default=s)}return n}function O(t){return t}export{d as Reactive,c as clone,O as definePropTypes,m as isClass,w as propsWithDefaults};
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `nestedProps(props, defaults)` — fill a nested object prop from its
3
+ * defaults, in place, so the class reads complete props at every depth.
4
+ *
5
+ * Vue resolves a prop's default only when the prop is ABSENT: pass
6
+ * `{ wheel: { gain: 2 } }` for a prop whose default is
7
+ * `{ wheel: { gain: 1, follow: 0.1 }, touch: { … } }` and the component
8
+ * receives exactly the object it was passed — `follow` and `touch` are
9
+ * gone. `propsWithDefaults` decides what the default IS and clones it per
10
+ * instance; it cannot reach inside a supplied object. The fill is possible
11
+ * at all because the defaults are a value the class owns — a compiler-only
12
+ * default has nothing to fill from.
13
+ *
14
+ * The semantics are lodash's `defaultsDeep` with arrays taken whole: for
15
+ * every prop whose value and default are both plain objects, each leaf the
16
+ * supplied object lacks is written into it from the default, recursively;
17
+ * a leaf it has is kept. Missing plain-object and array defaults are copied
18
+ * recursively so instances never share those mutable containers. Arrays
19
+ * are never merged; class instances and functions retain their identity. Vue's
20
+ * props proxy is shallow, so the nested objects are the parent's own and
21
+ * are written directly; the props object itself is untouched and returned.
22
+ *
23
+ * Call it once, at the seam where props enter the class:
24
+ *
25
+ * constructor(props: Scroller.Props, public emit: Scroller.Emits) {
26
+ * this.props = nestedProps(props, this.self.propsDefaults);
27
+ * }
28
+ *
29
+ * The parent passes a stable object: a constant inline literal (Vue hoists
30
+ * it), a `ref`'s value, a store field. An object built anew on every
31
+ * parent render is a new, unfilled object each time.
32
+ *
33
+ * `customCloner` is the same policy knob `propsWithDefaults` has: it copies
34
+ * each default branch written into the props. The default, `clone`, copies
35
+ * plain containers and keeps callbacks, constructors and opaque objects by
36
+ * reference, so no two instances share a mutable default. Pass
37
+ * `structuredClone` when `Date`, `Map` or `Set` defaults need their own
38
+ * copies; pass the identity, `value => value`, only when the caller owns
39
+ * every default it passes — a fresh tree per instance, never a shared one.
40
+ *
41
+ * `NestedPartial<T>` is the matching declaration for the prop's type — the
42
+ * shape an author may pass — and `NestedProps<P, D>` the type of the
43
+ * filled props, where every key both sides carry as an object is complete.
44
+ *
45
+ * Ships from `ivue/extras` (not the reactive core) so the primary `ivue`
46
+ * entry stays minimal.
47
+ */
48
+ /** Every key optional at every plain-object depth; arrays stay whole. */
49
+ export declare type NestedPartial<T> = T extends readonly unknown[] ? T : T extends object ? {
50
+ [K in keyof T]?: NestedPartial<T[K]>;
51
+ } : T;
52
+ /** The filled props' type: a key both sides carry as a plain object is complete. */
53
+ export declare type NestedProps<P, D> = {
54
+ [K in keyof P as K extends keyof D ? K : never]-?: NestedLeaf<NonNullable<P[K]>, D[K & keyof D]>;
55
+ } & {
56
+ [K in keyof P as K extends keyof D ? never : K]: P[K];
57
+ };
58
+ /** A value the fill takes whole: not a plain container. */
59
+ declare type Opaque = Date | RegExp | Map<unknown, unknown> | Set<unknown> | ((...args: never[]) => unknown);
60
+ declare type NestedLeaf<V, D> = V extends readonly unknown[] ? V : V extends Opaque ? V : V extends object ? D extends readonly unknown[] ? V : D extends object ? NestedProps<V, D> : V : V;
61
+ /**
62
+ * Fill every nested object prop from its default, in place, and return
63
+ * the props typed as complete. Top-level props are Vue's to default and
64
+ * are never written.
65
+ */
66
+ export declare function nestedProps<P extends object, D extends object>(props: P, defaults: D, customCloner?: (value: unknown) => unknown): NestedProps<P, D>;
67
+ export {};
package/lib/LazyShared.ts CHANGED
@@ -35,11 +35,11 @@
35
35
  * entry stays minimal.
36
36
  */
37
37
  export class LazyShared<T> {
38
- constructor(private readonly make: () => T) {}
38
+ constructor(protected readonly make: () => T) {}
39
39
 
40
- private constructed = false;
41
- private constructing = false;
42
- private stored: T | null = null;
40
+ protected constructed = false;
41
+ protected constructing = false;
42
+ protected stored: T | null = null;
43
43
 
44
44
  get value(): T {
45
45
  if (!this.constructed) {
package/lib/Reactive.ts CHANGED
@@ -7,6 +7,9 @@ import {
7
7
  type ExtractPropTypes,
8
8
  type Ref,
9
9
  } from 'vue';
10
+ import { clone } from './clone';
11
+
12
+ export { clone } from './clone';
10
13
 
11
14
  /**
12
15
  * Constants & Helpers
@@ -363,20 +366,20 @@ export function isClass(val: any): boolean {
363
366
  * but leave primitive properties and functions intact so that
364
367
  * the final object is fully defineComponent() style compatible.
365
368
  *
366
- * The default cloner is the native `structuredClone` (zero-dependency, handles
367
- * plain data, Map/Set/Date/typed arrays, circular refs). For defaults that
368
- * contain class instances or functions which `structuredClone` cannot clone —
369
- * pass a `customCloner` such as lodash `cloneDeep`.
369
+ * The default cloner copies acyclic plain-object and array trees while
370
+ * retaining callbacks, class constructors and opaque objects by reference.
371
+ * For independent Map/Set/Date values or cyclic data, pass a `customCloner`
372
+ * such as `structuredClone` when the values support it.
370
373
  *
371
374
  * @param defaults Regular object of default key -> values
372
375
  * @param typedProps Props declared in defineComponent() style with type and possibly required declared, but without default
373
- * @param customCloner Optional cloner used for object/array defaults (defaults to structuredClone)
376
+ * @param customCloner Optional cloner used for object/array defaults (defaults to clone)
374
377
  * @returns Props declared in defineComponent() style with all properties having default property declared.
375
378
  */
376
379
  export function propsWithDefaults<T extends VuePropsObject>(
377
380
  defaults: Record<string, any>,
378
381
  typedProps: T,
379
- // Optional: Allows user to pass a custom cloner if structuredClone isn't enough
382
+ // Optional: Choose different ownership semantics for opaque objects or cycles.
380
383
  customCloner?: (val: any) => any,
381
384
  ): VuePropsWithDefaults<T> {
382
385
  // NON-MUTATING: descriptor objects are routinely SHARED between props
@@ -394,7 +397,7 @@ export function propsWithDefaults<T extends VuePropsObject>(
394
397
 
395
398
  if (typeof def === 'object' && def !== null) {
396
399
  result[prop].default = () =>
397
- customCloner ? customCloner(def) : structuredClone(def);
400
+ customCloner ? customCloner(def) : clone(def);
398
401
  } else {
399
402
  if (isClass(def)) {
400
403
  result[prop].default = () => def;
@@ -432,17 +435,27 @@ type WritableGetters<T> = {
432
435
  ]-?: T[K];
433
436
  };
434
437
 
435
- export type ReactiveInstance<T> = T &
436
- WritableGetters<T> & {
437
- /** Register a watcher in the instance's lazy effect scope (same signature as Vue `watch`). */
438
- $watch: typeof watch;
439
- /** Register a watchEffect in the instance's lazy effect scope (same signature as Vue `watchEffect`). */
440
- $watchEffect: typeof watchEffect;
441
- /** Stop the instance's effect scope and drop cached cells (the next
442
- * touch re-materializes). `{ reset: false }` stops watchers only —
443
- * every cached cell survives with its current value. */
444
- $stopEffects: (options?: { reset?: boolean }) => void;
445
- };
438
+ /**
439
+ * The members `Reactive()` installs on every instance's prototype. A raw
440
+ * class body cannot see them (the transform runs after the class is typed),
441
+ * so a class that calls them merges this interface into its own instance
442
+ * type one declaration beside the class, zero runtime:
443
+ *
444
+ * class $Session { constructor() { this.$watch(…) } }
445
+ * interface $Session extends ReactiveHelpers {}
446
+ */
447
+ export interface ReactiveHelpers {
448
+ /** Register a watcher in the instance's lazy effect scope (same signature as Vue `watch`). */
449
+ $watch: typeof watch;
450
+ /** Register a watchEffect in the instance's lazy effect scope (same signature as Vue `watchEffect`). */
451
+ $watchEffect: typeof watchEffect;
452
+ /** Stop the instance's effect scope and drop cached cells (the next
453
+ * touch re-materializes). `{ reset: false }` stops watchers only —
454
+ * every cached cell survives with its current value. */
455
+ $stopEffects: (options?: { reset?: boolean }) => void;
456
+ }
457
+
458
+ export type ReactiveInstance<T> = T & WritableGetters<T> & ReactiveHelpers;
446
459
 
447
460
  export type ReactiveClass<C extends new (...args: any) => any> = {
448
461
  [Key in keyof C]: C[Key];
@@ -534,4 +547,4 @@ export type IFnParameter<
534
547
  T extends Record<any, any>,
535
548
  P extends keyof T,
536
549
  K extends number,
537
- > = FnParameter<NonNullable<T[P]> extends AnyFn ? NonNullable<T[P]> : never, K>;
550
+ > = FnParameter<NonNullable<T[P]> extends AnyFn ? NonNullable<T[P]> : never, K>;
package/lib/Static.ts CHANGED
@@ -70,6 +70,22 @@ export function Static<Class extends ClassConstructor>(targetClass: Class): Clas
70
70
  const descriptor = Object.getOwnPropertyDescriptor(currentClass, key)!;
71
71
 
72
72
  if (typeof descriptor.value === 'function') {
73
+ // HOT-LOOP READY — measured, twice, after two wrong theories. The
74
+ // bind happens ONCE: the first read defines an own bind-key
75
+ // property holding the bound function; every later read returns
76
+ // it. A HOISTED bound method is exactly plain-function speed
77
+ // (in-browser, 9M calls, fresh-page medians: module fn 31.7ms,
78
+ // hoisted bound method 30.0ms). The ONLY per-call cost is reading
79
+ // the method THROUGH the accessor inside the loop (84.6ms same
80
+ // loop) — so in a million-call loop, destructure the methods once
81
+ // (`const { method } = X.Class` — a late read of the mutable slot,
82
+ // so a subclass swap is still honored) and pay the accessor once.
83
+ // Ordinary call counts never notice any of this.
84
+ //
85
+ // Benchmark honestly: a shared bench(fn) harness makes the call
86
+ // site megamorphic and slows every variant measured after the
87
+ // first — that artifact once misread bound calls as "48% slower."
88
+ // Fresh page per variant, dedicated loops.
73
89
  const method = descriptor.value;
74
90
  const bindKey =
75
91
  typeof key === 'string'
@@ -13,6 +13,7 @@ import {
13
13
  } from 'vue';
14
14
 
15
15
  import {
16
+ clone,
16
17
  isClass,
17
18
  propsWithDefaults,
18
19
  Reactive,
@@ -986,7 +987,7 @@ describe('propsWithDefaults()', () => {
986
987
  expect(out.nul.default).toBe(null); // null → else branch, assigned directly
987
988
  });
988
989
 
989
- it('wraps object/array defaults in a factory that structuredClones', () => {
990
+ it('wraps object/array defaults in a factory that copies their containers', () => {
990
991
  const typed = { o: { type: Object }, a: { type: Array } };
991
992
  const defaults = { o: { nested: { k: 1 } }, a: [1, 2, 3] };
992
993
  const out = propsWithDefaults(defaults, { ...typed }) as Record<
@@ -1022,6 +1023,49 @@ describe('propsWithDefaults()', () => {
1022
1023
  expect(v).toEqual({ k: 1, cloned: true });
1023
1024
  });
1024
1025
 
1026
+ it('isolates default containers while preserving nested constructors, callbacks and opaque objects', () => {
1027
+ class Runner {}
1028
+ class Tuning { gain = 1; }
1029
+ const onChange = () => 1;
1030
+ const tuning = new Tuning();
1031
+ const date = new Date(0);
1032
+ const cache = new Map([['gain', 1]]);
1033
+ const defaults = { options: { limits: { count: 5 }, runner: Runner, onChange, tuning, date, cache } };
1034
+ const props = propsWithDefaults(defaults, { options: { type: Object } }) as Record<string, any>;
1035
+ const first = props.options.default();
1036
+ const second = props.options.default();
1037
+
1038
+ first.limits.count = 2;
1039
+ expect(second.limits.count).toBe(5);
1040
+ expect(defaults.options.limits.count).toBe(5);
1041
+ expect(first.runner).toBe(Runner);
1042
+ expect(first.onChange).toBe(onChange);
1043
+ expect(first.tuning).toBe(tuning);
1044
+ expect(first.date).toBe(date);
1045
+ expect(first.cache).toBe(cache);
1046
+ // The public copier uses the same ownership policy as the props factory.
1047
+ const copied = clone(defaults.options);
1048
+ expect(copied.limits).not.toBe(defaults.options.limits);
1049
+ expect(copied.runner).toBe(Runner);
1050
+ });
1051
+
1052
+ it('accepts structuredClone explicitly for cyclic data and independent built-in objects', () => {
1053
+ const options: { date: Date; cache: Map<string, number>; self?: unknown } = {
1054
+ date: new Date(0), cache: new Map([['gain', 1]]),
1055
+ };
1056
+ options.self = options;
1057
+ const props = propsWithDefaults({ options }, { options: { type: Object } }, structuredClone) as Record<string, any>;
1058
+ const first = props.options.default();
1059
+ const second = props.options.default();
1060
+
1061
+ expect(first.self).toBe(first);
1062
+ expect(first.date).not.toBe(second.date);
1063
+ expect(first.date.getTime()).toBe(0);
1064
+ first.cache.set('gain', 9);
1065
+ expect(second.cache.get('gain')).toBe(1);
1066
+ expect(options.cache.get('gain')).toBe(1);
1067
+ });
1068
+
1025
1069
  it('wraps a class default in a factory that returns the class itself', () => {
1026
1070
  class Cool {
1027
1071
  x = 1;