theatre/packages/dataverse/src/derivations/prism/discoveryMechanism.ts

99 lines
2.4 KiB
TypeScript

import type {$IntentionalAny} from '../../types'
import Stack from '../../utils/Stack'
import type {IDerivation} from '../IDerivation'
function createMechanism() {
const noop = () => {}
const stack = new Stack<Collector>()
const noopCollector: Collector = noop
type Collector = (d: IDerivation<$IntentionalAny>) => void
const pushCollector = (collector: Collector): void => {
stack.push(collector)
}
const popCollector = (collector: Collector): void => {
const existing = stack.peek()
if (existing !== collector) {
throw new Error(`Popped collector is not on top of the stack`)
}
stack.pop()
}
const startIgnoringDependencies = () => {
stack.push(noopCollector)
}
const stopIgnoringDependencies = () => {
if (stack.peek() !== noopCollector) {
if (process.env.NODE_ENV === 'development') {
console.warn('This should never happen')
}
} else {
stack.pop()
}
}
const reportResolutionStart = (d: IDerivation<$IntentionalAny>) => {
const possibleCollector = stack.peek()
if (possibleCollector) {
possibleCollector(d)
}
stack.push(noopCollector)
}
const reportResolutionEnd = (_d: IDerivation<$IntentionalAny>) => {
stack.pop()
}
return {
type: 'Dataverse_discoveryMechanism' as 'Dataverse_discoveryMechanism',
startIgnoringDependencies,
stopIgnoringDependencies,
reportResolutionStart,
reportResolutionEnd,
pushCollector,
popCollector,
}
}
function getSharedMechanism(): ReturnType<typeof createMechanism> {
const varName = '__dataverse_discoveryMechanism_sharedStack'
const root =
typeof window !== 'undefined'
? window
: typeof global !== 'undefined'
? global
: {}
if (root) {
const existingMechanism: ReturnType<typeof createMechanism> | undefined =
// @ts-ignore ignore
root[varName]
if (
existingMechanism &&
typeof existingMechanism === 'object' &&
existingMechanism.type === 'Dataverse_discoveryMechanism'
) {
return existingMechanism
} else {
const mechanism = createMechanism()
// @ts-ignore ignore
root[varName] = mechanism
return mechanism
}
} else {
return createMechanism()
}
}
export const {
startIgnoringDependencies,
stopIgnoringDependencies,
reportResolutionEnd,
reportResolutionStart,
pushCollector,
popCollector,
} = getSharedMechanism()