Initial commit

This commit is contained in:
yuding
2025-12-03 12:00:46 +08:00
commit 5763b764a3
5365 changed files with 1483113 additions and 0 deletions

21
node_modules/alien-signals/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024-present Johnson Chu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

198
node_modules/alien-signals/README.md generated vendored Normal file
View File

@@ -0,0 +1,198 @@
<p align="center">
<img src="assets/logo.png" width="250"><br>
<p>
<p align="center">
<a href="https://npmjs.com/package/alien-signals"><img src="https://badgen.net/npm/v/alien-signals" alt="npm package"></a>
</p>
<h3 align="center">
<p>[<a href="https://github.com/YanqingXu/alien-signals-in-lua">Alien Signals in Lua</a>]</p>
<p>[<a href="https://github.com/medz/alien-signals-dart">Alien Signals in Dart</a>]</p>
<p>[<a href="https://github.com/Rajaniraiyn/react-alien-signals">React Binding</a>]</p>
</h3>
# alien-signals
The goal of `alien-signals` is to create a ~~push-pull~~ [push-pull-push model](https://github.com/stackblitz/alien-signals/pull/19) based signal library with the lowest overhead.
We have set the following constraints in scheduling logic:
1. No dynamic object fields
2. No use of Array/Set/Map
3. No recursion calls
4. Class properties must be fewer than 10 (https://v8.dev/blog/fast-properties)
Experimental results have shown that with these constraints, it is possible to achieve excellent performance for a Signal library without using sophisticated scheduling strategies. The overall performance of `alien-signals` is approximately 400% that of Vue 3.4's reactivity system.
For more detailed performance comparisons, please visit: https://github.com/transitive-bullshit/js-reactivity-benchmark
## Motivation
To achieve high-performance code generation in https://github.com/vuejs/language-tools, I needed to write some on-demand computed logic using Signals, but I couldn't find a low-cost Signal library that satisfied me.
In the past, I accumulated some knowledge of reactivity systems in https://github.com/vuejs/core/pull/5912, so I attempted to develop `alien-signals` with the goal of creating a Signal library with minimal memory usage and excellent performance.
Since Vue 3.5 switched to a Pull reactivity system in https://github.com/vuejs/core/pull/10397, I continued to research the Push-Pull reactivity system here. It is worth mentioning that I was inspired by the doubly-linked concept, but `alien-signals` does not use a similar implementation.
## Adoptions
- Used in Vue language tools (https://github.com/vuejs/language-tools) for virtual code generation.
- The core reactivity system code was ported to Vue 3.6 and later. (https://github.com/vuejs/core/pull/12349)
## Usage
### Basic
```ts
import { signal, computed, effect } from 'alien-signals';
const count = signal(1);
const doubleCount = computed(() => count.get() * 2);
effect(() => {
console.log(`Count is: ${count.get()}`);
}); // Console: Count is: 1
console.log(doubleCount.get()); // 2
count.set(2); // Console: Count is: 2
console.log(doubleCount.get()); // 4
```
### Effect Scope
```ts
import { signal, effectScope } from 'alien-signals';
const count = signal(1);
const scope = effectScope();
scope.run(() => {
effect(() => {
console.log(`Count in scope: ${count.get()}`);
}); // Console: Count in scope: 1
count.set(2); // Console: Count in scope: 2
});
scope.stop();
count.set(3); // No console output
```
## About `propagate` and `checkDirty` functions
In order to eliminate recursive calls and improve performance, we record the last link node of the previous loop in `propagate` and `checkDirty` functions, and implement the rollback logic to return to this node.
This results in code that is difficult to understand, and you don't necessarily get the same performance improvements in other languages, so we record the original implementation without eliminating recursive calls here for reference.
#### `propagate`
```ts
export function propagate(link: Link, targetFlag: SubscriberFlags = SubscriberFlags.Dirty): void {
do {
const sub = link.sub;
const subFlags = sub.flags;
if (
(
!(subFlags & (SubscriberFlags.Tracking | SubscriberFlags.Recursed | SubscriberFlags.InnerEffectsPending | SubscriberFlags.ToCheckDirty | SubscriberFlags.Dirty))
&& (sub.flags = subFlags | targetFlag, true)
)
|| (
(subFlags & (SubscriberFlags.Tracking | SubscriberFlags.Recursed)) === SubscriberFlags.Recursed
&& (sub.flags = (subFlags & ~SubscriberFlags.Recursed) | targetFlag, true)
)
|| (
!(subFlags & (SubscriberFlags.InnerEffectsPending | SubscriberFlags.ToCheckDirty | SubscriberFlags.Dirty))
&& isValidLink(link, sub)
&& (
sub.flags = subFlags | SubscriberFlags.Recursed | targetFlag,
(sub as Dependency).subs !== undefined
)
)
) {
const subSubs = (sub as Dependency).subs;
if (subSubs !== undefined) {
propagate(
subSubs,
'notify' in sub
? SubscriberFlags.InnerEffectsPending
: SubscriberFlags.ToCheckDirty
);
} else if ('notify' in sub) {
if (queuedEffectsTail !== undefined) {
queuedEffectsTail.nextNotify = sub;
} else {
queuedEffects = sub;
}
queuedEffectsTail = sub;
}
} else if (
!(subFlags & (SubscriberFlags.Tracking | targetFlag))
|| (
!(subFlags & targetFlag)
&& (subFlags & (SubscriberFlags.InnerEffectsPending | SubscriberFlags.ToCheckDirty | SubscriberFlags.Dirty))
&& isValidLink(link, sub)
)
) {
sub.flags = subFlags | targetFlag;
}
link = link.nextSub!;
} while (link !== undefined);
if (targetFlag === SubscriberFlags.Dirty && !batchDepth) {
drainQueuedEffects();
}
}
```
#### `checkDirty`
```ts
export function checkDirty(link: Link): boolean {
do {
const dep = link.dep;
if ('update' in dep) {
const depFlags = dep.flags;
if (depFlags & SubscriberFlags.Dirty) {
if (dep.update()) {
const subs = dep.subs!;
if (subs.nextSub !== undefined) {
shallowPropagate(subs);
}
return true;
}
} else if (depFlags & SubscriberFlags.ToCheckDirty) {
if (checkDirty(dep.deps!)) {
if (dep.update()) {
const subs = dep.subs!;
if (subs.nextSub !== undefined) {
shallowPropagate(subs);
}
return true;
}
} else {
dep.flags = depFlags & ~SubscriberFlags.ToCheckDirty;
}
}
}
link = link.nextDep!;
} while (link !== undefined);
return false;
}
```
## Roadmap
| Version | Savings |
|---------|-----------------------------------------------------------------------------------------------|
| 0.3 | Satisfy all 4 constraints |
| 0.2 | Correctly schedule computed side effects |
| 0.1 | Correctly schedule inner effect callbacks |
| 0.0 | Add APIs: `signal()`, `computed()`, `effect()`, `effectScope()`, `startBatch()`, `endBatch()` |

24
node_modules/alien-signals/benchs/complex.mjs generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import { run, bench, boxplot } from 'mitata';
import { computed, effect, signal } from '../esm/index.mjs';
boxplot(() => {
bench('complex: $w * $h', function* (state) {
const w = state.get('w');
const h = state.get('h');
const src = signal({ w, h });
for (let i = 0; i < w; i++) {
let last = src;
for (let j = 0; j < h; j++) {
const prev = last;
last = computed(() => ({ [`${i}-${j}`]: prev.get() }));
}
effect(() => last.get());
}
yield () => src.set({ upstream: src.get() });
})
.args('h', [1, 10, 100])
.args('w', [1, 10, 100]);
});
run({ format: 'markdown' });

23
node_modules/alien-signals/benchs/memoryUsage.mjs generated vendored Normal file
View File

@@ -0,0 +1,23 @@
import { computed, effect, signal } from '../esm/index.mjs';
globalThis.gc();
const start = process.memoryUsage().heapUsed;
const w = 100;
const h = 100;
const src = signal(1);
for (let i = 0; i < w; i++) {
let last = src;
for (let j = 0; j < h; j++) {
const prev = last;
last = computed(() => prev.get() + 1);
}
effect(() => last.get());
}
src.set(src.get() + 1);
globalThis.gc();
const end = process.memoryUsage().heapUsed;
console.log(`Memory Usage: ${((end - start) / 1024).toFixed(2)} KB`);

23
node_modules/alien-signals/benchs/propagate.mjs generated vendored Normal file
View File

@@ -0,0 +1,23 @@
import { run, bench, boxplot } from 'mitata';
import { computed, effect, signal } from '../esm/index.mjs';
boxplot(() => {
bench('propagate: $w * $h', function* (state) {
const w = state.get('w');
const h = state.get('h');
const src = signal(1);
for (let i = 0; i < w; i++) {
let last = src;
for (let j = 0; j < h; j++) {
const prev = last;
last = computed(() => prev.get() + 1);
}
effect(() => last.get());
}
yield () => src.set(src.get() + 1);
})
.args('h', [1, 10, 100])
.args('w', [1, 10, 100]);
});
run({ format: 'markdown' });

19
node_modules/alien-signals/cjs/computed.d.ts generated vendored Normal file
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(): boolean;
}

17
node_modules/alien-signals/cjs/effect.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import { Dependency, DirtyLevels, IEffect, Link } from './system.js';
export declare function effect(fn: () => void): Effect<void>;
export declare class Effect<T = any> implements IEffect, Dependency {
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;
}

13
node_modules/alien-signals/cjs/effectScope.d.ts generated vendored Normal file
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;
}

895
node_modules/alien-signals/cjs/index.cjs generated vendored Normal file
View File

@@ -0,0 +1,895 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
Computed: () => Computed,
Effect: () => Effect,
EffectScope: () => EffectScope,
Signal: () => Signal,
SubscriberFlags: () => SubscriberFlags,
activeEffectScope: () => activeEffectScope,
activeScopeTrackId: () => activeScopeTrackId,
activeSub: () => activeSub,
activeTrackId: () => activeTrackId,
checkDirty: () => checkDirty,
computed: () => computed,
effect: () => effect,
effectScope: () => effectScope,
endBatch: () => endBatch,
endTrack: () => endTrack,
lastTrackId: () => lastTrackId,
link: () => link,
nextTrackId: () => nextTrackId,
propagate: () => propagate,
setActiveScope: () => setActiveScope,
setActiveSub: () => setActiveSub,
shallowPropagate: () => shallowPropagate,
signal: () => signal,
startBatch: () => startBatch,
startTrack: () => startTrack,
unstable: () => unstable,
untrack: () => untrack,
untrackScope: () => untrackScope
});
module.exports = __toCommonJS(src_exports);
// src/system.ts
var SubscriberFlags = /* @__PURE__ */ ((SubscriberFlags2) => {
SubscriberFlags2[SubscriberFlags2["None"] = 0] = "None";
SubscriberFlags2[SubscriberFlags2["Tracking"] = 1] = "Tracking";
SubscriberFlags2[SubscriberFlags2["Recursed"] = 2] = "Recursed";
SubscriberFlags2[SubscriberFlags2["InnerEffectsPending"] = 4] = "InnerEffectsPending";
SubscriberFlags2[SubscriberFlags2["ToCheckDirty"] = 8] = "ToCheckDirty";
SubscriberFlags2[SubscriberFlags2["Dirty"] = 16] = "Dirty";
return SubscriberFlags2;
})(SubscriberFlags || {});
var batchDepth = 0;
var queuedEffects;
var queuedEffectsTail;
var linkPool;
function startBatch() {
++batchDepth;
}
function endBatch() {
if (!--batchDepth) {
drainQueuedEffects();
}
}
function drainQueuedEffects() {
while (queuedEffects !== void 0) {
const effect2 = queuedEffects;
const queuedNext = effect2.nextNotify;
if (queuedNext !== void 0) {
effect2.nextNotify = void 0;
queuedEffects = queuedNext;
} else {
queuedEffects = void 0;
queuedEffectsTail = void 0;
}
effect2.notify();
}
}
function link(dep, sub) {
const currentDep = sub.depsTail;
const nextDep = currentDep !== void 0 ? currentDep.nextDep : sub.deps;
if (nextDep !== void 0 && nextDep.dep === dep) {
sub.depsTail = nextDep;
} else {
linkNewDep(dep, sub, nextDep, currentDep);
}
}
function linkNewDep(dep, sub, nextDep, depsTail) {
let newLink;
if (linkPool !== void 0) {
newLink = linkPool;
linkPool = newLink.nextDep;
newLink.nextDep = nextDep;
newLink.dep = dep;
newLink.sub = sub;
} else {
newLink = {
dep,
sub,
nextDep,
prevSub: void 0,
nextSub: void 0
};
}
if (depsTail === void 0) {
sub.deps = newLink;
} else {
depsTail.nextDep = newLink;
}
if (dep.subs === void 0) {
dep.subs = newLink;
} else {
const oldTail = dep.subsTail;
newLink.prevSub = oldTail;
oldTail.nextSub = newLink;
}
sub.depsTail = newLink;
dep.subsTail = newLink;
}
function propagate(link2) {
let targetFlag = 16 /* Dirty */;
let subs = link2;
let stack = 0;
top: do {
const sub = link2.sub;
const subFlags = sub.flags;
if (!(subFlags & (1 /* Tracking */ | 2 /* Recursed */ | 4 /* InnerEffectsPending */ | 8 /* ToCheckDirty */ | 16 /* Dirty */)) && (sub.flags = subFlags | targetFlag, true) || (subFlags & (1 /* Tracking */ | 2 /* Recursed */)) === 2 /* Recursed */ && (sub.flags = subFlags & ~2 /* Recursed */ | targetFlag, true) || !(subFlags & (4 /* InnerEffectsPending */ | 8 /* ToCheckDirty */ | 16 /* Dirty */)) && isValidLink(link2, sub) && (sub.flags = subFlags | 2 /* Recursed */ | targetFlag, sub.subs !== void 0)) {
const subSubs = sub.subs;
if (subSubs !== void 0) {
if (subSubs.nextSub !== void 0) {
subSubs.prevSub = subs;
link2 = subs = subSubs;
targetFlag = 8 /* ToCheckDirty */;
++stack;
} else {
link2 = subSubs;
targetFlag = "notify" in sub ? 4 /* InnerEffectsPending */ : 8 /* ToCheckDirty */;
}
continue;
}
if ("notify" in sub) {
if (queuedEffectsTail !== void 0) {
queuedEffectsTail.nextNotify = sub;
} else {
queuedEffects = sub;
}
queuedEffectsTail = sub;
}
} else if (!(subFlags & (1 /* Tracking */ | targetFlag)) || !(subFlags & targetFlag) && subFlags & (4 /* InnerEffectsPending */ | 8 /* ToCheckDirty */ | 16 /* Dirty */) && isValidLink(link2, sub)) {
sub.flags = subFlags | targetFlag;
}
if ((link2 = subs.nextSub) !== void 0) {
subs = link2;
targetFlag = stack ? 8 /* ToCheckDirty */ : 16 /* Dirty */;
continue;
}
while (stack) {
--stack;
const dep = subs.dep;
const depSubs = dep.subs;
subs = depSubs.prevSub;
depSubs.prevSub = void 0;
if ((link2 = subs.nextSub) !== void 0) {
subs = link2;
targetFlag = stack ? 8 /* ToCheckDirty */ : 16 /* Dirty */;
continue top;
}
}
break;
} while (true);
if (!batchDepth) {
drainQueuedEffects();
}
}
function shallowPropagate(link2) {
do {
const updateSub = link2.sub;
const updateSubFlags = updateSub.flags;
if ((updateSubFlags & (8 /* ToCheckDirty */ | 16 /* Dirty */)) === 8 /* ToCheckDirty */) {
updateSub.flags = updateSubFlags | 16 /* Dirty */;
}
link2 = link2.nextSub;
} while (link2 !== void 0);
}
function isValidLink(subLink, sub) {
const depsTail = sub.depsTail;
if (depsTail !== void 0) {
let link2 = sub.deps;
do {
if (link2 === subLink) {
return true;
}
if (link2 === depsTail) {
break;
}
link2 = link2.nextDep;
} while (link2 !== void 0);
}
return false;
}
function checkDirty(link2) {
let stack = 0;
let dirty;
top: do {
dirty = false;
const dep = link2.dep;
if ("update" in dep) {
const depFlags = dep.flags;
if (depFlags & 16 /* Dirty */) {
if (dep.update()) {
const subs = dep.subs;
if (subs.nextSub !== void 0) {
shallowPropagate(subs);
}
dirty = true;
}
} else if (depFlags & 8 /* ToCheckDirty */) {
const depSubs = dep.subs;
if (depSubs.nextSub !== void 0) {
depSubs.prevSub = link2;
}
link2 = dep.deps;
++stack;
continue;
}
}
if (!dirty && link2.nextDep !== void 0) {
link2 = link2.nextDep;
continue;
}
if (stack) {
let sub = link2.sub;
do {
--stack;
const subSubs = sub.subs;
if (dirty) {
if (sub.update()) {
if ((link2 = subSubs.prevSub) !== void 0) {
subSubs.prevSub = void 0;
shallowPropagate(sub.subs);
sub = link2.sub;
} else {
sub = subSubs.sub;
}
continue;
}
} else {
sub.flags &= ~8 /* ToCheckDirty */;
}
if ((link2 = subSubs.prevSub) !== void 0) {
subSubs.prevSub = void 0;
if (link2.nextDep !== void 0) {
link2 = link2.nextDep;
continue top;
}
sub = link2.sub;
} else {
if ((link2 = subSubs.nextDep) !== void 0) {
continue top;
}
sub = subSubs.sub;
}
dirty = false;
} while (stack);
}
return dirty;
} while (true);
}
function startTrack(sub) {
sub.depsTail = void 0;
sub.flags = 1 /* Tracking */;
}
function endTrack(sub) {
const depsTail = sub.depsTail;
if (depsTail !== void 0) {
const nextDep = depsTail.nextDep;
if (nextDep !== void 0) {
clearTrack(nextDep);
depsTail.nextDep = void 0;
}
} else if (sub.deps !== void 0) {
clearTrack(sub.deps);
sub.deps = void 0;
}
sub.flags &= ~1 /* Tracking */;
}
function clearTrack(link2) {
do {
const dep = link2.dep;
const nextDep = link2.nextDep;
const nextSub = link2.nextSub;
const prevSub = link2.prevSub;
if (nextSub !== void 0) {
nextSub.prevSub = prevSub;
link2.nextSub = void 0;
} else {
dep.subsTail = prevSub;
if ("lastTrackedId" in dep) {
dep.lastTrackedId = 0;
}
}
if (prevSub !== void 0) {
prevSub.nextSub = nextSub;
link2.prevSub = void 0;
} else {
dep.subs = nextSub;
}
link2.dep = void 0;
link2.sub = void 0;
link2.nextDep = linkPool;
linkPool = link2;
if (dep.subs === void 0 && "deps" in dep) {
if ("notify" in dep) {
dep.flags = 0 /* None */;
} else {
const depFlags = dep.flags;
if (!(depFlags & 16 /* Dirty */)) {
dep.flags = depFlags | 16 /* Dirty */;
}
}
const depDeps = dep.deps;
if (depDeps !== void 0) {
link2 = depDeps;
dep.depsTail.nextDep = nextDep;
dep.deps = void 0;
dep.depsTail = void 0;
continue;
}
}
link2 = nextDep;
} while (link2 !== void 0);
}
// src/effectScope.ts
var activeEffectScope = void 0;
var activeScopeTrackId = 0;
function untrackScope(fn) {
const prevSub = activeEffectScope;
const prevTrackId = activeScopeTrackId;
setActiveScope(void 0, 0);
try {
return fn();
} finally {
setActiveScope(prevSub, prevTrackId);
}
}
function setActiveScope(sub, trackId) {
activeEffectScope = sub;
activeScopeTrackId = trackId;
}
function effectScope() {
return new EffectScope();
}
var EffectScope = class {
constructor() {
// Subscriber
this.deps = void 0;
this.depsTail = void 0;
this.flags = 0 /* None */;
this.trackId = nextTrackId();
}
notify() {
const flags = this.flags;
if (flags & 4 /* InnerEffectsPending */) {
this.flags = flags & ~4 /* InnerEffectsPending */;
let link2 = this.deps;
do {
const dep = link2.dep;
if ("notify" in dep) {
dep.notify();
}
link2 = link2.nextDep;
} while (link2 !== void 0);
}
}
run(fn) {
const prevSub = activeEffectScope;
const prevTrackId = activeScopeTrackId;
setActiveScope(this, this.trackId);
try {
return fn();
} finally {
setActiveScope(prevSub, prevTrackId);
}
}
stop() {
startTrack(this);
endTrack(this);
}
};
// src/effect.ts
var activeSub;
var activeTrackId = 0;
var lastTrackId = 0;
function untrack(fn) {
const prevSub = activeSub;
const prevTrackId = activeTrackId;
setActiveSub(void 0, 0);
try {
return fn();
} finally {
setActiveSub(prevSub, prevTrackId);
}
}
function setActiveSub(sub, trackId) {
activeSub = sub;
activeTrackId = trackId;
}
function nextTrackId() {
return ++lastTrackId;
}
function effect(fn) {
const e = new Effect(fn);
e.run();
return e;
}
var Effect = class {
constructor(fn) {
this.fn = fn;
this.nextNotify = void 0;
// Dependency
this.subs = void 0;
this.subsTail = void 0;
// Subscriber
this.deps = void 0;
this.depsTail = void 0;
this.flags = 16 /* Dirty */;
if (activeTrackId) {
link(this, activeSub);
} else if (activeScopeTrackId) {
link(this, activeEffectScope);
}
}
notify() {
let flags = this.flags;
if (flags & 16 /* Dirty */) {
this.run();
return;
}
if (flags & 8 /* ToCheckDirty */) {
if (checkDirty(this.deps)) {
this.run();
return;
} else {
this.flags = flags &= ~8 /* ToCheckDirty */;
}
}
if (flags & 4 /* InnerEffectsPending */) {
this.flags = flags & ~4 /* InnerEffectsPending */;
let link2 = this.deps;
do {
const dep = link2.dep;
if ("notify" in dep) {
dep.notify();
}
link2 = link2.nextDep;
} while (link2 !== void 0);
}
}
run() {
const prevSub = activeSub;
const prevTrackId = activeTrackId;
setActiveSub(this, nextTrackId());
startTrack(this);
try {
return this.fn();
} finally {
setActiveSub(prevSub, prevTrackId);
endTrack(this);
}
}
stop() {
startTrack(this);
endTrack(this);
}
};
// src/computed.ts
function computed(getter) {
return new Computed(getter);
}
var Computed = class {
constructor(getter) {
this.getter = getter;
this.currentValue = void 0;
// Dependency
this.subs = void 0;
this.subsTail = void 0;
this.lastTrackedId = 0;
// Subscriber
this.deps = void 0;
this.depsTail = void 0;
this.flags = 16 /* Dirty */;
}
get() {
const flags = this.flags;
if (flags & 16 /* Dirty */) {
if (this.update()) {
const subs = this.subs;
if (subs !== void 0) {
shallowPropagate(subs);
}
}
} else if (flags & 8 /* ToCheckDirty */) {
if (checkDirty(this.deps)) {
if (this.update()) {
const subs = this.subs;
if (subs !== void 0) {
shallowPropagate(subs);
}
}
} else {
this.flags = flags & ~8 /* ToCheckDirty */;
}
}
if (activeTrackId) {
if (this.lastTrackedId !== activeTrackId) {
this.lastTrackedId = activeTrackId;
link(this, activeSub);
}
} else if (activeScopeTrackId) {
if (this.lastTrackedId !== activeScopeTrackId) {
this.lastTrackedId = activeScopeTrackId;
link(this, activeEffectScope);
}
}
return this.currentValue;
}
update() {
const prevSub = activeSub;
const prevTrackId = activeTrackId;
setActiveSub(this, nextTrackId());
startTrack(this);
try {
const oldValue = this.currentValue;
const newValue = this.getter(oldValue);
if (oldValue !== newValue) {
this.currentValue = newValue;
return true;
}
return false;
} finally {
setActiveSub(prevSub, prevTrackId);
endTrack(this);
}
}
};
// src/signal.ts
function signal(oldValue) {
return new Signal(oldValue);
}
var Signal = class {
constructor(currentValue) {
this.currentValue = currentValue;
// Dependency
this.subs = void 0;
this.subsTail = void 0;
this.lastTrackedId = 0;
}
get() {
if (activeTrackId && this.lastTrackedId !== activeTrackId) {
this.lastTrackedId = activeTrackId;
link(this, activeSub);
}
return this.currentValue;
}
set(value) {
if (this.currentValue !== value) {
this.currentValue = value;
const subs = this.subs;
if (subs !== void 0) {
propagate(subs);
}
}
}
};
// src/unstable/asyncSystem.ts
async function asyncCheckDirty(link2) {
let stack = 0;
let dirty;
let nextDep;
top: do {
dirty = false;
const dep = link2.dep;
if ("update" in dep) {
const depFlags = dep.flags;
if (depFlags & 16 /* Dirty */) {
if (await dep.update()) {
const subs = dep.subs;
if (subs.nextSub !== void 0) {
shallowPropagate(subs);
}
dirty = true;
}
} else if (depFlags & 8 /* ToCheckDirty */) {
const depSubs = dep.subs;
if (depSubs.nextSub !== void 0) {
depSubs.prevSub = link2;
}
link2 = dep.deps;
++stack;
continue;
}
}
if (dirty || (nextDep = link2.nextDep) === void 0) {
if (stack) {
let sub = link2.sub;
do {
--stack;
const subSubs = sub.subs;
let prevLink = subSubs.prevSub;
if (prevLink !== void 0) {
subSubs.prevSub = void 0;
if (dirty) {
if (await sub.update()) {
shallowPropagate(sub.subs);
sub = prevLink.sub;
continue;
}
} else {
sub.flags &= ~8 /* ToCheckDirty */;
}
} else {
if (dirty) {
if (await sub.update()) {
sub = subSubs.sub;
continue;
}
} else {
sub.flags &= ~8 /* ToCheckDirty */;
}
prevLink = subSubs;
}
link2 = prevLink.nextDep;
if (link2 !== void 0) {
continue top;
}
sub = prevLink.sub;
dirty = false;
} while (stack);
}
return dirty;
}
link2 = nextDep;
} while (true);
}
// src/unstable/asyncComputed.ts
function asyncComputed(getter) {
return new AsyncComputed(getter);
}
var AsyncComputed = class extends Computed {
async get() {
const flags = this.flags;
if (flags & 16 /* Dirty */) {
if (await this.update()) {
const subs = this.subs;
if (subs !== void 0) {
shallowPropagate(subs);
}
}
} else if (flags & 8 /* ToCheckDirty */) {
if (await asyncCheckDirty(this.deps)) {
if (await this.update()) {
const subs = this.subs;
if (subs !== void 0) {
shallowPropagate(subs);
}
}
} else {
this.flags = flags & ~8 /* ToCheckDirty */;
}
}
return this.currentValue;
}
// @ts-expect-error
async update() {
try {
startTrack(this);
const trackId = nextTrackId();
const oldValue = this.currentValue;
const generator = this.getter(oldValue);
let current = await generator.next();
while (!current.done) {
const dep = current.value;
if (dep.lastTrackedId !== trackId) {
dep.lastTrackedId = trackId;
link(dep, this);
}
current = await generator.next();
}
const newValue = await current.value;
if (oldValue !== newValue) {
this.currentValue = newValue;
return true;
}
return false;
} finally {
endTrack(this);
}
}
};
// src/unstable/asyncEffect.ts
function asyncEffect(fn) {
const e = new AsyncEffect(fn);
e.run();
return e;
}
var AsyncEffect = class extends Effect {
async notify() {
let flags = this.flags;
if (flags & 16 /* Dirty */) {
this.run();
return;
}
if (flags & 8 /* ToCheckDirty */) {
if (await asyncCheckDirty(this.deps)) {
this.run();
return;
} else {
this.flags = flags &= ~8 /* ToCheckDirty */;
}
}
if (flags & 4 /* InnerEffectsPending */) {
this.flags = flags & ~4 /* InnerEffectsPending */;
let link2 = this.deps;
do {
const dep = link2.dep;
if ("notify" in dep) {
dep.notify();
}
link2 = link2.nextDep;
} while (link2 !== void 0);
}
}
async run() {
try {
startTrack(this);
const trackId = nextTrackId();
const generator = this.fn();
let current = await generator.next();
while (!current.done) {
const dep = current.value;
if (dep.lastTrackedId !== trackId) {
dep.lastTrackedId = trackId;
link(dep, this);
}
current = await generator.next();
}
return await current.value;
} finally {
endTrack(this);
}
}
};
// src/unstable/computedArray.ts
function computedArray(arr, getGetter) {
const length = computed(() => arr.get().length);
const keys = computed(
() => {
const keys2 = [];
for (let i = 0; i < length.get(); i++) {
keys2.push(String(i));
}
return keys2;
}
);
const items = computed(
(array) => {
array ??= [];
while (array.length < length.get()) {
const index = array.length;
const item = computed(() => arr.get()[index]);
array.push(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();
}
});
}
// src/unstable/computedSet.ts
function computedSet(source) {
return computed(
(oldValue) => {
const newValue = source.get();
if (oldValue?.size === newValue.size && [...oldValue].every((c) => newValue.has(c))) {
return oldValue;
}
return newValue;
}
);
}
// src/unstable/equalityComputed.ts
function equalityComputed(getter) {
return new EqualityComputed(getter);
}
var EqualityComputed = class extends 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;
}
return false;
}
};
// src/unstable/index.ts
var unstable = {
AsyncComputed,
asyncComputed,
AsyncEffect,
asyncEffect,
asyncCheckDirty,
computedArray,
computedSet,
EqualityComputed,
equalityComputed
};

