Retire DerivationFromSource (1/2)

This is supposed to break the build. In the next commit, I'll implement `HotScope.source()` to fix the build.
This commit is contained in:
Aria Minaei 2022-11-28 14:45:39 +01:00
parent 918dd754a7
commit b117ee0aff
5 changed files with 66 additions and 103 deletions

View file

@ -1,7 +1,6 @@
import get from 'lodash-es/get'
import isPlainObject from 'lodash-es/isPlainObject'
import last from 'lodash-es/last'
import DerivationFromSource from './derivations/DerivationFromSource'
import type {IDerivation} from './derivations/IDerivation'
import {isDerivation} from './derivations/IDerivation'
import type {Pointer, PointerType} from './pointer'
@ -10,6 +9,7 @@ import pointer, {getPointerMeta} from './pointer'
import type {$FixMe, $IntentionalAny} from './types'
import type {PathBasedReducer} from './utils/PathBasedReducer'
import updateDeep from './utils/updateDeep'
import prism from './derivations/prism/prism'
type Listener = (newVal: unknown) => void
@ -247,10 +247,14 @@ export default class Atom<State extends {}>
* @param path - The path to create the derivation at.
*/
getIdentityDerivation(path: Array<string | number>): IDerivation<unknown> {
return new DerivationFromSource<$IntentionalAny>(
(listener) => this._onPathValueChange(path, listener),
() => this.getIn(path),
)
const subscribe = (listener: (val: unknown) => void) =>
this._onPathValueChange(path, listener)
const getValue = () => this.getIn(path)
return prism(() => {
return prism.source('value', subscribe, getValue)
})
}
}

View file

@ -1,5 +1,5 @@
import DerivationFromSource from './derivations/DerivationFromSource'
import type {IDerivation} from './derivations/IDerivation'
import prism from './derivations/prism/prism'
import Emitter from './utils/Emitter'
/**
@ -51,10 +51,12 @@ export default class Box<V> implements IBox<V> {
*/
protected _value: V,
) {
this._publicDerivation = new DerivationFromSource(
(listener) => this._emitter.tappable.tap(listener),
this.get.bind(this),
)
const subscribe = (listener: (val: V) => void) =>
this._emitter.tappable.tap(listener)
const getValue = () => this._value
this._publicDerivation = prism(() => {
return prism.source('value', subscribe, getValue)
})
}
/**

View file

@ -1,72 +0,0 @@
import type {VoidFn} from '../types'
import AbstractDerivation from './AbstractDerivation'
const noop = () => {}
/**
* Represents a derivation based on a tappable (subscribable) data source.
*/
export default class DerivationFromSource<V> extends AbstractDerivation<V> {
private _untapFromChanges: () => void
private _cachedValue: undefined | V
private _hasCachedValue: boolean
/**
* @param _tapToSource - A function that takes a listener and subscribes it to the underlying data source.
* @param _getValueFromSource - A function that returns the current value of the data source.
*/
constructor(
private readonly _tapToSource: (listener: (newValue: V) => void) => VoidFn,
private readonly _getValueFromSource: () => V,
) {
super()
this._untapFromChanges = noop
this._cachedValue = undefined
this._hasCachedValue = false
}
/**
* @internal
*/
_recalculate() {
if (this.isHot) {
if (!this._hasCachedValue) {
this._cachedValue = this._getValueFromSource()
this._hasCachedValue = true
}
return this._cachedValue as V
} else {
return this._getValueFromSource()
}
}
/**
* @internal
*/
_keepHot() {
this._hasCachedValue = false
this._cachedValue = undefined
this._untapFromChanges = this._tapToSource((newValue) => {
this._hasCachedValue = true
this._cachedValue = newValue
this._markAsStale(this)
})
}
/**
* @internal
*/
_becomeCold() {
this._untapFromChanges()
this._untapFromChanges = noop
this._hasCachedValue = false
this._cachedValue = undefined
}
/**
* @internal
*/
_reactToDependencyBecomingStale() {}
}

