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 get from 'lodash-es/get'
import isPlainObject from 'lodash-es/isPlainObject' import isPlainObject from 'lodash-es/isPlainObject'
import last from 'lodash-es/last' import last from 'lodash-es/last'
import DerivationFromSource from './derivations/DerivationFromSource'
import type {IDerivation} from './derivations/IDerivation' import type {IDerivation} from './derivations/IDerivation'
import {isDerivation} from './derivations/IDerivation' import {isDerivation} from './derivations/IDerivation'
import type {Pointer, PointerType} from './pointer' import type {Pointer, PointerType} from './pointer'
@ -10,6 +9,7 @@ import pointer, {getPointerMeta} from './pointer'
import type {$FixMe, $IntentionalAny} from './types' import type {$FixMe, $IntentionalAny} from './types'
import type {PathBasedReducer} from './utils/PathBasedReducer' import type {PathBasedReducer} from './utils/PathBasedReducer'
import updateDeep from './utils/updateDeep' import updateDeep from './utils/updateDeep'
import prism from './derivations/prism/prism'
type Listener = (newVal: unknown) => void type Listener = (newVal: unknown) => void
@ -247,10 +247,14 @@ export default class Atom<State extends {}>
* @param path - The path to create the derivation at. * @param path - The path to create the derivation at.
*/ */
getIdentityDerivation(path: Array<string | number>): IDerivation<unknown> { getIdentityDerivation(path: Array<string | number>): IDerivation<unknown> {
return new DerivationFromSource<$IntentionalAny>( const subscribe = (listener: (val: unknown) => void) =>
(listener) => this._onPathValueChange(path, listener), this._onPathValueChange(path, listener)
() => this.getIn(path),
) 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 type {IDerivation} from './derivations/IDerivation'
import prism from './derivations/prism/prism'
import Emitter from './utils/Emitter' import Emitter from './utils/Emitter'
/** /**
@ -51,10 +51,12 @@ export default class Box<V> implements IBox<V> {
*/ */
protected _value: V, protected _value: V,
) { ) {
this._publicDerivation = new DerivationFromSource( const subscribe = (listener: (val: V) => void) =>
(listener) => this._emitter.tappable.tap(listener), this._emitter.tappable.tap(listener)
this.get.bind(this), 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) this._dependents.delete(d)
} }
addDependent(d: IDependent) { addDependent(d: IDependent) {
// having no dependents means the prism is currently cold
this._dependents.add(d) this._dependents.add(d)
} }
private _didMarkDependentsAsStale: boolean = false private _didMarkDependentsAsStale: boolean = false
@ -328,7 +327,7 @@ class PrismDerivation<V> implements IDerivation<V> {
if (state.hot) { if (state.hot) {
val = state.handle.getValue() val = state.handle.getValue()
} else { } else {
val = ColdStuff.calculateColdPrism(this._fn) val = calculateColdPrism(this._fn)
} }
reportResolutionEnd(this) reportResolutionEnd(this)
@ -383,6 +382,11 @@ interface PrismScope {
state<T>(key: string, initialValue: T): [T, (val: T) => void] state<T>(key: string, initialValue: T): [T, (val: T) => void]
ref<T>(key: string, initialValue: T): IRef<T> ref<T>(key: string, initialValue: T): IRef<T>
sub(key: string): PrismScope sub(key: string): PrismScope
source<V>(
key: string,
subscribe: (fn: (val: V) => void) => VoidFn,
getValue: () => V,
): V
} }
class HotScope implements PrismScope { class HotScope implements PrismScope {
@ -482,6 +486,12 @@ class HotScope implements PrismScope {
} }
this.effects.clear() this.effects.clear()
} }
source<V>(
key: string,
subscribe: (fn: (val: V) => void) => VoidFn,
getValue: () => V,
): V {}
} }
function cleanupScopeStack(scope: HotScope) { 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 = { type IPrismFn = {
<T>(fn: () => T): IDerivation<T> <T>(fn: () => T): IDerivation<T>
ref: typeof ref ref: typeof ref
@ -704,6 +727,7 @@ type IPrismFn = {
scope: typeof scope scope: typeof scope
sub: typeof sub sub: typeof sub
inPrism: typeof inPrism inPrism: typeof inPrism
source: typeof source
} }
/** /**
@ -736,28 +760,33 @@ class ColdScope implements PrismScope {
sub(key: string): ColdScope { sub(key: string): ColdScope {
return new ColdScope() return new ColdScope()
} }
source<V>(
key: string,
subscribe: (fn: (val: V) => void) => VoidFn,
getValue: () => V,
): V {
return getValue()
}
} }
namespace ColdStuff { function calculateColdPrism<V>(fn: () => V): V {
export function calculateColdPrism<V>(fn: () => V): V { const scope = new ColdScope()
const scope = new ColdScope() hookScopeStack.push(scope)
hookScopeStack.push(scope) let value: V
let value: V try {
try { value = fn()
value = fn() } catch (error) {
} catch (error) { console.error(error)
console.error(error) } finally {
} finally { const topOfTheStack = hookScopeStack.pop()
const topOfTheStack = hookScopeStack.pop() if (topOfTheStack !== scope) {
if (topOfTheStack !== scope) { console.warn(
console.warn( // @todo guide the user to report the bug in an issue
// @todo guide the user to report the bug in an issue `The Prism hook stack has slipped. This is a bug.`,
`The Prism hook stack has slipped. This is a bug.`, )
)
}
} }
return value!
} }
return value!
} }
prism.ref = ref prism.ref = ref
@ -768,5 +797,6 @@ prism.state = state
prism.scope = scope prism.scope = scope
prism.sub = sub prism.sub = sub
prism.inPrism = inPrism prism.inPrism = inPrism
prism.source = source
export default prism export default prism

View file

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