6
node_modules/alien-signals/cjs/index.d.ts generated vendored Normal file
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';

15
node_modules/alien-signals/cjs/signal.d.ts generated vendored Normal file
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;
}

56
node_modules/alien-signals/cjs/system.d.ts generated vendored Normal file
View File

@@ -0,0 +1,56 @@
export interface IEffect extends Subscriber {
nextNotify: IEffect | undefined;
notify(): void;
}
export interface IComputed extends Dependency, Subscriber {
update(): boolean;
}
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 | (Dependency & 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 {
function link(dep: Dependency, sub: Subscriber): void;
function propagate(subs: Link): void;
}
export declare namespace Subscriber {
function checkDirty(link: Link, depth?: number): boolean;
function startTrack(sub: Subscriber): Subscriber | undefined;
function endTrack(sub: Subscriber, prevSub: Subscriber | undefined): void;
function clearTrack(link: Link): void;
}

View File

@@ -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>[];

View File

@@ -0,0 +1,2 @@
import { ISignal } from '../index.js';
export declare function computedSet<T>(source: ISignal<Set<T>>): ISignal<Set<T>>;

View File

@@ -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;
}

3
node_modules/alien-signals/cjs/unstable/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
export * from './computedArray.js';
export * from './computedSet.js';
export * from './equalityComputed.js';

