Skip to content

Commit

Permalink
feat: new export getParent
Browse files Browse the repository at this point in the history
  • Loading branch information
mihar-22 committed Jul 8, 2022
1 parent 61fe544 commit 88310aa
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 1 deletion.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ $: yarn add @maverick-js/observables
- [`onDispose`](#ondispose)
- [`isObservable`](#isobservable)
- [`isSubject`](#issubject)
- [`getParent`](#getparent)
- [`getScheduler`](#getscheduler)

## `$root`
Expand Down Expand Up @@ -392,6 +393,18 @@ isSubject($computed(() => 10));
isSubject($readonly($observable(10)));
```

### `getParent`

Returns the parent/owner of the given function (if defined). You can use this function to
recursively walk up the computation tree (useful for implementing a context API).

```js
$root(() => {
const $a = $observable(0);
getParent($a); // returns `$root`
});
```

### `getScheduler`

Returns the global scheduler which can be used to queue additional tasks or synchronously flush
Expand Down
23 changes: 22 additions & 1 deletion src/observables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type MaybeObservable<T> = MaybeFunction | Observable<T>;

const NOOP = () => {};

const PARENT = Symbol();
const OBSERVABLE = Symbol();
const COMPUTED = Symbol();
const DIRTY = Symbol();
Expand Down Expand Up @@ -279,6 +280,7 @@ export function $dispose(fn: () => void) {
unrefSet(fn, DISPOSAL);
unrefSet(fn, OBSERVERS);

fn[PARENT] = undefined;
fn[DIRTY] = false;
fn[DISPOSED] = true;
}
Expand Down Expand Up @@ -379,6 +381,22 @@ export function isSubject<T>(fn: MaybeObservable<T>): fn is ObservableSubject<T>
return isObservable(fn) && !!(fn as ObservableSubject<T>).set;
}

/**
* Returns the parent/owner of the given function (if defined). You can use this to walk up
* the computation tree.
*
* @example
* ```js
* $root(() => {
* const $a = $observable(0);
* getParent($a); // returns `$root`
* });
* ```
*/
export function getParent(fn: Observable<unknown>): Observable<unknown> | undefined {
return fn[PARENT];
}

/**
* Returns the global scheduler.
*/
Expand Down Expand Up @@ -416,7 +434,10 @@ function compute<T>(parent: () => void, child: () => T): T {
}

function adoptChild(node: Node) {
if (_parent) addChild(_parent, node);
if (_parent) {
node[PARENT] = _parent;
addChild(_parent, node);
}
}

function addChild(node: Node, child: Node) {
Expand Down
40 changes: 40 additions & 0 deletions tests/getParent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { $effect, $observable, $peek, $root, getParent } from '../src';

it('should be orphan', () => {
const $a = $observable(0);
expect(getParent($a)).toBeUndefined();
});

it('should return parent', () => {
$root(() => {
const $a = $observable(0);
expect(getParent($a)).toBeInstanceOf(Function);
});
});

it('should return parent from inside peek', () => {
$root(() => {
$peek(() => {
const $a = $observable(0);
expect(getParent($a)).toBeInstanceOf(Function);
});
});
});

it('should return grandparent', () => {
$root(() => {
$effect(() => {
const $a = $observable(0);
expect(getParent($a)).toBeInstanceOf(Function);
expect(getParent(getParent($a)!)).toBeInstanceOf(Function);
});
});
});

it('should remove parent on dispose', () => {
$root((dispose) => {
const $a = $observable(0);
dispose();
expect(getParent($a)).toBeUndefined();
});
});

0 comments on commit 88310aa

Please sign in to comment.