@nanostores/logger
Version:
Pretty logger of lifecycles, changes and actions for Nano Stores
109 lines (89 loc) • 2.99 kB
JavaScript
import { getPath, onMount, onNotify, onSet } from 'nanostores'
import { lastActionId, lastActionName, onAction } from '../action/index.js'
const isAtom = store => store.setKey === undefined
const isPrimitive = value => value !== Object(value) || value === null
/* v8 ignore next 7 */
const clone = value => {
try {
return structuredClone(value)
} catch {
return { ...value }
}
}
function handleMount(store, storeName, messages, events) {
return onMount(store, () => {
if (messages.mount !== false) {
events.mount({ storeName })
}
return () => {
if (messages.unmount !== false) {
events.unmount({ storeName })
}
}
})
}
function handleSet(store, storeName, messages, ignoreActions, events) {
return onSet(store, () => {
let currentActionId = store[lastActionId]
let currentActionName = store[lastActionName]
if (messages.action === false && currentActionId) return
if (ignoreActions.includes(currentActionName)) return
let oldValue = clone(store.value)
let unbindNotify = onNotify(store, ({ changed }) => {
let newValue = clone(store.value)
let valueMessage
if (isAtom(store)) {
if (isPrimitive(newValue) && isPrimitive(oldValue)) {
valueMessage = `${oldValue} → ${newValue}`
oldValue = undefined
newValue = undefined
}
} else if (changed) {
let oldPrimitiveValue = getPath(oldValue, changed)
let newPrimitiveValue = getPath(newValue, changed)
if (isPrimitive(oldPrimitiveValue) && isPrimitive(newPrimitiveValue)) {
valueMessage = `${oldPrimitiveValue} → ${newPrimitiveValue}`
}
}
events.change({
actionId: currentActionId,
actionName: currentActionName,
changed,
newValue,
oldValue,
storeName,
valueMessage
})
unbindNotify()
})
})
}
function handleAction(store, storeName, ignoreActions, events) {
return onAction(store, ({ actionName, args, id, onEnd, onError }) => {
if (ignoreActions.includes(actionName)) return
events.action.start({ actionId: id, actionName, args, storeName })
onError(({ error }) => {
events.action.error({ actionId: id, actionName, error, storeName })
})
onEnd(() => {
events.action.end({ actionId: id, actionName, storeName })
})
})
}
export function buildLogger(store, storeName, events, opts = {}) {
let ignoreActions = opts.ignoreActions || []
let messages = opts.messages || {}
let unbind = []
if (messages.mount !== false || messages.unmount !== false) {
unbind.push(handleMount(store, storeName, messages, events))
}
if (messages.change !== false) {
unbind.push(handleSet(store, storeName, messages, ignoreActions, events))
}
if (messages.action !== false) {
unbind.push(handleAction(store, storeName, ignoreActions, events))
}
return () => {
for (let i of unbind) i()
}
}