Comparing version 4.1.1 to 5.0.0
@@ -1,14 +0,27 @@ | ||
declare module 'quarx' { | ||
type Disposer = () => void; | ||
type ObservableOptions<T> = { | ||
name?: string; | ||
equals?: (a: T, b: T) => boolean; | ||
} | ||
export interface Atom { | ||
reportObserved: () => boolean; | ||
reportChanged: () => void; | ||
} | ||
type Disposer = () => void; | ||
export interface CoreOptions { | ||
name?: string; | ||
onError?: () => void; | ||
} | ||
type Atom = { | ||
reportObserved: () => boolean; | ||
reportChanged: () => void; | ||
} | ||
type CoreOptions = { | ||
name?: string; | ||
onError?: () => void; | ||
} | ||
type Observable<T> = { | ||
get: () => T; | ||
} | ||
type Box<T> = Observable<T> & { | ||
set: (value: T) => void; | ||
} | ||
declare module 'quarx' { | ||
export function createAtom(onBecomeObserved?: () => Disposer | void, options?: CoreOptions): Atom; | ||
@@ -19,21 +32,14 @@ export function autorun(computation: () => void, options?: CoreOptions): Disposer; | ||
export function untracked<T>(fn: () => T): T; | ||
} | ||
export interface Observable<T> { | ||
get: () => T; | ||
} | ||
declare module 'quarx/box' { | ||
export function box<T>(value: T, options?: ObservableOptions<T>): Box<T>; | ||
} | ||
export interface Box<T> extends Observable<T> { | ||
set: (value: T) => void; | ||
} | ||
export interface ObservableOptions<T> { | ||
name?: string; | ||
equals?: (a: T, b: T) => boolean; | ||
} | ||
export namespace observable { | ||
export function box<T>(value: T, options?: ObservableOptions<T>): Box<T>; | ||
} | ||
declare module 'quarx/computed' { | ||
export function computed<T>(computation: () => T, options?: ObservableOptions<T>): Observable<T>; | ||
} | ||
declare module 'quarx/map' { | ||
export function observableMap<K, V>(underlyingMap?: Map<K, V>, options?: ObservableOptions<V>): Map<K, V>; | ||
} |
{ | ||
"name": "quarx", | ||
"version": "4.1.1", | ||
"description": "Simple dependency graph engine, MobX inspired", | ||
"version": "5.0.0", | ||
"description": "Simple tiny reactivity engine", | ||
"type": "module", | ||
"main": "index.js", | ||
"module": "index.js", | ||
"main": "src/core.js", | ||
"module": "src/core.js", | ||
"exports": { | ||
".": "./src/core.js", | ||
"./box": "./src/box.js", | ||
"./computed": "./src/computed.js", | ||
"./map": "./src/map.js" | ||
}, | ||
"types": "index.d.ts", | ||
@@ -30,7 +36,6 @@ "directories": { | ||
"keywords": [ | ||
"Reactive", | ||
"reactivity", | ||
"dependency", | ||
"graph", | ||
"engine", | ||
"MobX" | ||
"engine" | ||
], | ||
@@ -37,0 +42,0 @@ "author": "Dmitry Maevsky", |
# 🜉 Quarx | ||
Simple tiny dependency graph engine, MobX inspired | ||
Simple tiny reactivity engine, MobX inspired | ||
@@ -7,3 +7,3 @@ ## Introduction | ||
- `createAtom`, `autorun` are the low-level core primitives of the Quarx reactive engine | ||
- `computed`, `observable.box` are built on top of those primitives | ||
- `computed`, observable `box` are built on top of those primitives | ||
- all of the above behave the same way as their MobX equivalents | ||
@@ -19,6 +19,8 @@ | ||
```js | ||
import { autorun, computed, observable, batch } from 'quarx'; | ||
import { autorun, batch } from 'quarx'; | ||
import { box } from 'quarx/box'; | ||
import { computed } from 'quarx/computed'; | ||
const a = observable.box(1); | ||
const b = observable.box(2); | ||
const a = box(1); | ||
const b = box(2); | ||
const a_plus_b = computed(() => a.get() + b.get()); | ||
@@ -91,3 +93,3 @@ | ||
Using the primitives defined in the previous section one can construct observables of arbitrarily complex behavior. | ||
`observable.box` and `computed` are two classical basic building blocks of a dependency graph. | ||
observable `box` and `computed` are two classical basic building blocks of a dependency graph. | ||
@@ -100,6 +102,3 @@ ```typescript | ||
export namespace observable { | ||
export function box<T>(value: T, options?: ObservableOptions<T>): Box<T>; | ||
} | ||
export function box<T>(value: T, options?: ObservableOptions<T>): Box<T>; | ||
export function computed<T>(computation: () => T, options?: ObservableOptions<T>): Observable<T>; | ||
@@ -118,5 +117,5 @@ ``` | ||
## Goals and non-goals | ||
The goal for Quarx is to remain a *dry essence* of a dependency graph engine. As simple and tiny as it is, it will replace MobX in production at [ellx.io](https://ellx.io) shortly. | ||
The goal for Quarx is to remain a *dry essence* of a reactivity engine. As simple and tiny as it is, it is used in production at [ellx.io](https://ellx.io). | ||
Out of the box, Quarx is not designed to be a state management solution. However, it can be used in combination with [Tinyx](https://github.com/dmaevsky/tinyx) or even Redux. Just put the root store into a single `observable.box`, and derive the rest of the state reactively with a network of `computed` selectors. | ||
Out of the box, Quarx is not designed to be a state management solution. However, it can be used in combination with [Tinyx](https://github.com/dmaevsky/tinyx) or even Redux. Just put the root store into a single `box`, and derive the rest of the state reactively with a network of `computed` selectors. | ||
@@ -123,0 +122,0 @@ **On a side note...** |
@@ -16,3 +16,4 @@ const TAG = '@dmaevsky/quarx'; | ||
batchDepth: 0, | ||
processingQueue: 0, | ||
hydrating: false, | ||
cleaningUp: false, | ||
debug: () => {}, | ||
@@ -98,5 +99,11 @@ error: console.error | ||
function invalidate() { | ||
if (Quarx.processingQueue + (seqNo === Quarx.sequenceNumber) >= 2) { | ||
return Quarx.debug(`[Quarx]: prevent invalidating ${name} ${Quarx.processingQueue === 1 ? ': cycle detected' : 'during cleanup'}`); | ||
if (Quarx.cleaningUp) { | ||
// No invalidations allowed in dispose callbacks | ||
return Quarx.error(`[Quarx]: prevent invalidating ${name} while running the dispose queue`); | ||
} | ||
if (Quarx.hydrating && seqNo === Quarx.sequenceNumber) { | ||
// Invalidating a freshly hydrated computation == cycle, but cannot throw here yet, because we don't have the stack to report | ||
return Quarx.error(`[Quarx]: prevent invalidating ${name}: cycle detected`); | ||
} | ||
seqNo = 0; | ||
@@ -157,3 +164,3 @@ Quarx.invalidated.add(run); | ||
function dispose() { | ||
function off() { | ||
for (let dep of dependencies) dep.unlink(); | ||
@@ -165,11 +172,11 @@ dependencies.clear(); | ||
batch(run); | ||
return dispose; | ||
return off; | ||
} | ||
function collectUnobserved() { | ||
if (Quarx.batchDepth + Quarx.processingQueue) return; | ||
if (Quarx.hydrating || Quarx.cleaningUp) return; | ||
Quarx.processingQueue += 2; | ||
Quarx.cleaningUp = true; | ||
for (let dispose of Quarx.pendingDispose) dispose(); | ||
Quarx.processingQueue -= 2; | ||
Quarx.cleaningUp = false; | ||
@@ -180,3 +187,3 @@ Quarx.pendingDispose.clear(); | ||
function hydrate() { | ||
if (!Quarx.invalidated.size || Quarx.batchDepth + Quarx.processingQueue) return; | ||
if (Quarx.hydrating || Quarx.cleaningUp || Quarx.batchDepth || !Quarx.invalidated.size) return; | ||
@@ -186,5 +193,5 @@ ++Quarx.sequenceNumber; | ||
++Quarx.processingQueue; | ||
Quarx.hydrating = true; | ||
for (let run of Quarx.invalidated) run(); | ||
--Quarx.processingQueue; | ||
Quarx.hydrating = false; | ||
@@ -191,0 +198,0 @@ collectUnobserved(); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
18336
334
123