872
node_modules/alien-signals/esm/index.mjs generated vendored Normal file
View File

@@ -0,0 +1,872 @@
// src/system.ts
var SubscriberFlags = /* @__PURE__ */ ((SubscriberFlags2) => {
SubscriberFlags2[SubscriberFlags2["None"] = 0] = "None";
SubscriberFlags2[SubscriberFlags2["Tracking"] = 1] = "Tracking";
SubscriberFlags2[SubscriberFlags2["Recursed"] = 2] = "Recursed";
SubscriberFlags2[SubscriberFlags2["InnerEffectsPending"] = 4] = "InnerEffectsPending";
SubscriberFlags2[SubscriberFlags2["ToCheckDirty"] = 8] = "ToCheckDirty";
SubscriberFlags2[SubscriberFlags2["Dirty"] = 16] = "Dirty";
return SubscriberFlags2;
})(SubscriberFlags || {});
var batchDepth = 0;
var queuedEffects;
var queuedEffectsTail;
var linkPool;
function startBatch() {
++batchDepth;
}
function endBatch() {
if (!--batchDepth) {
drainQueuedEffects();
}
}
function drainQueuedEffects() {
while (queuedEffects !== void 0) {
const effect2 = queuedEffects;
const queuedNext = effect2.nextNotify;
if (queuedNext !== void 0) {
effect2.nextNotify = void 0;
queuedEffects = queuedNext;
} else {
queuedEffects = void 0;
queuedEffectsTail = void 0;
}
effect2.notify();
}
}
function link(dep, sub) {
const currentDep = sub.depsTail;
const nextDep = currentDep !== void 0 ? currentDep.nextDep : sub.deps;
if (nextDep !== void 0 && nextDep.dep === dep) {
sub.depsTail = nextDep;
} else {
linkNewDep(dep, sub, nextDep, currentDep);
}
}
function linkNewDep(dep, sub, nextDep, depsTail) {
let newLink;
if (linkPool !== void 0) {
newLink = linkPool;
linkPool = newLink.nextDep;
newLink.nextDep = nextDep;
newLink.dep = dep;
newLink.sub = sub;
} else {
newLink = {
dep,
sub,
nextDep,
prevSub: void 0,
nextSub: void 0
};
}
if (depsTail === void 0) {
sub.deps = newLink;
} else {
depsTail.nextDep = newLink;
}
if (dep.subs === void 0) {
dep.subs = newLink;
} else {
const oldTail = dep.subsTail;
newLink.prevSub = oldTail;
oldTail.nextSub = newLink;
}
sub.depsTail = newLink;
dep.subsTail = newLink;
}
function propagate(link2) {
let targetFlag = 16 /* Dirty */;
let subs = link2;
let stack = 0;
top: do {
const sub = link2.sub;
const subFlags = sub.flags;
if (!(subFlags & (1 /* Tracking */ | 2 /* Recursed */ | 4 /* InnerEffectsPending */ | 8 /* ToCheckDirty */ | 16 /* Dirty */)) && (sub.flags = subFlags | targetFlag, true) || (subFlags & (1 /* Tracking */ | 2 /* Recursed */)) === 2 /* Recursed */ && (sub.flags = subFlags & ~2 /* Recursed */ | targetFlag, true) || !(subFlags & (4 /* InnerEffectsPending */ | 8 /* ToCheckDirty */ | 16 /* Dirty */)) && isValidLink(link2, sub) && (sub.flags = subFlags | 2 /* Recursed */ | targetFlag, sub.subs !== void 0)) {
const subSubs = sub.subs;
if (subSubs !== void 0) {
if (subSubs.nextSub !== void 0) {
subSubs.prevSub = subs;
link2 = subs = subSubs;
targetFlag = 8 /* ToCheckDirty */;
++stack;
} else {
link2 = subSubs;
targetFlag = "notify" in sub ? 4 /* InnerEffectsPending */ : 8 /* ToCheckDirty */;
}
continue;
}
if ("notify" in sub) {
if (queuedEffectsTail !== void 0) {
queuedEffectsTail.nextNotify = sub;
} else {
queuedEffects = sub;
}
queuedEffectsTail = sub;
}
} else if (!(subFlags & (1 /* Tracking */ | targetFlag)) || !(subFlags & targetFlag) && subFlags & (4 /* InnerEffectsPending */ | 8 /* ToCheckDirty */ | 16 /* Dirty */) && isValidLink(link2, sub)) {
sub.flags = subFlags | targetFlag;
}
if ((link2 = subs.nextSub) !== void 0) {
subs = link2;
targetFlag = stack ? 8 /* ToCheckDirty */ : 16 /* Dirty */;
continue;
}
while (stack) {
--stack;
const dep = subs.dep;
const depSubs = dep.subs;
subs = depSubs.prevSub;
depSubs.prevSub = void 0;
if ((link2 = subs.nextSub) !== void 0) {
subs = link2;
targetFlag = stack ? 8 /* ToCheckDirty */ : 16 /* Dirty */;
continue top;
}
}
break;
} while (true);
if (!batchDepth) {
drainQueuedEffects();
}
}
function shallowPropagate(link2) {
do {
const updateSub = link2.sub;
const updateSubFlags = updateSub.flags;
if ((updateSubFlags & (8 /* ToCheckDirty */ | 16 /* Dirty */)) === 8 /* ToCheckDirty */) {
updateSub.flags = updateSubFlags | 16 /* Dirty */;
}
link2 = link2.nextSub;
} while (link2 !== void 0);
}
function isValidLink(subLink, sub) {
const depsTail = sub.depsTail;
if (depsTail !== void 0) {
let link2 = sub.deps;
do {
if (link2 === subLink) {
return true;
}
if (link2 === depsTail) {
break;
}
link2 = link2.nextDep;
} while (link2 !== void 0);
}
return false;
}
function checkDirty(link2) {
let stack = 0;
let dirty;
top: do {
dirty = false;
const dep = link2.dep;
if ("update" in dep) {
const depFlags = dep.flags;
if (depFlags & 16 /* Dirty */) {
if (dep.update()) {
const subs = dep.subs;
if (subs.nextSub !== void 0) {
shallowPropagate(subs);
}
dirty = true;
}
} else if (depFlags & 8 /* ToCheckDirty */) {
const depSubs = dep.subs;
if (depSubs.nextSub !== void 0) {
depSubs.prevSub = link2;
}
link2 = dep.deps;
++stack;
continue;
}
}
if (!dirty && link2.nextDep !== void 0) {
link2 = link2.nextDep;
continue;
}
if (stack) {
let sub = link2.sub;
do {
--stack;
const subSubs = sub.subs;
if (dirty) {
if (sub.update()) {
if ((link2 = subSubs.prevSub) !== void 0) {
subSubs.prevSub = void 0;
shallowPropagate(sub.subs);
sub = link2.sub;
} else {
sub = subSubs.sub;
}
continue;
}
} else {
sub.flags &= ~8 /* ToCheckDirty */;
}
if ((link2 = subSubs.prevSub) !== void 0) {
subSubs.prevSub = void 0;
if (link2.nextDep !== void 0) {
link2 = link2.nextDep;
continue top;
}
sub = link2.sub;
} else {
if ((link2 = subSubs.nextDep) !== void 0) {
continue top;
}
sub = subSubs.sub;
}
dirty = false;
} while (stack);
}
return dirty;
} while (true);
}
function startTrack(sub) {
sub.depsTail = void 0;
sub.flags = 1 /* Tracking */;
}
function endTrack(sub) {
const depsTail = sub.depsTail;
if (depsTail !== void 0) {
const nextDep = depsTail.nextDep;
if (nextDep !== void 0) {
clearTrack(nextDep);
depsTail.nextDep = void 0;
}
} else if (sub.deps !== void 0) {
clearTrack(sub.deps);
sub.deps = void 0;
}
sub.flags &= ~1 /* Tracking */;
}
function clearTrack(link2) {
do {
const dep = link2.dep;
const nextDep = link2.nextDep;
const nextSub = link2.nextSub;
const prevSub = link2.prevSub;
if (nextSub !== void 0) {
nextSub.prevSub = prevSub;
link2.nextSub = void 0;
} else {
dep.subsTail = prevSub;
if ("lastTrackedId" in dep) {
dep.lastTrackedId = 0;
}
}
if (prevSub !== void 0) {
prevSub.nextSub = nextSub;
link2.prevSub = void 0;
} else {
dep.subs = nextSub;
}
link2.dep = void 0;
link2.sub = void 0;
link2.nextDep = linkPool;
linkPool = link2;
if (dep.subs === void 0 && "deps" in dep) {
if ("notify" in dep) {
dep.flags = 0 /* None */;
} else {
const depFlags = dep.flags;
if (!(depFlags & 16 /* Dirty */)) {
dep.flags = depFlags | 16 /* Dirty */;
}
}
const depDeps = dep.deps;
if (depDeps !== void 0) {
link2 = depDeps;
dep.depsTail.nextDep = nextDep;
dep.deps = void 0;
dep.depsTail = void 0;
continue;
}
}
link2 = nextDep;
} while (link2 !== void 0);
}
// src/effectScope.ts
var activeEffectScope = void 0;
var activeScopeTrackId = 0;
function untrackScope(fn) {
const prevSub = activeEffectScope;
const prevTrackId = activeScopeTrackId;
setActiveScope(void 0, 0);
try {
return fn();
} finally {
setActiveScope(prevSub, prevTrackId);
}
}
function setActiveScope(sub, trackId) {
activeEffectScope = sub;
activeScopeTrackId = trackId;
}
function effectScope() {
return new EffectScope();
}
var EffectScope = class {
constructor() {
// Subscriber
this.deps = void 0;
this.depsTail = void 0;
this.flags = 0 /* None */;
this.trackId = nextTrackId();
}
notify() {
const flags = this.flags;
if (flags & 4 /* InnerEffectsPending */) {
this.flags = flags & ~4 /* InnerEffectsPending */;
let link2 = this.deps;
do {
const dep = link2.dep;
if ("notify" in dep) {
dep.notify();
}
link2 = link2.nextDep;
} while (link2 !== void 0);
}
}
run(fn) {
const prevSub = activeEffectScope;
const prevTrackId = activeScopeTrackId;
setActiveScope(this, this.trackId);
try {
return fn();
} finally {
setActiveScope(prevSub, prevTrackId);
}
}
stop() {
startTrack(this);
endTrack(this);
}
};
// src/effect.ts
var activeSub;
var activeTrackId = 0;
var lastTrackId = 0;
function untrack(fn) {
const prevSub = activeSub;
const prevTrackId = activeTrackId;
setActiveSub(void 0, 0);
try {
return fn();
} finally {
setActiveSub(prevSub, prevTrackId);
}
}
function setActiveSub(sub, trackId) {
activeSub = sub;
activeTrackId = trackId;
}
function nextTrackId() {
return ++lastTrackId;
}
function effect(fn) {
const e = new Effect(fn);
e.run();
return e;
}
var Effect = class {
constructor(fn) {
this.fn = fn;
this.nextNotify = void 0;
// Dependency
this.subs = void 0;
this.subsTail = void 0;
// Subscriber
this.deps = void 0;
this.depsTail = void 0;
this.flags = 16 /* Dirty */;
if (activeTrackId) {
link(this, activeSub);
} else if (activeScopeTrackId) {
link(this, activeEffectScope);
}
}
notify() {
let flags = this.flags;
if (flags & 16 /* Dirty */) {
this.run();
return;
}
if (flags & 8 /* ToCheckDirty */) {
if (checkDirty(this.deps)) {
this.run();
return;
} else {
this.flags = flags &= ~8 /* ToCheckDirty */;
}
}
if (flags & 4 /* InnerEffectsPending */) {
this.flags = flags & ~4 /* InnerEffectsPending */;
let link2 = this.deps;
do {
const dep = link2.dep;
if ("notify" in dep) {
dep.notify();
}
link2 = link2.nextDep;
} while (link2 !== void 0);
}
}
run() {
const prevSub = activeSub;
const prevTrackId = activeTrackId;
setActiveSub(this, nextTrackId());
startTrack(this);
try {
return this.fn();
} finally {
setActiveSub(prevSub, prevTrackId);
endTrack(this);
}
}
stop() {
startTrack(this);
endTrack(this);
}
};
// src/computed.ts
function computed(getter) {
return new Computed(getter);
}
var Computed = class {
constructor(getter) {
this.getter = getter;
this.currentValue = void 0;
// Dependency
this.subs = void 0;
this.subsTail = void 0;
this.lastTrackedId = 0;
// Subscriber
this.deps = void 0;
this.depsTail = void 0;
this.flags = 16 /* Dirty */;
}
get() {
const flags = this.flags;
if (flags & 16 /* Dirty */) {
if (this.update()) {
const subs = this.subs;
if (subs !== void 0) {
shallowPropagate(subs);
}
}
} else if (flags & 8 /* ToCheckDirty */) {
if (checkDirty(this.deps)) {
if (this.update()) {
const subs = this.subs;
if (subs !== void 0) {
shallowPropagate(subs);
}
}
} else {
this.flags = flags & ~8 /* ToCheckDirty */;
}
}
if (activeTrackId) {
if (this.lastTrackedId !== activeTrackId) {
this.lastTrackedId = activeTrackId;
link(this, activeSub);
}
} else if (activeScopeTrackId) {
if (this.lastTrackedId !== activeScopeTrackId) {
this.lastTrackedId = activeScopeTrackId;
link(this, activeEffectScope);
}
}
return this.currentValue;
}
update() {
const prevSub = activeSub;
const prevTrackId = activeTrackId;
setActiveSub(this, nextTrackId());
startTrack(this);
try {
const oldValue = this.currentValue;
const newValue = this.getter(oldValue);
if (oldValue !== newValue) {
this.currentValue = newValue;
return true;
}
return false;
} finally {
setActiveSub(prevSub, prevTrackId);
endTrack(this);
}
}
};
// src/signal.ts
function signal(oldValue) {
return new Signal(oldValue);
}
var Signal = class {
constructor(currentValue) {
this.currentValue = currentValue;
// Dependency
this.subs = void 0;
this.subsTail = void 0;
this.lastTrackedId = 0;
}
get() {
if (activeTrackId && this.lastTrackedId !== activeTrackId) {
this.lastTrackedId = activeTrackId;
link(this, activeSub);
}
return this.currentValue;
}
set(value) {
if (this.currentValue !== value) {
this.currentValue = value;
const subs = this.subs;
if (subs !== void 0) {
propagate(subs);
}
}
}
};
// src/unstable/asyncSystem.ts
async function asyncCheckDirty(link2) {
let stack = 0;
let dirty;
let nextDep;
top: do {
dirty = false;
const dep = link2.dep;
if ("update" in dep) {
const depFlags = dep.flags;
if (depFlags & 16 /* Dirty */) {
if (await dep.update()) {
const subs = dep.subs;
if (subs.nextSub !== void 0) {
shallowPropagate(subs);
}
dirty = true;
}
} else if (depFlags & 8 /* ToCheckDirty */) {
const depSubs = dep.subs;
if (depSubs.nextSub !== void 0) {
depSubs.prevSub = link2;
}
link2 = dep.deps;
++stack;
continue;
}
}
if (dirty || (nextDep = link2.nextDep) === void 0) {
if (stack) {
let sub = link2.sub;
do {
--stack;
const subSubs = sub.subs;
let prevLink = subSubs.prevSub;
if (prevLink !== void 0) {
subSubs.prevSub = void 0;
if (dirty) {
if (await sub.update()) {
shallowPropagate(sub.subs);
sub = prevLink.sub;
continue;
}
} else {
sub.flags &= ~8 /* ToCheckDirty */;
}
} else {
if (dirty) {
if (await sub.update()) {
sub = subSubs.sub;
continue;
}
} else {
sub.flags &= ~8 /* ToCheckDirty */;
}
prevLink = subSubs;
}
link2 = prevLink.nextDep;
if (link2 !== void 0) {
continue top;
}
sub = prevLink.sub;
dirty = false;
} while (stack);
}
return dirty;
}
link2 = nextDep;
} while (true);
}
// src/unstable/asyncComputed.ts
function asyncComputed(getter) {
return new AsyncComputed(getter);
}
var AsyncComputed = class extends Computed {
async get() {
const flags = this.flags;
if (flags & 16 /* Dirty */) {
if (await this.update()) {
const subs = this.subs;
if (subs !== void 0) {
shallowPropagate(subs);
}
}
} else if (flags & 8 /* ToCheckDirty */) {
if (await asyncCheckDirty(this.deps)) {
if (await this.update()) {
const subs = this.subs;
if (subs !== void 0) {
shallowPropagate(subs);
}
}
} else {
this.flags = flags & ~8 /* ToCheckDirty */;
}
}
return this.currentValue;
}
// @ts-expect-error
async update() {
try {
startTrack(this);
const trackId = nextTrackId();
const oldValue = this.currentValue;
const generator = this.getter(oldValue);
let current = await generator.next();
while (!current.done) {
const dep = current.value;
if (dep.lastTrackedId !== trackId) {
dep.lastTrackedId = trackId;
link(dep, this);
}
current = await generator.next();
}
const newValue = await current.value;
if (oldValue !== newValue) {
this.currentValue = newValue;
return true;
}
return false;
} finally {
endTrack(this);
}
}
};
// src/unstable/asyncEffect.ts
function asyncEffect(fn) {
const e = new AsyncEffect(fn);
e.run();
return e;
}
var AsyncEffect = class extends Effect {
async notify() {
let flags = this.flags;
if (flags & 16 /* Dirty */) {
this.run();
return;
}
if (flags & 8 /* ToCheckDirty */) {
if (await asyncCheckDirty(this.deps)) {
this.run();
return;
} else {
this.flags = flags &= ~8 /* ToCheckDirty */;
}
}
if (flags & 4 /* InnerEffectsPending */) {
this.flags = flags & ~4 /* InnerEffectsPending */;
let link2 = this.deps;
do {
const dep = link2.dep;
if ("notify" in dep) {
dep.notify();
}
link2 = link2.nextDep;
} while (link2 !== void 0);
}
}
async run() {
try {
startTrack(this);
const trackId = nextTrackId();
const generator = this.fn();
let current = await generator.next();
while (!current.done) {
const dep = current.value;
if (dep.lastTrackedId !== trackId) {
dep.lastTrackedId = trackId;
link(dep, this);
}
current = await generator.next();
}
return await current.value;
} finally {
endTrack(this);
}
}
};
// src/unstable/computedArray.ts
function computedArray(arr, getGetter) {
const length = computed(() => arr.get().length);
const keys = computed(
() => {
const keys2 = [];
for (let i = 0; i < length.get(); i++) {
keys2.push(String(i));
}
return keys2;
}
);
const items = computed(
(array) => {
array ??= [];
while (array.length < length.get()) {
const index = array.length;
const item = computed(() => arr.get()[index]);
array.push(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();
}
});
}
// src/unstable/computedSet.ts
function computedSet(source) {
return computed(
(oldValue) => {
const newValue = source.get();
if (oldValue?.size === newValue.size && [...oldValue].every((c) => newValue.has(c))) {
return oldValue;
}
return newValue;
}
);
}
// src/unstable/equalityComputed.ts
function equalityComputed(getter) {
return new EqualityComputed(getter);
}
var EqualityComputed = class extends 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;
}
return false;
}
};
// src/unstable/index.ts
var unstable = {
AsyncComputed,
asyncComputed,
AsyncEffect,
asyncEffect,
asyncCheckDirty,
computedArray,
computedSet,
EqualityComputed,
equalityComputed
};
export {
Computed,
Effect,
EffectScope,
Signal,
SubscriberFlags,
activeEffectScope,
activeScopeTrackId,
activeSub,
activeTrackId,
checkDirty,
computed,
effect,
effectScope,
endBatch,
endTrack,
lastTrackId,
link,
nextTrackId,
propagate,
setActiveScope,
setActiveSub,
shallowPropagate,
signal,
startBatch,
startTrack,
unstable,
untrack,
untrackScope
};

