Skip to content

Commit

Permalink
feat: update alien-signals to 1.1.0-alpha.2
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Jan 20, 2025
1 parent 4f38bd6 commit 677dfa9
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 88 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@preact/signals": "^2.0.0",
"@reactively/core": "^0.0.8",
"@vue/reactivity": "^3.5.13",
"alien-signals": "1.0.0",
"alien-signals": "1.1.0-alpha.2",
"compostate": "0.6.0-alpha.1",
"kairo": "0.6.0-rc.0",
"mobx": "^6.13.5",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

132 changes: 50 additions & 82 deletions src/frameworks/tc39-proposal-signals-alien-polyfill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ export namespace Signal {
const WATCHER_PLACEHOLDER = Symbol('watcher') as any;

const {
endTracking,
link,
propagate,
checkDirty,
endTracking,
startTracking,
processComputedUpdate,
processEffectNotifications,
} = alien.createReactiveSystem({
} = alien.pullmodel.createReactiveSystem({
updateComputed(computed: Computed) {
return computed.update();
},
Expand All @@ -22,8 +23,22 @@ export namespace Signal {
}
return false;
},
shouldCheckDirty(computed: Computed) {
if (computed.globalVersion !== globalVersion) {
computed.globalVersion = globalVersion;
return true;
}
return false;
},
onWatched(dep: AnySignal) {
dep.options?.[subtle.watched]?.call(dep);
},
onUnwatched(dep: AnySignal) {
dep.options?.[subtle.unwatched]?.call(dep);
},
});

let globalVersion = 0;
let activeSub: alien.Subscriber | undefined;

export function untrack<T>(fn: () => T) {
Expand All @@ -37,13 +52,13 @@ export namespace Signal {
}

export class State<T = any> implements alien.Dependency {
version = 0;
subs: alien.Link | undefined = undefined;
subsTail: alien.Link | undefined = undefined;
watchCount = 0;

constructor(
private currentValue: T,
private options?: Options<T>,
public options?: Options<T>,
) {
if (options?.equals !== undefined) {
this.equals = options.equals;
Expand All @@ -54,29 +69,12 @@ export namespace Signal {
return Object.is(t, t2);
}

onWatched() {
if (this.watchCount++ === 0) {
this.options?.[subtle.watched]?.call(this);
}
}

onUnwatched() {
if (--this.watchCount === 0) {
this.options?.[subtle.unwatched]?.call(this);
}
}

get() {
if (activeSub === WATCHER_PLACEHOLDER) {
throw new Error('Cannot read from state inside watcher');
}
if (activeSub !== undefined) {
if (link(this, activeSub)) {
const newSub = this.subsTail!.sub;
if (newSub instanceof Computed && newSub.watchCount) {
this.onWatched();
}
}
link(this, activeSub);
}
return this.currentValue;
}
Expand All @@ -86,6 +84,8 @@ export namespace Signal {
throw new Error('Cannot write to state inside watcher');
}
if (!this.equals(this.currentValue, value)) {
globalVersion++;
this.version++;
this.currentValue = value;
const subs = this.subs;
if (subs !== undefined) {
Expand All @@ -96,19 +96,21 @@ export namespace Signal {
}
}

const ErrorFlag = 1 << 8;

export class Computed<T = any> implements alien.Dependency, alien.Subscriber {
subs: alien.Link | undefined = undefined;
subsTail: alien.Link | undefined = undefined;
deps: alien.Link | undefined = undefined;
depsTail: alien.Link | undefined = undefined;
flags = alien.SubscriberFlags.Computed | alien.SubscriberFlags.Dirty;
isError = true;
watchCount = 0;
flags = alien.SubscriberFlags.Computed | alien.SubscriberFlags.Dirty | ErrorFlag;
currentValue: T | undefined = undefined;
version = 0;
globalVersion = globalVersion;

constructor(
private getter: () => T,
private options?: Options<T>,
public options?: Options<T>,
) {
if (options?.equals !== undefined) {
this.equals = options.equals;
Expand All @@ -119,26 +121,6 @@ export namespace Signal {
return Object.is(t, t2);
}

onWatched() {
if (this.watchCount++ === 0) {
this.options?.[subtle.watched]?.call(this);
for (let link = this.deps; link !== undefined; link = link.nextDep) {
const dep = link.dep as AnySignal;
dep.onWatched();
}
}
}

onUnwatched() {
if (--this.watchCount === 0) {
this.options?.[subtle.unwatched]?.call(this);
for (let link = this.deps; link !== undefined; link = link.nextDep) {
const dep = link.dep as AnySignal;
dep.onUnwatched();
}
}
}

get() {
if (activeSub === WATCHER_PLACEHOLDER) {
throw new Error('Cannot read from computed inside watcher');
Expand All @@ -147,16 +129,23 @@ export namespace Signal {
if (flags & alien.SubscriberFlags.Tracking) {
throw new Error('Cycles detected');
}
if (flags & (alien.SubscriberFlags.Dirty | alien.SubscriberFlags.PendingComputed)) {
if (flags & alien.SubscriberFlags.Dirty) {
processComputedUpdate(this, flags);
} else if (this.subs === undefined) {
if (this.globalVersion !== globalVersion) {
this.globalVersion = globalVersion;
const deps = this.deps;
if (deps !== undefined && checkDirty(deps)) {
this.update();
}
}
} else if (flags & alien.SubscriberFlags.PendingComputed) {
processComputedUpdate(this, flags);
}
if (activeSub !== undefined) {
const newSub = link(this, activeSub)?.sub;
if (newSub instanceof Computed && newSub.watchCount) {
this.onWatched();
}
link(this, activeSub);
}
if (this.isError) {
if (this.flags & ErrorFlag) {
throw this.currentValue;
}
return this.currentValue!;
Expand All @@ -169,30 +158,22 @@ export namespace Signal {
const oldValue = this.currentValue;
try {
const newValue = this.getter();
if (this.isError || !this.equals(oldValue!, newValue)) {
this.isError = false;
if (this.flags & ErrorFlag || !this.equals(oldValue!, newValue)) {
this.version++;
this.flags &= ~ErrorFlag;
this.currentValue = newValue;
return true;
}
return false;
} catch (err) {
if (!this.isError || !this.equals(oldValue!, err as any)) {
this.isError = true;
if (!(this.flags & ErrorFlag) || !this.equals(oldValue!, err as any)) {
this.version++;
this.flags |= ErrorFlag;
this.currentValue = err as any;
return true;
}
return false;
} finally {
if (this.watchCount) {
for (
let link = this.depsTail !== undefined ? this.depsTail.nextDep : this.deps;
link !== undefined;
link = link.nextDep
) {
const dep = link.dep as AnySignal;
dep.onUnwatched();
}
}
activeSub = prevSub;
endTracking(this);
}
Expand All @@ -206,9 +187,8 @@ export namespace Signal {
deps: alien.Link | undefined = undefined;
depsTail: alien.Link | undefined = undefined;
flags = alien.SubscriberFlags.Effect;
watchList = new Set<AnySignal>();

constructor(private fn: () => void) {}
constructor(private fn: () => void) { }

run() {
const prevSub = activeSub;
Expand All @@ -222,27 +202,15 @@ export namespace Signal {

watch(...signals: AnySignal[]): void {
for (const signal of signals) {
if (this.watchList.has(signal)) {
continue;
}
this.watchList.add(signal);
link(signal, this);
signal.onWatched();
}
}

unwatch(...signals: AnySignal[]): void {
for (const signal of signals) {
if (!this.watchList.has(signal)) {
continue;
}
this.watchList.delete(signal);
signal.onUnwatched();
}
startTracking(this);
for (let _link = this.deps; _link !== undefined; _link = _link.nextDep) {
const dep = _link.dep as AnySignal;
if (this.watchList.has(dep)) {
if (!signals.includes(dep)) {
link(dep, this);
}
}
Expand All @@ -259,7 +227,7 @@ export namespace Signal {
}

export function hasSinks(signal: AnySignal) {
return signal.watchCount > 0;
return signal.subs !== undefined;
}

export function introspectSinks(signal: AnySignal) {
Expand Down

0 comments on commit 677dfa9

Please sign in to comment.