JVM port of stackblitz/alien-signals 3.1.2. Line-for-line, same algorithm, same flags, same DLL semantics.
alien-signals is a small reactive-signals library: signals, computed
values, effects, an automatic dependency graph with pull-on-read and
push-mark-dirty propagation. It was previously available only on
JavaScript runtimes via npm. This artifact ports the same algorithm to
the JVM so any Java, Kotlin, Scala, or Clojure consumer can use it
with no JS bridge.
src/main/java/hbt/aliensignals/
ReactiveFlags.java Bit-flag constants
ReactiveNode.java Base node (deps, depsTail, subs, subsTail, flags)
Link.java Doubly-linked-list edge between dep and sub
ReactiveSystem.java Algorithm core: link, unlink, propagate,
checkDirty, shallowPropagate, startTracking,
endTracking (port of system.ts)
SignalNode.java value + previousValue
ComputedNode.java value + getter
EffectNode.java fn
Signal.java User-facing get / set
Computed.java User-facing get
Effect.java User-facing stop
Signals.java Static facade: signal, computed, effect, batch,
untrack, effectScope, trigger (port of index.ts)
import static hbt.aliensignals.Signals.*;
Signal<Integer> a = signal(1);
Computed<Integer> b = computed(prev -> a.get() * 2);
Effect e = effect(() -> System.out.println(b.get()));
a.set(5); // prints 10
batch(() -> {
a.set(7);
a.set(9);
}); // prints 18 once
e.stop();mvn installInstalls hbt:alien-signals:3.1.2 to ~/.m2/repository.
In a deps.edn consumer:
{:deps {hbt/alien-signals {:mvn/version "3.1.2"}}}21 JUnit tests cover the load-bearing cases ported from upstream Vitest:
- signal read/write semantics, value-equality skip
- computed memoisation and chained propagation
- effect lifecycle (eager run, dispose, nested stop)
- batch coalescing
- untrack via
Signals.untrackand via directsetActiveSub(matches the upstream pattern inuntrack.spec.ts) - diamond topology — both signal-only and computed-via-checkDirty
- signal-revert: writing then reverting must NOT force recompute
- effectScope dispose
mvn test
[INFO] Tests run: 21, Failures: 0, Errors: 0, Skipped: 0
Single-threaded, same as upstream. The shared Signals static state
(activeSub, activeScope, batchDepth, notify queue) is not
synchronised. Calling from multiple threads is unsafe.
Tracks upstream npm. When stackblitz publishes a new version, this artifact moves to the same version with the corresponding system.ts and index.ts changes ported.
MIT — same as upstream.