@zedux/core
Version:
A high-level, declarative, composable form of Redux
94 lines (75 loc) • 2.51 kB
text/typescript
import { Action, ActionChain, ActionMeta } from '../types'
import { detailedTypeof } from './detailedTypeof'
const assertActionExists = (action: ActionChain) => {
if (action) return
throw new Error(
`Zedux: Invalid action chain. The last node in the chain must be either a valid action object with a non-empty "type" property or an effect with a non-empty "effectType" property. Received ${detailedTypeof(
action
)}`
)
}
const getNewRoot = <T extends ActionChain>(
currentNode: T,
prevNode: T | null,
rootNode: T | null
): T => {
// If the match is at the top layer, just return the next layer
if (!prevNode || !rootNode) return currentNode.payload
// If the match is at least one layer deep, swap out the target layer
// and return the new root of the action chain
prevNode.payload = currentNode.payload
return rootNode
}
/**
* Returns the value of the metaData field of the first ActionMeta object in the
* chain with the given metaType.
*/
export const getMetaData = (action: ActionChain, metaType: string) => {
while ((action as ActionMeta).metaType) {
if ((action as ActionMeta).metaType === metaType) {
return (action as ActionMeta).metaData
}
action = action.payload
if (DEV) {
assertActionExists(action)
}
}
}
/**
* Strips all ActionMeta nodes off an ActionChain and returns the wrapped Action
*/
export const removeAllMeta = (action: ActionChain) => {
while ((action as ActionMeta).metaType) {
action = action.payload
if (DEV) {
assertActionExists(action)
}
}
return action as Action
}
/**
* Removes the first found meta node with the given metaType in the given action
* chain.
*
* The metaType does not have to exist in the action chain (though this'll be
* pretty inefficient and wasteful if it doesn't).
*/
export const removeMeta = (action: ActionChain, metaType: string) => {
let currentNode = action
let prevNode = null
let rootNode = null
while ((currentNode as ActionMeta).metaType) {
if ((currentNode as ActionMeta).metaType === metaType) {
return getNewRoot(currentNode, prevNode, rootNode)
}
// Move down the chain
const clonedNode = { ...currentNode }
prevNode && (prevNode.payload = clonedNode)
prevNode = clonedNode
currentNode = currentNode.payload
// If this will be the new root, remember it
rootNode || (rootNode = prevNode)
}
// No match found; return the original action chain
return action
}