Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [v1.0.1] - 2026-03-11

### Added
- Add tests

## [v1.0.0] - 2026-03-11

Initial Release
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ npm install @aegisjsproject/iota
<script type="importmap">
"imports": {
"@shgysk8zer0/signals": "https://unpkg.com/@shgysk8zer0/signals@0.0.3/signals.js,
"@aegisjsproject/iota": "https://unpkg.com/@aegisjsproject/iota/iota.js"
"@aegisjsproject/iota": "https://unpkg.com/@aegisjsproject/iota@1.0.1/iota.js"
}
</script>
```
Expand Down
100 changes: 100 additions & 0 deletions iota.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import '@shgysk8zer0/polyfills';
import test from 'node:test';
import assert from 'node:assert/strict';
import {
getRef,
RegistryKey,
hasSignalRef,
getSignalFromRef,
unregisterSignal,
$signal,
$computed,
$watch,
$unwatch
} from '@aegisjsproject/iota';

test('RegistryKey generation and disposal', () => {
const key = getRef('test');
assert.ok(key instanceof RegistryKey);
assert.match(key.toString(), /^test-\d+-[0-9a-f]+$/);
assert.equal(key.disposed, false);

key[Symbol.dispose]();
assert.equal(key.disposed, true);
});

test('Signal Registry operations', () => {
const state = $signal(10);
const ref = state.ref;

assert.equal(hasSignalRef(ref), true);
assert.equal(getSignalFromRef(ref), state);

unregisterSignal(ref);
assert.equal(hasSignalRef(ref), false);
assert.equal(getSignalFromRef(ref), undefined);
});

test('$signal (DisposableState) value tracking and disposal', () => {
const count = $signal(0);
assert.equal(count.get(), 0);

count.set(5);
assert.equal(count.get(), 5);

const ref = count.ref;
assert.equal(hasSignalRef(ref), true);

count[Symbol.dispose]();
assert.equal(count.disposed, true);
assert.equal(hasSignalRef(ref), false); // Disposal should trigger unregister
});

test('$computed (DisposableComputed) reactivity and disposal', () => {
const base = $signal(5);
const square = $computed(() => base.get() ** 2);

assert.equal(square.get(), 25);

base.set(10);
assert.equal(square.get(), 100);

const ref = square.ref;
assert.equal(hasSignalRef(ref), true);

square[Symbol.dispose]();
assert.equal(square.disposed, true);
assert.equal(hasSignalRef(ref), false);
});

test('$watch and $unwatch microtask batching', async () => {
const text = $signal('a');
let watcherRuns = 0;
let lastValue = null;

const callback = (val) => {
watcherRuns++;
lastValue = val;
};

$watch(text, callback);

// Trigger multiple synchronous updates
text.set('b');
text.set('c');
text.set('d');

// Yield to event loop to allow queueMicrotask to process
await new Promise(resolve => setTimeout(resolve, 0));

assert.equal(lastValue, 'd');
assert.equal(watcherRuns, 1); // Batched into a single run

$unwatch(text);

text.set('e');
await new Promise(resolve => setTimeout(resolve, 0));

assert.equal(lastValue, 'd'); // Should not have updated
assert.equal(watcherRuns, 1);
});
16 changes: 8 additions & 8 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@aegisjsproject/iota",
"version": "1.0.0",
"version": "1.0.1",
"description": "A Signals-based reactivity library",
"keywords": [
"signals",
Expand Down
2 changes: 1 addition & 1 deletion refs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export class RegistryKey extends String {
#stack = new DisposableStack();

get disposed() {
return this.#stack.diposed;
return this.#stack.disposed;
}

adopt(what, onDiposed) {
Expand Down
Loading