@niceties/draftlog-appender 1.3.2 → 2.0.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
@@ -1,6 +1,6 @@
1
1
  # Draftlog Appender
2
2
 
3
- Appender for [`'@niceites/logger'`](../logger/README.md) implemented using draftlog package.
3
+ Appender for [`'@niceties/logger'`](../logger/README.md) implemented using the @niceties/draftlog package.
4
4
 
5
5
  - Uses animation in the console to display log messages
6
6
 
@@ -8,7 +8,7 @@ Appender for [`'@niceites/logger'`](../logger/README.md) implemented using draft
8
8
 
9
9
  - Doesn't hold your event loop on exit
10
10
 
11
- - Creates maximum one active interval (timer) at a time
11
+ - Creates at most one active interval (timer) at a time
12
12
 
13
13
  - Supports multilevel spinners
14
14
 
@@ -29,17 +29,15 @@ or
29
29
  npm install --save @niceties/draftlog-appender
30
30
  ```
31
31
 
32
- No umd packages published because draftlog appender does not exists in umd format.
33
-
34
32
  # Example
35
33
 
36
- To install appender use next import:
34
+ To install the appender, use the following import:
37
35
 
38
36
  ```javascript
39
37
  import "@niceties/draftlog-appender";
40
38
  ```
41
39
 
42
- It is better to do it before other imports so the default appender in `'@niceites/logger'` is not installed.
40
+ It is better to do it before other imports so that the default appender in `'@niceties/logger'` is not installed.
43
41
 
44
42
  ## Sub-packages
45
43
 
@@ -47,7 +45,7 @@ Default sub-package `'@niceties/draftlog-appender'` exports nothing.
47
45
 
48
46
  Sub-package `'@niceties/draftlog-appender/core'` exports `createDraftlogAppender()` factory.
49
47
 
50
- Sub-package `'@niceties/draftlog-appender/spinners'` exports spinners definitions used in default config.
48
+ Sub-package `'@niceties/draftlog-appender/spinners'` exports spinner definitions used in the default config.
51
49
 
52
50
  ## Prior art
53
51
 
@@ -58,4 +56,4 @@ Sub-package `'@niceties/draftlog-appender/spinners'` exports spinners definition
58
56
 
59
57
  # License
60
58
 
61
- [MIT](https://github.com/kshutkin/niceties/blob/main/LICENSE)
59
+ [MIT](https://github.com/kshutkin/niceties/blob/main/LICENSE)
package/core.js ADDED
@@ -0,0 +1,33 @@
1
+ import { createCanvas } from './details/canvas.js';
2
+ import { createModel } from './details/model.js';
3
+
4
+ export function createDraftlogAppender(spinner, formatter, logAboveSpinners, ident) {
5
+
6
+ let interval;
7
+
8
+ const [updateModel, getModel] = createModel(logAboveSpinners);
9
+ const renderModel = createCanvas(spinner, formatter, ident);
10
+
11
+ return ( message) => {
12
+ renderModel(updateModel(message));
13
+ checkTimeout();
14
+ };
15
+
16
+ function checkTimeout() {
17
+ const spinning = getModel().spinning;
18
+ if (spinning && !interval) {
19
+ interval = setInterval(updateSpinners, spinner.interval);
20
+ interval.unref();
21
+ } else if (!spinning && interval) {
22
+ clearInterval(interval);
23
+ interval = undefined;
24
+ }
25
+ }
26
+
27
+ function updateSpinners() {
28
+ const model = getModel();
29
+ model.tick++;
30
+ model.tick %= spinner.frames.length;
31
+ renderModel(model);
32
+ }
33
+ }
@@ -0,0 +1,80 @@
1
+ import { draft } from '@niceties/draftlog';
2
+ import { Action } from '@niceties/logger/types';
3
+
4
+ import splitByLines from './split-by-lines.js';
5
+
6
+ export function createCanvas(spinner, formatter, ident) {
7
+
8
+ const updaters = [];
9
+
10
+ return modelFn;
11
+
12
+ function modelFn(model, dirty = false) {
13
+ if (model.skipLines) {
14
+ updaters.splice(0, model.skipLines);
15
+ model.skipLines = 0;
16
+ }
17
+ let key = 0;
18
+
19
+ const stack = [];
20
+ for (const item of model) {
21
+ if (dirty || item.dirty || item.status) {
22
+ let prefix = getPrefix( (item.status), model.tick);
23
+ let prefixUpdated = false;
24
+ const subitems = splitByLines(item.message);
25
+ for (const message of subitems) {
26
+ let updater = updaters[key++];
27
+ if (!updater) {
28
+ updater = draft('');
29
+ updaters.push(updater);
30
+ }
31
+ updater(
32
+ formatter(
33
+ {
34
+ loglevel: item.loglevel,
35
+ message,
36
+ context: item.context,
37
+ action: (item.status === undefined ? Action.log : undefined),
38
+ tag: item.tag,
39
+ },
40
+ prefix,
41
+ ident * stack.length
42
+ )
43
+ );
44
+ if (subitems.length > 1 && typeof prefix === 'string' && !prefixUpdated) {
45
+ prefix = prefix.replaceAll(/./g, ' ');
46
+ prefixUpdated = true;
47
+ }
48
+ }
49
+ if (item.dirty) {
50
+ item.dirty = false;
51
+ dirty = true;
52
+ }
53
+ } else {
54
+
55
+ key += splitByLines(item.message).length;
56
+ }
57
+ if (stack[stack.length - 1] === item) {
58
+ stack[stack.length - 1] = null;
59
+ }
60
+ if (item.lastLeaf) {
61
+ stack.push(item.lastLeaf);
62
+ }
63
+ while (stack.length && stack[stack.length - 1] == null) {
64
+ stack.pop();
65
+ }
66
+ }
67
+
68
+ while (key < updaters.length) {
69
+ updaters[key++]('');
70
+ }
71
+ }
72
+
73
+ function getPrefix(status, tick) {
74
+
75
+ return status
76
+ ? (spinner.frames[tick])
77
+ :
78
+ status != null;
79
+ }
80
+ }
@@ -0,0 +1,116 @@
1
+ import { Action } from '@niceties/logger/types';
2
+ import { append, appendRange, List, prepend, remove, removeRange } from '@slimlib/list';
3
+
4
+ export const ItemStatus = ({
5
+ finished: 0,
6
+ inprogress: 1,
7
+ });
8
+
9
+ export function createModel(logAboveSpinners) {
10
+
11
+ const model = (new List());
12
+
13
+ const itemById = Object.create(null);
14
+
15
+ model.tick = model.skipLines = model.spinning = 0;
16
+
17
+ return [
18
+ ( { action, ...item }) => {
19
+
20
+ item.dirty = true;
21
+ const { inputId } = item;
22
+ if (action === Action.start) {
23
+ item.status = ItemStatus.inprogress;
24
+ }
25
+ if (action === Action.finish) {
26
+ item.status = ItemStatus.finished;
27
+ }
28
+ if (action !== Action.log) {
29
+
30
+ updateModel( (inputId), item);
31
+ }
32
+ cleanupModel();
33
+ if (action === Action.log) {
34
+ appendToModel(item, logAboveSpinners);
35
+ }
36
+ return model;
37
+ },
38
+ () => {
39
+ cleanupModel();
40
+ return model;
41
+ },
42
+ ];
43
+
44
+ function appendToModel(item, head) {
45
+ if (head) {
46
+ prepend(model, item);
47
+ } else {
48
+ append(model, item);
49
+ }
50
+ model.spinning += item.status || 0;
51
+ }
52
+
53
+ function updateModel(inputId, options) {
54
+ const modelItem = itemById[inputId];
55
+ if (!modelItem) {
56
+
57
+ const item = { inputId: inputId, ...options };
58
+ itemById[inputId] = item;
59
+ const itemParentId = item.parentId;
60
+ if (itemParentId != null) {
61
+ putIntoChildren(itemParentId, item, item);
62
+ } else {
63
+ appendToModel(item, false);
64
+ }
65
+ } else {
66
+ const statusDiff = (options.status || 0) - (modelItem.status || 0);
67
+ const moveIntoParent = options.parentId != null && modelItem.parentId == null;
68
+ Object.assign(modelItem, options);
69
+ model.spinning += statusDiff;
70
+ if (moveIntoParent) {
71
+ const lastLeaf = getLastLeaf(modelItem);
72
+ model.spinning -= modelItem.status || 0;
73
+ modelItem.dirty = true;
74
+ removeRange( (modelItem), (lastLeaf));
75
+ putIntoChildren( (modelItem.parentId), modelItem, lastLeaf);
76
+ }
77
+ }
78
+ }
79
+
80
+ function putIntoChildren(itemParentId, begin, end) {
81
+ let parent = itemById[itemParentId];
82
+ if (!parent) {
83
+ parent = ({
84
+ inputId: itemParentId,
85
+ message: '',
86
+ loglevel: 0,
87
+ ref: (new WeakRef(model)),
88
+ });
89
+ appendToModel(parent, false);
90
+ itemById[itemParentId] = parent;
91
+ }
92
+ appendRange( (getLastLeaf(parent)), (begin), (end));
93
+ parent.lastLeaf = begin;
94
+ model.spinning += begin.status || 0;
95
+ }
96
+
97
+ function cleanupModel() {
98
+ for (const item of model) {
99
+ if (!item.ref?.deref()) {
100
+ model.skipLines += 1;
101
+ item.inputId != null && delete itemById[item.inputId];
102
+ remove(item);
103
+ } else {
104
+ break;
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ function getLastLeaf(modelItem) {
111
+ let lastLeaf = modelItem;
112
+ while (lastLeaf.lastLeaf) {
113
+ lastLeaf = lastLeaf.lastLeaf;
114
+ }
115
+ return lastLeaf;
116
+ }
@@ -0,0 +1,16 @@
1
+ export default function splitByLines(message) {
2
+ return message.match(getSubstringsRegex()) ?? [];
3
+ }
4
+
5
+ let substringsRegex;
6
+
7
+ let substringsColumns;
8
+
9
+ function getSubstringsRegex() {
10
+ const newColumns = process.stdout.columns || 80;
11
+ if (substringsColumns !== newColumns) {
12
+ substringsRegex = new RegExp(`.{1,${newColumns}}`, 'g');
13
+ substringsColumns = newColumns;
14
+ }
15
+ return (substringsRegex);
16
+ }
package/index.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ declare module '@niceties/draftlog-appender' {
2
+ export type LogMessage = import("@niceties/logger/types").LogMessage;
3
+
4
+ export {};
5
+ }
6
+
7
+ declare module '@niceties/draftlog-appender/core' {
8
+ export function createDraftlogAppender(spinner: Spinner, formatter: Formatter, logAboveSpinners: boolean, ident: number): (message: LogMessage) => void;
9
+ export type Formatter = import("@niceties/logger/types").Formatter;
10
+ export type LogMessage = import("@niceties/logger/types").LogMessage;
11
+ export type Spinner = Spinner_1;
12
+ type Spinner_1 = {
13
+ interval: number;
14
+ frames: string[];
15
+ };
16
+
17
+ export {};
18
+ }
19
+
20
+ declare module '@niceties/draftlog-appender/spinners' {
21
+ export const dots: Spinner;
22
+
23
+ export const line: Spinner;
24
+ export type Spinner = {
25
+ interval: number;
26
+ frames: string[];
27
+ };
28
+
29
+ export {};
30
+ }
31
+
32
+ //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "version": 3,
3
+ "file": "index.d.ts",
4
+ "names": [
5
+ "LogMessage",
6
+ "createDraftlogAppender",
7
+ "Formatter",
8
+ "Spinner",
9
+ "dots",
10
+ "line"
11
+ ],
12
+ "sources": [
13
+ "index.js",
14
+ "core.js",
15
+ "spinners.js"
16
+ ],
17
+ "sourcesContent": [
18
+ null,
19
+ null,
20
+ null
21
+ ],
22
+ "mappings": ";;;;;;;iBCGgBC,sBAAsBA;;;;;;;;;;;;;cCHzBG,IAAIA;;cAKJC,IAAIA",
23
+ "ignoreList": []
24
+ }
package/index.js ADDED
@@ -0,0 +1,40 @@
1
+ import { filterMessages } from '@niceties/logger/appender-utils';
2
+ import {
3
+ asciiLogPrefixes,
4
+ asciiPrefixes,
5
+ colors,
6
+ tagFactory,
7
+ unicodeLogPrefixes,
8
+ unicodePrefixes,
9
+ } from '@niceties/logger/default-formatting';
10
+ import { createFormatter, terminalSupportsUnicode } from '@niceties/logger/format-utils';
11
+ import { appender } from '@niceties/logger/global-appender';
12
+ import { LogLevel } from '@niceties/logger/types';
13
+
14
+ import { createDraftlogAppender } from './core.js';
15
+ import { dots, line } from './spinners.js';
16
+
17
+ if (!process.env.CI) {
18
+ const supportsUnicode = terminalSupportsUnicode();
19
+ const spinner = supportsUnicode ? dots : line;
20
+ const formatter = createFormatter(
21
+ colors,
22
+ supportsUnicode ? unicodePrefixes : asciiPrefixes,
23
+ supportsUnicode ? unicodeLogPrefixes : asciiLogPrefixes,
24
+ tagFactory
25
+ );
26
+
27
+ let minLogLevel = LogLevel.info;
28
+ const filtered = filterMessages(
29
+
30
+ message => (message.loglevel) >= minLogLevel,
31
+ createDraftlogAppender(spinner, formatter, true, 2)
32
+ );
33
+ filtered.api = {
34
+
35
+ setMinLevel(logLevel) {
36
+ minLogLevel = logLevel;
37
+ },
38
+ };
39
+ appender(filtered);
40
+ }
package/package.json CHANGED
@@ -1,34 +1,29 @@
1
1
  {
2
- "version": "1.3.2",
2
+ "version": "2.0.0",
3
3
  "license": "MIT",
4
4
  "name": "@niceties/draftlog-appender",
5
5
  "author": {
6
6
  "name": "Konstantin Shutkin"
7
7
  },
8
8
  "type": "module",
9
+ "types": "./index.d.ts",
9
10
  "exports": {
10
11
  ".": {
11
- "require": "./dist/index.cjs",
12
- "default": "./dist/index.mjs"
12
+ "types": "./index.d.ts",
13
+ "default": "./index.js"
13
14
  },
14
15
  "./core": {
15
- "require": "./dist/core.cjs",
16
- "default": "./dist/core.mjs"
16
+ "types": "./index.d.ts",
17
+ "default": "./core.js"
17
18
  },
18
19
  "./spinners": {
19
- "require": "./dist/spinners.cjs",
20
- "default": "./dist/spinners.mjs"
20
+ "types": "./index.d.ts",
21
+ "default": "./spinners.js"
21
22
  },
22
23
  "./package.json": "./package.json"
23
24
  },
24
- "main": "./dist/index.cjs",
25
- "module": "./dist/index.mjs",
26
- "typings": "./dist/index.d.ts",
27
- "files": [
28
- "dist",
29
- "core",
30
- "spinners"
31
- ],
25
+ "main": "./index.js",
26
+ "module": "./index.js",
32
27
  "engines": {
33
28
  "node": ">=15"
34
29
  },
@@ -48,19 +43,11 @@
48
43
  "draftlog",
49
44
  "appender"
50
45
  ],
51
- "devDependencies": {
52
- "@niceties/logger": "1.1.12"
53
- },
54
46
  "peerDependencies": {
55
- "@niceties/logger": "^1.1.12"
47
+ "@niceties/logger": "^2.0.0"
56
48
  },
57
49
  "dependencies": {
58
- "draftlog": "^1.0.13",
59
- "@slimlib/list": "^1.0.3"
60
- },
61
- "scripts": {
62
- "build": "pkgbld-internal",
63
- "test": "node --expose-gc ../node_modules/jest/bin/jest.js --collectCoverage",
64
- "lint": "eslint ./src"
50
+ "@slimlib/list": "^2.0.1",
51
+ "@niceties/draftlog": "^1.0.0"
65
52
  }
66
53
  }
@@ -1,10 +1,9 @@
1
- const dots = {
1
+ export const dots = {
2
2
  interval: 50,
3
- frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
3
+ frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
4
4
  };
5
- const line = {
5
+
6
+ export const line = {
6
7
  interval: 130,
7
- frames: ['-', '\\', '|', '/']
8
+ frames: ['-', '\\', '|', '/'],
8
9
  };
9
-
10
- export { dots, line };
package/core/package.json DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "type": "module",
3
- "types": "../dist/core.d.ts",
4
- "main": "../dist/core.mjs"
5
- }
package/dist/core.cjs DELETED
@@ -1,233 +0,0 @@
1
- 'use strict';
2
-
3
- var draftlog = require('draftlog');
4
- var list = require('@slimlib/list');
5
-
6
- const allColumnsListeners = new Set();
7
- function subscribeToTerminalResize(listener) {
8
- allColumnsListeners.add(new WeakRef(listener));
9
- }
10
- process.stdout.on('resize', () => {
11
- for (const listener of allColumnsListeners) {
12
- const realListener = listener.deref();
13
- if (realListener) {
14
- realListener();
15
- }
16
- else {
17
- allColumnsListeners.delete(listener);
18
- }
19
- }
20
- });
21
-
22
- function splitByLines(message) {
23
- return message
24
- .match(getSubstringsRegex()) ?? [];
25
- }
26
- let substringsRegex, substringsColumns;
27
- function getSubstringsRegex() {
28
- const newColumns = process.stdout.columns || 80;
29
- if (substringsColumns !== newColumns) {
30
- substringsRegex = new RegExp(`.{1,${newColumns}}`, 'g');
31
- substringsColumns = newColumns;
32
- }
33
- return substringsRegex;
34
- }
35
-
36
- function createCanvas(spinner, formatter, ident) {
37
- draftlog(console);
38
- draftlog.defaults.canReWrite = false;
39
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
- const updaters = [];
41
- let lastModel;
42
- subscribeToTerminalResize(() => {
43
- if (lastModel) {
44
- modelFn(lastModel, true);
45
- }
46
- });
47
- return modelFn;
48
- function modelFn(model, dirty = false) {
49
- lastModel = model;
50
- if (model.skipLines) {
51
- updaters.splice(0, model.skipLines);
52
- model.skipLines = 0;
53
- }
54
- let key = 0;
55
- const stack = [];
56
- for (const item of model) {
57
- if (dirty || item.dirty || item.status) {
58
- let prefix = getPrefix(item.status, model.tick), prefixUpdated = false;
59
- const subitems = splitByLines(item.message);
60
- for (const message of subitems) {
61
- let updater = updaters[key++];
62
- if (!updater) {
63
- updater = console.draft(' ');
64
- updaters.push(updater);
65
- }
66
- updater(formatter({
67
- loglevel: item.loglevel,
68
- message,
69
- context: item.context,
70
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
- action: (item.status === undefined ? 3 /* Action.log */ : undefined),
72
- tag: item.tag
73
- }, prefix, ident * stack.length));
74
- if (subitems.length > 1 && typeof prefix === 'string' && !prefixUpdated) {
75
- prefix = prefix.replaceAll(/./g, ' ');
76
- prefixUpdated = true;
77
- }
78
- }
79
- if (item.dirty) {
80
- item.dirty = false;
81
- dirty = true;
82
- }
83
- }
84
- else {
85
- // iterate
86
- key += splitByLines(item.message).length;
87
- }
88
- if (stack[stack.length - 1] === item) {
89
- stack[stack.length - 1] = null;
90
- }
91
- if (item.lastLeaf) {
92
- stack.push(item.lastLeaf);
93
- }
94
- while (stack.length && stack[stack.length - 1] == null) {
95
- stack.pop();
96
- }
97
- }
98
- while (key < updaters.length) {
99
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
- updaters[key++]('');
101
- }
102
- }
103
- function getPrefix(status, tick) {
104
- // status is truthy when it is inprogress
105
- return status ? spinner.frames[tick] :
106
- // status not null when it is finished
107
- status != null;
108
- }
109
- }
110
-
111
- function createModel(logAboveSpinners) {
112
- const model = new list.List();
113
- const itemById = Object.create(null);
114
- model.tick = model.skipLines = model.spinning = 0;
115
- return [({ action, ...item }) => {
116
- // item has status undefined, so it is static by default
117
- item.dirty = true;
118
- const { inputId } = item;
119
- if (action === 0 /* Action.start */) {
120
- item.status = 1 /* ItemStatus.inprogress */;
121
- }
122
- if (action === 2 /* Action.finish */) {
123
- item.status = 0 /* ItemStatus.finished */;
124
- }
125
- if (action !== 3 /* Action.log */) {
126
- // if status still empty in the original item or item does not exists it will remain empty and static
127
- updateModel(inputId, item);
128
- }
129
- cleanupModel();
130
- if (action === 3 /* Action.log */) {
131
- appendToModel(item, logAboveSpinners);
132
- }
133
- return model;
134
- }, () => {
135
- cleanupModel();
136
- return model;
137
- }];
138
- function appendToModel(item, head) {
139
- if (head) {
140
- list.prepend(model, item);
141
- }
142
- else {
143
- list.append(model, item);
144
- }
145
- model.spinning += (item.status || 0);
146
- }
147
- function updateModel(inputId, options) {
148
- const modelItem = itemById[inputId];
149
- if (!modelItem) {
150
- const item = { inputId: inputId, ...options };
151
- itemById[inputId] = item;
152
- const itemParentId = item.parentId;
153
- if (itemParentId != null) {
154
- putIntoChildren(itemParentId, item, item);
155
- }
156
- else {
157
- appendToModel(item, false);
158
- }
159
- }
160
- else {
161
- const statusDiff = (options.status || 0) - (modelItem.status || 0);
162
- const moveIntoParent = options.parentId != null && modelItem.parentId == null;
163
- Object.assign(modelItem, options);
164
- model.spinning += statusDiff;
165
- if (moveIntoParent) {
166
- const lastLeaf = getLastLeaf(modelItem);
167
- model.spinning -= (modelItem.status || 0);
168
- modelItem.dirty = true;
169
- list.removeRange(modelItem, lastLeaf);
170
- putIntoChildren(modelItem.parentId, modelItem, lastLeaf);
171
- }
172
- }
173
- }
174
- function putIntoChildren(itemParentId, begin, end) {
175
- let parent = itemById[itemParentId];
176
- if (!parent) {
177
- parent = { inputId: itemParentId, message: '', loglevel: 0, ref: new WeakRef(model) };
178
- appendToModel(parent, false);
179
- itemById[itemParentId] = parent;
180
- }
181
- list.appendRange((getLastLeaf(parent)), begin, end);
182
- parent.lastLeaf = begin;
183
- model.spinning += (begin.status || 0);
184
- }
185
- function cleanupModel() {
186
- for (const item of model) {
187
- if (!item.ref?.deref()) {
188
- model.skipLines += 1;
189
- item.inputId != null && delete itemById[item.inputId];
190
- list.remove(item);
191
- }
192
- else {
193
- break;
194
- }
195
- }
196
- }
197
- }
198
- function getLastLeaf(modelItem) {
199
- let lastLeaf = modelItem;
200
- while (lastLeaf.lastLeaf) {
201
- lastLeaf = lastLeaf.lastLeaf;
202
- }
203
- return lastLeaf;
204
- }
205
-
206
- function createDraftlogAppender(spinner, formatter, logAboveSpinners, ident) {
207
- let interval;
208
- const [updateModel, getModel] = createModel(logAboveSpinners);
209
- const renderModel = createCanvas(spinner, formatter, ident);
210
- return (message) => {
211
- renderModel(updateModel(message));
212
- checkTimeout();
213
- };
214
- function checkTimeout() {
215
- const spinning = getModel().spinning;
216
- if (spinning && !interval) {
217
- interval = setInterval(updateSpinners, spinner.interval);
218
- interval.unref(); // unref immidiately just in case
219
- }
220
- else if (!spinning && interval) {
221
- clearInterval(interval);
222
- interval = undefined;
223
- }
224
- }
225
- function updateSpinners() {
226
- const model = getModel();
227
- model.tick++;
228
- model.tick %= spinner.frames.length;
229
- renderModel(model);
230
- }
231
- }
232
-
233
- exports.createDraftlogAppender = createDraftlogAppender;
package/dist/core.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import { Formatter, LogMessage } from '@niceties/logger/types';
2
- import { Spinner } from './spinners';
3
- export declare function createDraftlogAppender(spinner: Spinner, formatter: Formatter, logAboveSpinners: boolean, ident: number): (message: LogMessage) => void;
package/dist/core.mjs DELETED
@@ -1,231 +0,0 @@
1
- import draftlog from 'draftlog';
2
- import { List, prepend, append, removeRange, appendRange, remove } from '@slimlib/list';
3
-
4
- const allColumnsListeners = new Set();
5
- function subscribeToTerminalResize(listener) {
6
- allColumnsListeners.add(new WeakRef(listener));
7
- }
8
- process.stdout.on('resize', () => {
9
- for (const listener of allColumnsListeners) {
10
- const realListener = listener.deref();
11
- if (realListener) {
12
- realListener();
13
- }
14
- else {
15
- allColumnsListeners.delete(listener);
16
- }
17
- }
18
- });
19
-
20
- function splitByLines(message) {
21
- return message
22
- .match(getSubstringsRegex()) ?? [];
23
- }
24
- let substringsRegex, substringsColumns;
25
- function getSubstringsRegex() {
26
- const newColumns = process.stdout.columns || 80;
27
- if (substringsColumns !== newColumns) {
28
- substringsRegex = new RegExp(`.{1,${newColumns}}`, 'g');
29
- substringsColumns = newColumns;
30
- }
31
- return substringsRegex;
32
- }
33
-
34
- function createCanvas(spinner, formatter, ident) {
35
- draftlog(console);
36
- draftlog.defaults.canReWrite = false;
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
- const updaters = [];
39
- let lastModel;
40
- subscribeToTerminalResize(() => {
41
- if (lastModel) {
42
- modelFn(lastModel, true);
43
- }
44
- });
45
- return modelFn;
46
- function modelFn(model, dirty = false) {
47
- lastModel = model;
48
- if (model.skipLines) {
49
- updaters.splice(0, model.skipLines);
50
- model.skipLines = 0;
51
- }
52
- let key = 0;
53
- const stack = [];
54
- for (const item of model) {
55
- if (dirty || item.dirty || item.status) {
56
- let prefix = getPrefix(item.status, model.tick), prefixUpdated = false;
57
- const subitems = splitByLines(item.message);
58
- for (const message of subitems) {
59
- let updater = updaters[key++];
60
- if (!updater) {
61
- updater = console.draft(' ');
62
- updaters.push(updater);
63
- }
64
- updater(formatter({
65
- loglevel: item.loglevel,
66
- message,
67
- context: item.context,
68
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
- action: (item.status === undefined ? 3 /* Action.log */ : undefined),
70
- tag: item.tag
71
- }, prefix, ident * stack.length));
72
- if (subitems.length > 1 && typeof prefix === 'string' && !prefixUpdated) {
73
- prefix = prefix.replaceAll(/./g, ' ');
74
- prefixUpdated = true;
75
- }
76
- }
77
- if (item.dirty) {
78
- item.dirty = false;
79
- dirty = true;
80
- }
81
- }
82
- else {
83
- // iterate
84
- key += splitByLines(item.message).length;
85
- }
86
- if (stack[stack.length - 1] === item) {
87
- stack[stack.length - 1] = null;
88
- }
89
- if (item.lastLeaf) {
90
- stack.push(item.lastLeaf);
91
- }
92
- while (stack.length && stack[stack.length - 1] == null) {
93
- stack.pop();
94
- }
95
- }
96
- while (key < updaters.length) {
97
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
- updaters[key++]('');
99
- }
100
- }
101
- function getPrefix(status, tick) {
102
- // status is truthy when it is inprogress
103
- return status ? spinner.frames[tick] :
104
- // status not null when it is finished
105
- status != null;
106
- }
107
- }
108
-
109
- function createModel(logAboveSpinners) {
110
- const model = new List();
111
- const itemById = Object.create(null);
112
- model.tick = model.skipLines = model.spinning = 0;
113
- return [({ action, ...item }) => {
114
- // item has status undefined, so it is static by default
115
- item.dirty = true;
116
- const { inputId } = item;
117
- if (action === 0 /* Action.start */) {
118
- item.status = 1 /* ItemStatus.inprogress */;
119
- }
120
- if (action === 2 /* Action.finish */) {
121
- item.status = 0 /* ItemStatus.finished */;
122
- }
123
- if (action !== 3 /* Action.log */) {
124
- // if status still empty in the original item or item does not exists it will remain empty and static
125
- updateModel(inputId, item);
126
- }
127
- cleanupModel();
128
- if (action === 3 /* Action.log */) {
129
- appendToModel(item, logAboveSpinners);
130
- }
131
- return model;
132
- }, () => {
133
- cleanupModel();
134
- return model;
135
- }];
136
- function appendToModel(item, head) {
137
- if (head) {
138
- prepend(model, item);
139
- }
140
- else {
141
- append(model, item);
142
- }
143
- model.spinning += (item.status || 0);
144
- }
145
- function updateModel(inputId, options) {
146
- const modelItem = itemById[inputId];
147
- if (!modelItem) {
148
- const item = { inputId: inputId, ...options };
149
- itemById[inputId] = item;
150
- const itemParentId = item.parentId;
151
- if (itemParentId != null) {
152
- putIntoChildren(itemParentId, item, item);
153
- }
154
- else {
155
- appendToModel(item, false);
156
- }
157
- }
158
- else {
159
- const statusDiff = (options.status || 0) - (modelItem.status || 0);
160
- const moveIntoParent = options.parentId != null && modelItem.parentId == null;
161
- Object.assign(modelItem, options);
162
- model.spinning += statusDiff;
163
- if (moveIntoParent) {
164
- const lastLeaf = getLastLeaf(modelItem);
165
- model.spinning -= (modelItem.status || 0);
166
- modelItem.dirty = true;
167
- removeRange(modelItem, lastLeaf);
168
- putIntoChildren(modelItem.parentId, modelItem, lastLeaf);
169
- }
170
- }
171
- }
172
- function putIntoChildren(itemParentId, begin, end) {
173
- let parent = itemById[itemParentId];
174
- if (!parent) {
175
- parent = { inputId: itemParentId, message: '', loglevel: 0, ref: new WeakRef(model) };
176
- appendToModel(parent, false);
177
- itemById[itemParentId] = parent;
178
- }
179
- appendRange((getLastLeaf(parent)), begin, end);
180
- parent.lastLeaf = begin;
181
- model.spinning += (begin.status || 0);
182
- }
183
- function cleanupModel() {
184
- for (const item of model) {
185
- if (!item.ref?.deref()) {
186
- model.skipLines += 1;
187
- item.inputId != null && delete itemById[item.inputId];
188
- remove(item);
189
- }
190
- else {
191
- break;
192
- }
193
- }
194
- }
195
- }
196
- function getLastLeaf(modelItem) {
197
- let lastLeaf = modelItem;
198
- while (lastLeaf.lastLeaf) {
199
- lastLeaf = lastLeaf.lastLeaf;
200
- }
201
- return lastLeaf;
202
- }
203
-
204
- function createDraftlogAppender(spinner, formatter, logAboveSpinners, ident) {
205
- let interval;
206
- const [updateModel, getModel] = createModel(logAboveSpinners);
207
- const renderModel = createCanvas(spinner, formatter, ident);
208
- return (message) => {
209
- renderModel(updateModel(message));
210
- checkTimeout();
211
- };
212
- function checkTimeout() {
213
- const spinning = getModel().spinning;
214
- if (spinning && !interval) {
215
- interval = setInterval(updateSpinners, spinner.interval);
216
- interval.unref(); // unref immidiately just in case
217
- }
218
- else if (!spinning && interval) {
219
- clearInterval(interval);
220
- interval = undefined;
221
- }
222
- }
223
- function updateSpinners() {
224
- const model = getModel();
225
- model.tick++;
226
- model.tick %= spinner.frames.length;
227
- renderModel(model);
228
- }
229
- }
230
-
231
- export { createDraftlogAppender };
@@ -1,4 +0,0 @@
1
- import { Formatter } from '@niceties/logger/types';
2
- import { Spinner } from '../spinners';
3
- import { Model } from './model';
4
- export declare function createCanvas(spinner: Spinner, formatter: Formatter, ident: number): (model: Model, dirty?: boolean) => void;
@@ -1,24 +0,0 @@
1
- import { LogLevel, LogMessage } from '@niceties/logger/types';
2
- import { List, ListNode } from '@slimlib/list';
3
- export declare const enum ItemStatus {
4
- finished = 0,
5
- inprogress = 1
6
- }
7
- export interface ModelItem extends Partial<ListNode> {
8
- inputId?: number;
9
- message: string;
10
- status?: ItemStatus;
11
- loglevel: LogLevel;
12
- ref?: WeakRef<never>;
13
- parentId?: number;
14
- dirty?: boolean;
15
- lastLeaf?: ModelItem;
16
- tag?: string;
17
- context?: any;
18
- }
19
- export type Model = List<ModelItem> & {
20
- skipLines: number;
21
- tick: number;
22
- spinning: number;
23
- };
24
- export declare function createModel(logAboveSpinners: boolean): [(logMessage: LogMessage) => Model, () => Model];
@@ -1 +0,0 @@
1
- export default function splitByLines(message: string): string[];
@@ -1 +0,0 @@
1
- export declare function subscribeToTerminalResize(listener: () => void): void;
package/dist/index.cjs DELETED
@@ -1,20 +0,0 @@
1
- 'use strict';
2
-
3
- var appenderUtils = require('@niceties/logger/appender-utils');
4
- var globalAppender = require('@niceties/logger/global-appender');
5
- var formatUtils = require('@niceties/logger/format-utils');
6
- var defaultFormatting = require('@niceties/logger/default-formatting');
7
- var core = require('./core.cjs');
8
- var spinners = require('./spinners.cjs');
9
- require('draftlog');
10
- require('@slimlib/list');
11
-
12
- if (!process.env.CI) {
13
- const supportsUnicode = formatUtils.terminalSupportsUnicode();
14
- const spinner = supportsUnicode ? spinners.dots : spinners.line;
15
- const formatter = formatUtils.createFormatter(defaultFormatting.colors, supportsUnicode ? defaultFormatting.unicodePrefixes : defaultFormatting.asciiPrefixes, defaultFormatting.tagFactory);
16
- let minLogLevel = 1 /* LogLevel.info */;
17
- globalAppender.appender(appenderUtils.filterMessages((message) => message.loglevel >= minLogLevel, core.createDraftlogAppender(spinner, formatter, true, 2), // eslint-disable-line indent
18
- { setMinLevel(logLevel) { minLogLevel = logLevel; } } // eslint-disable-line indent
19
- ));
20
- }
package/dist/index.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/dist/index.mjs DELETED
@@ -1,18 +0,0 @@
1
- import { filterMessages } from '@niceties/logger/appender-utils';
2
- import { appender } from '@niceties/logger/global-appender';
3
- import { terminalSupportsUnicode, createFormatter } from '@niceties/logger/format-utils';
4
- import { colors, unicodePrefixes, asciiPrefixes, tagFactory } from '@niceties/logger/default-formatting';
5
- import { createDraftlogAppender } from './core.mjs';
6
- import { dots, line } from './spinners.mjs';
7
- import 'draftlog';
8
- import '@slimlib/list';
9
-
10
- if (!process.env.CI) {
11
- const supportsUnicode = terminalSupportsUnicode();
12
- const spinner = supportsUnicode ? dots : line;
13
- const formatter = createFormatter(colors, supportsUnicode ? unicodePrefixes : asciiPrefixes, tagFactory);
14
- let minLogLevel = 1 /* LogLevel.info */;
15
- appender(filterMessages((message) => message.loglevel >= minLogLevel, createDraftlogAppender(spinner, formatter, true, 2), // eslint-disable-line indent
16
- { setMinLevel(logLevel) { minLogLevel = logLevel; } } // eslint-disable-line indent
17
- ));
18
- }
package/dist/spinners.cjs DELETED
@@ -1,13 +0,0 @@
1
- 'use strict';
2
-
3
- const dots = {
4
- interval: 50,
5
- frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
6
- };
7
- const line = {
8
- interval: 130,
9
- frames: ['-', '\\', '|', '/']
10
- };
11
-
12
- exports.dots = dots;
13
- exports.line = line;
@@ -1,12 +0,0 @@
1
- export interface Spinner {
2
- interval: number;
3
- frames: string[];
4
- }
5
- export declare const dots: {
6
- interval: number;
7
- frames: string[];
8
- };
9
- export declare const line: {
10
- interval: number;
11
- frames: string[];
12
- };
@@ -1,5 +0,0 @@
1
- {
2
- "type": "module",
3
- "types": "../dist/spinners.d.ts",
4
- "main": "../dist/spinners.mjs"
5
- }