50
node_modules/alien-signals/package.json generated vendored Normal file
View File

@@ -0,0 +1,50 @@
{
"name": "alien-signals",
"version": "0.4.14",
"sideEffects": false,
"license": "MIT",
"description": "The lightest signal library.",
"packageManager": "pnpm@9.12.0",
"types": "./types/index.d.ts",
"exports": {
".": {
"types": "./types/index.d.ts",
"import": "./esm/index.mjs",
"require": "./cjs/index.cjs"
},
"./cjs": {
"types": "./types/index.d.ts",
"import": "./cjs/index.cjs",
"require": "./cjs/index.cjs"
},
"./esm": {
"types": "./types/index.d.ts",
"import": "./esm/index.mjs",
"require": "./esm/index.mjs"
}
},
"files": [
"**/*.cjs",
"**/*.mjs",
"**/*.d.ts"
],
"repository": {
"type": "git",
"url": "git+https://github.com/johnsoncodehk/signals.git"
},
"scripts": {
"prepublishOnly": "npm run build",
"build": "tsc && npm run build:esm && npm run build:cjs",
"build:esm": "esbuild src/index.ts --bundle --format=esm --outfile=esm/index.mjs",
"build:cjs": "esbuild src/index.ts --bundle --format=cjs --outfile=cjs/index.cjs",
"test": "vitest run",
"bench": "npm run build:esm && node --jitless --expose-gc benchs/propagate.mjs && node --jitless --expose-gc benchs/complex.mjs",
"bench:memory": "npm run build:esm && node --expose-gc benchs/memoryUsage.mjs"
},
"devDependencies": {
"esbuild": "latest",
"mitata": "latest",
"typescript": "latest",
"vitest": "latest"
}
}

