chore: use const enums

This commit is contained in:
Josep M Sobrepere 2020-09-25 13:00:15 +02:00
parent 1fe4f41045
commit 008a3b6b85
6 changed files with 47 additions and 30 deletions

View File

@ -3,3 +3,9 @@ import { Observable } from "rxjs"
export interface BehaviorObservable<T> extends Observable<T> {
getValue: () => any
}
export const enum Action {
Error,
Value,
Suspense,
}

View File

@ -1,7 +1,7 @@
import { Observable, noop } from "rxjs"
import { take, filter, tap } from "rxjs/operators"
import { SUSPENSE } from "../SUSPENSE"
import { BehaviorObservable } from "./BehaviorObservable"
import { BehaviorObservable, Action } from "./BehaviorObservable"
import { EMPTY_VALUE } from "./empty-value"
const reactEnhancer = <T>(source$: Observable<T>): BehaviorObservable<T> => {
@ -42,9 +42,11 @@ const reactEnhancer = <T>(source$: Observable<T>): BehaviorObservable<T> => {
}
}) as BehaviorObservable<T>
let promise: any
let error = EMPTY_VALUE
const getValue = () => {
let promise: undefined | { type: Action.Suspense; payload: Promise<T | void> }
let error:
| typeof EMPTY_VALUE
| { type: Action.Error; payload: any } = EMPTY_VALUE
const getValue = (): { type: Action; payload: any } => {
let timeoutToken
if (error !== EMPTY_VALUE) {
clearTimeout(timeoutToken)
@ -56,25 +58,27 @@ const reactEnhancer = <T>(source$: Observable<T>): BehaviorObservable<T> => {
try {
return {
type: "v",
type: Action.Value,
payload: (source$ as BehaviorObservable<T>).getValue(),
}
} catch (e) {
if (promise) return promise
let value = EMPTY_VALUE
let value:
| typeof EMPTY_VALUE
| { type: Action.Value; payload: T } = EMPTY_VALUE
promise = {
type: "s",
type: Action.Suspense,
payload: result
.pipe(
filter((x) => x !== (SUSPENSE as any)),
take(1),
tap({
next(v) {
value = { type: "v", payload: v }
value = { type: Action.Value, payload: v }
},
error(e) {
error = { type: "e", payload: e }
error = { type: Action.Error, payload: e }
timeoutToken = setTimeout(() => {
error = EMPTY_VALUE
}, 50)
@ -99,7 +103,7 @@ const reactEnhancer = <T>(source$: Observable<T>): BehaviorObservable<T> => {
return promise
}
}
result.getValue = getValue as () => T | Promise<T>
result.getValue = getValue
return result
}

View File

@ -1,12 +1,8 @@
import { useEffect, useReducer } from "react"
import { BehaviorObservable } from "./BehaviorObservable"
import { BehaviorObservable, Action } from "./BehaviorObservable"
import { SUSPENSE } from "../SUSPENSE"
import { Observable } from "rxjs"
const ERROR: "e" = "e"
const VALUE: "v" = "v"
type Action = "e" | "v" | "s"
const reducer = (
current: { type: Action; payload: any },
action: { type: Action; payload: any },
@ -47,14 +43,14 @@ export const useObservable = <O>(
dispatch(source$.getValue())
} else {
dispatch({
type: VALUE,
type: Action.Value,
payload: value,
})
}
},
(error) =>
dispatch({
type: ERROR,
type: Action.Error,
payload: error,
}),
)
@ -62,6 +58,6 @@ export const useObservable = <O>(
}, [source$])
const { type, payload } = state
if (type === VALUE) return payload
if (type === Action.Value) return payload
throw payload
}

View File

@ -7,7 +7,7 @@ import {
distinctUntilChanged,
skipWhile,
} from "rxjs/operators"
import { set, del, collector } from "./internal-utils"
import { CollectorAction, collector } from "./internal-utils"
const defaultFilter = (source$: Observable<any>) =>
source$.pipe(ignoreElements(), startWith(true), endWith(false))
@ -37,6 +37,12 @@ export const collect = <K, V>(
return (source$: Observable<GroupedObservable<K, V>>) =>
collector(source$, (o) =>
map((x) => ({ t: x ? set : del, k: o.key, v: o }))(enhancer(o)),
map((x) => ({
t: x
? (CollectorAction.Set as const)
: (CollectorAction.Delete as const),
k: o.key,
v: o,
}))(enhancer(o)),
)
}

View File

@ -1,6 +1,6 @@
import { Observable, GroupedObservable, OperatorFunction } from "rxjs"
import { map, endWith } from "rxjs/operators"
import { set, del, collector } from "./internal-utils"
import { CollectorAction, collector } from "./internal-utils"
/**
* A pipeable operator that collects all the GroupedObservables emitted by
@ -12,7 +12,7 @@ export const collectValues = <K, V>(): OperatorFunction<
> => (source$: Observable<GroupedObservable<K, V>>): Observable<Map<K, V>> =>
collector(source$, (inner$) =>
inner$.pipe(
map((v) => ({ t: set, k: inner$.key, v })),
endWith({ t: del, k: inner$.key }),
map((v) => ({ t: CollectorAction.Set as const, k: inner$.key, v })),
endWith({ t: CollectorAction.Delete, k: inner$.key }),
),
)

View File

@ -37,24 +37,29 @@ export const scanWithDefaultValue = <I, O>(
return source.pipe(scan(accumulator, seed), defaultStart(seed))
})
export const set = "s" as const
export const del = "d" as const
export const complete = "c" as const
export const enum CollectorAction {
Set,
Delete,
Complete,
}
export const collector = <K, V, VV>(
source: Observable<GroupedObservable<K, V>>,
enhancer: (
source: GroupedObservable<K, V>,
) => Observable<{ t: "d"; k: K } | { t: "s"; k: K; v: VV }>,
) => Observable<
| { t: CollectorAction.Delete; k: K }
| { t: CollectorAction.Set; k: K; v: VV }
>,
): Observable<Map<K, VV>> =>
source.pipe(
publish((x) => x.pipe(mergeMap(enhancer), takeUntil(takeLast(1)(x)))),
endWith({ t: complete }),
endWith({ t: CollectorAction.Complete as const }),
scanWithDefaultValue(
(acc, val) => {
if (val.t === set) {
if (val.t === CollectorAction.Set) {
acc.set(val.k, val.v)
} else if (val.t === del) {
} else if (val.t === CollectorAction.Delete) {
acc.delete(val.k)
} else {
acc.clear()