stateshot
Version:
💾 Non-aggressive history state management with structure sharing.
56 lines (50 loc) • 1.71 kB
JavaScript
import { hashFunc } from './hash'
import { safeStringify } from './utils'
const defaultRule = {
// StateNode => { Chunks, Children }
toRecord: node => ({
chunks: [{ ...node, children: undefined }], children: node.children
}),
// { Chunks, Children } => StateNode
fromRecord: ({ chunks, children }) => ({ ...chunks[0], children })
}
export const state2Record = (
stateNode, chunkPool, rules = [], prevRecord = null, pickIndex = -1
) => {
const ruleIndex = rules.findIndex(({ match }) => match(stateNode))
const rule = (rules[ruleIndex] || defaultRule)
const { chunks, children } = rule.toRecord(stateNode)
const recordChildren = children
const hashes = []
for (let i = 0; i < chunks.length; i++) {
const chunkStr = safeStringify(chunks[i], 0)
const hashKey = hashFunc(chunkStr)
hashes.push(hashKey)
chunkPool[hashKey] = chunkStr
}
if (pickIndex !== -1 && Array.isArray(prevRecord && prevRecord.children)) {
const childrenCopy = [...prevRecord.children]
childrenCopy[pickIndex] = state2Record(
recordChildren[pickIndex], chunkPool, rules
)
return { hashes, ruleIndex, children: childrenCopy }
} else {
return {
hashes,
ruleIndex,
children: children &&
children.map(node => state2Record(node, chunkPool, rules))
}
}
}
export const record2State = (recordNode, chunkPool, rules = []) => {
const { hashes, ruleIndex, children } = recordNode
const chunks = hashes.map(hash => JSON.parse(chunkPool[hash]))
const rule = (rules[ruleIndex] || defaultRule)
return rule.fromRecord({
chunks,
children: children && children.map(
node => record2State(node, chunkPool, rules)
)
})
}