feat: create-signal

This commit is contained in:
Víctor Oliva 2022-10-19 17:51:45 +02:00
parent 6300214de0
commit d9544fde0f
4 changed files with 67 additions and 5 deletions

View File

@ -0,0 +1,52 @@
import { Subject } from "rxjs"
import {
getInternals,
inactiveContext,
NestedMap,
recursiveError,
} from "./internal"
import type { Signal, StateNode, StringRecord } from "./types"
export const createSignal = <T, K extends StringRecord<any>>(
parent: StateNode<any, K>,
): Signal<T, K> => {
const instances = new NestedMap<any[], Subject<T>>()
const parentInternals = getInternals(parent)
parentInternals.childRunners.push((key, isActive) => {
const current = instances.get(key)
if (isActive && !current) {
instances.set(key, new Subject())
}
if (!isActive && current) {
instances.delete(key)
current.complete()
}
})
return {
getSignal$(keyObj: K = {} as K) {
const sortedKey = parentInternals.keysOrder.map((key) => keyObj[key])
const instance = instances.get(sortedKey)
if (!instance)
throw (
recursiveError(sortedKey, parentInternals, new Set()) ||
inactiveContext()
)
return instance
},
push(keyOrValue: T | K, value?: T) {
const keyObj = (arguments.length > 1 ? keyOrValue : {}) as K
const safeValue = arguments.length > 1 ? value! : (keyOrValue as T)
const sortedKey = parentInternals.keysOrder.map((key) => keyObj[key])
const instance = instances.get(sortedKey)
if (!instance)
throw (
recursiveError(sortedKey, parentInternals, new Set()) ||
inactiveContext()
)
instance.next(safeValue)
},
}
}

View File

@ -1,5 +1,5 @@
import { Observable, ReplaySubject, Subscription } from "rxjs"
import type { CtxFn, StateNode, StringRecord } from "../types"
import type { CtxFn, Signal, StateNode, StringRecord } from "../types"
import {
InternalStateNode,
EMPTY_VALUE,
@ -13,7 +13,7 @@ import {
} from "./"
import { NestedMap } from "./nested-map"
const recursiveError = (
export const recursiveError = (
key: any[],
start: InternalStateNode<any, any>,
searched: Set<InternalStateNode<any, any>>,
@ -153,9 +153,13 @@ export const detachedNode = <T, K extends StringRecord<any>>(
}
const ctxObservable = <V, CK extends StringRecord<any>>(
node: StateNode<V, any>,
node: StateNode<V, CK> | Signal<V, CK>,
partialKey: Omit<CK, keyof K>,
): Observable<V> => node.getState$({ ...objKey, ...partialKey })
): Observable<V> =>
("getSignal$" in node ? node.getSignal$ : node.getState$)({
...objKey,
...partialKey,
} as CK)
const onError = (err: any) => {
const prevPromise = actualInstance.promise

View File

@ -4,3 +4,4 @@ export * from "./promisses"
export * from "./internals"
export * from "./detached-node"
export * from "./record-utils"
export * from "./nested-map"

View File

@ -12,10 +12,15 @@ export interface StateNode<T, K extends StringRecord<any>> {
: (key: K) => Observable<T>
}
export interface Signal<T, K extends StringRecord<any>> {
push: {} extends K ? (value: T) => void : (key: K, value: T) => void
getSignal$: {} extends K ? () => Observable<T> : (key: K) => Observable<T>
}
export type CtxFn<T, K extends StringRecord<any>> = (
ctxValue: <CT>(node: StateNode<CT, any>) => CT,
ctxObservable: <CT, CK extends StringRecord<any>>(
node: StateNode<CT, any>,
node: StateNode<CT, CK> | Signal<CT, CK>,
key: Omit<CK, keyof K>,
) => Observable<CT>,
key: K,