View file

@ -28,7 +28,6 @@ class HotHandle<V> {
this._dependents.delete(d)
}
addDependent(d: IDependent) {
// having no dependents means the prism is currently cold
this._dependents.add(d)
}
private _didMarkDependentsAsStale: boolean = false
@ -328,7 +327,7 @@ class PrismDerivation<V> implements IDerivation<V> {
if (state.hot) {
val = state.handle.getValue()
} else {
val = ColdStuff.calculateColdPrism(this._fn)
val = calculateColdPrism(this._fn)
}
reportResolutionEnd(this)
@ -383,6 +382,11 @@ interface PrismScope {
state<T>(key: string, initialValue: T): [T, (val: T) => void]
ref<T>(key: string, initialValue: T): IRef<T>
sub(key: string): PrismScope
source<V>(
key: string,
subscribe: (fn: (val: V) => void) => VoidFn,
getValue: () => V,
): V
}
class HotScope implements PrismScope {
@ -482,6 +486,12 @@ class HotScope implements PrismScope {
}
this.effects.clear()
}
source<V>(
key: string,
subscribe: (fn: (val: V) => void) => VoidFn,
getValue: () => V,
): V {}
}
function cleanupScopeStack(scope: HotScope) {
@ -694,6 +704,19 @@ const possibleDerivationToValue = <
}
}
function source<V>(
key: string,
subscribe: (fn: (val: V) => void) => VoidFn,
getValue: () => V,
): V {
const scope = hookScopeStack.peek()
if (!scope) {
throw new Error(`prism.source() is called outside of a prism() call.`)
}
return scope.source(key, subscribe, getValue)
}
type IPrismFn = {
<T>(fn: () => T): IDerivation<T>
ref: typeof ref
@ -704,6 +727,7 @@ type IPrismFn = {
scope: typeof scope
sub: typeof sub
inPrism: typeof inPrism
source: typeof source
}
/**
@ -736,28 +760,33 @@ class ColdScope implements PrismScope {
sub(key: string): ColdScope {
return new ColdScope()
}
source<V>(
key: string,
subscribe: (fn: (val: V) => void) => VoidFn,
getValue: () => V,
): V {
return getValue()
}
}
namespace ColdStuff {
export function calculateColdPrism<V>(fn: () => V): V {
const scope = new ColdScope()
hookScopeStack.push(scope)
let value: V
try {
value = fn()
} catch (error) {
console.error(error)
} finally {
const topOfTheStack = hookScopeStack.pop()
if (topOfTheStack !== scope) {
console.warn(
// @todo guide the user to report the bug in an issue
`The Prism hook stack has slipped. This is a bug.`,
)
}
function calculateColdPrism<V>(fn: () => V): V {
const scope = new ColdScope()
hookScopeStack.push(scope)
let value: V
try {
value = fn()
} catch (error) {
console.error(error)
} finally {
const topOfTheStack = hookScopeStack.pop()
if (topOfTheStack !== scope) {
console.warn(
// @todo guide the user to report the bug in an issue
`The Prism hook stack has slipped. This is a bug.`,
)
}
return value!
}
return value!
}
prism.ref = ref
@ -768,5 +797,6 @@ prism.state = state
prism.scope = scope
prism.sub = sub
prism.inPrism = inPrism
prism.source = source
export default prism

View file

@ -9,7 +9,6 @@ export {default as Atom, val, valueDerivation} from './Atom'
export {default as Box} from './Box'
export type {IBox} from './Box'
export {default as AbstractDerivation} from './derivations/AbstractDerivation'
export {default as DerivationFromSource} from './derivations/DerivationFromSource'
export {isDerivation} from './derivations/IDerivation'
export type {IDerivation} from './derivations/IDerivation'
export {default as iterateAndCountTicks} from './derivations/iterateAndCountTicks'