mutts 1.0.0 → 1.0.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/chunks/{decorator-BXsign4Z.js → decorator-8qjFb7dw.js} +2 -2
- package/dist/chunks/decorator-8qjFb7dw.js.map +1 -0
- package/dist/chunks/{decorator-CPbZNnsX.esm.js → decorator-AbRkXM5O.esm.js} +2 -2
- package/dist/chunks/decorator-AbRkXM5O.esm.js.map +1 -0
- package/dist/decorator.d.ts +1 -1
- package/dist/decorator.esm.js +1 -1
- package/dist/decorator.js +1 -1
- package/dist/destroyable.esm.js +1 -1
- package/dist/destroyable.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/mutts.umd.js +1 -1
- package/dist/mutts.umd.js.map +1 -1
- package/dist/mutts.umd.min.js +1 -1
- package/dist/mutts.umd.min.js.map +1 -1
- package/dist/reactive.d.ts +4 -3
- package/dist/reactive.esm.js +61 -57
- package/dist/reactive.esm.js.map +1 -1
- package/dist/reactive.js +61 -56
- package/dist/reactive.js.map +1 -1
- package/dist/std-decorators.esm.js +1 -1
- package/dist/std-decorators.js +1 -1
- package/docs/reactive.md +616 -0
- package/package.json +1 -2
- package/dist/chunks/decorator-BXsign4Z.js.map +0 -1
- package/dist/chunks/decorator-CPbZNnsX.esm.js.map +0 -1
- package/src/decorator.test.ts +0 -495
- package/src/decorator.ts +0 -205
- package/src/destroyable.test.ts +0 -155
- package/src/destroyable.ts +0 -158
- package/src/eventful.test.ts +0 -380
- package/src/eventful.ts +0 -69
- package/src/index.ts +0 -7
- package/src/indexable.test.ts +0 -388
- package/src/indexable.ts +0 -124
- package/src/promiseChain.test.ts +0 -201
- package/src/promiseChain.ts +0 -99
- package/src/reactive/array.test.ts +0 -923
- package/src/reactive/array.ts +0 -352
- package/src/reactive/core.test.ts +0 -1663
- package/src/reactive/core.ts +0 -866
- package/src/reactive/index.ts +0 -28
- package/src/reactive/interface.test.ts +0 -1477
- package/src/reactive/interface.ts +0 -231
- package/src/reactive/map.test.ts +0 -866
- package/src/reactive/map.ts +0 -162
- package/src/reactive/set.test.ts +0 -289
- package/src/reactive/set.ts +0 -142
- package/src/std-decorators.test.ts +0 -679
- package/src/std-decorators.ts +0 -182
- package/src/utils.ts +0 -52
package/dist/reactive.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { LegacyClassDecorator, ModernClassDecorator,
|
|
1
|
+
import { LegacyPropertyDecorator, ModernMethodDecorator, LegacyClassDecorator, ModernClassDecorator, ModernGetterDecorator, ModernAccessorDecorator, GenericClassDecorator } from './decorator.js';
|
|
2
2
|
|
|
3
3
|
type DependencyFunction = <T>(cb: () => T) => T;
|
|
4
4
|
type ScopedCallback = () => void;
|
|
5
5
|
type PropEvolution = {
|
|
6
|
-
type: 'set' | 'del' | 'add';
|
|
6
|
+
type: 'set' | 'del' | 'add' | 'invalidate';
|
|
7
7
|
prop: any;
|
|
8
8
|
};
|
|
9
9
|
type BunchEvolution = {
|
|
@@ -60,6 +60,7 @@ declare const options: {
|
|
|
60
60
|
warn: (...args: any[]) => void;
|
|
61
61
|
};
|
|
62
62
|
declare function getState(obj: any): State;
|
|
63
|
+
declare const atomic: LegacyPropertyDecorator<any> & ModernMethodDecorator<any> & (<Args extends any[], Return>(original: (...args: Args) => Return) => (...args: Args) => Return);
|
|
63
64
|
declare class ReactiveBase {
|
|
64
65
|
constructor();
|
|
65
66
|
}
|
|
@@ -110,5 +111,5 @@ declare function unreactiveApplication<T extends object>(...args: (keyof T)[]):
|
|
|
110
111
|
declare function unreactiveApplication<T extends object>(obj: T): T;
|
|
111
112
|
declare const unreactive: LegacyClassDecorator<new (...args: any[]) => any> & ModernClassDecorator<new (...args: any[]) => any> & typeof unreactiveApplication;
|
|
112
113
|
|
|
113
|
-
export { ReactiveBase, ReactiveError, computed, effect, getState, immutables, invalidateComputed, isNonReactive, isReactive, profileInfo, reactive, options as reactiveOptions, unreactive, untracked, unwrap, watch };
|
|
114
|
+
export { ReactiveBase, ReactiveError, atomic, computed, effect, getState, immutables, invalidateComputed, isNonReactive, isReactive, profileInfo, reactive, options as reactiveOptions, unreactive, untracked, unwrap, watch };
|
|
114
115
|
export type { ScopedCallback };
|
package/dist/reactive.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as decorator, r as renamed } from './chunks/decorator-
|
|
1
|
+
import { d as decorator, r as renamed } from './chunks/decorator-AbRkXM5O.esm.js';
|
|
2
2
|
import { Indexable } from './indexable.esm.js';
|
|
3
3
|
|
|
4
4
|
// biome-ignore-all lint/suspicious/noConfusingVoidType: Type 'void' is not assignable to type 'ScopedCallback | undefined'.
|
|
@@ -19,6 +19,7 @@ const deepWatchers = new WeakMap();
|
|
|
19
19
|
const effectToDeepWatchedObjects = new WeakMap();
|
|
20
20
|
// Track objects that should never be reactive and cannot be modified
|
|
21
21
|
const nonReactiveObjects = new WeakSet();
|
|
22
|
+
const absent = Symbol('absent');
|
|
22
23
|
/**
|
|
23
24
|
* Converts an iterator to a generator that yields reactive values
|
|
24
25
|
*/
|
|
@@ -140,7 +141,7 @@ function raiseDeps(objectWatchers, ...keyChains) {
|
|
|
140
141
|
const deps = objectWatchers.get(key);
|
|
141
142
|
if (deps)
|
|
142
143
|
for (const effect of Array.from(deps))
|
|
143
|
-
|
|
144
|
+
atomicEffect(effect);
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
function touched1(obj, evolution, prop) {
|
|
@@ -180,7 +181,6 @@ function getState(obj) {
|
|
|
180
181
|
return state;
|
|
181
182
|
}
|
|
182
183
|
function dependant(obj, prop = allProps) {
|
|
183
|
-
// TODO: avoid depending on property get?
|
|
184
184
|
obj = unwrap(obj);
|
|
185
185
|
if (activeEffect && (typeof prop !== 'symbol' || prop === allProps)) {
|
|
186
186
|
let objectWatchers = watchers.get(obj);
|
|
@@ -212,29 +212,53 @@ let parentEffect;
|
|
|
212
212
|
let batchedEffects;
|
|
213
213
|
// Track which sub-effects have been executed to prevent infinite loops
|
|
214
214
|
// These are all the effects triggered under `activeEffect` and all their sub-effects
|
|
215
|
-
function
|
|
215
|
+
function atomicEffect(effect, immediate) {
|
|
216
216
|
const root = getRoot(effect);
|
|
217
217
|
options?.chain(getRoot(effect), getRoot(activeEffect));
|
|
218
|
-
if (batchedEffects)
|
|
218
|
+
if (batchedEffects) {
|
|
219
219
|
batchedEffects.set(root, effect);
|
|
220
|
+
if (immediate)
|
|
221
|
+
try {
|
|
222
|
+
return effect();
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
batchedEffects.delete(root);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
220
228
|
else {
|
|
221
229
|
const runEffects = [];
|
|
222
230
|
batchedEffects = new Map([[root, effect]]);
|
|
231
|
+
const firstReturn = {};
|
|
223
232
|
try {
|
|
224
233
|
while (batchedEffects.size) {
|
|
225
234
|
if (runEffects.length > options.maxEffectChain)
|
|
226
235
|
throw new ReactiveError('[reactive] Max effect chain reached');
|
|
227
236
|
const [root, effect] = batchedEffects.entries().next().value;
|
|
228
237
|
runEffects.push(root);
|
|
229
|
-
effect();
|
|
238
|
+
const rv = effect();
|
|
239
|
+
if (!('value' in firstReturn))
|
|
240
|
+
firstReturn.value = rv;
|
|
230
241
|
batchedEffects.delete(root);
|
|
231
242
|
}
|
|
243
|
+
return firstReturn.value;
|
|
232
244
|
}
|
|
233
245
|
finally {
|
|
234
246
|
batchedEffects = undefined;
|
|
235
247
|
}
|
|
236
248
|
}
|
|
237
249
|
}
|
|
250
|
+
const atomic = decorator({
|
|
251
|
+
method(original) {
|
|
252
|
+
return function (...args) {
|
|
253
|
+
return atomicEffect(markWithRoot(() => original.apply(this, args), original), 'immediate');
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
default(original) {
|
|
257
|
+
return function (...args) {
|
|
258
|
+
return atomicEffect(markWithRoot(() => original.apply(this, args), original), 'immediate');
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
});
|
|
238
262
|
function withEffect(effect, fn, keepParent) {
|
|
239
263
|
if (getRoot(effect) === getRoot(activeEffect))
|
|
240
264
|
return fn();
|
|
@@ -309,7 +333,7 @@ function bubbleUpChange(changedObject, evolution) {
|
|
|
309
333
|
const parentDeepWatchers = deepWatchers.get(parent);
|
|
310
334
|
if (parentDeepWatchers)
|
|
311
335
|
for (const watcher of parentDeepWatchers)
|
|
312
|
-
|
|
336
|
+
atomicEffect(watcher);
|
|
313
337
|
// Continue bubbling up
|
|
314
338
|
bubbleUpChange(parent);
|
|
315
339
|
}
|
|
@@ -338,9 +362,8 @@ const reactiveHandlers = {
|
|
|
338
362
|
// Check if this property is marked as unreactive
|
|
339
363
|
if (obj[unreactiveProperties]?.has(prop) || typeof prop === 'symbol')
|
|
340
364
|
return Reflect.get(obj, prop, receiver);
|
|
341
|
-
const absent = !(prop in obj);
|
|
342
365
|
// Depend if...
|
|
343
|
-
if (!options.instanceMembers || Object.hasOwn(receiver, prop) ||
|
|
366
|
+
if (!options.instanceMembers || Object.hasOwn(receiver, prop) || !Reflect.has(receiver, prop))
|
|
344
367
|
dependant(obj, prop);
|
|
345
368
|
const value = Reflect.get(obj, prop, receiver);
|
|
346
369
|
if (typeof value === 'object' && value !== null) {
|
|
@@ -367,13 +390,12 @@ const reactiveHandlers = {
|
|
|
367
390
|
obj[prop] = newValue;
|
|
368
391
|
return true;
|
|
369
392
|
}
|
|
370
|
-
const oldVal = obj
|
|
371
|
-
const oldPresent = prop in obj;
|
|
393
|
+
const oldVal = Reflect.has(receiver, prop) ? Reflect.get(obj, prop, receiver) : absent;
|
|
372
394
|
track1(obj, prop, oldVal, newValue);
|
|
373
395
|
if (oldVal !== newValue) {
|
|
374
396
|
Reflect.set(obj, prop, newValue, receiver);
|
|
375
397
|
// try to find a "generic" way to express that
|
|
376
|
-
touched1(obj, { type:
|
|
398
|
+
touched1(obj, { type: oldVal !== absent ? 'set' : 'add', prop }, prop);
|
|
377
399
|
}
|
|
378
400
|
return true;
|
|
379
401
|
},
|
|
@@ -517,25 +539,7 @@ function effect(fn, ...args) {
|
|
|
517
539
|
}
|
|
518
540
|
// Mark the runEffect callback with the original function as its root
|
|
519
541
|
markWithRoot(runEffect, fn);
|
|
520
|
-
|
|
521
|
-
if (!batchedEffects) {
|
|
522
|
-
hasEffect(runEffect);
|
|
523
|
-
}
|
|
524
|
-
else {
|
|
525
|
-
const oldBatchedEffects = batchedEffects;
|
|
526
|
-
try {
|
|
527
|
-
// Simulate a hasEffect who batches, but do not execute the batch, give it back to the parent batch,
|
|
528
|
-
// Only the immediate effect has to be executed, the sub-effects will be executed by the parent batch
|
|
529
|
-
batchedEffects = new Map([[fn, runEffect]]);
|
|
530
|
-
runEffect();
|
|
531
|
-
batchedEffects.delete(fn);
|
|
532
|
-
for (const [root, effect] of batchedEffects)
|
|
533
|
-
oldBatchedEffects.set(root, effect);
|
|
534
|
-
}
|
|
535
|
-
finally {
|
|
536
|
-
batchedEffects = oldBatchedEffects;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
542
|
+
atomicEffect(runEffect, 'immediate');
|
|
539
543
|
const mainCleanup = () => {
|
|
540
544
|
if (effectStopped)
|
|
541
545
|
return;
|
|
@@ -556,7 +560,6 @@ function effect(fn, ...args) {
|
|
|
556
560
|
fr.register(callIfCollected, mainCleanup, callIfCollected);
|
|
557
561
|
return callIfCollected;
|
|
558
562
|
}
|
|
559
|
-
// TODO: parentEffect = last non-undefined activeEffect
|
|
560
563
|
// Register this effect to be cleaned up with the parent effect
|
|
561
564
|
let children = effectChildren.get(parentEffect);
|
|
562
565
|
if (!children) {
|
|
@@ -786,28 +789,30 @@ function computedFunction(getter) {
|
|
|
786
789
|
dependant(computedCache, key);
|
|
787
790
|
if (computedCache.has(key))
|
|
788
791
|
return computedCache.get(key);
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
792
|
+
let stopped = false;
|
|
793
|
+
const stop = effect(markWithRoot((dep) => {
|
|
794
|
+
if (stopped)
|
|
795
|
+
return;
|
|
796
|
+
const oldCI = computedInvalidations;
|
|
797
|
+
if (computedCache.has(key)) {
|
|
798
|
+
// This should *not* be called in the cleanup chain, as its effects would be lost and cleaned-up
|
|
799
|
+
for (const cb of invalidations)
|
|
800
|
+
cb();
|
|
801
|
+
invalidations = [];
|
|
802
|
+
computedCache.delete(key);
|
|
803
|
+
touched1(computedCache, { type: 'invalidate', prop: key }, key);
|
|
804
|
+
stop();
|
|
805
|
+
stopped = true;
|
|
806
|
+
}
|
|
807
|
+
else
|
|
808
|
+
try {
|
|
809
|
+
computedInvalidations = invalidations;
|
|
810
|
+
computedCache.set(key, getter(dep));
|
|
800
811
|
}
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
}
|
|
806
|
-
finally {
|
|
807
|
-
computedInvalidations = oldCI;
|
|
808
|
-
}
|
|
809
|
-
}, getter));
|
|
810
|
-
});
|
|
812
|
+
finally {
|
|
813
|
+
computedInvalidations = oldCI;
|
|
814
|
+
}
|
|
815
|
+
}, getter));
|
|
811
816
|
return computedCache.get(key);
|
|
812
817
|
}
|
|
813
818
|
/**
|
|
@@ -1197,7 +1202,8 @@ class ReactiveArray extends Indexable(ReactiveBaseArray, {
|
|
|
1197
1202
|
dependant(this);
|
|
1198
1203
|
this[native$2].forEach(callbackfn, thisArg);
|
|
1199
1204
|
}
|
|
1200
|
-
// TODO: re-implement for fun dependencies? (eg - every only check the first ones until it find some)
|
|
1205
|
+
// TODO: re-implement for fun dependencies? (eg - every only check the first ones until it find some),
|
|
1206
|
+
// no need to make it dependant on indexes after the found one
|
|
1201
1207
|
every(callbackfn, thisArg) {
|
|
1202
1208
|
dependant(this);
|
|
1203
1209
|
return this[native$2].every(callbackfn, thisArg);
|
|
@@ -1209,7 +1215,6 @@ class ReactiveArray extends Indexable(ReactiveBaseArray, {
|
|
|
1209
1215
|
}
|
|
1210
1216
|
|
|
1211
1217
|
const native$1 = Symbol('native');
|
|
1212
|
-
// TODO: [prototypeForwarding]
|
|
1213
1218
|
class ReactiveWeakMap {
|
|
1214
1219
|
constructor(original) {
|
|
1215
1220
|
Object.defineProperties(this, {
|
|
@@ -1332,7 +1337,6 @@ class ReactiveMap {
|
|
|
1332
1337
|
}
|
|
1333
1338
|
|
|
1334
1339
|
const native = Symbol('native');
|
|
1335
|
-
// TODO: [prototypeForwarding]
|
|
1336
1340
|
class ReactiveWeakSet {
|
|
1337
1341
|
constructor(original) {
|
|
1338
1342
|
Object.defineProperties(this, {
|
|
@@ -1451,5 +1455,5 @@ registerNativeReactivity(WeakSet, ReactiveWeakSet);
|
|
|
1451
1455
|
registerNativeReactivity(Set, ReactiveSet);
|
|
1452
1456
|
registerNativeReactivity(Array, ReactiveArray);
|
|
1453
1457
|
|
|
1454
|
-
export { ReactiveBase, ReactiveError, computed, effect, getState, immutables, invalidateComputed, isNonReactive, isReactive, profileInfo, reactive, options as reactiveOptions, unreactive, untracked, unwrap, watch };
|
|
1458
|
+
export { ReactiveBase, ReactiveError, atomic, computed, effect, getState, immutables, invalidateComputed, isNonReactive, isReactive, profileInfo, reactive, options as reactiveOptions, unreactive, untracked, unwrap, watch };
|
|
1455
1459
|
//# sourceMappingURL=reactive.esm.js.map
|