@nanostores/logger 0.1.0 → 0.2.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 CHANGED
@@ -3,10 +3,24 @@
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, actions and changes for **[Nano Stores]**,
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
+ * **Clean.** All messages are stacked in compact, collapsible nested groups.
10
+ * **Descriptive.** Detailed descriptions with a clear comparison of the old and new values.
11
+ * **Pretty designed.** Compact logo and color badges for quick reading.
12
+ * **Flexible.** Ability to disable and filter certain types of messages.
13
+ * **Supports all types of stores**: Atom, Map and Deep Map.
14
+
9
15
  [Nano Stores]: https://github.com/nanostores/nanostores/
10
16
 
17
+ <p align="center">
18
+ <picture>
19
+ <source media="(prefers-color-scheme: dark)" srcset="./img/dark.png">
20
+ <source media="(prefers-color-scheme: light)" srcset="./img/light.png">
21
+ <img alt="Nano Stores Logger" src="./img/light.png">
22
+ </picture>
23
+ </p>
24
+
11
25
  ## Docs
12
26
  Read full docs **[here](https://github.com/nanostores/logger#readme)**.
@@ -0,0 +1,126 @@
1
+ import type { AnyStore, Store, StoreValue } from 'nanostores'
2
+
3
+ interface LoggerOptionsMessages {
4
+ /**
5
+ * Disable action logs.
6
+ */
7
+ action?: boolean
8
+
9
+ /**
10
+ * Disable change logs.
11
+ */
12
+ change?: boolean
13
+
14
+ /**
15
+ * Disable mount logs.
16
+ */
17
+ mount?: boolean
18
+
19
+ /**
20
+ * Disable unmount logs.
21
+ */
22
+ unmount?: boolean
23
+ }
24
+
25
+ export interface LoggerOptions {
26
+ /**
27
+ * Disable logs of actions with a specific name.
28
+ */
29
+ ignoreActions?: string[]
30
+
31
+ /**
32
+ * Disable specific types of logs.
33
+ */
34
+ messages?: LoggerOptionsMessages
35
+ }
36
+
37
+ interface EventPayloadBase {
38
+ storeName: string
39
+ }
40
+
41
+ interface EventChangePayload extends EventPayloadBase {
42
+ actionId?: number
43
+ actionName?: string
44
+ changed?: keyof StoreValue<Store>
45
+ newValue: any
46
+ oldValue?: any
47
+ valueMessage?: string
48
+ }
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
+
63
+ interface BuildLoggerEvents {
64
+ action?: {
65
+ end?: (payload: EventActionPayload) => void
66
+ error?: (payload: EventActionErrorPayload) => void
67
+ start?: (payload: EventActionStartPayload) => void
68
+ }
69
+ change?: (payload: EventChangePayload) => void
70
+ mount?: (payload: EventPayloadBase) => void
71
+ unmount?: (payload: EventPayloadBase) => void
72
+ }
73
+
74
+ /**
75
+ * Builds logger for Nano Stores.
76
+ *
77
+ * ```js
78
+ * import { buildLogger } from '@nanostores/logger'
79
+ * import { $profile } from './stores/index.js'
80
+ *
81
+ * let destroy = buildLogger($profile, 'Profile', {
82
+ * mount: ({ storeName }) => {
83
+ * console.log(`${storeName} was mounted`)
84
+ * },
85
+ *
86
+ * unmount: ({ storeName }) => {
87
+ * console.log(`${storeName} was unmounted`)
88
+ * },
89
+ *
90
+ * change: ({ actionName, changed, newValue, oldValue, valueMessage }) => {
91
+ * let message = `${storeName} was changed`
92
+ * if (changed) message += `in the ${changed} key`
93
+ * if (oldValue) message += `from ${oldValue}`
94
+ * message += `to ${newValue}`
95
+ * if (actionName) message += `by action ${actionName}`
96
+ * console.log(message, valueMessage)
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
+ * }
114
+ * ```
115
+ *
116
+ * @param store Any Nano Store
117
+ * @param storeName Store name.
118
+ * @param events Events to log.
119
+ * @param opts Logger options.
120
+ */
121
+ export function buildLogger(
122
+ store: AnyStore,
123
+ storeName: string,
124
+ events: BuildLoggerEvents,
125
+ opts?: LoggerOptions
126
+ ): () => void
@@ -0,0 +1,94 @@
1
+ import {
2
+ actionId,
3
+ lastAction,
4
+ onAction,
5
+ onMount,
6
+ onNotify,
7
+ onSet
8
+ } from 'nanostores'
9
+
10
+ const isAtom = store => store.setKey === undefined
11
+ const isDeepMapKey = key => /.+(\..+|\[\d+\.*])/.test(key)
12
+
13
+ function handleMount(store, storeName, messages, events) {
14
+ return onMount(store, () => {
15
+ if (messages.mount !== false) {
16
+ events.mount({ storeName })
17
+ }
18
+ return () => {
19
+ if (messages.unmount !== false) {
20
+ events.unmount({ storeName })
21
+ }
22
+ }
23
+ })
24
+ }
25
+
26
+ function handleAction(store, storeName, ignoreActions, events) {
27
+ return onAction(store, ({ actionName, args, id, onEnd, onError }) => {
28
+ if (ignoreActions && ignoreActions.includes(actionName)) return
29
+
30
+ events.action.start({ actionId: id, actionName, args, storeName })
31
+
32
+ onError(({ error }) => {
33
+ events.action.error({ actionId: id, actionName, error, storeName })
34
+ })
35
+
36
+ onEnd(() => {
37
+ events.action.end({ actionId: id, actionName, storeName })
38
+ })
39
+ })
40
+ }
41
+
42
+ function handleSet(store, storeName, messages, ignoreActions, events) {
43
+ return onSet(store, ({ changed }) => {
44
+ let currentActionId = store[actionId]
45
+ let currentActionName = store[lastAction]
46
+
47
+ if (messages.action === false && currentActionId) return
48
+ if (ignoreActions && ignoreActions.includes(currentActionName)) return
49
+
50
+ let oldValue = isAtom(store) ? store.value : { ...store.value }
51
+ oldValue = isDeepMapKey(changed) ? structuredClone(oldValue) : oldValue
52
+ let unbindNotify = onNotify(store, () => {
53
+ let newValue = store.value
54
+ let valueMessage
55
+ if (changed && !isDeepMapKey(changed)) {
56
+ valueMessage = `${oldValue[changed]} → ${newValue[changed]}`
57
+ }
58
+
59
+ events.change({
60
+ actionId: currentActionId,
61
+ actionName: currentActionName,
62
+ changed,
63
+ newValue,
64
+ oldValue,
65
+ storeName,
66
+ valueMessage
67
+ })
68
+
69
+ unbindNotify()
70
+ })
71
+ })
72
+ }
73
+
74
+ export function buildLogger(store, storeName, events, opts = {}) {
75
+ let ignoreActions = opts.ignoreActions
76
+ let messages = opts.messages || {}
77
+ let unbind = []
78
+
79
+ if (messages.mount !== false || messages.unmount !== false) {
80
+ unbind.push(handleMount(store, storeName, messages, events))
81
+ }
82
+
83
+ if (messages.action !== false) {
84
+ unbind.push(handleAction(store, storeName, ignoreActions, events))
85
+ }
86
+
87
+ if (messages.change !== false) {
88
+ unbind.push(handleSet(store, storeName, messages, ignoreActions, events))
89
+ }
90
+
91
+ return () => {
92
+ for (let i of unbind) i()
93
+ }
94
+ }
@@ -0,0 +1,25 @@
1
+ import type { MapCreator, MapStore } from 'nanostores'
2
+
3
+ import type { LoggerOptions } from '../build-logger/index.js'
4
+
5
+ interface CreatorLoggerOptions extends LoggerOptions {
6
+ /**
7
+ * Custom name getter for stores built with creators.
8
+ *
9
+ * @param creatorName Name of the creator.
10
+ * @param store Store built by the creator.
11
+ * @returns Custom store name.
12
+ */
13
+ nameGetter: (creatorName: string, store: MapStore) => string
14
+ }
15
+
16
+ /**
17
+ * Displays Nano Stores events in browser console.
18
+ *
19
+ * @param creators Creators for logging.
20
+ * @param opts Logger options.
21
+ */
22
+ export function creatorLogger(
23
+ creators: { [key: string]: MapCreator },
24
+ opts?: CreatorLoggerOptions
25
+ ): () => void
@@ -0,0 +1,60 @@
1
+ import { logger } from '../logger/index.js'
2
+ import { log } from '../printer/index.js'
3
+
4
+ function onBuild(creator, listener) {
5
+ let originBuild = creator.build
6
+ creator.build = (...args) => {
7
+ let store = originBuild(...args)
8
+ listener(store)
9
+ return store
10
+ }
11
+ return () => {
12
+ creator.build = originBuild
13
+ }
14
+ }
15
+
16
+ function createCreatorLogger(creator, creatorName, opts) {
17
+ let nameGetter = opts.nameGetter
18
+ delete opts.nameGetter
19
+
20
+ let unbind = []
21
+ unbind.push(
22
+ onBuild(creator, store => {
23
+ let storeName = nameGetter(creatorName, store)
24
+
25
+ log({
26
+ logo: true,
27
+ message: [
28
+ ['bold', storeName],
29
+ ['regular', 'store was built by'],
30
+ ['bold', creatorName],
31
+ ['regular', 'creator']
32
+ ],
33
+ type: 'build'
34
+ })
35
+
36
+ unbind.push(logger({ [storeName]: store }, opts))
37
+ })
38
+ )
39
+
40
+ return () => {
41
+ for (let i of unbind) i()
42
+ }
43
+ }
44
+
45
+ const defaultNameGetter = (creatorName, store) => {
46
+ return `${creatorName}:${store.value.id}`
47
+ }
48
+
49
+ export function creatorLogger(creators, opts = {}) {
50
+ opts = {
51
+ nameGetter: defaultNameGetter,
52
+ ...opts
53
+ }
54
+ let unbind = Object.entries(creators).map(([creatorName, creator]) =>
55
+ createCreatorLogger(creator, creatorName, opts)
56
+ )
57
+ return () => {
58
+ for (let i of unbind) i()
59
+ }
60
+ }
package/index.d.ts CHANGED
@@ -1 +1,4 @@
1
+ export { buildLogger } from './build-logger/index.js'
2
+ export { creatorLogger } from './creator-logger/index.js'
1
3
  export { logger } from './logger/index.js'
4
+ export { group, groupEnd, log } from './printer/index.js'
package/index.js CHANGED
@@ -1 +1,4 @@
1
+ export { buildLogger } from './build-logger/index.js'
2
+ export { creatorLogger } from './creator-logger/index.js'
1
3
  export { logger } from './logger/index.js'
4
+ export { group, groupEnd, log } from './printer/index.js'
package/logger/index.d.ts CHANGED
@@ -1,49 +1,17 @@
1
1
  import type { AnyStore } from 'nanostores'
2
2
 
3
- interface LoggerOptionsMessages {
4
- /**
5
- * Disable action logs.
6
- */
7
- action?: boolean
8
-
9
- /**
10
- * Disable change logs.
11
- */
12
- change?: boolean
13
-
14
- /**
15
- * Disable mount logs.
16
- */
17
- mount?: boolean
18
-
19
- /**
20
- * Disable unmount logs.
21
- */
22
- unmount?: boolean
23
- }
24
-
25
- interface LoggerOptions {
26
- /**
27
- * Disable action logs with specific name.
28
- */
29
- ignoreActions?: string[]
30
-
31
- /**
32
- * Disable specific log types.
33
- */
34
- messages?: LoggerOptionsMessages
35
- }
3
+ import type { LoggerOptions } from '../build-logger/index.js'
36
4
 
37
5
  /**
38
- * Display Nanostores events in browser console.
6
+ * Displays Nano Stores events in browser console.
39
7
  *
40
8
  * ```js
41
9
  * import { logger } from '@nanostores/logger'
42
10
  * import { $profile, $users } from './stores/index.js'
43
11
  *
44
12
  * let destroy = logger({
45
- * 'Profile Store': $profile,
46
- * 'Users Store': $users
13
+ * 'Profile': $profile,
14
+ * 'Users': $users
47
15
  * })
48
16
  * ```
49
17
  *
package/logger/index.js CHANGED
@@ -1,253 +1,133 @@
1
- import {
2
- actionId,
3
- lastAction,
4
- onAction,
5
- onMount,
6
- onNotify,
7
- onSet
8
- } from 'nanostores'
1
+ import { buildLogger } from '../build-logger/index.js'
2
+ import { group, groupEnd, log } from '../printer/index.js'
9
3
 
10
- function badge(color) {
11
- return `
12
- padding: 0 5px 2px;
13
- margin-right: 5px;
14
- font-weight: 400;
15
- color: white;
16
- background-color: ${color};
17
- `
18
- }
19
-
20
- function borders(full) {
21
- return `border-radius: ${full ? '4px' : '0 4px 4px 0'};`
22
- }
23
-
24
- const STYLES = {
25
- badges: {
26
- action: badge('#5351A4'),
27
- arguments: badge('#429BD7'),
28
- change: badge('#0E8A00'),
29
- error: badge('#c21f1f'),
30
- mount: badge('#1F49E0'),
31
- new: badge('#4FA574'),
32
- old: badge('#a44f4f'),
33
- unmount: badge('#5C5C5C'),
34
- value: badge('#429BD7')
35
- },
36
- bold: 'font-weight: 700',
37
- logo: `
38
- padding: 0 5px 2px;
39
- color: white;
40
- background-color: black;
41
- border-radius: 4px 0 0 4px;
42
- `,
43
- regular: 'font-weight: 400'
44
- }
45
-
46
- function createLog({ logo, message, type, value }) {
47
- let template = ''
48
- let args = []
49
-
50
- if (logo) {
51
- template = `%c𝖓`
52
- args.push(STYLES.logo)
53
- }
54
-
55
- template += `%c${type}`
56
- args.push(STYLES.badges[type] + borders(!logo))
57
-
58
- if (message) {
59
- if (Array.isArray(message)) {
60
- message.forEach(([style, text]) => {
61
- template += `%c ${text}`
62
- args.push(STYLES[style])
63
- })
64
- } else {
65
- template += `%c ${message}`
66
- args.push(STYLES.text)
67
- }
68
- }
69
-
70
- if (value) {
71
- args.push(value)
72
- }
4
+ function createLogger(store, storeName, opts) {
5
+ let queue = {}
73
6
 
74
- args.unshift(template)
7
+ return buildLogger(
8
+ store,
9
+ storeName,
10
+ {
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
+ },
75
61
 
76
- return args
77
- }
62
+ change: ({ actionId, changed, newValue, oldValue, valueMessage }) => {
63
+ let groupLog = {
64
+ logo: typeof actionId === 'undefined',
65
+ message: [
66
+ ['bold', storeName],
67
+ ['regular', 'store was changed']
68
+ ],
69
+ type: 'change'
70
+ }
71
+ if (changed) {
72
+ groupLog.message.push(
73
+ ['regular', 'in the'],
74
+ ['bold', changed],
75
+ ['regular', 'key']
76
+ )
77
+ }
78
78
 
79
- const log = args => console.log(...createLog(args))
80
- const group = args => console.groupCollapsed(...createLog(args))
81
- const groupEnd = () => console.groupEnd()
79
+ let run = () => {
80
+ group(groupLog)
81
+ if (valueMessage) {
82
+ log({
83
+ message: valueMessage,
84
+ type: 'value'
85
+ })
86
+ }
87
+ log({
88
+ type: 'new',
89
+ value: newValue
90
+ })
91
+ if (oldValue) {
92
+ log({
93
+ type: 'old',
94
+ value: oldValue
95
+ })
96
+ }
97
+ groupEnd()
98
+ }
82
99
 
83
- const isAtom = store => store.setKey === undefined
84
- const isDeepMapKey = key => /.+(\..+|\[\d+\.*])/.test(key)
100
+ if (actionId) {
101
+ queue[actionId].push(run)
102
+ } else {
103
+ run()
104
+ }
105
+ },
85
106
 
86
- function handleMount(store, storeName, messages) {
87
- return onMount(store, () => {
88
- if (messages.mount !== false) {
89
- log({
90
- logo: true,
91
- message: [
92
- ['bold', storeName],
93
- ['regular', 'store was mounted']
94
- ],
95
- type: 'mount'
96
- })
97
- }
98
- return () => {
99
- if (messages.unmount !== false) {
107
+ mount: () => {
100
108
  log({
101
109
  logo: true,
102
110
  message: [
103
111
  ['bold', storeName],
104
- ['regular', 'store was unmounted']
112
+ ['regular', 'store was mounted']
105
113
  ],
106
- type: 'unmount'
114
+ type: 'mount'
107
115
  })
108
- }
109
- }
110
- })
111
- }
116
+ },
112
117
 
113
- function handleAction(store, storeName, queue, ignoreActions) {
114
- return onAction(store, ({ actionName, args, id, onEnd, onError }) => {
115
- if (ignoreActions && ignoreActions.includes(actionName)) return
116
-
117
- queue[id] = []
118
-
119
- let message = [
120
- ['bold', storeName],
121
- ['regular', 'store was changed by action'],
122
- ['bold', actionName]
123
- ]
124
-
125
- queue[id].push(() =>
126
- group({
127
- logo: true,
128
- message,
129
- type: 'action'
130
- })
131
- )
132
- if (args.length > 0) {
133
- message.push(['regular', 'with arguments'])
134
- queue[id].push(() =>
135
- log({
136
- type: 'arguments',
137
- value: args
138
- })
139
- )
140
- }
141
-
142
- onError(({ error }) => {
143
- queue[id].push(() =>
118
+ unmount: () => {
144
119
  log({
120
+ logo: true,
145
121
  message: [
146
122
  ['bold', storeName],
147
- ['regular', 'store handled error in action'],
148
- ['bold', actionName]
123
+ ['regular', 'store was unmounted']
149
124
  ],
150
- type: 'error',
151
- value: {
152
- message: error.message
153
- }
125
+ type: 'unmount'
154
126
  })
155
- )
156
- })
157
-
158
- onEnd(() => {
159
- for (let i of queue[id]) i()
160
- delete queue[id]
161
- groupEnd()
162
- })
163
- })
164
- }
165
-
166
- function handleSet(store, storeName, queue, messages, ignoreActions) {
167
- return onSet(store, ({ changed }) => {
168
- let currentActionId = store[actionId]
169
- let currentActionName = store[lastAction]
170
-
171
- if (messages.action === false && currentActionId) return
172
- if (ignoreActions && ignoreActions.includes(currentActionName)) return
173
-
174
- let groupLog = {
175
- logo: typeof currentActionId === 'undefined',
176
- message: [
177
- ['bold', storeName],
178
- ['regular', 'store was changed']
179
- ],
180
- type: 'change'
181
- }
182
- if (changed) {
183
- groupLog.message.push(
184
- ['regular', 'in the'],
185
- ['bold', changed],
186
- ['regular', 'key']
187
- )
188
- }
189
-
190
- let oldValue = isAtom(store) ? store.value : { ...store.value }
191
- oldValue = isDeepMapKey(changed) ? structuredClone(oldValue) : oldValue
192
- let unbindNotify = onNotify(store, () => {
193
- let newValue = store.value
194
- let valueMessage
195
- if (changed && !isDeepMapKey(changed)) {
196
- valueMessage = `${oldValue[changed]} → ${newValue[changed]}`
197
127
  }
198
-
199
- let run = () => {
200
- group(groupLog)
201
- if (valueMessage) {
202
- log({
203
- message: valueMessage,
204
- type: 'value'
205
- })
206
- }
207
- log({
208
- type: 'new',
209
- value: newValue
210
- })
211
- if (oldValue) {
212
- log({
213
- type: 'old',
214
- value: oldValue
215
- })
216
- }
217
- groupEnd()
218
- }
219
-
220
- if (currentActionId) {
221
- queue[currentActionId].push(run)
222
- } else {
223
- run()
224
- }
225
- unbindNotify()
226
- })
227
- })
228
- }
229
-
230
- function createLogger(store, storeName, opts) {
231
- let ignoreActions = opts.ignoreActions
232
- let messages = opts.messages || {}
233
- let unbind = []
234
- let queue = {}
235
-
236
- if (messages.mount !== false || messages.unmount !== false) {
237
- unbind.push(handleMount(store, storeName, messages))
238
- }
239
-
240
- if (messages.action !== false) {
241
- unbind.push(handleAction(store, storeName, queue, ignoreActions))
242
- }
243
-
244
- if (messages.change !== false) {
245
- unbind.push(handleSet(store, storeName, queue, messages, ignoreActions))
246
- }
247
-
248
- return () => {
249
- for (let i of unbind) i()
250
- }
128
+ },
129
+ opts
130
+ )
251
131
  }
252
132
 
253
133
  export function logger(stores, opts = {}) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nanostores/logger",
3
- "version": "0.1.0",
4
- "description": "Logger of lifecycles, actions and changes for Nano Stores",
3
+ "version": "0.2.0",
4
+ "description": "Pretty logger of lifecycles, changes and actions for Nano Stores",
5
5
  "keywords": [
6
6
  "nanostores",
7
7
  "devtools",
@@ -0,0 +1,55 @@
1
+ type LogType =
2
+ | 'action'
3
+ | 'arguments'
4
+ | 'build'
5
+ | 'change'
6
+ | 'error'
7
+ | 'mount'
8
+ | 'new'
9
+ | 'old'
10
+ | 'unmount'
11
+ | 'value'
12
+ | {
13
+ color: string
14
+ name: string
15
+ }
16
+
17
+ type LogMessageStyle = 'bold' | 'regular'
18
+
19
+ interface CreateLogOptions {
20
+ /**
21
+ * Whether to display the Nano Stores logo.
22
+ */
23
+ logo?: boolean
24
+ /**
25
+ * Message in string or array format to be logged.
26
+ */
27
+ message?: [LogMessageStyle, string][] | string
28
+ /**
29
+ * The type of log.
30
+ */
31
+ type: LogType
32
+ /**
33
+ * Any value, object or array to be logged.
34
+ */
35
+ value?: any
36
+ }
37
+
38
+ /**
39
+ * Creates a log message.
40
+ *
41
+ * @param options Object with the options to create the log message.
42
+ */
43
+ export function log(options: CreateLogOptions): void
44
+
45
+ /**
46
+ * Creates a collapsed log message.
47
+ *
48
+ * @param options Object with the options to create the log message.
49
+ */
50
+ export function group(options: CreateLogOptions): void
51
+
52
+ /**
53
+ * Exits the current collapsed log message.
54
+ */
55
+ export function groupEnd(): void
@@ -0,0 +1,78 @@
1
+ function badge(color) {
2
+ return `
3
+ padding: 0 5px 2px;
4
+ margin-right: 5px;
5
+ font-weight: 400;
6
+ color: white;
7
+ background-color: ${color};
8
+ `
9
+ }
10
+
11
+ function borders(full) {
12
+ return `border-radius: ${full ? '4px' : '0 4px 4px 0'};`
13
+ }
14
+
15
+ const STYLES = {
16
+ badges: {
17
+ action: badge('#00899A'),
18
+ arguments: badge('#007281'),
19
+ build: badge('#BB5100'),
20
+ change: badge('#0E8A00'),
21
+ error: badge('#C30000'),
22
+ mount: badge('#0059D1'),
23
+ new: badge('#0C7800'),
24
+ old: badge('#943636'),
25
+ unmount: badge('#5E5E5E'),
26
+ value: badge('#8A6F00')
27
+ },
28
+ bold: 'font-weight: 700;',
29
+ logo: `
30
+ padding: 0 5px 2px;
31
+ color: white;
32
+ background-color: black;
33
+ border-radius: 4px 0 0 4px;
34
+ `,
35
+ regular: 'font-weight: 400;'
36
+ }
37
+
38
+ function createLog({ logo, message, type, value }) {
39
+ let template = ''
40
+ let args = []
41
+
42
+ if (logo) {
43
+ template = `%c𝖓`
44
+ args.push(STYLES.logo)
45
+ }
46
+
47
+ if (typeof type === 'string') {
48
+ template += `%c${type}`
49
+ args.push(STYLES.badges[type] + borders(!logo))
50
+ } else if (typeof type === 'object') {
51
+ template += `%c${type.name.toLowerCase()}`
52
+ args.push(badge(type.color) + borders(!logo))
53
+ }
54
+
55
+ if (message) {
56
+ if (Array.isArray(message)) {
57
+ message.forEach(([style, text]) => {
58
+ template += `%c ${text}`
59
+ args.push(STYLES[style])
60
+ })
61
+ } else {
62
+ template += `%c ${message}`
63
+ args.push(STYLES.text)
64
+ }
65
+ }
66
+
67
+ if (value) {
68
+ args.push(value)
69
+ }
70
+
71
+ args.unshift(template)
72
+
73
+ return args
74
+ }
75
+
76
+ export const log = args => console.log(...createLog(args))
77
+ export const group = args => console.groupCollapsed(...createLog(args))
78
+ export const groupEnd = () => console.groupEnd()