feature: vor und nachteile

This commit is contained in:
Hikyu
2026-05-31 13:54:31 +02:00
parent 552a947a1c
commit e3dad17446
23270 changed files with 3024794 additions and 200 deletions
+19
View File
@@ -0,0 +1,19 @@
import { DirtyLevels, IComputed, Link } from './system.js';
export interface ISignal<T = any> {
get(): T;
}
export declare function computed<T>(getter: (cachedValue?: T) => T): ISignal<T>;
export declare class Computed<T = any> implements IComputed {
getter: (cachedValue?: T) => T;
cachedValue: T | undefined;
subs: Link | undefined;
subsTail: Link | undefined;
deps: Link | undefined;
depsTail: Link | undefined;
trackId: number;
dirtyLevel: DirtyLevels;
canPropagate: boolean;
constructor(getter: (cachedValue?: T) => T);
get(): T;
update(): void;
}
+60
View File
@@ -0,0 +1,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Computed = void 0;
exports.computed = computed;
const system_js_1 = require("./system.js");
function computed(getter) {
return new Computed(getter);
}
class Computed {
constructor(getter) {
this.getter = getter;
this.cachedValue = undefined;
// Dependency
this.subs = undefined;
this.subsTail = undefined;
// Subscriber
this.deps = undefined;
this.depsTail = undefined;
this.trackId = 0;
this.dirtyLevel = 3 /* DirtyLevels.Dirty */;
this.canPropagate = false;
}
get() {
let dirtyLevel = this.dirtyLevel;
if (dirtyLevel === 2 /* DirtyLevels.MaybeDirty */) {
system_js_1.Subscriber.resolveMaybeDirty(this);
dirtyLevel = this.dirtyLevel;
}
if (dirtyLevel >= 3 /* DirtyLevels.Dirty */) {
this.update();
}
const activeTrackId = system_js_1.System.activeTrackId;
if (activeTrackId !== 0) {
const subsTail = this.subsTail;
if (subsTail === undefined || subsTail.trackId !== activeTrackId) {
system_js_1.Dependency.link(this, system_js_1.System.activeSub);
}
}
return this.cachedValue;
}
update() {
const prevSub = system_js_1.Subscriber.startTrack(this);
const oldValue = this.cachedValue;
let newValue;
try {
newValue = this.getter(oldValue);
}
finally {
system_js_1.Subscriber.endTrack(this, prevSub);
}
if (oldValue !== newValue) {
this.cachedValue = newValue;
const subs = this.subs;
if (subs !== undefined) {
system_js_1.Dependency.propagate(subs);
}
}
}
}
exports.Computed = Computed;
+17
View File
@@ -0,0 +1,17 @@
import { DirtyLevels, IEffect, Link } from './system.js';
export declare function effect(fn: () => void): Effect<void>;
export declare class Effect<T = any> implements IEffect {
fn: () => T;
nextNotify: IEffect | undefined;
subs: Link | undefined;
subsTail: Link | undefined;
deps: Link | undefined;
depsTail: Link | undefined;
trackId: number;
dirtyLevel: DirtyLevels;
canPropagate: boolean;
constructor(fn: () => T);
notify(): void;
run(): T;
stop(): void;
}
+78
View File
@@ -0,0 +1,78 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Effect = void 0;
exports.effect = effect;
const effectScope_js_1 = require("./effectScope.js");
const system_js_1 = require("./system.js");
function effect(fn) {
const e = new Effect(fn);
e.run();
return e;
}
class Effect {
constructor(fn) {
this.fn = fn;
this.nextNotify = undefined;
// Dependency
this.subs = undefined;
this.subsTail = undefined;
// Subscriber
this.deps = undefined;
this.depsTail = undefined;
this.trackId = 0;
this.dirtyLevel = 3 /* DirtyLevels.Dirty */;
this.canPropagate = false;
const activeTrackId = system_js_1.System.activeTrackId;
if (activeTrackId !== 0) {
system_js_1.Dependency.link(this, system_js_1.System.activeSub);
return;
}
if (effectScope_js_1.activeEffectScope !== undefined) {
const subsTail = this.subsTail;
if (subsTail === undefined || subsTail.trackId !== effectScope_js_1.activeEffectScope.trackId) {
system_js_1.Dependency.link(this, effectScope_js_1.activeEffectScope);
}
}
}
notify() {
let dirtyLevel = this.dirtyLevel;
if (dirtyLevel > 0 /* DirtyLevels.None */) {
if (dirtyLevel === 2 /* DirtyLevels.MaybeDirty */) {
system_js_1.Subscriber.resolveMaybeDirty(this);
dirtyLevel = this.dirtyLevel;
}
if (dirtyLevel === 3 /* DirtyLevels.Dirty */) {
this.run();
}
else {
this.dirtyLevel = 0 /* DirtyLevels.None */;
let link = this.deps;
while (link !== undefined) {
const dep = link.dep;
if ('notify' in dep) {
dep.notify();
}
link = link.nextDep;
}
}
}
}
run() {
const prevSub = system_js_1.Subscriber.startTrack(this);
try {
return this.fn();
}
finally {
system_js_1.Subscriber.endTrack(this, prevSub);
}
}
stop() {
if (this.deps !== undefined) {
system_js_1.Subscriber.clearTrack(this.deps);
this.deps = undefined;
this.depsTail = undefined;
}
this.dirtyLevel = 3 /* DirtyLevels.Dirty */;
}
}
exports.Effect = Effect;
+13
View File
@@ -0,0 +1,13 @@
import { DirtyLevels, Link, Subscriber } from './system.js';
export declare let activeEffectScope: EffectScope | undefined;
export declare function effectScope(): EffectScope;
export declare class EffectScope implements Subscriber {
deps: Link | undefined;
depsTail: Link | undefined;
trackId: number;
dirtyLevel: DirtyLevels;
canPropagate: boolean;
notify(): void;
run<T>(fn: () => T): T;
stop(): void;
}
+53
View File
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EffectScope = exports.activeEffectScope = void 0;
exports.effectScope = effectScope;
const system_js_1 = require("./system.js");
exports.activeEffectScope = undefined;
function effectScope() {
return new EffectScope();
}
class EffectScope {
constructor() {
// Subscriber
this.deps = undefined;
this.depsTail = undefined;
this.trackId = -(++system_js_1.System.lastTrackId);
this.dirtyLevel = 0 /* DirtyLevels.None */;
this.canPropagate = false;
}
notify() {
if (this.dirtyLevel !== 0 /* DirtyLevels.None */) {
this.dirtyLevel = 0 /* DirtyLevels.None */;
let link = this.deps;
while (link !== undefined) {
const dep = link.dep;
if ('notify' in dep) {
dep.notify();
}
link = link.nextDep;
}
}
}
run(fn) {
const prevSub = exports.activeEffectScope;
exports.activeEffectScope = this;
this.trackId = Math.abs(this.trackId);
try {
return fn();
}
finally {
exports.activeEffectScope = prevSub;
this.trackId = -Math.abs(this.trackId);
}
}
stop() {
if (this.deps !== undefined) {
system_js_1.Subscriber.clearTrack(this.deps);
this.deps = undefined;
this.depsTail = undefined;
}
this.dirtyLevel = 0 /* DirtyLevels.None */;
}
}
exports.EffectScope = EffectScope;
+6
View File
@@ -0,0 +1,6 @@
export * from './computed.js';
export * from './effect.js';
export * from './effectScope.js';
export * from './signal.js';
export * from './system.js';
export * as Unstable from './unstable/index.js';
+23
View File
@@ -0,0 +1,23 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Unstable = void 0;
__exportStar(require("./computed.js"), exports);
__exportStar(require("./effect.js"), exports);
__exportStar(require("./effectScope.js"), exports);
__exportStar(require("./signal.js"), exports);
__exportStar(require("./system.js"), exports);
exports.Unstable = require("./unstable/index.js");
+15
View File
@@ -0,0 +1,15 @@
import { ISignal } from './computed.js';
import { Dependency, Link } from './system.js';
export interface IWritableSignal<T = any> extends ISignal<T> {
set(value: T): void;
}
export declare function signal<T>(): Signal<T | undefined>;
export declare function signal<T>(oldValue: T): Signal<T>;
export declare class Signal<T = any> implements Dependency {
currentValue: T;
subs: Link | undefined;
subsTail: Link | undefined;
constructor(currentValue: T);
get(): NonNullable<T>;
set(value: T): void;
}
+37
View File
@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Signal = void 0;
exports.signal = signal;
const system_js_1 = require("./system.js");
function signal(oldValue) {
return new Signal(oldValue);
}
class Signal {
constructor(currentValue) {
this.currentValue = currentValue;
// Dependency
this.subs = undefined;
this.subsTail = undefined;
}
get() {
const activeTrackId = system_js_1.System.activeTrackId;
if (activeTrackId !== 0) {
const subsTail = this.subsTail;
if (subsTail === undefined || subsTail.trackId !== activeTrackId) {
system_js_1.Dependency.link(this, system_js_1.System.activeSub);
}
}
return this.currentValue;
}
set(value) {
if (this.currentValue !== (this.currentValue = value)) {
const subs = this.subs;
if (subs !== undefined) {
(0, system_js_1.startBatch)();
system_js_1.Dependency.propagate(subs);
(0, system_js_1.endBatch)();
}
}
}
}
exports.Signal = Signal;
+69
View File
@@ -0,0 +1,69 @@
export interface IEffect extends Dependency, Subscriber {
nextNotify: IEffect | undefined;
notify(): void;
}
export interface IComputed extends Dependency, Subscriber {
update(): void;
}
export interface Dependency {
subs: Link | undefined;
subsTail: Link | undefined;
}
export interface Subscriber {
trackId: number;
canPropagate: boolean;
dirtyLevel: DirtyLevels;
deps: Link | undefined;
depsTail: Link | undefined;
}
export interface Link {
dep: Dependency | IComputed | IEffect;
sub: Subscriber | IComputed | IEffect;
trackId: number;
prevSub: Link | undefined;
nextSub: Link | undefined;
nextDep: Link | undefined;
}
export declare const enum DirtyLevels {
None = 0,
SideEffectsOnly = 1,
MaybeDirty = 2,
Dirty = 3
}
export declare namespace System {
let activeSub: Subscriber | undefined;
let activeTrackId: number;
let batchDepth: number;
let lastTrackId: number;
let queuedEffects: IEffect | undefined;
let queuedEffectsTail: IEffect | undefined;
}
export declare function startBatch(): void;
export declare function endBatch(): void;
export declare namespace Link {
function get(dep: Dependency, sub: Subscriber, nextDep: Link | undefined): Link;
function release(link: Link): void;
}
export declare namespace Dependency {
/**
* @deprecated Use `startTrack` instead.
*/
function linkSubscriber(dep: Dependency, sub: Subscriber): void;
function link(dep: Dependency, sub: Subscriber): void;
function propagate(subs: Link): void;
}
export declare namespace Subscriber {
function resolveMaybeDirty(sub: IComputed | IEffect, depth?: number): void;
function resolveMaybeDirtyNonRecursive(sub: IComputed | IEffect): void;
/**
* @deprecated Use `startTrack` instead.
*/
function startTrackDependencies(sub: Subscriber): Subscriber | undefined;
/**
* @deprecated Use `endTrack` instead.
*/
function endTrackDependencies(sub: Subscriber, prevSub: Subscriber | undefined): void;
function startTrack(sub: Subscriber): Subscriber | undefined;
function endTrack(sub: Subscriber, prevSub: Subscriber | undefined): void;
function clearTrack(link: Link): void;
}
+402
View File
@@ -0,0 +1,402 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Subscriber = exports.Dependency = exports.Link = exports.System = void 0;
exports.startBatch = startBatch;
exports.endBatch = endBatch;
var System;
(function (System) {
System.activeSub = undefined;
System.activeTrackId = 0;
System.batchDepth = 0;
System.lastTrackId = 0;
System.queuedEffects = undefined;
System.queuedEffectsTail = undefined;
})(System || (exports.System = System = {}));
function startBatch() {
System.batchDepth++;
}
function endBatch() {
System.batchDepth--;
if (System.batchDepth === 0) {
while (System.queuedEffects !== undefined) {
const effect = System.queuedEffects;
const queuedNext = System.queuedEffects.nextNotify;
if (queuedNext !== undefined) {
System.queuedEffects.nextNotify = undefined;
System.queuedEffects = queuedNext;
}
else {
System.queuedEffects = undefined;
System.queuedEffectsTail = undefined;
}
effect.notify();
}
}
}
var Link;
(function (Link) {
let pool = undefined;
function get(dep, sub, nextDep) {
if (pool !== undefined) {
const newLink = pool;
pool = newLink.nextDep;
newLink.nextDep = nextDep;
newLink.dep = dep;
newLink.sub = sub;
newLink.trackId = sub.trackId;
return newLink;
}
else {
return {
dep,
sub,
trackId: sub.trackId,
nextDep: nextDep,
prevSub: undefined,
nextSub: undefined,
};
}
}
Link.get = get;
function release(link) {
const dep = link.dep;
const nextSub = link.nextSub;
const prevSub = link.prevSub;
if (nextSub !== undefined) {
nextSub.prevSub = prevSub;
}
if (prevSub !== undefined) {
prevSub.nextSub = nextSub;
}
if (nextSub === undefined) {
dep.subsTail = prevSub;
}
if (prevSub === undefined) {
dep.subs = nextSub;
}
// @ts-expect-error
link.dep = undefined;
// @ts-expect-error
link.sub = undefined;
link.prevSub = undefined;
link.nextSub = undefined;
link.nextDep = pool;
pool = link;
}
Link.release = release;
})(Link || (exports.Link = Link = {}));
var Dependency;
(function (Dependency) {
const system = System;
/**
* @deprecated Use `startTrack` instead.
*/
function linkSubscriber(dep, sub) {
return link(dep, sub);
}
Dependency.linkSubscriber = linkSubscriber;
function link(dep, sub) {
const depsTail = sub.depsTail;
const old = depsTail !== undefined
? depsTail.nextDep
: sub.deps;
if (old === undefined || old.dep !== dep) {
const newLink = Link.get(dep, sub, old);
if (depsTail === undefined) {
sub.deps = newLink;
}
else {
depsTail.nextDep = newLink;
}
if (dep.subs === undefined) {
dep.subs = newLink;
}
else {
const oldTail = dep.subsTail;
newLink.prevSub = oldTail;
oldTail.nextSub = newLink;
}
sub.depsTail = newLink;
dep.subsTail = newLink;
}
else {
old.trackId = sub.trackId;
sub.depsTail = old;
}
}
Dependency.link = link;
function propagate(subs) {
let link = subs;
let dep = subs.dep;
let dirtyLevel = 3 /* DirtyLevels.Dirty */;
let remainingQuantity = 0;
do {
if (link !== undefined) {
const sub = link.sub;
const subTrackId = sub.trackId;
if (subTrackId > 0) {
if (subTrackId === link.trackId) {
const subDirtyLevel = sub.dirtyLevel;
if (subDirtyLevel < dirtyLevel) {
sub.dirtyLevel = dirtyLevel;
if (subDirtyLevel === 0 /* DirtyLevels.None */) {
sub.canPropagate = true;
if ('subs' in sub && sub.subs !== undefined) {
sub.depsTail.nextDep = link;
dep = sub;
link = sub.subs;
if ('notify' in sub) {
dirtyLevel = 1 /* DirtyLevels.SideEffectsOnly */;
}
else {
dirtyLevel = 2 /* DirtyLevels.MaybeDirty */;
}
remainingQuantity++;
continue;
}
}
}
}
}
else if (subTrackId === -link.trackId) {
const subDirtyLevel = sub.dirtyLevel;
const notDirty = subDirtyLevel === 0 /* DirtyLevels.None */;
if (subDirtyLevel < dirtyLevel) {
sub.dirtyLevel = dirtyLevel;
}
if (notDirty || sub.canPropagate) {
if (!notDirty) {
sub.canPropagate = false;
}
if ('subs' in sub && sub.subs !== undefined) {
sub.depsTail.nextDep = link;
dep = sub;
link = sub.subs;
if ('notify' in sub) {
dirtyLevel = 1 /* DirtyLevels.SideEffectsOnly */;
}
else {
dirtyLevel = 2 /* DirtyLevels.MaybeDirty */;
}
remainingQuantity++;
continue;
}
else if ('notify' in sub) {
const queuedEffectsTail = system.queuedEffectsTail;
if (queuedEffectsTail !== undefined) {
queuedEffectsTail.nextNotify = sub;
}
else {
system.queuedEffects = sub;
}
system.queuedEffectsTail = sub;
}
}
}
link = link.nextSub;
continue;
}
if (remainingQuantity !== 0) {
const depsTail = dep.depsTail;
const prevLink = depsTail.nextDep;
const prevSub = prevLink.sub;
depsTail.nextDep = undefined;
dep = prevLink.dep;
link = prevLink.nextSub;
remainingQuantity--;
if (remainingQuantity === 0) {
dirtyLevel = 3 /* DirtyLevels.Dirty */;
}
else if ('notify' in dep) {
dirtyLevel = 1 /* DirtyLevels.SideEffectsOnly */;
}
else {
dirtyLevel = 2 /* DirtyLevels.MaybeDirty */;
}
if ('notify' in prevSub) {
const queuedEffectsTail = system.queuedEffectsTail;
if (queuedEffectsTail !== undefined) {
queuedEffectsTail.nextNotify = prevSub;
}
else {
system.queuedEffects = prevSub;
}
system.queuedEffectsTail = prevSub;
}
continue;
}
break;
} while (true);
}
Dependency.propagate = propagate;
})(Dependency || (exports.Dependency = Dependency = {}));
var Subscriber;
(function (Subscriber) {
const system = System;
function resolveMaybeDirty(sub, depth = 0) {
let link = sub.deps;
while (link !== undefined) {
const dep = link.dep;
if ('update' in dep) {
let dirtyLevel = dep.dirtyLevel;
if (dirtyLevel === 2 /* DirtyLevels.MaybeDirty */) {
if (depth >= 4) {
resolveMaybeDirtyNonRecursive(dep);
}
else {
resolveMaybeDirty(dep, depth + 1);
}
dirtyLevel = dep.dirtyLevel;
}
if (dirtyLevel === 3 /* DirtyLevels.Dirty */) {
dep.update();
if (sub.dirtyLevel === 3 /* DirtyLevels.Dirty */) {
break;
}
}
}
link = link.nextDep;
}
if (sub.dirtyLevel === 2 /* DirtyLevels.MaybeDirty */) {
sub.dirtyLevel = 0 /* DirtyLevels.None */;
}
}
Subscriber.resolveMaybeDirty = resolveMaybeDirty;
function resolveMaybeDirtyNonRecursive(sub) {
let link = sub.deps;
let remaining = 0;
do {
if (link !== undefined) {
const dep = link.dep;
if ('update' in dep) {
const depDirtyLevel = dep.dirtyLevel;
if (depDirtyLevel === 2 /* DirtyLevels.MaybeDirty */) {
dep.subs.prevSub = link;
sub = dep;
link = dep.deps;
remaining++;
continue;
}
else if (depDirtyLevel === 3 /* DirtyLevels.Dirty */) {
dep.update();
if (sub.dirtyLevel === 3 /* DirtyLevels.Dirty */) {
if (remaining !== 0) {
const subSubs = sub.subs;
const prevLink = subSubs.prevSub;
sub.update();
subSubs.prevSub = undefined;
sub = prevLink.sub;
link = prevLink.nextDep;
remaining--;
continue;
}
break;
}
}
}
link = link.nextDep;
continue;
}
const dirtyLevel = sub.dirtyLevel;
if (dirtyLevel === 2 /* DirtyLevels.MaybeDirty */) {
sub.dirtyLevel = 0 /* DirtyLevels.None */;
if (remaining !== 0) {
const subSubs = sub.subs;
const prevLink = subSubs.prevSub;
subSubs.prevSub = undefined;
sub = prevLink.sub;
link = prevLink.nextDep;
remaining--;
continue;
}
}
else if (remaining !== 0) {
if (dirtyLevel === 3 /* DirtyLevels.Dirty */) {
sub.update();
}
const subSubs = sub.subs;
const prevLink = subSubs.prevSub;
subSubs.prevSub = undefined;
sub = prevLink.sub;
link = prevLink.nextDep;
remaining--;
continue;
}
break;
} while (true);
}
Subscriber.resolveMaybeDirtyNonRecursive = resolveMaybeDirtyNonRecursive;
/**
* @deprecated Use `startTrack` instead.
*/
function startTrackDependencies(sub) {
return startTrack(sub);
}
Subscriber.startTrackDependencies = startTrackDependencies;
/**
* @deprecated Use `endTrack` instead.
*/
function endTrackDependencies(sub, prevSub) {
return endTrack(sub, prevSub);
}
Subscriber.endTrackDependencies = endTrackDependencies;
function startTrack(sub) {
const newTrackId = system.lastTrackId + 1;
const prevSub = system.activeSub;
system.activeSub = sub;
system.activeTrackId = newTrackId;
system.lastTrackId = newTrackId;
sub.depsTail = undefined;
sub.trackId = newTrackId;
sub.dirtyLevel = 0 /* DirtyLevels.None */;
return prevSub;
}
Subscriber.startTrack = startTrack;
function endTrack(sub, prevSub) {
if (prevSub !== undefined) {
system.activeSub = prevSub;
system.activeTrackId = prevSub.trackId;
}
else {
system.activeSub = undefined;
system.activeTrackId = 0;
}
const depsTail = sub.depsTail;
if (depsTail !== undefined) {
if (depsTail.nextDep !== undefined) {
clearTrack(depsTail.nextDep);
depsTail.nextDep = undefined;
}
}
else if (sub.deps !== undefined) {
clearTrack(sub.deps);
sub.deps = undefined;
}
sub.trackId = -sub.trackId;
}
Subscriber.endTrack = endTrack;
function clearTrack(link) {
do {
const dep = link.dep;
const nextDep = link.nextDep;
Link.release(link);
if (dep.subs === undefined && 'deps' in dep) {
if ('notify' in dep) {
dep.dirtyLevel = 0 /* DirtyLevels.None */;
}
else {
dep.dirtyLevel = 3 /* DirtyLevels.Dirty */;
}
if (dep.deps !== undefined) {
link = dep.deps;
dep.depsTail.nextDep = nextDep;
dep.deps = undefined;
dep.depsTail = undefined;
continue;
}
}
link = nextDep;
} while (link !== undefined);
}
Subscriber.clearTrack = clearTrack;
})(Subscriber || (exports.Subscriber = Subscriber = {}));
@@ -0,0 +1,2 @@
import { ISignal } from '../index.js';
export declare function computedArray<I, O>(arr: ISignal<I[]>, getGetter: (item: ISignal<I>, index: number) => () => O): readonly Readonly<O>[];
+43
View File
@@ -0,0 +1,43 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computedArray = computedArray;
const index_js_1 = require("../index.js");
function computedArray(arr, getGetter) {
const length = (0, index_js_1.computed)(() => arr.get().length);
const keys = (0, index_js_1.computed)(() => {
const keys = [];
for (let i = 0; i < length.get(); i++) {
keys.push(String(i));
}
return keys;
});
const items = (0, index_js_1.computed)((array) => {
array ??= [];
while (array.length < length.get()) {
const index = array.length;
const item = (0, index_js_1.computed)(() => arr.get()[index]);
array.push((0, index_js_1.computed)(getGetter(item, index)));
}
if (array.length > length.get()) {
array.length = length.get();
}
return array;
});
return new Proxy({}, {
get(_, p, receiver) {
if (p === 'length') {
return length.get();
}
if (typeof p === 'string' && !isNaN(Number(p))) {
return items.get()[Number(p)]?.get();
}
return Reflect.get(items.get(), p, receiver);
},
has(_, p) {
return Reflect.has(items.get(), p);
},
ownKeys() {
return keys.get();
},
});
}
@@ -0,0 +1,2 @@
import { ISignal } from '../index.js';
export declare function computedSet<T>(source: ISignal<Set<T>>): ISignal<Set<T>>;
+13
View File
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computedSet = computedSet;
const index_js_1 = require("../index.js");
function computedSet(source) {
return (0, index_js_1.computed)((oldValue) => {
const newValue = source.get();
if (oldValue?.size === newValue.size && [...oldValue].every(c => newValue.has(c))) {
return oldValue;
}
return newValue;
});
}
@@ -0,0 +1,6 @@
import { Computed, ISignal } from '../index.js';
export declare function equalityComputed<T>(getter: () => T): ISignal<T>;
export declare class EqualityComputed<T = any> extends Computed<T> {
constructor(getter: () => T);
equals(a: any, b: any): boolean;
}
@@ -0,0 +1,58 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EqualityComputed = void 0;
exports.equalityComputed = equalityComputed;
const index_js_1 = require("../index.js");
function equalityComputed(getter) {
return new EqualityComputed(getter);
}
class EqualityComputed extends index_js_1.Computed {
constructor(getter) {
super(oldValue => {
const newValue = getter();
if (this.equals(oldValue, newValue)) {
return oldValue;
}
return newValue;
});
}
equals(a, b) {
if (a === b) {
return true;
}
if (a === null || b === null || typeof a !== typeof b) {
return false;
}
if (typeof a === 'object') {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (!this.equals(a[i], b[i])) {
return false;
}
}
return true;
}
if (!Array.isArray(a) && !Array.isArray(b)) {
for (const key in a) {
if (a.hasOwnProperty(key)) {
if (!b.hasOwnProperty(key) || !this.equals(a[key], b[key])) {
return false;
}
}
}
for (const key in b) {
if (b.hasOwnProperty(key) && !a.hasOwnProperty(key)) {
return false;
}
}
return true;
}
return false; // One is array and the other is not
}
return false;
}
}
exports.EqualityComputed = EqualityComputed;
+3
View File
@@ -0,0 +1,3 @@
export * from './computedArray.js';
export * from './computedSet.js';
export * from './equalityComputed.js';
+19
View File
@@ -0,0 +1,19 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./computedArray.js"), exports);
__exportStar(require("./computedSet.js"), exports);
__exportStar(require("./equalityComputed.js"), exports);