16
node_modules/alien-signals/types/computed.d.ts generated vendored Normal file
View File

@@ -0,0 +1,16 @@
import { IComputed, Link, SubscriberFlags } from './system.js';
import type { ISignal } from './types.js';
export declare function computed<T>(getter: (cachedValue?: T) => T): Computed<T>;
export declare class Computed<T = any> implements IComputed, ISignal<T> {
getter: (cachedValue?: T) => T;
currentValue: T | undefined;
subs: Link | undefined;
subsTail: Link | undefined;
lastTrackedId: number;
deps: Link | undefined;
depsTail: Link | undefined;
flags: SubscriberFlags;
constructor(getter: (cachedValue?: T) => T);
get(): T;
update(): boolean;
}

21
node_modules/alien-signals/types/effect.d.ts generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import { Dependency, IEffect, Link, Subscriber, SubscriberFlags } from './system.js';
export declare let activeSub: Subscriber | undefined;
export declare let activeTrackId: number;
export declare let lastTrackId: number;
export declare function untrack<T>(fn: () => T): T;
export declare function setActiveSub(sub: Subscriber | undefined, trackId: number): void;
export declare function nextTrackId(): number;
export declare function effect<T>(fn: () => T): Effect<T>;
export declare class Effect<T = any> implements IEffect, Dependency {
fn: () => T;
nextNotify: IEffect | undefined;
subs: Link | undefined;
subsTail: Link | undefined;
deps: Link | undefined;
depsTail: Link | undefined;
flags: SubscriberFlags;
constructor(fn: () => T);
notify(): void;
run(): T;
stop(): void;
}

