sia-reactor 0.0.6 → 0.0.7

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 OLUWATOBILOBA OKETADE
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,8 +1,264 @@
1
- # sia-reactor
1
+ # sia-reacor
2
2
 
3
- The Programmable Data DOM. A high-performance State Intent Architecture (S.I.A.) Engine with zero-allocation loops, event propagation, and structural sharing.
3
+ > The Programmable Data DOM. A high-performance State & Intent Architecture (S.I.A.) Engine featuring zero-allocation loops, DOM-style event propagation, microtask batching, and structural sharing.
4
4
 
5
- ## Installation
5
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+ [![NPM Version](https://img.shields.io/npm/v/sia-reactor.svg)](https://www.npmjs.com/package/sia-reactor)
7
+
8
+ [Live Demo & Benchmarks](https://tobi007-del.github.io/t007-tools/packages/sia-reactor/src/index.html) | [Report Bug](https://github.com/Tobi007-del/t007-tools/issues)
9
+
10
+ [CHRONICLES](https://github.com/Tobi007-del/tmg-media-player/blob/main/CHRONICLES.md) | [FOLKLORE](https://github.com/Tobi007-del/tmg-media-player/blob/main/FOLKLORE.md)
11
+
12
+ ---
13
+
14
+ ## Table of contents
15
+
16
+ - [sia-reacor](#sia-reacor)
17
+ - [Table of contents](#table-of-contents)
18
+ - [Overview: The Paradigm Shift](#overview-the-paradigm-shift)
19
+ - [The Philosophy: Collecting Like Terms](#the-philosophy-collecting-like-terms)
20
+ - [State vs. Intent](#state-vs-intent)
21
+ - [The Art of Resolution: The Power Line](#the-art-of-resolution-the-power-line)
22
+ - [The Triad of Notifications](#the-triad-of-notifications)
23
+ - [Tech Stack](#tech-stack)
24
+ - [Getting Started](#getting-started)
25
+ - [Usage](#usage)
26
+ - [API Reference](#api-reference)
27
+ - [Benchmarks](#benchmarks)
28
+ - [Author](#author)
29
+ - [Acknowledgments](#acknowledgments)
30
+
31
+ ---
32
+
33
+ ## Overview: The Paradigm Shift
34
+
35
+ **sia-reactor** is not just another state management library. It is an architectural paradigm shift.
36
+
37
+ Instead of treating your application's data as a flat object, the S.I.A. Engine converts your data into a **Programmable Data DOM**. Deeply nested object properties now possess the exact same lifecycle as HTML elements: they support strict event phases (Capture, Target, Bubble), they can intercept intents before memory is written, and they batch mutations synchronously to guarantee 60FPS UI renders.
38
+
39
+ Built for engineer surgeons, this engine allows you to wire up massive, deeply nested UIs with zero-allocation performance.
40
+
41
+ ---
42
+
43
+ ## The Philosophy: Collecting Like Terms
44
+
45
+ Most developers build systems that are entirely too rigid. They create Adapters, Contexts, and Request Managers just to make two different entities behave the same way.
46
+
47
+ > Picture a room with air conditioners. When the entity inside gets hot, the AC should turn on.
48
+ > A standard developer sees a human in the room and writes: *"When human sweats, AC on."*
49
+ > Then, the human is replaced by a pig. Pigs don't sweat. Now the developer has to build an entire adapter layer just to simulate fake sweat so the AC will trigger.
50
+
51
+ **The S.I.A. approach is declarative state pluralism.** We do not care *why* or *how* the entity gets hot. We establish a stable core and collect like terms: **"If entity is hot, turn AC on."** The adapter simply gives the entity a state (`hot = false`). When the entity gets hot, it flips the state to `true`. We just listen.
52
+
53
+ ---
54
+
55
+ ## State vs. Intent
56
+
57
+ We divide the world into two concepts to completely eliminate the need for bloated class methods (`makeNervous()`, `straightenNose()`).
58
+
59
+ 1. **State (Fact):** The current reality of the system. It can only be determined *after* something happens. The UI is a mirror reflecting this state.
60
+ 2. **Intent (Request/Wish):** A request to change reality.
61
+
62
+ Instead of learning complex APIs to trigger actions, you simply declare your intent:
63
+ `pig.intent.hot = true` (The Request)
64
+ ↳ *The system internally evaluates* ↳ `pig.state.hot = true` (The Fact).
65
+
66
+ This brings the "appeal" directly into the state tree.
67
+
68
+ ---
69
+
70
+ ### Semantic Structuring: Plain State vs. Intentful State
71
+
72
+ You are not forced to use Intents. If you are building a simple application where data updates are immediate and undisputed, the S.I.A. engine functions perfectly as a hyper-fast, standard state manager. You can strictly use plain state and ignore the complexities of the rejection event loop.
73
+
74
+ However, the moment you introduce Intents into your architecture, **semantics matter**.
75
+
76
+ > If you use an `intent` object to capture user requests, your `state` object must act strictly as the factual mirror to that `intent`. Because `state` is now semantically locked to your intents, you must separate your other data.
77
+
78
+ Do not pollute your `state` object with data that doesn't require an intent. Instead, categorize them semantically:
79
+ - **`intent`**: For asynchronous requests or delayed validations (e.g., `intent.playing = true`).
80
+ - **`state`**: The factual mirror of granted intents (e.g., `state.playing = true`).
81
+ - **`settings` / `config`**: For immediate, undisputed user preferences (e.g., `settings.playbackRate = 2`).
82
+ - **`status`**: For read-only system facts (e.g., `status.network = "offline"`).
83
+
84
+ ```javascript
85
+ import { reactive, intent } from 'sia-reactor';
86
+
87
+ // A perfectly structured S.I.A. Data DOM
88
+ const player = reactive({
89
+ intent: intent({ playing: false, fullscreen: false }), // Can be rejected
90
+ state: { playing: false, fullscreen: false }, // The factual mirror
91
+ settings: { volume: 50, theme: "dark" }, // Immediate, plain state
92
+ status: { buffering: false, duration: 120 } // System facts
93
+ });
94
+ ```
95
+
96
+ ---
97
+
98
+ ## The Art of Resolution: The Power Line
99
+
100
+ Because an **Intent** is just a wish, the system must be able to reject it. This introduces a political hierarchy; a Chain of Responsibility driven by the Event Loop.
101
+
102
+ ### The Parable of the King
103
+ Imagine a King wishes to fly: `man.intent.flying = true`.
104
+ You cannot stop him from wishing it. But the system can determine if it will grant the wish.
105
+
106
+ Everything crucial happens in the **Capture Phase**:
107
+ 1. **The Higher Power:** A plugin that registers first. It intercepts the wish and can choose to `resolve(message)` or `reject(reason)`.
108
+ 2. **The Adviser (The Tech):** Listens further down the capture line. If it sees `e.resolved`, it stands down. If it sees `e.rejected`, it knows the Higher Power failed and can attempt to save the situation or allow the failure.
109
+ 3. **The Observers (The UI):** Listens on the **Bubble Phase**. They don't get involved in politics; they just watch the aftermath.
110
+
111
+ #### The Observer Types
112
+ - **The Smart Optimist (Court Man):** Checks if the intent was rejected before updating the UI.
113
+ - **The Reckless Optimist (Artist):** Doesn't care about rejections and paints the wish immediately, trusting the system will snap back later if needed.
114
+
115
+ ---
116
+
117
+ ## The Triad of Notifications
118
+
119
+ This architecture replaces the chaos of traditional state management with three distinct layers of surgical precision.
120
+
121
+ ### 1. The Gatekeepers (Mediators) - `get`, `set`, `delete`
122
+ Synchronous operations that occur *before* or *during* a state change.
123
+ - Use `.set()` for data integrity and sanitization. You can intercept a value, modify it, or completely block the memory write by returning the `TERMINATOR` symbol.
124
+ - Use `.get()` to format or derive output on the fly without altering the underlying data.
125
+
126
+ ### 2. The Rule of Survival (Watchers) - `watch`
127
+ Synchronous operations that occur *immediately after* a state change.
128
+ - Use `.watch()` when the very next line of code will crash if a system isn't updated instantly (e.g., `video.src`, internal engine states). This bypasses the async event loop for immediate execution.
129
+
130
+ ### 3. The Rule of the Cloud (Listeners) - `on`
131
+ Asynchronous operations that run in the next microtask.
132
+ - Use `.on()` for **all UI updates** (e.g., `volume`, `brightness`). The reactor will automatically smash 1,000 synchronous mutations into a single `queueMicrotask` UI render tick.
133
+
134
+ ---
135
+
136
+ ## Tech Stack
137
+
138
+ ### Built with
139
+ - ECMAScript 2015+ Proxy API
140
+ - `queueMicrotask` Async Batching
141
+ - Bitwise Operations & Zero-Allocation Caching
142
+ - Bundled via `tsup` (ESM, CJS, IIFE outputs)
143
+
144
+ ---
145
+
146
+ ## Getting Started
147
+
148
+ ### Installation
149
+
150
+ Install via your preferred package manager:
6
151
 
7
152
  ```bash
8
- npm install sia-reactor
153
+ npm install sia-reactor
154
+ # or
155
+ yarn add sia-reactor
156
+ # or
157
+ pnpm add sia-reactor
158
+ ```
159
+
160
+ ```javascript
161
+ // 1. Core Engine
162
+ import { reactive, Reactor, TERMINATOR } from 'sia-reactor';
163
+
164
+ // 2. Deep Object Utilities
165
+ import { setAny, getAny, mergeObjs } from 'sia-reactor/utils';
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Usage
171
+
172
+ ### Modern Bundlers (ESM)
173
+
174
+ ```javascript
175
+ import { reactive, Reactor } from 'sia-reactor'; // also attached to window.sia in non-module scripts
176
+ ```
177
+
178
+ ### CDN / Browser (Global)
179
+
180
+ ```javascript
181
+ const { reactive, Reactor } = window.sia;
182
+ ```
183
+
184
+ ## API Reference
185
+
186
+ ### Initialization (`reactive` & `Reactor`)
187
+
188
+ The primary way to use the engine is to wrap an object using `reactive()`, which directly mixes the reactor methods into your target object for a pristine, flat API.
189
+
190
+ ```javascript
191
+ const state = reactive({ player: { volume: 50 } });
192
+
193
+ // Methods are attached directly to the object!
194
+ state.set("player.volume", (val) => Math.min(val, 100));
195
+ state.on("player.volume", (e) => console.log(e.value));
196
+
197
+ state.player.volume = 150; // Triggers mediation, clamps to 100, fires listener.
198
+ ```
199
+
200
+ Alternatively, you can instantiate the `Reactor` class directly to keep the API separate from your data:
201
+ ```javascript
202
+ const engine = new Reactor({ player: { volume: 50 } }, { debug: true, referenceTracking: true });
203
+ engine.core.player.volume = 100;
204
+ ```
205
+
206
+ ### Memory & Granular Control Flags
207
+
208
+ You can wrap properties in special flags *before* initializing the reactor to dictate exactly how the Proxy treats them.
209
+
210
+ - **`inert(obj)` / `live(obj)`**: Tells the proxy to completely ignore an object. It will not be deeply tracked.
211
+ - **`intent(obj)` / `state(obj)`**: Marks an object as rejectable. Allows listeners to call `e.reject()` during the Capture phase.
212
+ - **`volatile(obj)` / `stable(obj)`**: Forces the engine to fire event waves even if the new value is identical to the old value (bypassing the Proxy's unchanged performance check).
213
+
214
+ ```javascript
215
+ import { reactive, intent, volatile, inert } from 'sia-reactor';
216
+
217
+ const data = reactive({
218
+ apiResponse: inert({ heavy: "data" }), // Proxy won't traverse this
219
+ userWish: intent({ flying: false }), // Can be rejected by a Higher Power
220
+ trigger: volatile({ clickCount: 0 }) // Fires events even if set to 0 again
221
+ });
222
+ ```
223
+
224
+ ### Core Methods
225
+
226
+ All methods are available on `Reactor` instances or objects wrapped in `reactive()`.
227
+
228
+ #### **Mediators (Synchronous Gatekeepers)**
229
+ - **`set(path, callback, options)`**: Intercept memory writes. Return a value to modify it, or return `TERMINATOR` to block the write entirely.
230
+ - **`get(path, callback, options)`**: Intercept and format data during retrieval.
231
+ - **`delete(path, callback, options)`**: Intercept property deletion.
232
+
233
+ #### **Watchers (Synchronous Observers)**
234
+ - **`watch(path, callback, options)`**: Fires instantly after a mutation. Use strictly for critical internal engine syncing.
235
+
236
+ #### **Listeners (Asynchronous/Batched UI Observers)**
237
+ - **`on(path, callback, options)`**: Attach DOM-style event listeners. Supports `{ capture: true, depth: 1, once: true, immediate: true }`.
238
+ - **`once(path, callback, options)`**: Fires once and self-destructs.
239
+ - **`off(path, callback, options)`**: Removes a listener.
240
+
241
+ #### **Lifecycle & Utilities**
242
+ - **`tick(path)`**: Forces a synchronous flush of the batch queue for a specific path.
243
+ - **`stall(task)` / `nostall(task)`**: Manually stall the queue to wait for calculations before rendering.
244
+ - **`cascade(payload)`**: Manually trigger deep-object event waves, bypassing strict unchanged-proxy traps. Perfect for dumping massive API payloads into the tree.
245
+ - **`snapshot(raw)`**: Generates a strict, structurally-shared, un-proxied clone of the current state tree.
246
+
247
+ ---
248
+
249
+ ## Benchmarks
250
+
251
+ No fancy screenshots here. True engineers look at performance metrics.
252
+
253
+ To see the S.I.A Engine handle deep DAG mutations, DOM-style event routing, and microtask batching in real-time, visit the **[Live Demo](https://tobi007-del.github.io/t007-tools/packages/sia-reactor/src/index.html)**, open your DevTools console, and run the built-in Grand Master Stress Suite directly on your own CPU.
254
+
255
+ ---
256
+
257
+ ## Author
258
+
259
+ - Architect & Developer - [Oketade Oluwatobiloba (Tobi007-del)](https://github.com/Tobi007-del)
260
+ - Project - [t007-tools](https://github.com/Tobi007-del/t007-tools)
261
+
262
+ ## Acknowledgments
263
+
264
+ Designed to bring absolute architectural dominance and rendering efficiency to complex front-end systems. The foundational data layer of the `@t007` ecosystem.
package/dist/index.cjs CHANGED
@@ -255,10 +255,15 @@ var Reactor = class {
255
255
  isLogging = false;
256
256
  // keeping track so API getter doesn't slow down internal iterations in any way
257
257
  isTracing = false;
258
+ // Lineage Tracing
258
259
  isTracking = false;
260
+ // Reference Tracking
259
261
  isSCloning = false;
260
262
  // Smart Cloning
261
263
  isBatching = false;
264
+ // Async Batching
265
+ isCascading = false;
266
+ // Setter Cascading
262
267
  constructor(obj = {}, options) {
263
268
  this[INERTIA] = true;
264
269
  this.config = { crossRealms: false, eventBubbling: true, batchingFunction: R_BATCH, ...options };
@@ -307,7 +312,7 @@ var Reactor = class {
307
312
  safeValue = value?.[RAW] || value;
308
313
  unchanged = Object.is(safeValue, safeOldValue);
309
314
  }
310
- if (!indiffable && unchanged) return true;
315
+ if (!indiffable && unchanged && !this.isCascading) return true;
311
316
  this.log(`\u270F\uFE0F [SET Trap] Initiated for "${safeKey}" on "${paths}"`);
312
317
  if (this.config.set) terminated = (value = this.config.set(object, key2, value, oldValue, receiver, paths)) === TERMINATOR;
313
318
  if (this.setters) {
@@ -605,7 +610,9 @@ var Reactor = class {
605
610
  cascade({ type, currentTarget: { path, value: news, oldValue: olds } }, objSafe = true) {
606
611
  if (type !== "set" && type !== "delete" || !(isStrictObj(news, this.config.crossRealms) || isArr(news)) || (objSafe ? !(isStrictObj(olds, this.config.crossRealms) || isArr(olds)) : false)) return;
607
612
  const obj = objSafe ? mergeObjs(olds, news) : news, keys = Object.keys(obj);
613
+ this.isCascading = true;
608
614
  for (let i = 0, len = keys.length; i < len; i++) setAny(this.core, path + "." + keys[i], obj[keys[i]]);
615
+ this.isCascading = false;
609
616
  }
610
617
  reset() {
611
618
  this.getters?.clear(), this.setters?.clear(), this.deleters?.clear(), this.watchers?.clear(), this.listeners?.clear(), this.queue?.clear(), this.batch?.clear();
@@ -615,7 +622,7 @@ var Reactor = class {
615
622
  this.reset(), nuke(this);
616
623
  }
617
624
  get canLog() {
618
- return this.log === R_LOG;
625
+ return this.isLogging;
619
626
  }
620
627
  set canLog(value) {
621
628
  this.log = (this.isLogging = value) ? R_LOG : NOOP;
@@ -255,10 +255,15 @@ var sia = (() => {
255
255
  isLogging = false;
256
256
  // keeping track so API getter doesn't slow down internal iterations in any way
257
257
  isTracing = false;
258
+ // Lineage Tracing
258
259
  isTracking = false;
260
+ // Reference Tracking
259
261
  isSCloning = false;
260
262
  // Smart Cloning
261
263
  isBatching = false;
264
+ // Async Batching
265
+ isCascading = false;
266
+ // Setter Cascading
262
267
  constructor(obj = {}, options) {
263
268
  this[INERTIA] = true;
264
269
  this.config = { crossRealms: false, eventBubbling: true, batchingFunction: R_BATCH, ...options };
@@ -307,7 +312,7 @@ var sia = (() => {
307
312
  safeValue = value?.[RAW] || value;
308
313
  unchanged = Object.is(safeValue, safeOldValue);
309
314
  }
310
- if (!indiffable && unchanged) return true;
315
+ if (!indiffable && unchanged && !this.isCascading) return true;
311
316
  this.log(`\u270F\uFE0F [SET Trap] Initiated for "${safeKey}" on "${paths}"`);
312
317
  if (this.config.set) terminated = (value = this.config.set(object, key2, value, oldValue, receiver, paths)) === TERMINATOR;
313
318
  if (this.setters) {
@@ -605,7 +610,9 @@ var sia = (() => {
605
610
  cascade({ type, currentTarget: { path, value: news, oldValue: olds } }, objSafe = true) {
606
611
  if (type !== "set" && type !== "delete" || !(isStrictObj(news, this.config.crossRealms) || isArr(news)) || (objSafe ? !(isStrictObj(olds, this.config.crossRealms) || isArr(olds)) : false)) return;
607
612
  const obj = objSafe ? mergeObjs(olds, news) : news, keys = Object.keys(obj);
613
+ this.isCascading = true;
608
614
  for (let i = 0, len = keys.length; i < len; i++) setAny(this.core, path + "." + keys[i], obj[keys[i]]);
615
+ this.isCascading = false;
609
616
  }
610
617
  reset() {
611
618
  this.getters?.clear(), this.setters?.clear(), this.deleters?.clear(), this.watchers?.clear(), this.listeners?.clear(), this.queue?.clear(), this.batch?.clear();
@@ -615,7 +622,7 @@ var sia = (() => {
615
622
  this.reset(), nuke(this);
616
623
  }
617
624
  get canLog() {
618
- return this.log === R_LOG;
625
+ return this.isLogging;
619
626
  }
620
627
  set canLog(value) {
621
628
  this.log = (this.isLogging = value) ? R_LOG : NOOP;
package/dist/index.js CHANGED
@@ -1,16 +1,114 @@
1
- import {
2
- deleteAny,
3
- getAny,
4
- getTrailPaths,
5
- getTrailRecords,
6
- inAny,
7
- isArr,
8
- isStrictObj,
9
- mergeObjs,
10
- nuke,
11
- parseEvOpts,
12
- setAny
13
- } from "./chunk-GN5OE7KB.js";
1
+ // src/utils/obj.ts
2
+ var arrRx = /^([^\[\]]+)\[(\d+)\]$/;
3
+ function isArr(obj) {
4
+ return Array.isArray(obj);
5
+ }
6
+ function isObj(obj, checkArr = true) {
7
+ return "object" === typeof obj && obj !== null && (checkArr ? !Array.isArray(obj) : true);
8
+ }
9
+ function isStrictObj(obj, crossRealms = false, typecheck = true) {
10
+ return (typecheck ? isObj(obj, false) : true) && (crossRealms ? Object.prototype.toString.call(obj) === "[object Object]" : obj.constructor === Object);
11
+ }
12
+ function setAny(target, key, value, separator = ".", keyFunc) {
13
+ if (!key.includes(separator)) return void (target[keyFunc ? keyFunc(key) : key] = value);
14
+ const keys = key.split(separator);
15
+ for (let currObj = target, i = 0, len = keys.length; i < len; i++) {
16
+ const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
17
+ if (match) {
18
+ const [, key3, iStr] = match;
19
+ if (!isArr(currObj[key3])) currObj[key3] = [];
20
+ if (i === len - 1) currObj[key3][Number(iStr)] = value;
21
+ else currObj[key3][Number(iStr)] ||= {}, currObj = currObj[key3][Number(iStr)];
22
+ } else {
23
+ if (i === len - 1) currObj[key2] = value;
24
+ else currObj[key2] ||= {}, currObj = currObj[key2];
25
+ }
26
+ }
27
+ }
28
+ function getAny(source, key, separator = ".", keyFunc) {
29
+ if (!key.includes(separator)) return source[keyFunc ? keyFunc(key) : key];
30
+ const keys = key.split(separator);
31
+ let currObj = source;
32
+ for (let i = 0, len = keys.length; i < len; i++) {
33
+ const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
34
+ if (match) {
35
+ const [, key3, iStr] = match;
36
+ if (!isArr(currObj[key3]) || !(key3 in currObj)) return void 0;
37
+ currObj = currObj[key3][Number(iStr)];
38
+ } else {
39
+ if (!isObj(currObj) || !(key2 in currObj)) return void 0;
40
+ currObj = currObj[key2];
41
+ }
42
+ }
43
+ return currObj;
44
+ }
45
+ function deleteAny(target, key, separator = ".", keyFunc) {
46
+ if (!key.includes(separator)) return void delete target[keyFunc ? keyFunc(key) : key];
47
+ const keys = key.split(separator);
48
+ for (let currObj = target, i = 0, len = keys.length; i < len; i++) {
49
+ const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
50
+ if (match) {
51
+ const [, key3, iStr] = match;
52
+ if (!isArr(currObj[key3]) || !(key3 in currObj)) return;
53
+ if (i === len - 1) delete currObj[key3][Number(iStr)];
54
+ else currObj = currObj[key3][Number(iStr)];
55
+ } else {
56
+ if (!isObj(currObj) || !(key2 in currObj)) return;
57
+ if (i === len - 1) delete currObj[key2];
58
+ else currObj = currObj[key2];
59
+ }
60
+ }
61
+ }
62
+ function inAny(source, key, separator = ".", keyFunc) {
63
+ if (!key.includes(separator)) return key in source;
64
+ const keys = key.split(separator);
65
+ for (let currObj = source, i = 0, len = keys.length; i < len; i++) {
66
+ const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
67
+ if (match) {
68
+ const [, key3, iStr] = match;
69
+ if (!isArr(currObj[key3]) || !(key3 in currObj)) return false;
70
+ if (i === len - 1) return true;
71
+ currObj = currObj[key3][Number(iStr)];
72
+ } else {
73
+ if (!isObj(currObj) || !(key2 in currObj)) return false;
74
+ if (i === len - 1) return true;
75
+ currObj = currObj[key2];
76
+ }
77
+ }
78
+ return true;
79
+ }
80
+ function parseEvOpts(options, opts, boolOpt = opts[0], result = {}) {
81
+ return Object.assign(result, "boolean" === typeof options ? { [boolOpt]: options } : options), result;
82
+ }
83
+ function mergeObjs(o1 = {}, o2 = {}) {
84
+ const merged = { ...o1 || {}, ...o2 || {} };
85
+ return Object.keys(merged).forEach((k) => isObj(o1?.[k]) && isObj(o2?.[k]) && (merged[k] = mergeObjs(o1[k], o2[k]))), merged;
86
+ }
87
+ function getTrailPaths(path, reverse = true) {
88
+ const parts = path.split("."), chain = ["*"];
89
+ let acc = "";
90
+ for (let i = 0, len = parts.length; i < len; i++) chain.push(acc += (i === 0 ? "" : ".") + parts[i]);
91
+ return reverse ? chain.reverse() : chain;
92
+ }
93
+ function getTrailRecords(obj, path) {
94
+ const parts = path.split("."), record = [["*", obj, obj]];
95
+ let acc = "", currObj = obj;
96
+ for (let i = 0, len = parts.length; i < len; i++) record.push([acc += (i ? "." : "") + parts[i], currObj, currObj = currObj?.[parts[i]]]);
97
+ return record;
98
+ }
99
+ function nuke(target) {
100
+ let proto = target;
101
+ while (proto && proto !== Object.prototype) {
102
+ const keys = Object.getOwnPropertyNames(proto);
103
+ for (let i = 0, len = keys.length; i < len; i++) {
104
+ if (keys[i] === "constructor") continue;
105
+ const desc = Object.getOwnPropertyDescriptor(proto, keys[i]);
106
+ if (desc && ("function" === typeof desc.value || desc.get || desc.set)) continue;
107
+ proto[keys[i]] = null;
108
+ }
109
+ proto = Object.getPrototypeOf(proto);
110
+ }
111
+ }
14
112
 
15
113
  // src/core/reactor.ts
16
114
  var RAW = /* @__PURE__ */ Symbol.for("S.I.A_RAW");
@@ -116,10 +214,15 @@ var Reactor = class {
116
214
  isLogging = false;
117
215
  // keeping track so API getter doesn't slow down internal iterations in any way
118
216
  isTracing = false;
217
+ // Lineage Tracing
119
218
  isTracking = false;
219
+ // Reference Tracking
120
220
  isSCloning = false;
121
221
  // Smart Cloning
122
222
  isBatching = false;
223
+ // Async Batching
224
+ isCascading = false;
225
+ // Setter Cascading
123
226
  constructor(obj = {}, options) {
124
227
  this[INERTIA] = true;
125
228
  this.config = { crossRealms: false, eventBubbling: true, batchingFunction: R_BATCH, ...options };
@@ -168,7 +271,7 @@ var Reactor = class {
168
271
  safeValue = value?.[RAW] || value;
169
272
  unchanged = Object.is(safeValue, safeOldValue);
170
273
  }
171
- if (!indiffable && unchanged) return true;
274
+ if (!indiffable && unchanged && !this.isCascading) return true;
172
275
  this.log(`\u270F\uFE0F [SET Trap] Initiated for "${safeKey}" on "${paths}"`);
173
276
  if (this.config.set) terminated = (value = this.config.set(object, key2, value, oldValue, receiver, paths)) === TERMINATOR;
174
277
  if (this.setters) {
@@ -466,7 +569,9 @@ var Reactor = class {
466
569
  cascade({ type, currentTarget: { path, value: news, oldValue: olds } }, objSafe = true) {
467
570
  if (type !== "set" && type !== "delete" || !(isStrictObj(news, this.config.crossRealms) || isArr(news)) || (objSafe ? !(isStrictObj(olds, this.config.crossRealms) || isArr(olds)) : false)) return;
468
571
  const obj = objSafe ? mergeObjs(olds, news) : news, keys = Object.keys(obj);
572
+ this.isCascading = true;
469
573
  for (let i = 0, len = keys.length; i < len; i++) setAny(this.core, path + "." + keys[i], obj[keys[i]]);
574
+ this.isCascading = false;
470
575
  }
471
576
  reset() {
472
577
  this.getters?.clear(), this.setters?.clear(), this.deleters?.clear(), this.watchers?.clear(), this.listeners?.clear(), this.queue?.clear(), this.batch?.clear();
@@ -476,7 +581,7 @@ var Reactor = class {
476
581
  this.reset(), nuke(this);
477
582
  }
478
583
  get canLog() {
479
- return this.log === R_LOG;
584
+ return this.isLogging;
480
585
  }
481
586
  set canLog(value) {
482
587
  this.log = (this.isLogging = value) ? R_LOG : NOOP;
package/dist/utils.cjs CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/utils.ts
21
21
  var utils_exports = {};
22
22
  __export(utils_exports, {
23
+ deepClone: () => deepClone,
23
24
  deleteAny: () => deleteAny,
24
25
  getAny: () => getAny,
25
26
  getTrailPaths: () => getTrailPaths,
@@ -153,6 +154,14 @@ function getTrailRecords(obj, path) {
153
154
  for (let i = 0, len = parts.length; i < len; i++) record.push([acc += (i ? "." : "") + parts[i], currObj, currObj = currObj?.[parts[i]]]);
154
155
  return record;
155
156
  }
157
+ function deepClone(obj, crossRealms, visited = /* @__PURE__ */ new WeakMap()) {
158
+ if (!(isStrictObj(obj, crossRealms) || isArr(obj)) || visited.has(obj)) return obj;
159
+ const clone = isArr(obj) ? [] : {};
160
+ visited.set(obj, clone);
161
+ const keys = Object.keys(obj);
162
+ for (let i = 0, len = keys.length; i < len; i++) clone[keys[i]] = deepClone(obj[keys[i]], crossRealms, visited);
163
+ return clone;
164
+ }
156
165
  function nuke(target) {
157
166
  let proto = target;
158
167
  while (proto && proto !== Object.prototype) {
@@ -168,6 +177,7 @@ function nuke(target) {
168
177
  }
169
178
  // Annotate the CommonJS export names for ESM import in node:
170
179
  0 && (module.exports = {
180
+ deepClone,
171
181
  deleteAny,
172
182
  getAny,
173
183
  getTrailPaths,
package/dist/utils.d.cts CHANGED
@@ -386,6 +386,7 @@ declare function mergeObjs<T1 extends object>(o1: T1): T1;
386
386
  declare function mergeObjs<T2 extends object>(o1: undefined | null, o2: T2): T2;
387
387
  declare function getTrailPaths<T>(path: WildPaths<T>, reverse?: boolean): WildPaths<T>[];
388
388
  declare function getTrailRecords<T extends object>(obj: T, path: WildPaths<T>): [WildPaths<T>, PathValue<T, WildPaths<T>>, PathValue<T, WildPaths<T>>][];
389
+ declare function deepClone<T>(obj: T, crossRealms?: boolean, visited?: WeakMap<WeakKey, any>): T;
389
390
  declare function nuke(target: any): void;
390
391
 
391
392
  declare const INERTIA: unique symbol;
@@ -444,6 +445,7 @@ declare class Reactor<T extends object> {
444
445
  protected isTracking: boolean;
445
446
  protected isSCloning: boolean;
446
447
  protected isBatching: boolean;
448
+ protected isCascading: boolean;
447
449
  constructor(obj?: T, options?: ReactorOptions<T>);
448
450
  protected proxied<O extends object>(obj: O, rejectable?: boolean, indiffable?: boolean, parent?: object, key?: string, path?: string): O;
449
451
  protected trace(target: object, path: string, paths?: string[], visited?: WeakSet<object>): Paths<T>[];
@@ -494,4 +496,4 @@ declare class Reactor<T extends object> {
494
496
  get canSmartClone(): boolean;
495
497
  }
496
498
 
497
- export { live as $, type StrictPathKey as A, type SyncOptions as B, type ChildPaths as C, type DeepKeys as D, type SyncOptionsTuple as E, type Target as F, type Getter as G, type UnionToIntersection as H, type Inert as I, type UpdatePayload as J, type WatcherRecord as K, type Listener as L, type WildPaths as M, getSnapshotVersion as N, getVersion as O, type PathBranch as P, inert as Q, type REvent as R, type Setter as S, TERMINATOR as T, type Unflatten as U, type Volatile as V, type Watcher as W, intent as X, isInert as Y, isIntent as Z, isVolatile as _, type DeepMerge as a, methods as a0, reactive as a1, stable as a2, state as a3, volatile as a4, type DeepPartial as b, type DeepRequired as c, type Deleter as d, deleteAny, type DeleterRecord as e, type DirectPayload as f, type GetterRecord as g, getAny, getTrailPaths, getTrailRecords, type Intent as h, type ListenerOptions as i, inAny, inBoolArrOpt, isArr, isDef, isIter, isObj, isStrictObj, type ListenerOptionsTuple as j, type ListenerRecord as k, type Live as l, type PathBranchValue as m, mergeObjs, type PathKey as n, nuke, type PathLeaf as o, type PathValue as p, parseAnyObj, parseEvOpts, type Paths as q, type Payload as r, type Reactive as s, setAny, type ReactivePrefs as t, Reactor as u, ReactorEvent as v, type ReactorOptions as w, type SetterRecord as x, type Stable as y, type State as z };
499
+ export { live as $, type StrictPathKey as A, type SyncOptions as B, type ChildPaths as C, type DeepKeys as D, type SyncOptionsTuple as E, type Target as F, type Getter as G, type UnionToIntersection as H, type Inert as I, type UpdatePayload as J, type WatcherRecord as K, type Listener as L, type WildPaths as M, getSnapshotVersion as N, getVersion as O, type PathBranch as P, inert as Q, type REvent as R, type Setter as S, TERMINATOR as T, type Unflatten as U, type Volatile as V, type Watcher as W, intent as X, isInert as Y, isIntent as Z, isVolatile as _, type DeepMerge as a, methods as a0, reactive as a1, stable as a2, state as a3, volatile as a4, type DeepPartial as b, type DeepRequired as c, type Deleter as d, deepClone, deleteAny, type DeleterRecord as e, type DirectPayload as f, type GetterRecord as g, getAny, getTrailPaths, getTrailRecords, type Intent as h, type ListenerOptions as i, inAny, inBoolArrOpt, isArr, isDef, isIter, isObj, isStrictObj, type ListenerOptionsTuple as j, type ListenerRecord as k, type Live as l, type PathBranchValue as m, mergeObjs, type PathKey as n, nuke, type PathLeaf as o, type PathValue as p, parseAnyObj, parseEvOpts, type Paths as q, type Payload as r, type Reactive as s, setAny, type ReactivePrefs as t, Reactor as u, ReactorEvent as v, type ReactorOptions as w, type SetterRecord as x, type Stable as y, type State as z };
package/dist/utils.d.ts CHANGED
@@ -386,6 +386,7 @@ declare function mergeObjs<T1 extends object>(o1: T1): T1;
386
386
  declare function mergeObjs<T2 extends object>(o1: undefined | null, o2: T2): T2;
387
387
  declare function getTrailPaths<T>(path: WildPaths<T>, reverse?: boolean): WildPaths<T>[];
388
388
  declare function getTrailRecords<T extends object>(obj: T, path: WildPaths<T>): [WildPaths<T>, PathValue<T, WildPaths<T>>, PathValue<T, WildPaths<T>>][];
389
+ declare function deepClone<T>(obj: T, crossRealms?: boolean, visited?: WeakMap<WeakKey, any>): T;
389
390
  declare function nuke(target: any): void;
390
391
 
391
392
  declare const INERTIA: unique symbol;
@@ -444,6 +445,7 @@ declare class Reactor<T extends object> {
444
445
  protected isTracking: boolean;
445
446
  protected isSCloning: boolean;
446
447
  protected isBatching: boolean;
448
+ protected isCascading: boolean;
447
449
  constructor(obj?: T, options?: ReactorOptions<T>);
448
450
  protected proxied<O extends object>(obj: O, rejectable?: boolean, indiffable?: boolean, parent?: object, key?: string, path?: string): O;
449
451
  protected trace(target: object, path: string, paths?: string[], visited?: WeakSet<object>): Paths<T>[];
@@ -494,4 +496,4 @@ declare class Reactor<T extends object> {
494
496
  get canSmartClone(): boolean;
495
497
  }
496
498
 
497
- export { live as $, type StrictPathKey as A, type SyncOptions as B, type ChildPaths as C, type DeepKeys as D, type SyncOptionsTuple as E, type Target as F, type Getter as G, type UnionToIntersection as H, type Inert as I, type UpdatePayload as J, type WatcherRecord as K, type Listener as L, type WildPaths as M, getSnapshotVersion as N, getVersion as O, type PathBranch as P, inert as Q, type REvent as R, type Setter as S, TERMINATOR as T, type Unflatten as U, type Volatile as V, type Watcher as W, intent as X, isInert as Y, isIntent as Z, isVolatile as _, type DeepMerge as a, methods as a0, reactive as a1, stable as a2, state as a3, volatile as a4, type DeepPartial as b, type DeepRequired as c, type Deleter as d, deleteAny, type DeleterRecord as e, type DirectPayload as f, type GetterRecord as g, getAny, getTrailPaths, getTrailRecords, type Intent as h, type ListenerOptions as i, inAny, inBoolArrOpt, isArr, isDef, isIter, isObj, isStrictObj, type ListenerOptionsTuple as j, type ListenerRecord as k, type Live as l, type PathBranchValue as m, mergeObjs, type PathKey as n, nuke, type PathLeaf as o, type PathValue as p, parseAnyObj, parseEvOpts, type Paths as q, type Payload as r, type Reactive as s, setAny, type ReactivePrefs as t, Reactor as u, ReactorEvent as v, type ReactorOptions as w, type SetterRecord as x, type Stable as y, type State as z };
499
+ export { live as $, type StrictPathKey as A, type SyncOptions as B, type ChildPaths as C, type DeepKeys as D, type SyncOptionsTuple as E, type Target as F, type Getter as G, type UnionToIntersection as H, type Inert as I, type UpdatePayload as J, type WatcherRecord as K, type Listener as L, type WildPaths as M, getSnapshotVersion as N, getVersion as O, type PathBranch as P, inert as Q, type REvent as R, type Setter as S, TERMINATOR as T, type Unflatten as U, type Volatile as V, type Watcher as W, intent as X, isInert as Y, isIntent as Z, isVolatile as _, type DeepMerge as a, methods as a0, reactive as a1, stable as a2, state as a3, volatile as a4, type DeepPartial as b, type DeepRequired as c, type Deleter as d, deepClone, deleteAny, type DeleterRecord as e, type DirectPayload as f, type GetterRecord as g, getAny, getTrailPaths, getTrailRecords, type Intent as h, type ListenerOptions as i, inAny, inBoolArrOpt, isArr, isDef, isIter, isObj, isStrictObj, type ListenerOptionsTuple as j, type ListenerRecord as k, type Live as l, type PathBranchValue as m, mergeObjs, type PathKey as n, nuke, type PathLeaf as o, type PathValue as p, parseAnyObj, parseEvOpts, type Paths as q, type Payload as r, type Reactive as s, setAny, type ReactivePrefs as t, Reactor as u, ReactorEvent as v, type ReactorOptions as w, type SetterRecord as x, type Stable as y, type State as z };
@@ -21,6 +21,7 @@ var sia = (() => {
21
21
  // src/utils.ts
22
22
  var utils_exports = {};
23
23
  __export(utils_exports, {
24
+ deepClone: () => deepClone,
24
25
  deleteAny: () => deleteAny,
25
26
  getAny: () => getAny,
26
27
  getTrailPaths: () => getTrailPaths,
@@ -153,6 +154,14 @@ var sia = (() => {
153
154
  for (let i = 0, len = parts.length; i < len; i++) record.push([acc += (i ? "." : "") + parts[i], currObj, currObj = currObj?.[parts[i]]]);
154
155
  return record;
155
156
  }
157
+ function deepClone(obj, crossRealms, visited = /* @__PURE__ */ new WeakMap()) {
158
+ if (!(isStrictObj(obj, crossRealms) || isArr(obj)) || visited.has(obj)) return obj;
159
+ const clone = isArr(obj) ? [] : {};
160
+ visited.set(obj, clone);
161
+ const keys = Object.keys(obj);
162
+ for (let i = 0, len = keys.length; i < len; i++) clone[keys[i]] = deepClone(obj[keys[i]], crossRealms, visited);
163
+ return clone;
164
+ }
156
165
  function nuke(target) {
157
166
  let proto = target;
158
167
  while (proto && proto !== Object.prototype) {
package/dist/utils.js CHANGED
@@ -1,22 +1,140 @@
1
- import {
2
- deleteAny,
3
- getAny,
4
- getTrailPaths,
5
- getTrailRecords,
6
- inAny,
7
- inBoolArrOpt,
8
- isArr,
9
- isDef,
10
- isIter,
11
- isObj,
12
- isStrictObj,
13
- mergeObjs,
14
- nuke,
15
- parseAnyObj,
16
- parseEvOpts,
17
- setAny
18
- } from "./chunk-GN5OE7KB.js";
1
+ // src/utils/obj.ts
2
+ var arrRx = /^([^\[\]]+)\[(\d+)\]$/;
3
+ function isDef(val) {
4
+ return val !== void 0;
5
+ }
6
+ function isArr(obj) {
7
+ return Array.isArray(obj);
8
+ }
9
+ function isObj(obj, checkArr = true) {
10
+ return "object" === typeof obj && obj !== null && (checkArr ? !Array.isArray(obj) : true);
11
+ }
12
+ function isStrictObj(obj, crossRealms = false, typecheck = true) {
13
+ return (typecheck ? isObj(obj, false) : true) && (crossRealms ? Object.prototype.toString.call(obj) === "[object Object]" : obj.constructor === Object);
14
+ }
15
+ function isIter(obj) {
16
+ return obj != null && "function" === typeof obj[Symbol.iterator];
17
+ }
18
+ function inBoolArrOpt(opt, str) {
19
+ return opt?.includes?.(str) ?? opt;
20
+ }
21
+ function setAny(target, key, value, separator = ".", keyFunc) {
22
+ if (!key.includes(separator)) return void (target[keyFunc ? keyFunc(key) : key] = value);
23
+ const keys = key.split(separator);
24
+ for (let currObj = target, i = 0, len = keys.length; i < len; i++) {
25
+ const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
26
+ if (match) {
27
+ const [, key3, iStr] = match;
28
+ if (!isArr(currObj[key3])) currObj[key3] = [];
29
+ if (i === len - 1) currObj[key3][Number(iStr)] = value;
30
+ else currObj[key3][Number(iStr)] ||= {}, currObj = currObj[key3][Number(iStr)];
31
+ } else {
32
+ if (i === len - 1) currObj[key2] = value;
33
+ else currObj[key2] ||= {}, currObj = currObj[key2];
34
+ }
35
+ }
36
+ }
37
+ function getAny(source, key, separator = ".", keyFunc) {
38
+ if (!key.includes(separator)) return source[keyFunc ? keyFunc(key) : key];
39
+ const keys = key.split(separator);
40
+ let currObj = source;
41
+ for (let i = 0, len = keys.length; i < len; i++) {
42
+ const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
43
+ if (match) {
44
+ const [, key3, iStr] = match;
45
+ if (!isArr(currObj[key3]) || !(key3 in currObj)) return void 0;
46
+ currObj = currObj[key3][Number(iStr)];
47
+ } else {
48
+ if (!isObj(currObj) || !(key2 in currObj)) return void 0;
49
+ currObj = currObj[key2];
50
+ }
51
+ }
52
+ return currObj;
53
+ }
54
+ function deleteAny(target, key, separator = ".", keyFunc) {
55
+ if (!key.includes(separator)) return void delete target[keyFunc ? keyFunc(key) : key];
56
+ const keys = key.split(separator);
57
+ for (let currObj = target, i = 0, len = keys.length; i < len; i++) {
58
+ const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
59
+ if (match) {
60
+ const [, key3, iStr] = match;
61
+ if (!isArr(currObj[key3]) || !(key3 in currObj)) return;
62
+ if (i === len - 1) delete currObj[key3][Number(iStr)];
63
+ else currObj = currObj[key3][Number(iStr)];
64
+ } else {
65
+ if (!isObj(currObj) || !(key2 in currObj)) return;
66
+ if (i === len - 1) delete currObj[key2];
67
+ else currObj = currObj[key2];
68
+ }
69
+ }
70
+ }
71
+ function inAny(source, key, separator = ".", keyFunc) {
72
+ if (!key.includes(separator)) return key in source;
73
+ const keys = key.split(separator);
74
+ for (let currObj = source, i = 0, len = keys.length; i < len; i++) {
75
+ const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
76
+ if (match) {
77
+ const [, key3, iStr] = match;
78
+ if (!isArr(currObj[key3]) || !(key3 in currObj)) return false;
79
+ if (i === len - 1) return true;
80
+ currObj = currObj[key3][Number(iStr)];
81
+ } else {
82
+ if (!isObj(currObj) || !(key2 in currObj)) return false;
83
+ if (i === len - 1) return true;
84
+ currObj = currObj[key2];
85
+ }
86
+ }
87
+ return true;
88
+ }
89
+ function parseAnyObj(obj, separator = ".", keyFunc = (p) => p, visited = /* @__PURE__ */ new WeakSet()) {
90
+ if (!isObj(obj) || visited.has(obj)) return obj;
91
+ visited.add(obj);
92
+ const result = {};
93
+ Object.keys(obj).forEach((k) => k.includes(separator) ? setAny(result, k, parseAnyObj(obj[k], separator, keyFunc, visited), separator, keyFunc) : result[k] = isObj(obj[k]) ? parseAnyObj(obj[k], separator, keyFunc, visited) : obj[k]);
94
+ return result;
95
+ }
96
+ function parseEvOpts(options, opts, boolOpt = opts[0], result = {}) {
97
+ return Object.assign(result, "boolean" === typeof options ? { [boolOpt]: options } : options), result;
98
+ }
99
+ function mergeObjs(o1 = {}, o2 = {}) {
100
+ const merged = { ...o1 || {}, ...o2 || {} };
101
+ return Object.keys(merged).forEach((k) => isObj(o1?.[k]) && isObj(o2?.[k]) && (merged[k] = mergeObjs(o1[k], o2[k]))), merged;
102
+ }
103
+ function getTrailPaths(path, reverse = true) {
104
+ const parts = path.split("."), chain = ["*"];
105
+ let acc = "";
106
+ for (let i = 0, len = parts.length; i < len; i++) chain.push(acc += (i === 0 ? "" : ".") + parts[i]);
107
+ return reverse ? chain.reverse() : chain;
108
+ }
109
+ function getTrailRecords(obj, path) {
110
+ const parts = path.split("."), record = [["*", obj, obj]];
111
+ let acc = "", currObj = obj;
112
+ for (let i = 0, len = parts.length; i < len; i++) record.push([acc += (i ? "." : "") + parts[i], currObj, currObj = currObj?.[parts[i]]]);
113
+ return record;
114
+ }
115
+ function deepClone(obj, crossRealms, visited = /* @__PURE__ */ new WeakMap()) {
116
+ if (!(isStrictObj(obj, crossRealms) || isArr(obj)) || visited.has(obj)) return obj;
117
+ const clone = isArr(obj) ? [] : {};
118
+ visited.set(obj, clone);
119
+ const keys = Object.keys(obj);
120
+ for (let i = 0, len = keys.length; i < len; i++) clone[keys[i]] = deepClone(obj[keys[i]], crossRealms, visited);
121
+ return clone;
122
+ }
123
+ function nuke(target) {
124
+ let proto = target;
125
+ while (proto && proto !== Object.prototype) {
126
+ const keys = Object.getOwnPropertyNames(proto);
127
+ for (let i = 0, len = keys.length; i < len; i++) {
128
+ if (keys[i] === "constructor") continue;
129
+ const desc = Object.getOwnPropertyDescriptor(proto, keys[i]);
130
+ if (desc && ("function" === typeof desc.value || desc.get || desc.set)) continue;
131
+ proto[keys[i]] = null;
132
+ }
133
+ proto = Object.getPrototypeOf(proto);
134
+ }
135
+ }
19
136
  export {
137
+ deepClone,
20
138
  deleteAny,
21
139
  getAny,
22
140
  getTrailPaths,
package/package.json CHANGED
@@ -1,23 +1,24 @@
1
1
  {
2
2
  "name": "sia-reactor",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "The Programmable Data DOM. A high-performance State Intent Architecture (S.I.A.) Engine with zero-allocation loops, event propagation, and structural sharing.",
5
5
  "author": "Oketade Oluwatobiloba <tobioketade007@gmail.com>",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/tobi007-del/t007-tools.git",
9
+ "url": "git+https://github.com/Tobi007-del/t007-tools.git",
10
10
  "directory": "packages/sia-reactor"
11
11
  },
12
- "homepage": "https://github.com/tobi007-del/tree/main/packages/sia-reactor#readme",
12
+ "homepage": "https://github.com/Tobi007-del/tree/main/packages/sia-reactor#readme",
13
13
  "bugs": {
14
- "url": "https://github.com/tobi007-del/sia-reactor/issues"
14
+ "url": "https://github.com/Tobi007-del/sia-reactor/issues"
15
15
  },
16
16
  "type": "module",
17
17
  "main": "./dist/index.cjs",
18
18
  "module": "./dist/index.js",
19
19
  "browser": "./dist/index.global.js",
20
20
  "unpkg": "./dist/index.global.js",
21
+ "jsdelivr": "./dist/index.global.js",
21
22
  "types": "./dist/index.d.ts",
22
23
  "sideEffects": false,
23
24
  "exports": {
@@ -34,13 +35,19 @@
34
35
  "default": "./dist/utils.js"
35
36
  }
36
37
  },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
37
41
  "scripts": {
38
- "build": "tsup src/index.ts src/utils.ts src/types.ts --format cjs,esm,iife --global-name sia --dts --clean"
42
+ "build": "tsup src/index.ts src/utils.ts src/types.ts --format cjs,esm,iife --global-name sia --dts --clean --no-splitting",
43
+ "prepublishOnly": "shx cp ../../LICENSE ."
39
44
  },
40
45
  "files": [
41
46
  "dist"
42
47
  ],
43
48
  "keywords": [
49
+ "t007",
50
+ "ecosystem",
44
51
  "reactor",
45
52
  "sia",
46
53
  "state",
@@ -1,146 +0,0 @@
1
- // src/utils/obj.ts
2
- var arrRx = /^([^\[\]]+)\[(\d+)\]$/;
3
- function isDef(val) {
4
- return val !== void 0;
5
- }
6
- function isArr(obj) {
7
- return Array.isArray(obj);
8
- }
9
- function isObj(obj, checkArr = true) {
10
- return "object" === typeof obj && obj !== null && (checkArr ? !Array.isArray(obj) : true);
11
- }
12
- function isStrictObj(obj, crossRealms = false, typecheck = true) {
13
- return (typecheck ? isObj(obj, false) : true) && (crossRealms ? Object.prototype.toString.call(obj) === "[object Object]" : obj.constructor === Object);
14
- }
15
- function isIter(obj) {
16
- return obj != null && "function" === typeof obj[Symbol.iterator];
17
- }
18
- function inBoolArrOpt(opt, str) {
19
- return opt?.includes?.(str) ?? opt;
20
- }
21
- function setAny(target, key, value, separator = ".", keyFunc) {
22
- if (!key.includes(separator)) return void (target[keyFunc ? keyFunc(key) : key] = value);
23
- const keys = key.split(separator);
24
- for (let currObj = target, i = 0, len = keys.length; i < len; i++) {
25
- const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
26
- if (match) {
27
- const [, key3, iStr] = match;
28
- if (!isArr(currObj[key3])) currObj[key3] = [];
29
- if (i === len - 1) currObj[key3][Number(iStr)] = value;
30
- else currObj[key3][Number(iStr)] ||= {}, currObj = currObj[key3][Number(iStr)];
31
- } else {
32
- if (i === len - 1) currObj[key2] = value;
33
- else currObj[key2] ||= {}, currObj = currObj[key2];
34
- }
35
- }
36
- }
37
- function getAny(source, key, separator = ".", keyFunc) {
38
- if (!key.includes(separator)) return source[keyFunc ? keyFunc(key) : key];
39
- const keys = key.split(separator);
40
- let currObj = source;
41
- for (let i = 0, len = keys.length; i < len; i++) {
42
- const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
43
- if (match) {
44
- const [, key3, iStr] = match;
45
- if (!isArr(currObj[key3]) || !(key3 in currObj)) return void 0;
46
- currObj = currObj[key3][Number(iStr)];
47
- } else {
48
- if (!isObj(currObj) || !(key2 in currObj)) return void 0;
49
- currObj = currObj[key2];
50
- }
51
- }
52
- return currObj;
53
- }
54
- function deleteAny(target, key, separator = ".", keyFunc) {
55
- if (!key.includes(separator)) return void delete target[keyFunc ? keyFunc(key) : key];
56
- const keys = key.split(separator);
57
- for (let currObj = target, i = 0, len = keys.length; i < len; i++) {
58
- const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
59
- if (match) {
60
- const [, key3, iStr] = match;
61
- if (!isArr(currObj[key3]) || !(key3 in currObj)) return;
62
- if (i === len - 1) delete currObj[key3][Number(iStr)];
63
- else currObj = currObj[key3][Number(iStr)];
64
- } else {
65
- if (!isObj(currObj) || !(key2 in currObj)) return;
66
- if (i === len - 1) delete currObj[key2];
67
- else currObj = currObj[key2];
68
- }
69
- }
70
- }
71
- function inAny(source, key, separator = ".", keyFunc) {
72
- if (!key.includes(separator)) return key in source;
73
- const keys = key.split(separator);
74
- for (let currObj = source, i = 0, len = keys.length; i < len; i++) {
75
- const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRx);
76
- if (match) {
77
- const [, key3, iStr] = match;
78
- if (!isArr(currObj[key3]) || !(key3 in currObj)) return false;
79
- if (i === len - 1) return true;
80
- currObj = currObj[key3][Number(iStr)];
81
- } else {
82
- if (!isObj(currObj) || !(key2 in currObj)) return false;
83
- if (i === len - 1) return true;
84
- currObj = currObj[key2];
85
- }
86
- }
87
- return true;
88
- }
89
- function parseAnyObj(obj, separator = ".", keyFunc = (p) => p, visited = /* @__PURE__ */ new WeakSet()) {
90
- if (!isObj(obj) || visited.has(obj)) return obj;
91
- visited.add(obj);
92
- const result = {};
93
- Object.keys(obj).forEach((k) => k.includes(separator) ? setAny(result, k, parseAnyObj(obj[k], separator, keyFunc, visited), separator, keyFunc) : result[k] = isObj(obj[k]) ? parseAnyObj(obj[k], separator, keyFunc, visited) : obj[k]);
94
- return result;
95
- }
96
- function parseEvOpts(options, opts, boolOpt = opts[0], result = {}) {
97
- return Object.assign(result, "boolean" === typeof options ? { [boolOpt]: options } : options), result;
98
- }
99
- function mergeObjs(o1 = {}, o2 = {}) {
100
- const merged = { ...o1 || {}, ...o2 || {} };
101
- return Object.keys(merged).forEach((k) => isObj(o1?.[k]) && isObj(o2?.[k]) && (merged[k] = mergeObjs(o1[k], o2[k]))), merged;
102
- }
103
- function getTrailPaths(path, reverse = true) {
104
- const parts = path.split("."), chain = ["*"];
105
- let acc = "";
106
- for (let i = 0, len = parts.length; i < len; i++) chain.push(acc += (i === 0 ? "" : ".") + parts[i]);
107
- return reverse ? chain.reverse() : chain;
108
- }
109
- function getTrailRecords(obj, path) {
110
- const parts = path.split("."), record = [["*", obj, obj]];
111
- let acc = "", currObj = obj;
112
- for (let i = 0, len = parts.length; i < len; i++) record.push([acc += (i ? "." : "") + parts[i], currObj, currObj = currObj?.[parts[i]]]);
113
- return record;
114
- }
115
- function nuke(target) {
116
- let proto = target;
117
- while (proto && proto !== Object.prototype) {
118
- const keys = Object.getOwnPropertyNames(proto);
119
- for (let i = 0, len = keys.length; i < len; i++) {
120
- if (keys[i] === "constructor") continue;
121
- const desc = Object.getOwnPropertyDescriptor(proto, keys[i]);
122
- if (desc && ("function" === typeof desc.value || desc.get || desc.set)) continue;
123
- proto[keys[i]] = null;
124
- }
125
- proto = Object.getPrototypeOf(proto);
126
- }
127
- }
128
-
129
- export {
130
- isDef,
131
- isArr,
132
- isObj,
133
- isStrictObj,
134
- isIter,
135
- inBoolArrOpt,
136
- setAny,
137
- getAny,
138
- deleteAny,
139
- inAny,
140
- parseAnyObj,
141
- parseEvOpts,
142
- mergeObjs,
143
- getTrailPaths,
144
- getTrailRecords,
145
- nuke
146
- };