@endgame45/nodescript 1.2.0 → 1.4.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 +50 -40
- package/package.json +3 -2
- package/src/nodescript.js +103 -1
package/README.md
CHANGED
|
@@ -1,85 +1,95 @@
|
|
|
1
1
|
# nodescript
|
|
2
2
|
|
|
3
|
-
Node.js logging and scheduling
|
|
3
|
+
Lightweight Node.js logging, styling and scheduling helpers.
|
|
4
4
|
|
|
5
5
|
Features
|
|
6
|
-
-
|
|
7
|
-
- Namespaced
|
|
6
|
+
- Styled logging with sensible level colors: nsc.log / nsc.info / nsc.warn / nsc.error / nsc.debug
|
|
7
|
+
- Namespaced instances: nsc.create(namespace, opts)
|
|
8
8
|
- Auto color detection (respects NO_COLOR and TTY)
|
|
9
|
-
- Timestamping (ISO
|
|
9
|
+
- Timestamping (ISO, local, or custom formatter)
|
|
10
10
|
- Color parsing: hex, rgb/rgba, hsl/hsla, CSS keywords (alpha blended)
|
|
11
|
-
-
|
|
12
|
-
- Flow
|
|
13
|
-
-
|
|
11
|
+
- Theme presets and tagged-template styling
|
|
12
|
+
- Flow-control utilities: debounce, throttle, retry/backoff, pLimit
|
|
13
|
+
- Loop helpers with concurrency and scheduling
|
|
14
|
+
- Simple file sink (rotating by size) and writable stream support
|
|
15
|
+
- TypeScript declarations included
|
|
14
16
|
|
|
15
17
|
Installation
|
|
16
18
|
|
|
17
19
|
npm install nodescript
|
|
18
20
|
|
|
19
|
-
Quick
|
|
20
|
-
|
|
21
|
-
Basic logging
|
|
21
|
+
Quick start
|
|
22
22
|
|
|
23
23
|
```javascript
|
|
24
24
|
const nsc = require('nodescript');
|
|
25
|
+
|
|
26
|
+
// basic
|
|
25
27
|
nsc.info('Hello %s', 'world');
|
|
26
|
-
nsc.warn('
|
|
27
|
-
nsc.error('Oops: %s', 'failure');
|
|
28
|
+
nsc.warn('Low disk space: %d%%', 12);
|
|
28
29
|
|
|
29
30
|
// change global level
|
|
30
31
|
nsc.level = 'debug';
|
|
31
|
-
```
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
```javascript
|
|
33
|
+
// namespaced logger
|
|
36
34
|
const db = nsc.create('db', { textColor: 'cyan', level: 'debug', timestamp: { enabled: true } });
|
|
37
35
|
db.debug('Connected to %s', 'postgres://...');
|
|
38
|
-
```
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```javascript
|
|
37
|
+
// themes
|
|
43
38
|
nsc.registerTheme('errorTheme', { textColor: '#ff4444', font: 'bold', level: 'error' });
|
|
44
39
|
const err = nsc.useTheme('errorTheme');
|
|
45
40
|
err.error('Fatal: %s', 'something broke');
|
|
46
|
-
```
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```javascript
|
|
42
|
+
// tagged-template
|
|
51
43
|
const name = 'Alice';
|
|
52
44
|
console.log(nsc.style`Hello, ${name}!`);
|
|
45
|
+
// or log via tag
|
|
53
46
|
nsc.tagLog`Processed ${42} items for ${() => name}`;
|
|
54
|
-
```
|
|
55
47
|
|
|
56
|
-
|
|
48
|
+
// fluent style shortcuts
|
|
49
|
+
console.log(nsc.red.bold('Important: %s', 'value'));
|
|
50
|
+
nsc.red.bold.log('Important message');
|
|
57
51
|
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
// file sink
|
|
53
|
+
const sink = nsc.logToFile('./logs/app.log', { maxBytes: 5 * 1024 * 1024 });
|
|
54
|
+
nsc.outStream = sink; // attach sink to instance
|
|
55
|
+
nsc.info('This goes to the log file');
|
|
56
|
+
|
|
57
|
+
// utilities
|
|
58
|
+
const deb = nsc.debounce(() => console.log('debounced'), 200);
|
|
59
|
+
deb();
|
|
60
|
+
|
|
61
|
+
const limited = nsc.pLimit(3);
|
|
62
|
+
// concurrency-controlled calls: limited(fn)(...)
|
|
63
|
+
|
|
64
|
+
// loops with concurrency
|
|
60
65
|
await nsc.loop.duration('200ms').call(asyncTask).concurrency(5).times(50);
|
|
61
66
|
|
|
62
|
-
// start
|
|
67
|
+
// start/stop controller
|
|
63
68
|
const ctl = nsc.loop.duration('1s').call(task).concurrency(2).start();
|
|
64
|
-
// stop
|
|
65
69
|
ctl.stop();
|
|
66
70
|
await ctl.done;
|
|
67
71
|
```
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
API summary
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
- nsc.create(namespace, opts) -> namespaced instance
|
|
76
|
+
- nsc.info/warn/error/debug(...args)
|
|
77
|
+
- nsc.level = 'error'|'warn'|'info'|'debug'
|
|
78
|
+
- nsc.timestamp = { enabled: boolean, format: 'iso'|'local'|fn }
|
|
79
|
+
- nsc.registerTheme(name, opts) / nsc.useTheme(name) / nsc.applyTheme(name)
|
|
80
|
+
- nsc.style`...` and nsc.tagLog`...` (tagged templates)
|
|
81
|
+
- nsc.red/.green/.blue etc. fluent proxies with .bold/.underline chaining
|
|
82
|
+
- Utilities: nsc.debounce, nsc.throttle, nsc.retry, nsc.pLimit
|
|
83
|
+
- nsc.logToFile(path, { maxBytes }) -> sink with write/close
|
|
84
|
+
|
|
85
|
+
TypeScript
|
|
74
86
|
|
|
75
|
-
|
|
76
|
-
await safe();
|
|
87
|
+
Types are included at types/nsc.d.ts. Import with:
|
|
77
88
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
await Promise.all(ids.map(id => limited(id)));
|
|
89
|
+
```ts
|
|
90
|
+
import nsc = require('nodescript');
|
|
81
91
|
```
|
|
82
92
|
|
|
83
93
|
License
|
|
84
94
|
|
|
85
|
-
MIT — see LICENSE
|
|
95
|
+
MIT — see LICENSE
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@endgame45/nodescript",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"main": "src/nodescript.js",
|
|
5
|
+
"types": "types/nsc.d.ts",
|
|
5
6
|
"files": [
|
|
6
7
|
"src"
|
|
7
8
|
],
|
|
@@ -29,5 +30,5 @@
|
|
|
29
30
|
"url": "https://github.com/horizon-std/nodescript"
|
|
30
31
|
},
|
|
31
32
|
"bugs": "https://github.com/horizon-std/nodescript/issues",
|
|
32
|
-
"readme": ""
|
|
33
|
+
"readme": "README.md"
|
|
33
34
|
}
|
package/src/nodescript.js
CHANGED
|
@@ -98,6 +98,53 @@ function buildStyler(config) {
|
|
|
98
98
|
return styler;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
// Fluent style proxy helper: returns a callable that produces styled strings
|
|
102
|
+
function makeStyleProxy(baseConfig = {}) {
|
|
103
|
+
const factory = function (...args) {
|
|
104
|
+
// when called, format like util.format and return styled string
|
|
105
|
+
const txt = util.format(...args);
|
|
106
|
+
const styler = buildStyler(baseConfig);
|
|
107
|
+
return styler(txt);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const handler = {
|
|
111
|
+
get(_, prop) {
|
|
112
|
+
const p = String(prop);
|
|
113
|
+
// allow access to .log/.info/.warn/.error which will print using the styled text
|
|
114
|
+
if (p === 'log') return (...a) => { console.log(factory(...a)); };
|
|
115
|
+
if (p === 'info') return (...a) => { console.log(factory(...a)); };
|
|
116
|
+
if (p === 'warn') return (...a) => { console.warn(factory(...a)); };
|
|
117
|
+
if (p === 'error') return (...a) => { console.error(factory(...a)); };
|
|
118
|
+
if (SUPPORTED_FONTS.has(p)) {
|
|
119
|
+
// return new proxy with font added
|
|
120
|
+
const next = Object.assign({}, baseConfig);
|
|
121
|
+
next.font = next.font ? (next.font + ' ' + p) : p;
|
|
122
|
+
return makeStyleProxy(next);
|
|
123
|
+
}
|
|
124
|
+
// treat other props as colors (e.g., .red)
|
|
125
|
+
const next = Object.assign({}, baseConfig);
|
|
126
|
+
next.textColor = p;
|
|
127
|
+
return makeStyleProxy(next);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return new Proxy(factory, handler);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Create a style object from config that supports .log/.info chaining
|
|
135
|
+
function styleConfig(config = {}) {
|
|
136
|
+
const inst = Object.create(nsc);
|
|
137
|
+
if (config.textColor) inst.textColor = config.textColor;
|
|
138
|
+
if (config.bgColor) inst.bgColor = config.bgColor;
|
|
139
|
+
if (config.font) inst.font = config.font;
|
|
140
|
+
// bind convenience
|
|
141
|
+
inst.log = inst.log.bind(inst);
|
|
142
|
+
inst.info = inst.info.bind(inst);
|
|
143
|
+
inst.warn = inst.warn.bind(inst);
|
|
144
|
+
inst.error = inst.error.bind(inst);
|
|
145
|
+
return inst;
|
|
146
|
+
}
|
|
147
|
+
|
|
101
148
|
/**
|
|
102
149
|
* Parse duration input into milliseconds.
|
|
103
150
|
* Supported inputs:
|
|
@@ -398,7 +445,12 @@ const nsc = {
|
|
|
398
445
|
});
|
|
399
446
|
}
|
|
400
447
|
const out = styler(text);
|
|
401
|
-
console
|
|
448
|
+
// if an outStream is configured on this instance, write to it; otherwise use console
|
|
449
|
+
if (this.outStream && typeof this.outStream.write === 'function') {
|
|
450
|
+
this.outStream.write(String(out) + (this.outStream._autoNewline === false ? '' : '\n'));
|
|
451
|
+
} else {
|
|
452
|
+
console.log(out);
|
|
453
|
+
}
|
|
402
454
|
},
|
|
403
455
|
|
|
404
456
|
// low-level logging method used by level helpers
|
|
@@ -517,11 +569,61 @@ const nsc = {
|
|
|
517
569
|
console.log(s);
|
|
518
570
|
},
|
|
519
571
|
|
|
572
|
+
// file sink: simple rotating file writer
|
|
573
|
+
logToFile(filename, opts = {}) {
|
|
574
|
+
const fs = require('fs');
|
|
575
|
+
const maxBytes = Number(opts.maxBytes || 0);
|
|
576
|
+
// create write stream
|
|
577
|
+
let stream = fs.createWriteStream(filename, { flags: 'a', encoding: 'utf8' });
|
|
578
|
+
|
|
579
|
+
const rotate = () => {
|
|
580
|
+
try {
|
|
581
|
+
stream.end();
|
|
582
|
+
} catch (e) {
|
|
583
|
+
// ignore errors when closing stream
|
|
584
|
+
}
|
|
585
|
+
const backup = filename + '.' + Date.now();
|
|
586
|
+
try {
|
|
587
|
+
fs.renameSync(filename, backup);
|
|
588
|
+
} catch (e) {
|
|
589
|
+
// ignore rotation errors
|
|
590
|
+
}
|
|
591
|
+
stream = fs.createWriteStream(filename, { flags: 'a', encoding: 'utf8' });
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
const writer = (text) => {
|
|
595
|
+
if (maxBytes > 0) {
|
|
596
|
+
try {
|
|
597
|
+
const st = fs.existsSync(filename) ? fs.statSync(filename) : null;
|
|
598
|
+
if (st && st.size >= maxBytes) rotate();
|
|
599
|
+
} catch (e) {
|
|
600
|
+
// ignore stat errors
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
stream.write(String(text) + '\n');
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
// return a simple sink object and attach to this instance if desired
|
|
607
|
+
return { write: writer, close: () => stream.end() };
|
|
608
|
+
},
|
|
609
|
+
|
|
520
610
|
// utilities: debounce/throttle/retry/pLimit
|
|
521
611
|
debounce: utils.debounce,
|
|
522
612
|
throttle: utils.throttle,
|
|
523
613
|
retry: utils.retry,
|
|
524
614
|
pLimit: utils.pLimit,
|
|
615
|
+
// Fluent style factory and color shortcuts
|
|
616
|
+
styleConfig,
|
|
617
|
+
// common color shortcuts (red, green, blue, yellow, cyan, magenta, white, gray, black)
|
|
618
|
+
red: makeStyleProxy({ textColor: 'red' }),
|
|
619
|
+
green: makeStyleProxy({ textColor: 'green' }),
|
|
620
|
+
blue: makeStyleProxy({ textColor: 'blue' }),
|
|
621
|
+
yellow: makeStyleProxy({ textColor: 'yellow' }),
|
|
622
|
+
cyan: makeStyleProxy({ textColor: 'cyan' }),
|
|
623
|
+
magenta: makeStyleProxy({ textColor: 'magenta' }),
|
|
624
|
+
white: makeStyleProxy({ textColor: 'white' }),
|
|
625
|
+
gray: makeStyleProxy({ textColor: 'gray' }),
|
|
626
|
+
black: makeStyleProxy({ textColor: 'black' }),
|
|
525
627
|
|
|
526
628
|
/**
|
|
527
629
|
* Wait for the given duration and resolve the returned Promise.
|