15
node_modules/alien-signals/types/effectScope.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import { Link, Subscriber, SubscriberFlags } from './system.js';
export declare let activeEffectScope: EffectScope | undefined;
export declare let activeScopeTrackId: number;
export declare function untrackScope<T>(fn: () => T): T;
export declare function setActiveScope(sub: EffectScope | undefined, trackId: number): void;
export declare function effectScope(): EffectScope;
export declare class EffectScope implements Subscriber {
deps: Link | undefined;
depsTail: Link | undefined;
flags: SubscriberFlags;
trackId: number;
notify(): void;
run<T>(fn: () => T): T;
stop(): void;
}

7
node_modules/alien-signals/types/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,7 @@
export * from './computed.js';
export * from './effect.js';
export * from './effectScope.js';
export * from './signal.js';
export * from './system.js';
export * from './types.js';
export * from './unstable/index.js';

13
node_modules/alien-signals/types/signal.d.ts generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import { Dependency, Link } from './system.js';
import type { IWritableSignal } from './types.js';
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, IWritableSignal<T> {
currentValue: T;
subs: Link | undefined;
subsTail: Link | undefined;
lastTrackedId: number;
constructor(currentValue: T);
get(): T;
set(value: T): void;
}

40
node_modules/alien-signals/types/system.d.ts generated vendored Normal file
View File

