@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 CHANGED
@@ -1,85 +1,95 @@
1
1
  # nodescript
2
2
 
3
- Node.js logging and scheduling utility with easy chalk styling.
3
+ Lightweight Node.js logging, styling and scheduling helpers.
4
4
 
5
5
  Features
6
- - Simple styled logging: nsc.log, nsc.info, nsc.warn, nsc.error, nsc.debug
7
- - Namespaced loggers: nsc.create(namespace, opts)
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/local/custom)
9
+ - Timestamping (ISO, local, or custom formatter)
10
10
  - Color parsing: hex, rgb/rgba, hsl/hsla, CSS keywords (alpha blended)
11
- - Themes and tagged-template styling
12
- - Flow control utilities: debounce, throttle, retry/backoff, pLimit
13
- - Looping helpers with concurrency
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 examples
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('This is a warning');
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
- Namespaced logger
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
- Themes
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
- Tagged template styling
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
- Looping and concurrency
48
+ // fluent style shortcuts
49
+ console.log(nsc.red.bold('Important: %s', 'value'));
50
+ nsc.red.bold.log('Important message');
57
51
 
58
- ```javascript
59
- // run task 50 times with up to 5 concurrent executions
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 infinite loop with 2 workers
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
- Utilities
73
+ API summary
70
74
 
71
- ```javascript
72
- const deb = nsc.debounce(() => console.log('debounced'), 200);
73
- deb();
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
- const safe = await nsc.retry(async () => fetchSomething(), { retries: 5 });
76
- await safe();
87
+ Types are included at types/nsc.d.ts. Import with:
77
88
 
78
- const limit = nsc.pLimit(3);
79
- const limited = limit(async (id) => fetch(id));
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 file.
95
+ MIT — see LICENSE
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@endgame45/nodescript",
3
- "version": "1.2.0",
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.log(out);
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.