@nanostores/logger 0.4.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/action/index.d.ts +35 -0
- package/action/index.js +85 -0
- package/build-logger/index.d.ts +49 -2
- package/build-logger/index.js +61 -11
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/logger/index.js +82 -18
- package/package.json +11 -4
- package/printer/index.d.ts +1 -0
- package/printer/index.js +1 -0
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<img align="right" width="92" height="92" title="Nano Stores logo"
|
|
4
4
|
src="https://nanostores.github.io/nanostores/logo.svg">
|
|
5
5
|
|
|
6
|
-
Logger of lifecycles and
|
|
6
|
+
Logger of lifecycles, changes and actions for **[Nano Stores]**,
|
|
7
7
|
a tiny state manager with many atomic tree-shakable stores.
|
|
8
8
|
|
|
9
9
|
* **Clean.** All messages are stacked in compact, collapsible nested groups.
|
|
@@ -22,5 +22,6 @@ a tiny state manager with many atomic tree-shakable stores.
|
|
|
22
22
|
</picture>
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
|
+
|
|
25
26
|
## Docs
|
|
26
27
|
Read full docs **[here](https://github.com/nanostores/logger#readme)**.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { WritableStore } from 'nanostores'
|
|
2
|
+
|
|
3
|
+
type OmitFirstArg<F> = F extends (x: any, ...args: infer P) => infer R
|
|
4
|
+
? (...args: P) => R
|
|
5
|
+
: never
|
|
6
|
+
|
|
7
|
+
export const lastActionName: unique symbol
|
|
8
|
+
export const lastActionId: unique symbol
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Action is a function which changes the store.
|
|
12
|
+
*
|
|
13
|
+
* This wrap allows DevTools to see the name of action, which changes the store.
|
|
14
|
+
*
|
|
15
|
+
* ```js
|
|
16
|
+
* export const increase = action($counter, 'increase', ($store, value = 1) => {
|
|
17
|
+
* if (validateMax($store.get() + value)) {
|
|
18
|
+
* $store.set($store.get() + value)
|
|
19
|
+
* }
|
|
20
|
+
* return $store.get()
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* increase() //=> 1
|
|
24
|
+
* increase(5) //=> 6
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @param store Store instance.
|
|
28
|
+
* @param actionName Action name for logs.
|
|
29
|
+
* @param cb Function changing the store.
|
|
30
|
+
* @returns Wrapped function with the same arguments.
|
|
31
|
+
*/
|
|
32
|
+
export function action<
|
|
33
|
+
SomeStore extends WritableStore,
|
|
34
|
+
Callback extends ($store: SomeStore, ...args: any[]) => any
|
|
35
|
+
>(store: SomeStore, actionName: string, cb: Callback): OmitFirstArg<Callback>
|
package/action/index.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { startTask } from 'nanostores'
|
|
2
|
+
|
|
3
|
+
export let lastActionId = Symbol('last-action-id')
|
|
4
|
+
export let lastActionName = Symbol('last-action-name')
|
|
5
|
+
|
|
6
|
+
let uid = 0
|
|
7
|
+
let actionHook = Symbol('action-hook')
|
|
8
|
+
|
|
9
|
+
export function onAction($store, listener) {
|
|
10
|
+
$store[actionHook] = (id, actionName, args) => {
|
|
11
|
+
let errorListeners = {}
|
|
12
|
+
let endListeners = {}
|
|
13
|
+
listener({
|
|
14
|
+
actionName,
|
|
15
|
+
args,
|
|
16
|
+
id,
|
|
17
|
+
onEnd: l => {
|
|
18
|
+
;(endListeners[id] || (endListeners[id] = [])).push(l)
|
|
19
|
+
},
|
|
20
|
+
onError: l => {
|
|
21
|
+
;(errorListeners[id] || (errorListeners[id] = [])).push(l)
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
return [
|
|
25
|
+
error => {
|
|
26
|
+
if (errorListeners[id]) {
|
|
27
|
+
for (let l of errorListeners[id]) l({ error })
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
() => {
|
|
31
|
+
if (endListeners[id]) {
|
|
32
|
+
for (let l of endListeners[id]) l()
|
|
33
|
+
delete errorListeners[id]
|
|
34
|
+
delete endListeners[id]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return () => {
|
|
41
|
+
delete $store[actionHook]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function action($store, actionName, cb) {
|
|
46
|
+
return (...args) => {
|
|
47
|
+
let id = ++uid
|
|
48
|
+
let tracker = { ...$store }
|
|
49
|
+
tracker.set = (...setArgs) => {
|
|
50
|
+
$store[lastActionName] = actionName
|
|
51
|
+
$store[lastActionId] = id
|
|
52
|
+
$store.set(...setArgs)
|
|
53
|
+
delete $store[lastActionName]
|
|
54
|
+
delete $store[lastActionId]
|
|
55
|
+
}
|
|
56
|
+
if ($store.setKey) {
|
|
57
|
+
tracker.setKey = (...setArgs) => {
|
|
58
|
+
$store[lastActionName] = actionName
|
|
59
|
+
$store[lastActionId] = id
|
|
60
|
+
$store.setKey(...setArgs)
|
|
61
|
+
delete $store[lastActionName]
|
|
62
|
+
delete $store[lastActionId]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
let onEnd, onError
|
|
66
|
+
if ($store[actionHook]) {
|
|
67
|
+
;[onError, onEnd] = $store[actionHook](id, actionName, args)
|
|
68
|
+
}
|
|
69
|
+
let result = cb(tracker, ...args)
|
|
70
|
+
if (result instanceof Promise) {
|
|
71
|
+
let endTask = startTask()
|
|
72
|
+
return result
|
|
73
|
+
.catch(error => {
|
|
74
|
+
if (onError) onError(error)
|
|
75
|
+
throw error
|
|
76
|
+
})
|
|
77
|
+
.finally(() => {
|
|
78
|
+
endTask()
|
|
79
|
+
if (onEnd) onEnd()
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
if (onEnd) onEnd()
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
85
|
+
}
|
package/build-logger/index.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { AnyStore, Store, StoreValue } from 'nanostores'
|
|
2
2
|
|
|
3
3
|
interface LoggerOptionsMessages {
|
|
4
|
+
/**
|
|
5
|
+
* Disable action logs.
|
|
6
|
+
*/
|
|
7
|
+
action?: boolean
|
|
8
|
+
|
|
4
9
|
/**
|
|
5
10
|
* Disable change logs.
|
|
6
11
|
*/
|
|
@@ -18,6 +23,11 @@ interface LoggerOptionsMessages {
|
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
export interface LoggerOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Disable logs of actions with a specific name.
|
|
28
|
+
*/
|
|
29
|
+
ignoreActions?: string[]
|
|
30
|
+
|
|
21
31
|
/**
|
|
22
32
|
* Disable specific types of logs.
|
|
23
33
|
*/
|
|
@@ -29,13 +39,33 @@ interface EventPayloadBase {
|
|
|
29
39
|
}
|
|
30
40
|
|
|
31
41
|
interface EventChangePayload extends EventPayloadBase {
|
|
42
|
+
actionId?: number
|
|
43
|
+
actionName?: string
|
|
32
44
|
changed?: keyof StoreValue<Store>
|
|
33
45
|
newValue: any
|
|
34
46
|
oldValue?: any
|
|
35
47
|
valueMessage?: string
|
|
36
48
|
}
|
|
37
49
|
|
|
50
|
+
interface EventActionPayload extends EventPayloadBase {
|
|
51
|
+
actionId: number
|
|
52
|
+
actionName: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface EventActionStartPayload extends EventActionPayload {
|
|
56
|
+
args: any[]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface EventActionErrorPayload extends EventActionPayload {
|
|
60
|
+
error: Error
|
|
61
|
+
}
|
|
62
|
+
|
|
38
63
|
interface BuildLoggerEvents {
|
|
64
|
+
action?: {
|
|
65
|
+
end?: (payload: EventActionPayload) => void
|
|
66
|
+
error?: (payload: EventActionErrorPayload) => void
|
|
67
|
+
start?: (payload: EventActionStartPayload) => void
|
|
68
|
+
}
|
|
39
69
|
change?: (payload: EventChangePayload) => void
|
|
40
70
|
mount?: (payload: EventPayloadBase) => void
|
|
41
71
|
unmount?: (payload: EventPayloadBase) => void
|
|
@@ -57,13 +87,30 @@ interface BuildLoggerEvents {
|
|
|
57
87
|
* console.log(`${storeName} was unmounted`)
|
|
58
88
|
* },
|
|
59
89
|
*
|
|
60
|
-
* change: ({ changed, newValue, oldValue, valueMessage }) => {
|
|
90
|
+
* change: ({ actionName, changed, newValue, oldValue, valueMessage }) => {
|
|
61
91
|
* let message = `${storeName} was changed`
|
|
62
92
|
* if (changed) message += `in the ${changed} key`
|
|
63
93
|
* if (oldValue) message += `from ${oldValue}`
|
|
64
94
|
* message += `to ${newValue}`
|
|
95
|
+
* if (actionName) message += `by action ${actionName}`
|
|
65
96
|
* console.log(message, valueMessage)
|
|
66
|
-
* }
|
|
97
|
+
* },
|
|
98
|
+
*
|
|
99
|
+
* action: {
|
|
100
|
+
* start: ({ actionName, args }) => {
|
|
101
|
+
* let message = `${actionName} was started`
|
|
102
|
+
* if (args.length) message += 'with arguments'
|
|
103
|
+
* console.log(message, args)
|
|
104
|
+
* },
|
|
105
|
+
*
|
|
106
|
+
* error: ({ actionName, error }) => {
|
|
107
|
+
* console.log(`${actionName} was failed`, error)
|
|
108
|
+
* },
|
|
109
|
+
*
|
|
110
|
+
* end: ({ actionName }) => {
|
|
111
|
+
* console.log(`${actionName} was ended`)
|
|
112
|
+
* }
|
|
113
|
+
* })
|
|
67
114
|
* ```
|
|
68
115
|
*
|
|
69
116
|
* @param store Any Nano Store
|
package/build-logger/index.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import { onMount, onNotify, onSet } from 'nanostores'
|
|
1
|
+
import { getPath, onMount, onNotify, onSet } from 'nanostores'
|
|
2
|
+
|
|
3
|
+
import { lastActionId, lastActionName, onAction } from '../action/index.js'
|
|
2
4
|
|
|
3
5
|
const isAtom = store => store.setKey === undefined
|
|
4
|
-
const
|
|
6
|
+
const isPrimitive = value => value !== Object(value) || value === null
|
|
7
|
+
/* v8 ignore next 7 */
|
|
8
|
+
const clone = value => {
|
|
9
|
+
try {
|
|
10
|
+
return structuredClone(value)
|
|
11
|
+
} catch {
|
|
12
|
+
return { ...value }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
5
15
|
|
|
6
16
|
function handleMount(store, storeName, messages, events) {
|
|
7
17
|
return onMount(store, () => {
|
|
@@ -16,18 +26,37 @@ function handleMount(store, storeName, messages, events) {
|
|
|
16
26
|
})
|
|
17
27
|
}
|
|
18
28
|
|
|
19
|
-
function handleSet(store, storeName, events) {
|
|
20
|
-
return onSet(store, (
|
|
21
|
-
let
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
function handleSet(store, storeName, messages, ignoreActions, events) {
|
|
30
|
+
return onSet(store, () => {
|
|
31
|
+
let currentActionId = store[lastActionId]
|
|
32
|
+
let currentActionName = store[lastActionName]
|
|
33
|
+
|
|
34
|
+
if (messages.action === false && currentActionId) return
|
|
35
|
+
if (ignoreActions.includes(currentActionName)) return
|
|
36
|
+
|
|
37
|
+
let oldValue = clone(store.value)
|
|
38
|
+
|
|
39
|
+
let unbindNotify = onNotify(store, ({ changed }) => {
|
|
40
|
+
let newValue = clone(store.value)
|
|
41
|
+
|
|
25
42
|
let valueMessage
|
|
26
|
-
if (
|
|
27
|
-
|
|
43
|
+
if (isAtom(store)) {
|
|
44
|
+
if (isPrimitive(newValue) && isPrimitive(oldValue)) {
|
|
45
|
+
valueMessage = `${oldValue} → ${newValue}`
|
|
46
|
+
oldValue = undefined
|
|
47
|
+
newValue = undefined
|
|
48
|
+
}
|
|
49
|
+
} else if (changed) {
|
|
50
|
+
let oldPrimitiveValue = getPath(oldValue, changed)
|
|
51
|
+
let newPrimitiveValue = getPath(newValue, changed)
|
|
52
|
+
if (isPrimitive(oldPrimitiveValue) && isPrimitive(newPrimitiveValue)) {
|
|
53
|
+
valueMessage = `${oldPrimitiveValue} → ${newPrimitiveValue}`
|
|
54
|
+
}
|
|
28
55
|
}
|
|
29
56
|
|
|
30
57
|
events.change({
|
|
58
|
+
actionId: currentActionId,
|
|
59
|
+
actionName: currentActionName,
|
|
31
60
|
changed,
|
|
32
61
|
newValue,
|
|
33
62
|
oldValue,
|
|
@@ -40,7 +69,24 @@ function handleSet(store, storeName, events) {
|
|
|
40
69
|
})
|
|
41
70
|
}
|
|
42
71
|
|
|
72
|
+
function handleAction(store, storeName, ignoreActions, events) {
|
|
73
|
+
return onAction(store, ({ actionName, args, id, onEnd, onError }) => {
|
|
74
|
+
if (ignoreActions.includes(actionName)) return
|
|
75
|
+
|
|
76
|
+
events.action.start({ actionId: id, actionName, args, storeName })
|
|
77
|
+
|
|
78
|
+
onError(({ error }) => {
|
|
79
|
+
events.action.error({ actionId: id, actionName, error, storeName })
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
onEnd(() => {
|
|
83
|
+
events.action.end({ actionId: id, actionName, storeName })
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
43
88
|
export function buildLogger(store, storeName, events, opts = {}) {
|
|
89
|
+
let ignoreActions = opts.ignoreActions || []
|
|
44
90
|
let messages = opts.messages || {}
|
|
45
91
|
let unbind = []
|
|
46
92
|
|
|
@@ -49,7 +95,11 @@ export function buildLogger(store, storeName, events, opts = {}) {
|
|
|
49
95
|
}
|
|
50
96
|
|
|
51
97
|
if (messages.change !== false) {
|
|
52
|
-
unbind.push(handleSet(store, storeName, events))
|
|
98
|
+
unbind.push(handleSet(store, storeName, messages, ignoreActions, events))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (messages.action !== false) {
|
|
102
|
+
unbind.push(handleAction(store, storeName, ignoreActions, events))
|
|
53
103
|
}
|
|
54
104
|
|
|
55
105
|
return () => {
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
package/logger/index.js
CHANGED
|
@@ -2,13 +2,66 @@ import { buildLogger } from '../build-logger/index.js'
|
|
|
2
2
|
import { group, groupEnd, log } from '../printer/index.js'
|
|
3
3
|
|
|
4
4
|
function createLogger(store, storeName, opts) {
|
|
5
|
+
let queue = {}
|
|
6
|
+
|
|
5
7
|
return buildLogger(
|
|
6
8
|
store,
|
|
7
9
|
storeName,
|
|
8
10
|
{
|
|
9
|
-
|
|
11
|
+
action: {
|
|
12
|
+
end: ({ actionId }) => {
|
|
13
|
+
for (let i of queue[actionId]) i()
|
|
14
|
+
delete queue[actionId]
|
|
15
|
+
groupEnd()
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
error: ({ actionId, actionName, error }) => {
|
|
19
|
+
queue[actionId].push(() =>
|
|
20
|
+
log({
|
|
21
|
+
message: [
|
|
22
|
+
['bold', storeName],
|
|
23
|
+
['regular', 'store handled error in action'],
|
|
24
|
+
['bold', actionName]
|
|
25
|
+
],
|
|
26
|
+
type: 'error',
|
|
27
|
+
value: {
|
|
28
|
+
message: error.message
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
)
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
start: ({ actionId, actionName, args }) => {
|
|
35
|
+
queue[actionId] = []
|
|
36
|
+
|
|
37
|
+
let message = [
|
|
38
|
+
['bold', storeName],
|
|
39
|
+
['regular', 'store was changed by action'],
|
|
40
|
+
['bold', actionName]
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
queue[actionId].push(() =>
|
|
44
|
+
group({
|
|
45
|
+
logo: true,
|
|
46
|
+
message,
|
|
47
|
+
type: 'action'
|
|
48
|
+
})
|
|
49
|
+
)
|
|
50
|
+
if (args.length > 0) {
|
|
51
|
+
message.push(['regular', 'with arguments'])
|
|
52
|
+
queue[actionId].push(() =>
|
|
53
|
+
log({
|
|
54
|
+
type: 'arguments',
|
|
55
|
+
value: args
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
change: ({ actionId, changed, newValue, oldValue, valueMessage }) => {
|
|
10
63
|
let groupLog = {
|
|
11
|
-
logo:
|
|
64
|
+
logo: typeof actionId === 'undefined',
|
|
12
65
|
message: [
|
|
13
66
|
['bold', storeName],
|
|
14
67
|
['regular', 'store was changed']
|
|
@@ -22,24 +75,35 @@ function createLogger(store, storeName, opts) {
|
|
|
22
75
|
['regular', 'key']
|
|
23
76
|
)
|
|
24
77
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
78
|
+
|
|
79
|
+
let run = () => {
|
|
80
|
+
group(groupLog)
|
|
81
|
+
if (valueMessage) {
|
|
82
|
+
log({
|
|
83
|
+
message: valueMessage,
|
|
84
|
+
type: 'value'
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
if (newValue) {
|
|
88
|
+
log({
|
|
89
|
+
type: 'new',
|
|
90
|
+
value: newValue
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
if (oldValue) {
|
|
94
|
+
log({
|
|
95
|
+
type: 'old',
|
|
96
|
+
value: oldValue
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
groupEnd()
|
|
31
100
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
log({
|
|
38
|
-
type: 'old',
|
|
39
|
-
value: oldValue
|
|
40
|
-
})
|
|
101
|
+
|
|
102
|
+
if (actionId) {
|
|
103
|
+
queue[actionId].push(run)
|
|
104
|
+
} else {
|
|
105
|
+
run()
|
|
41
106
|
}
|
|
42
|
-
groupEnd()
|
|
43
107
|
},
|
|
44
108
|
|
|
45
109
|
mount: () => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanostores/logger",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Pretty logger of lifecycles and
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Pretty logger of lifecycles, changes and actions for Nano Stores",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nanostores",
|
|
7
7
|
"devtools",
|
|
@@ -20,10 +20,17 @@
|
|
|
20
20
|
".": "./index.js",
|
|
21
21
|
"./package.json": "./package.json"
|
|
22
22
|
},
|
|
23
|
+
"packageManager": "pnpm@10.30.3+sha512.c961d1e0a2d8e354ecaa5166b822516668b7f44cb5bd95122d590dd81922f606f5473b6d23ec4a5be05e7fcd18e8488d47d978bbe981872f1145d06e9a740017",
|
|
23
24
|
"engines": {
|
|
24
|
-
"node": "^
|
|
25
|
+
"node": "^20.0.0 || >=22.0.0"
|
|
25
26
|
},
|
|
27
|
+
"funding": [
|
|
28
|
+
{
|
|
29
|
+
"type": "buymeacoffee",
|
|
30
|
+
"url": "https://buymeacoffee.com/euaaaio"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
26
33
|
"peerDependencies": {
|
|
27
|
-
"nanostores": "
|
|
34
|
+
"nanostores": "^0.10.0 || ^0.11.0 || ^1.0.0"
|
|
28
35
|
}
|
|
29
36
|
}
|
package/printer/index.d.ts
CHANGED