@@ -0,0 +1,40 @@
export interface IEffect extends Subscriber {
nextNotify: IEffect | undefined;
notify(): void;
}
export interface IComputed extends Dependency, Subscriber {
update(): boolean;
}
export interface Dependency {
subs: Link | undefined;
subsTail: Link | undefined;
lastTrackedId?: number;
}
export interface Subscriber {
flags: SubscriberFlags;
deps: Link | undefined;
depsTail: Link | undefined;
}
export interface Link {
dep: Dependency | IComputed | (Dependency & IEffect);
sub: Subscriber | IComputed | (Dependency & IEffect) | IEffect;
prevSub: Link | undefined;
nextSub: Link | undefined;
nextDep: Link | undefined;
}
export declare const enum SubscriberFlags {
None = 0,
Tracking = 1,
Recursed = 2,
InnerEffectsPending = 4,
ToCheckDirty = 8,
Dirty = 16
}
export declare function startBatch(): void;
export declare function endBatch(): void;
export declare function link(dep: Dependency, sub: Subscriber): void;
export declare function propagate(link: Link): void;
export declare function shallowPropagate(link: Link): void;
export declare function checkDirty(link: Link): boolean;
export declare function startTrack(sub: Subscriber): void;
export declare function endTrack(sub: Subscriber): void;

