@niceties/draftlog-appender 1.2.9 → 1.3.1

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 Konstantin Shutkin
3
+ Copyright (c) 2023 Konstantin Shutkin
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/README.md CHANGED
@@ -15,7 +15,7 @@ Appender for [`'@niceites/logger'`](../logger/README.md) implemented using draft
15
15
  ![Example](./example.gif "In terminal")
16
16
  ![Example](./cmdexe.gif "In windows terminal")
17
17
 
18
- ### [Changlelog](./CHANGELOG.md)
18
+ ### [Changelog](./CHANGELOG.md)
19
19
 
20
20
  # Installation
21
21
 
@@ -39,7 +39,7 @@ To install appender use next import:
39
39
  import "@niceties/draftlog-appender";
40
40
  ```
41
41
 
42
- It is better to do it before other imports so default appender in `'@niceites/logger'` not installed.
42
+ It is better to do it before other imports so the default appender in `'@niceites/logger'` is not installed.
43
43
 
44
44
  ## Subpackages
45
45
 
@@ -58,4 +58,4 @@ Subpackage `'@niceties/draftlog-appender/spinners'` exports spinners definitions
58
58
 
59
59
  # License
60
60
 
61
- [MIT](./LICENSE)
61
+ [MIT](https://github.com/kshutkin/niceties/blob/main/LICENSE)
package/dist/core.cjs CHANGED
@@ -3,226 +3,231 @@
3
3
  var draftlog = require('draftlog');
4
4
  var list = require('@slimlib/list');
5
5
 
6
- function createCanvas(spinner, formatter, ident) {
7
- draftlog(console);
8
- draftlog.defaults.canReWrite = false;
9
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
- const updaters = [];
11
- return (model) => {
12
- if (model.skipLines) {
13
- updaters.splice(0, model.skipLines);
14
- model.skipLines = 0;
15
- }
16
- let key = 0, dirty = false;
17
- const stack = [];
18
- for (const item of model) {
19
- if (dirty || item.dirty || item.status) {
20
- let prefix = getPrefix(item.status, model.tick), prefixUpdated = false;
21
- const subitems = substrings(item.message);
22
- for (const message of subitems) {
23
- let updater = updaters[key++];
24
- if (!updater) {
25
- updater = console.draft(' ');
26
- updaters.push(updater);
27
- }
28
- updater(formatter({
29
- loglevel: item.loglevel,
30
- message,
31
- context: item.context,
32
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
- action: (item.status === undefined ? 3 /* log */ : undefined),
34
- tag: item.tag
35
- }, prefix, ident * stack.length));
36
- if (subitems.length > 1 && typeof prefix === 'string' && !prefixUpdated) {
37
- prefix = prefix.replaceAll(/./g, ' ');
38
- prefixUpdated = true;
39
- }
40
- }
41
- if (item.dirty) {
42
- item.dirty = false;
43
- dirty = true;
44
- }
45
- }
46
- else {
47
- // iterate
48
- key += substrings(item.message).length;
49
- }
50
- if (stack[stack.length - 1] === item) {
51
- stack[stack.length - 1] = null;
52
- }
53
- if (item.lastLeaf) {
54
- stack.push(item.lastLeaf);
55
- }
56
- while (stack.length && stack[stack.length - 1] == null) {
57
- stack.pop();
58
- }
59
- }
60
- while (key !== updaters.length) {
61
- updaters[key++]('');
62
- }
63
- };
64
- function getPrefix(status, tick) {
65
- // status is truthy when it is inprogress
66
- return status ? spinner.frames[tick] :
67
- // status not null when it is finished
68
- status != null;
69
- }
70
- }
71
- function substrings(message) {
72
- var _a;
73
- return (_a = message
74
- .match(/.{1,80}/g)) !== null && _a !== void 0 ? _a : [];
6
+ const allColumnsListeners = new Set();
7
+ function subscribeToTerminalResize(listener) {
8
+ allColumnsListeners.add(new WeakRef(listener));
75
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
+ });
76
21
 
77
- /******************************************************************************
78
- Copyright (c) Microsoft Corporation.
79
-
80
- Permission to use, copy, modify, and/or distribute this software for any
81
- purpose with or without fee is hereby granted.
82
-
83
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
84
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
85
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
86
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
87
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
88
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
89
- PERFORMANCE OF THIS SOFTWARE.
90
- ***************************************************************************** */
91
-
92
- function __rest(s, e) {
93
- var t = {};
94
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
95
- t[p] = s[p];
96
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
97
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
98
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
99
- t[p[i]] = s[p[i]];
100
- }
101
- return t;
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
+ }
102
109
  }
103
110
 
104
- function createModel(logAboveSpinners) {
105
- const model = new list.List();
106
- const itemById = Object.create(null);
107
- model.tick = model.skipLines = model.spinning = 0;
108
- return [(_a) => {
109
- var { action } = _a, item = __rest(_a, ["action"]);
110
- // item has status undefined, so it is static by default
111
- item.dirty = true;
112
- const { inputId } = item;
113
- if (action === 0 /* start */) {
114
- item.status = 1 /* inprogress */;
115
- }
116
- if (action === 2 /* finish */) {
117
- item.status = 0 /* finished */;
118
- }
119
- if (action !== 3 /* log */) {
120
- // if status still empty in the original item or item does not exists it will remain empty and static
121
- updateModel(inputId, item);
122
- }
123
- cleanupModel();
124
- if (action === 3 /* log */) {
125
- appendToModel(item, logAboveSpinners);
126
- }
127
- return model;
128
- }, () => {
129
- cleanupModel();
130
- return model;
131
- }];
132
- function appendToModel(item, head) {
133
- if (head) {
134
- list.prepend(model, item);
135
- }
136
- else {
137
- list.append(model, item);
138
- }
139
- model.spinning += (item.status || 0);
140
- }
141
- function updateModel(inputId, options) {
142
- const modelItem = itemById[inputId];
143
- if (!modelItem) {
144
- const item = Object.assign({ inputId: inputId }, options);
145
- itemById[inputId] = item;
146
- const itemParentId = item.parentId;
147
- if (itemParentId != null) {
148
- putIntoChildren(itemParentId, item, item);
149
- }
150
- else {
151
- appendToModel(item, false);
152
- }
153
- }
154
- else {
155
- const statusDiff = (options.status || 0) - (modelItem.status || 0);
156
- const moveIntoParent = options.parentId != null && modelItem.parentId == null;
157
- Object.assign(modelItem, options);
158
- model.spinning += statusDiff;
159
- if (moveIntoParent) {
160
- const lastLeaf = getLastLeaf(modelItem);
161
- model.spinning -= (modelItem.status || 0);
162
- modelItem.dirty = true;
163
- list.removeRange(modelItem, lastLeaf);
164
- putIntoChildren(modelItem.parentId, modelItem, lastLeaf);
165
- }
166
- }
167
- }
168
- function putIntoChildren(itemParentId, begin, end) {
169
- let parent = itemById[itemParentId];
170
- if (!parent) {
171
- parent = { inputId: itemParentId, message: '', loglevel: 0, ref: new WeakRef(model) };
172
- appendToModel(parent, false);
173
- itemById[itemParentId] = parent;
174
- }
175
- list.appendRange((getLastLeaf(parent)), begin, end);
176
- parent.lastLeaf = begin;
177
- model.spinning += (begin.status || 0);
178
- }
179
- function cleanupModel() {
180
- var _a;
181
- for (const item of model) {
182
- if (!((_a = item.ref) === null || _a === void 0 ? void 0 : _a.deref())) {
183
- model.skipLines += 1;
184
- item.inputId != null && delete itemById[item.inputId];
185
- list.remove(item);
186
- }
187
- else {
188
- break;
189
- }
190
- }
191
- }
192
- }
193
- function getLastLeaf(modelItem) {
194
- let lastLeaf = modelItem;
195
- while (lastLeaf.lastLeaf) {
196
- lastLeaf = lastLeaf.lastLeaf;
197
- }
198
- return lastLeaf;
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;
199
204
  }
200
205
 
201
- function createDraftlogAppender(spinner, formatter, logAboveSpinners, ident) {
202
- let interval;
203
- const [updateModel, getModel] = createModel(logAboveSpinners);
204
- const renderModel = createCanvas(spinner, formatter, ident);
205
- return (message) => {
206
- renderModel(updateModel(message));
207
- checkTimeout();
208
- };
209
- function checkTimeout() {
210
- const spinning = getModel().spinning;
211
- if (spinning && !interval) {
212
- interval = setInterval(updateSpinners, spinner.interval);
213
- interval.unref(); // unref immidiately just in case
214
- }
215
- else if (!spinning && interval) {
216
- clearInterval(interval);
217
- interval = undefined;
218
- }
219
- }
220
- function updateSpinners() {
221
- const model = getModel();
222
- model.tick++;
223
- model.tick %= spinner.frames.length;
224
- renderModel(model);
225
- }
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
+ }
226
231
  }
227
232
 
228
233
  exports.createDraftlogAppender = createDraftlogAppender;
package/dist/core.d.ts CHANGED
@@ -1,3 +1,3 @@
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;
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 CHANGED
@@ -1,226 +1,231 @@
1
1
  import draftlog from 'draftlog';
2
2
  import { List, prepend, append, removeRange, appendRange, remove } from '@slimlib/list';
3
3
 
4
- function createCanvas(spinner, formatter, ident) {
5
- draftlog(console);
6
- draftlog.defaults.canReWrite = false;
7
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
- const updaters = [];
9
- return (model) => {
10
- if (model.skipLines) {
11
- updaters.splice(0, model.skipLines);
12
- model.skipLines = 0;
13
- }
14
- let key = 0, dirty = false;
15
- const stack = [];
16
- for (const item of model) {
17
- if (dirty || item.dirty || item.status) {
18
- let prefix = getPrefix(item.status, model.tick), prefixUpdated = false;
19
- const subitems = substrings(item.message);
20
- for (const message of subitems) {
21
- let updater = updaters[key++];
22
- if (!updater) {
23
- updater = console.draft(' ');
24
- updaters.push(updater);
25
- }
26
- updater(formatter({
27
- loglevel: item.loglevel,
28
- message,
29
- context: item.context,
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
- action: (item.status === undefined ? 3 /* log */ : undefined),
32
- tag: item.tag
33
- }, prefix, ident * stack.length));
34
- if (subitems.length > 1 && typeof prefix === 'string' && !prefixUpdated) {
35
- prefix = prefix.replaceAll(/./g, ' ');
36
- prefixUpdated = true;
37
- }
38
- }
39
- if (item.dirty) {
40
- item.dirty = false;
41
- dirty = true;
42
- }
43
- }
44
- else {
45
- // iterate
46
- key += substrings(item.message).length;
47
- }
48
- if (stack[stack.length - 1] === item) {
49
- stack[stack.length - 1] = null;
50
- }
51
- if (item.lastLeaf) {
52
- stack.push(item.lastLeaf);
53
- }
54
- while (stack.length && stack[stack.length - 1] == null) {
55
- stack.pop();
56
- }
57
- }
58
- while (key !== updaters.length) {
59
- updaters[key++]('');
60
- }
61
- };
62
- function getPrefix(status, tick) {
63
- // status is truthy when it is inprogress
64
- return status ? spinner.frames[tick] :
65
- // status not null when it is finished
66
- status != null;
67
- }
68
- }
69
- function substrings(message) {
70
- var _a;
71
- return (_a = message
72
- .match(/.{1,80}/g)) !== null && _a !== void 0 ? _a : [];
4
+ const allColumnsListeners = new Set();
5
+ function subscribeToTerminalResize(listener) {
6
+ allColumnsListeners.add(new WeakRef(listener));
73
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
+ });
74
19
 
75
- /******************************************************************************
76
- Copyright (c) Microsoft Corporation.
77
-
78
- Permission to use, copy, modify, and/or distribute this software for any
79
- purpose with or without fee is hereby granted.
80
-
81
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
82
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
83
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
84
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
85
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
86
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
87
- PERFORMANCE OF THIS SOFTWARE.
88
- ***************************************************************************** */
89
-
90
- function __rest(s, e) {
91
- var t = {};
92
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
93
- t[p] = s[p];
94
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
95
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
96
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
97
- t[p[i]] = s[p[i]];
98
- }
99
- return t;
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
+ }
100
107
  }
101
108
 
102
- function createModel(logAboveSpinners) {
103
- const model = new List();
104
- const itemById = Object.create(null);
105
- model.tick = model.skipLines = model.spinning = 0;
106
- return [(_a) => {
107
- var { action } = _a, item = __rest(_a, ["action"]);
108
- // item has status undefined, so it is static by default
109
- item.dirty = true;
110
- const { inputId } = item;
111
- if (action === 0 /* start */) {
112
- item.status = 1 /* inprogress */;
113
- }
114
- if (action === 2 /* finish */) {
115
- item.status = 0 /* finished */;
116
- }
117
- if (action !== 3 /* log */) {
118
- // if status still empty in the original item or item does not exists it will remain empty and static
119
- updateModel(inputId, item);
120
- }
121
- cleanupModel();
122
- if (action === 3 /* log */) {
123
- appendToModel(item, logAboveSpinners);
124
- }
125
- return model;
126
- }, () => {
127
- cleanupModel();
128
- return model;
129
- }];
130
- function appendToModel(item, head) {
131
- if (head) {
132
- prepend(model, item);
133
- }
134
- else {
135
- append(model, item);
136
- }
137
- model.spinning += (item.status || 0);
138
- }
139
- function updateModel(inputId, options) {
140
- const modelItem = itemById[inputId];
141
- if (!modelItem) {
142
- const item = Object.assign({ inputId: inputId }, options);
143
- itemById[inputId] = item;
144
- const itemParentId = item.parentId;
145
- if (itemParentId != null) {
146
- putIntoChildren(itemParentId, item, item);
147
- }
148
- else {
149
- appendToModel(item, false);
150
- }
151
- }
152
- else {
153
- const statusDiff = (options.status || 0) - (modelItem.status || 0);
154
- const moveIntoParent = options.parentId != null && modelItem.parentId == null;
155
- Object.assign(modelItem, options);
156
- model.spinning += statusDiff;
157
- if (moveIntoParent) {
158
- const lastLeaf = getLastLeaf(modelItem);
159
- model.spinning -= (modelItem.status || 0);
160
- modelItem.dirty = true;
161
- removeRange(modelItem, lastLeaf);
162
- putIntoChildren(modelItem.parentId, modelItem, lastLeaf);
163
- }
164
- }
165
- }
166
- function putIntoChildren(itemParentId, begin, end) {
167
- let parent = itemById[itemParentId];
168
- if (!parent) {
169
- parent = { inputId: itemParentId, message: '', loglevel: 0, ref: new WeakRef(model) };
170
- appendToModel(parent, false);
171
- itemById[itemParentId] = parent;
172
- }
173
- appendRange((getLastLeaf(parent)), begin, end);
174
- parent.lastLeaf = begin;
175
- model.spinning += (begin.status || 0);
176
- }
177
- function cleanupModel() {
178
- var _a;
179
- for (const item of model) {
180
- if (!((_a = item.ref) === null || _a === void 0 ? void 0 : _a.deref())) {
181
- model.skipLines += 1;
182
- item.inputId != null && delete itemById[item.inputId];
183
- remove(item);
184
- }
185
- else {
186
- break;
187
- }
188
- }
189
- }
190
- }
191
- function getLastLeaf(modelItem) {
192
- let lastLeaf = modelItem;
193
- while (lastLeaf.lastLeaf) {
194
- lastLeaf = lastLeaf.lastLeaf;
195
- }
196
- return lastLeaf;
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;
197
202
  }
198
203
 
199
- function createDraftlogAppender(spinner, formatter, logAboveSpinners, ident) {
200
- let interval;
201
- const [updateModel, getModel] = createModel(logAboveSpinners);
202
- const renderModel = createCanvas(spinner, formatter, ident);
203
- return (message) => {
204
- renderModel(updateModel(message));
205
- checkTimeout();
206
- };
207
- function checkTimeout() {
208
- const spinning = getModel().spinning;
209
- if (spinning && !interval) {
210
- interval = setInterval(updateSpinners, spinner.interval);
211
- interval.unref(); // unref immidiately just in case
212
- }
213
- else if (!spinning && interval) {
214
- clearInterval(interval);
215
- interval = undefined;
216
- }
217
- }
218
- function updateSpinners() {
219
- const model = getModel();
220
- model.tick++;
221
- model.tick %= spinner.frames.length;
222
- renderModel(model);
223
- }
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
+ }
224
229
  }
225
230
 
226
231
  export { createDraftlogAppender };
@@ -1,4 +1,4 @@
1
- import { Formatter } from '@niceties/logger/types';
2
- import { Model } from './model';
3
- import { Spinner } from '../spinners';
4
- export declare function createCanvas(spinner: Spinner, formatter: Formatter, ident: number): (model: Model) => void;
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 +1,24 @@
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 declare 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
+ 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];
@@ -0,0 +1 @@
1
+ export default function splitByLines(message: string): string[];
@@ -0,0 +1 @@
1
+ export declare function subscribeToTerminalResize(listener: () => void): void;
package/dist/index.cjs CHANGED
@@ -9,12 +9,12 @@ var spinners = require('./spinners.cjs');
9
9
  require('draftlog');
10
10
  require('@slimlib/list');
11
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 /* 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
- ));
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
20
  }
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export {};
1
+ export {};
package/dist/index.mjs CHANGED
@@ -7,12 +7,12 @@ import { dots, line } from './spinners.mjs';
7
7
  import 'draftlog';
8
8
  import '@slimlib/list';
9
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 /* 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
- ));
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
18
  }
package/dist/spinners.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
- const dots = {
4
- interval: 50,
5
- frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
6
- };
7
- const line = {
8
- interval: 130,
9
- frames: ['-', '\\', '|', '/']
3
+ const dots = {
4
+ interval: 50,
5
+ frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
6
+ };
7
+ const line = {
8
+ interval: 130,
9
+ frames: ['-', '\\', '|', '/']
10
10
  };
11
11
 
12
12
  exports.dots = dots;
@@ -1,12 +1,12 @@
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
+ 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
+ };
package/dist/spinners.mjs CHANGED
@@ -1,10 +1,10 @@
1
- const dots = {
2
- interval: 50,
3
- frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
4
- };
5
- const line = {
6
- interval: 130,
7
- frames: ['-', '\\', '|', '/']
1
+ const dots = {
2
+ interval: 50,
3
+ frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
4
+ };
5
+ const line = {
6
+ interval: 130,
7
+ frames: ['-', '\\', '|', '/']
8
8
  };
9
9
 
10
10
  export { dots, line };
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.2.9",
2
+ "version": "1.3.1",
3
3
  "license": "MIT",
4
4
  "name": "@niceties/draftlog-appender",
5
5
  "author": {
@@ -48,36 +48,20 @@
48
48
  "draftlog",
49
49
  "appender"
50
50
  ],
51
- "scripts": {
52
- "build": "pkgbld-internal",
53
- "test": "node --expose-gc ../node_modules/jest-cli/bin/jest.js --collectCoverage",
54
- "lint": "eslint ./src",
55
- "semantic-release": "npx semantic-release"
56
- },
57
51
  "devDependencies": {
58
- "@semantic-release/changelog": "6.0.1",
59
- "@semantic-release/commit-analyzer": "9.0.1",
60
- "@semantic-release/git": "10.0.1",
61
- "@semantic-release/npm": "8.0.2",
62
- "@semantic-release/release-notes-generator": "10.0.2",
63
- "@types/jest": "27.4.0",
64
- "@typescript-eslint/eslint-plugin": "5.11.0",
65
- "@typescript-eslint/parser": "5.11.0",
66
- "conventional-changelog-angular": "5.0.13",
67
- "eslint": "8.8.0",
68
- "jest": "27.5.1",
69
- "semantic-release": "18.0.0",
70
- "semantic-release-monorepo": "7.0.5",
71
- "ts-jest": "27.1.3",
72
- "typescript": "4.6.x",
73
- "update-monorepo-package-json": "0.2.0",
74
- "pkgbld-internal": "1.0.4"
52
+ "tslib": "2.5.0",
53
+ "@niceties/logger": "1.1.11"
75
54
  },
76
55
  "peerDependencies": {
77
- "@niceties/logger": "^1.1.10"
56
+ "@niceties/logger": "^1.1.11"
78
57
  },
79
58
  "dependencies": {
80
59
  "draftlog": "^1.0.13",
81
60
  "@slimlib/list": "^1.0.3"
61
+ },
62
+ "scripts": {
63
+ "build": "pkgbld-internal",
64
+ "test": "node --expose-gc ../node_modules/jest/bin/jest.js --collectCoverage",
65
+ "lint": "eslint ./src"
82
66
  }
83
- }
67
+ }