6
node_modules/alien-signals/types/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,6 @@
export interface ISignal<T = any> {
get(): T;
}
export interface IWritableSignal<T = any> extends ISignal<T> {
set(value: T): void;
}

View File

@@ -0,0 +1,7 @@
import { Computed } from '../computed.js';
import { Dependency } from '../system.js';
export declare function asyncComputed<T>(getter: (cachedValue?: T) => AsyncGenerator<Dependency, T>): AsyncComputed<T>;
export declare class AsyncComputed<T = any> extends Computed {
get(): Promise<T>;
update(): Promise<boolean>;
}

View File

@@ -0,0 +1,7 @@
import { Effect } from '../effect.js';
import { Dependency } from '../system.js';
export declare function asyncEffect<T>(fn: () => AsyncGenerator<Dependency, T>): AsyncEffect<T>;
export declare class AsyncEffect<T = any> extends Effect {
notify(): Promise<void>;
run(): Promise<T>;
}

View File

@@ -0,0 +1,2 @@
import { Link } from "../system";
export declare function asyncCheckDirty(link: Link): Promise<boolean>;

View File

@@ -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>[];

View File

@@ -0,0 +1,2 @@
import { ISignal } from '../index.js';
export declare function computedSet<T>(source: ISignal<Set<T>>): ISignal<Set<T>>;

View File

@@ -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;
}

17
node_modules/alien-signals/types/unstable/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import { AsyncComputed, asyncComputed } from './asyncComputed.js';
import { AsyncEffect, asyncEffect } from './asyncEffect.js';
import { asyncCheckDirty } from './asyncSystem.js';
import { computedArray } from './computedArray.js';
import { computedSet } from './computedSet.js';
import { EqualityComputed, equalityComputed } from './equalityComputed.js';
export declare const unstable: {
AsyncComputed: typeof AsyncComputed;
asyncComputed: typeof asyncComputed;
AsyncEffect: typeof AsyncEffect;
asyncEffect: typeof asyncEffect;
asyncCheckDirty: typeof asyncCheckDirty;
computedArray: typeof computedArray;
computedSet: typeof computedSet;
EqualityComputed: typeof EqualityComputed;
equalityComputed: typeof equalityComputed;
};