analogger 1.9.0 → 1.10.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
- # [1.9.0](https://github.com/thimpat/analogger/compare/v1.8.5...v1.9.0) (2022-03-06)
1
+ ## [1.10.1](https://github.com/thimpat/analogger/compare/v1.10.0...v1.10.1) (2022-04-16)
2
2
 
3
+ # [1.10.0](https://github.com/thimpat/analogger/compare/v1.9.1...v1.10.0) (2022-03-16)
4
+
5
+ ## [1.9.1](https://github.com/thimpat/analogger/compare/v1.9.0...v1.9.1) (2022-03-14)
6
+
7
+ # [1.9.0](https://github.com/thimpat/analogger/compare/v1.8.5...v1.9.0) (2022-03-06)
8
+
3
9
  ## [1.8.5](https://github.com/thimpat/analogger/compare/v1.8.4...v1.8.5) (2022-02-28)
4
10
 
5
11
  ## [1.8.4](https://github.com/thimpat/analogger/compare/v1.8.3...v1.8.4) (2022-02-28)
package/README.md CHANGED
@@ -71,6 +71,52 @@ anaLogger.error(`I'am some log`);
71
71
  ```
72
72
  <br/>
73
73
 
74
+ ### table()
75
+
76
+ Display data in tabular format on the terminal.
77
+
78
+ ```javascript
79
+ const table = [
80
+ {
81
+ "serverName" : "Nubia",
82
+ "silent" : false,
83
+ "defaultPage" : "index.html",
84
+ "port" : 10040,
85
+ "serverUrl" : "http://localhost:10040/",
86
+ },
87
+ {
88
+ "serverName" : "Lavern",
89
+ "silent" : false,
90
+ "defaultPage" : "index.html",
91
+ "port" : 10050,
92
+ "serverUrl" : "http://localhost:10050/",
93
+ },
94
+ {
95
+ "serverName" : "Kristal",
96
+ "silent" : false,
97
+ "defaultPage" : "index.html",
98
+ "host" : "localhost",
99
+ "port" : 10060,
100
+ "serverUrl" : "http://localhost:10060/",
101
+ }
102
+ ];
103
+ anaLogger.table(table);
104
+ ```
105
+
106
+ <br/>
107
+
108
+ Result:
109
+
110
+ ```shell
111
+ serverName │ silent │ defaultPage │ port │ serverUrl │
112
+ ────────── │ ────── │ ──────────── │ ───── │ ───────────────────────── │
113
+ Nubia │ false │ index.html │ 10040 │ http://localhost:10040/ │
114
+ Lavern │ false │ index.html │ 10050 │ http://localhost:10050/ │
115
+ Kristal │ false │ index.html │ 10060 │ http://localhost:10060/ │
116
+ ```
117
+
118
+ <br/>
119
+
74
120
  ### alert()
75
121
 
76
122
  ```javascript
@@ -129,6 +175,18 @@ Remove overridden console methods
129
175
 
130
176
  <br/>
131
177
 
178
+ ### rawLog() | rawInfo() | rawWarn() | rawInfo()
179
+
180
+ Use native console format after overrides.
181
+
182
+ ```javascript
183
+ anaLogger.overrideConsole();
184
+ console.log(`Example 1`); // <= Will use new format
185
+ console.rawLog(`Example 2`); // <= Will use native format
186
+ ```
187
+
188
+ <br/>
189
+
132
190
  ### setContexts()
133
191
 
134
192
  #### Contexts
@@ -7,9 +7,13 @@
7
7
  import path from "path";
8
8
  import fs from "fs";
9
9
  import os from "os";
10
+ import terminalSize from "./node_modules/window-size/index.mjs";
10
11
  import toAnsi from "./node_modules/to-ansi/index.mjs";
11
12
  import rgbHex from "./node_modules/rgb-hex/index.mjs";
12
13
  import {COLOR_TABLE, SYSTEM} from "./src/cjs/constants.mjs";
14
+ import {stringify} from "./node_modules/flatted/cjs/index.mjs";
15
+ terminalSize = {};
16
+
13
17
  /** to-esm-browser: remove **/
14
18
 
15
19
 
@@ -17,12 +21,14 @@ import {COLOR_TABLE, SYSTEM} from "./src/cjs/constants.mjs";
17
21
 
18
22
 
19
23
 
24
+
20
25
  const PREDEFINED_CONTEXT_NAMES = {
21
26
  "DEFAULT": "DEFAULT",
22
- "ERROR": "ERROR"
27
+ "ERROR" : "ERROR"
23
28
  };
24
29
 
25
- const EOL =`
30
+
31
+ const EOL = `
26
32
  `;
27
33
 
28
34
  class AnaLogger
@@ -49,6 +55,13 @@ class AnaLogger
49
55
  hideHookMessage: false
50
56
  };
51
57
 
58
+ #realConsoleLog = console.log;
59
+ #realConsoleInfo = console.info;
60
+ #realConsoleWarn = console.warn;
61
+ #realConsoleError = console.error;
62
+
63
+ isBrowser0 = null;
64
+
52
65
  static ALIGN = {
53
66
  LEFT : "LEFT",
54
67
  RIGHT: "RIGHT"
@@ -65,6 +78,7 @@ class AnaLogger
65
78
  {
66
79
  if (AnaLogger.Instance)
67
80
  {
81
+ /* istanbul ignore next */
68
82
  return AnaLogger.Instance;
69
83
  }
70
84
 
@@ -79,10 +93,26 @@ class AnaLogger
79
93
 
80
94
  this.setOptions(this.options);
81
95
 
82
- this.realConsoleLog = console.log;
83
- this.realConsoleInfo = console.info;
84
- this.realConsoleWarn = console.warn;
85
- this.realConsoleError = console.error;
96
+ this.rawLog = this.#realConsoleLog;
97
+ this.rawInfo = this.#realConsoleInfo;
98
+ this.rawWarn = this.#realConsoleWarn;
99
+ this.rawError = this.#realConsoleError;
100
+
101
+ console.rawLog = this.#realConsoleLog;
102
+ console.rawInfo = this.#realConsoleInfo;
103
+ console.rawWarn = this.#realConsoleWarn;
104
+ console.rawError = this.#realConsoleError;
105
+
106
+ console.table = this.table;
107
+ console.buildTable = this.buildTable;
108
+ console.isNode = this.isNode;
109
+ console.isBrowser = this.isBrowser;
110
+ console.truncateMessage = this.truncateMessage;
111
+ console.rawLog = this.rawLog;
112
+ console.rawInfo = this.rawInfo;
113
+ console.rawWarn = this.rawWarn;
114
+ console.rawError = this.rawError;
115
+ console.isBrowser0 = this.system === SYSTEM.BROWSER;
86
116
 
87
117
  this.ALIGN = AnaLogger.ALIGN;
88
118
  this.ENVIRONMENT_TYPE = AnaLogger.ENVIRONMENT_TYPE;
@@ -133,44 +163,34 @@ class AnaLogger
133
163
 
134
164
  resetLogger()
135
165
  {
136
- this.options = {
137
- contextLenMax : 10,
138
- idLenMax : 5,
139
- lidLenMax : 5,
140
- symbolLenMax : 2,
141
- messageLenMax : undefined,
142
- hideLog : undefined,
143
- hideError : undefined,
144
- hideHookMessage : undefined,
145
- hidePassingTests : undefined,
146
- logToDom : undefined,
147
- logToFile : undefined,
148
- oneConsolePerContext: undefined,
149
- silent : undefined
150
- };
151
- }
152
-
153
- resetOptions()
154
- {
166
+ this.options = {};
167
+ this.options.timeLenMax = 10;
155
168
  this.options.contextLenMax = 10;
156
169
  this.options.idLenMax = 5;
157
- this.options.lidLenMax = 5;
170
+ this.options.lidLenMax = 6;
158
171
  this.options.messageLenMax = undefined;
159
172
  this.options.symbolLenMax = 60;
160
- this.options.hideHookMessage = false;
161
- this.options.hidePassingTests = false;
162
- this.options.hideLog = false;
163
- this.options.hideError = false;
173
+ this.options.hideHookMessage = undefined;
174
+ this.options.hidePassingTests = undefined;
175
+ this.options.hideLog = undefined;
176
+ this.options.hideError = undefined;
164
177
  this.options.oneConsolePerContext = true;
165
178
  this.options.logToDom = undefined;
179
+ this.options.logToFile = undefined;
166
180
  this.options.logToDomlogToFile = undefined;
167
181
  this.options.silent = false;
182
+
183
+ }
184
+
185
+ resetOptions()
186
+ {
187
+ this.resetLogger();
168
188
  }
169
189
 
170
190
  setOptions({
171
191
  contextLenMax = 10,
172
192
  idLenMax = 5,
173
- lidLenMax = 5,
193
+ lidLenMax = 6,
174
194
  symbolLenMax = 2,
175
195
  messageLenMax = undefined,
176
196
  hideLog = undefined,
@@ -228,14 +248,14 @@ class AnaLogger
228
248
  /** to-esm-browser: remove **/
229
249
  // these require won't get compiled by to-esm
230
250
  this.options.logToFilePath = path.resolve(this.options.logToFile);
231
- this.logFile = fs.createWriteStream(this.options.logToFilePath, {flags : "a"});
251
+ this.logFile = fs.createWriteStream(this.options.logToFilePath, {flags: "a"});
232
252
  this.EOL = os.EOL;
233
253
  /** to-esm-browser: end-remove **/
234
254
  }
235
255
 
236
256
  /** to-esm-browser: add
237
- this.realConsoleLog("LogToFile is not supported in this environment. ")
238
- * **/
257
+ this.#realConsoleLog("LogToFile is not supported in this environment. ")
258
+ **/
239
259
 
240
260
  }
241
261
 
@@ -252,18 +272,162 @@ class AnaLogger
252
272
  return this.options;
253
273
  }
254
274
 
255
- truncateMessage(input = "", {fit = 0, align = AnaLogger.ALIGN.LEFT} = {})
275
+ truncateMessage(input = "", {fit = 0, align = AnaLogger.ALIGN.LEFT, ellipsis = "..."} = {})
256
276
  {
257
277
  input = "" + input;
258
- if (fit && input.length >= fit + 2)
278
+ if (fit && input.length > fit)
259
279
  {
260
- input = input.substring(0, fit - 3) + "...";
280
+ input = input.substring(0, fit - ellipsis.length) + ellipsis;
261
281
  }
262
282
 
263
283
  input = align === AnaLogger.ALIGN.LEFT ? input.padEnd(fit, " ") : input.padStart(fit, " ");
264
284
  return input;
265
285
  }
266
286
 
287
+ /**
288
+ * Display data
289
+ * @param {any[]} table
290
+ * @param ellipsis
291
+ * @param ColumnMinChars
292
+ * @param columnMaxChars
293
+ * @param verticalSeparator
294
+ * @param horizontalSeparator
295
+ * @param availableLength
296
+ */
297
+ buildTable(table, {
298
+ ellipsis = "...",
299
+ ColumnMinChars = 6,
300
+ columnMaxChars = 0,
301
+ verticalSeparator = " │ ",
302
+ horizontalSeparator = "─",
303
+ availableLength = 0
304
+ } = {})
305
+ {
306
+ let text = "";
307
+
308
+ const isArray = Array.isArray(table);
309
+ if (!isArray)
310
+ {
311
+ table = Object.values(Object.values(table));
312
+ }
313
+
314
+ if (!table || !table.length)
315
+ {
316
+ return "";
317
+ }
318
+
319
+ const firstLine = table[0];
320
+ const titles = Object.keys(firstLine);
321
+ table.unshift(titles);
322
+
323
+ horizontalSeparator = horizontalSeparator.repeat(100);
324
+
325
+ const fits = {};
326
+ for (let i = 1; i < table.length; ++i)
327
+ {
328
+ const line = table[i];
329
+ for (let ii = 0; ii < titles.length; ++ii)
330
+ {
331
+ const colName = titles[ii];
332
+ const colContent = line[colName];
333
+
334
+ fits[colName] = fits[colName] || 0;
335
+ let colLength;
336
+ try
337
+ {
338
+ colLength = JSON.stringify(colContent).length;
339
+ }
340
+ catch (e)
341
+ {
342
+ }
343
+
344
+ colLength = colLength || ColumnMinChars;
345
+ fits[colName] = Math.max(fits[colName], colLength, colName.length);
346
+ }
347
+ }
348
+
349
+ if (!this.isBrowser0)
350
+ {
351
+ terminalSize = terminalSize || {};
352
+
353
+ if (!availableLength)
354
+ {
355
+ availableLength = terminalSize.width || process.stdout.columns || 120 - verticalSeparator.length - 1 - 5;
356
+ }
357
+ }
358
+
359
+ let totalLength = Object.values(fits).reduce((a, b) => a + b, 0);
360
+ if (availableLength < totalLength)
361
+ {
362
+ const ratio = (availableLength) / totalLength;
363
+ for (let key in fits)
364
+ {
365
+ fits[key] = Math.floor(fits[key] * ratio) - 1;
366
+ if (ColumnMinChars && fits[key] < ColumnMinChars)
367
+ {
368
+ fits[key] = ColumnMinChars;
369
+ }
370
+
371
+ if (columnMaxChars && fits[key] > columnMaxChars)
372
+ {
373
+ fits[key] = columnMaxChars;
374
+ }
375
+
376
+ fits[key] = fits[key];
377
+ }
378
+
379
+ }
380
+
381
+ let strLine;
382
+
383
+ // Titles
384
+ strLine = "";
385
+ for (let i = 0; i < titles.length; ++i)
386
+ {
387
+ const colName = titles[i];
388
+ const fit = fits[colName];
389
+ strLine += this.truncateMessage(colName, {fit, ellipsis});
390
+ strLine += verticalSeparator;
391
+ }
392
+ text += this.truncateMessage(strLine, {fit: availableLength});
393
+ text += EOL;
394
+
395
+ // Separators
396
+ strLine = "";
397
+ const colContent = horizontalSeparator;
398
+ for (let i = 0; i < titles.length; ++i)
399
+ {
400
+ const colName = titles[i];
401
+ const fit = fits[colName];
402
+ strLine += this.truncateMessage(colContent, {fit, ellipsis: ""});
403
+ strLine += verticalSeparator;
404
+ }
405
+ text += this.truncateMessage(strLine, {fit: availableLength});
406
+ text += EOL;
407
+
408
+ // Content
409
+ for (let i = 1; i < table.length; ++i)
410
+ {
411
+ strLine = "";
412
+ const line = table[i];
413
+ for (let ii = 0; ii < titles.length; ++ii)
414
+ {
415
+ const colName = titles[ii];
416
+ const colContent = line[colName];
417
+ const fit = fits[colName];
418
+
419
+ strLine += this.truncateMessage(colContent, {fit, ellipsis});
420
+ strLine += verticalSeparator;
421
+ }
422
+ text += this.truncateMessage(strLine, {fit: availableLength});
423
+ text += EOL;
424
+ }
425
+
426
+ this.rawLog(text);
427
+
428
+ return text;
429
+ }
430
+
267
431
  /**
268
432
  * Format inputs
269
433
  * @see Override {@link setLogFormat}
@@ -281,9 +445,11 @@ class AnaLogger
281
445
  let time = ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2) + ":" + ("0" + date.getSeconds()).slice(-2);
282
446
 
283
447
  // Display content in columns
284
- time = this.truncateMessage(time, {fit: 7});
285
- contextName = this.truncateMessage(contextName, {fit: this.options.contextLenMax, align: AnaLogger.ALIGN.RIGHT});
286
- // id = this.truncateMessage(id, {fit: this.options.idLenMax})
448
+ time = this.truncateMessage(time, {fit: this.options.timeLenMax});
449
+ contextName = this.truncateMessage(contextName, {
450
+ fit : this.options.contextLenMax,
451
+ align: AnaLogger.ALIGN.RIGHT
452
+ });
287
453
  lid = this.truncateMessage(lid, {fit: this.options.lidLenMax});
288
454
 
289
455
  if (this.options.messageLenMax !== undefined)
@@ -541,7 +707,7 @@ class AnaLogger
541
707
  $line.setAttribute("data-log-counter", this.logCounter);
542
708
  $line.setAttribute("data-log-index", this.logIndex);
543
709
 
544
- this.setColumns($line ,context, text);
710
+ this.setColumns($line, context, text);
545
711
 
546
712
  $view.append($line);
547
713
  }
@@ -552,6 +718,44 @@ class AnaLogger
552
718
  this.logFile.write(text + this.EOL);
553
719
  }
554
720
 
721
+ convertArgumentsToText(args)
722
+ {
723
+ const strs = [];
724
+ let text;
725
+ const n = args.length;
726
+ for (let i = 0; i < n; ++i)
727
+ {
728
+ let str;
729
+ let arg = args[i];
730
+
731
+ try
732
+ {
733
+ str = JSON.stringify(arg);
734
+ }
735
+ catch (e)
736
+ {
737
+
738
+ }
739
+
740
+ if (!str)
741
+ {
742
+ try
743
+ {
744
+ str = stringify(arg);
745
+ }
746
+ catch (e)
747
+ {
748
+
749
+ }
750
+ }
751
+
752
+ strs.push(str);
753
+ }
754
+
755
+ text = strs.join("•");
756
+ return text;
757
+ }
758
+
555
759
  /**
556
760
  * Display log following template
557
761
  * @param context
@@ -560,6 +764,8 @@ class AnaLogger
560
764
  {
561
765
  try
562
766
  {
767
+ let message = "";
768
+
563
769
  if (!this.isTargetAllowed(context.target))
564
770
  {
565
771
  return;
@@ -568,10 +774,11 @@ class AnaLogger
568
774
  let args = Array.prototype.slice.call(arguments);
569
775
  args.shift();
570
776
 
571
- const message = args.join(" | ");
777
+ message = this.convertArgumentsToText(args);
572
778
 
573
779
  let output = "";
574
- const text = this.format({...context, message});
780
+ let text = "";
781
+ text = this.format({...context, message});
575
782
 
576
783
  ++this.logCounter;
577
784
 
@@ -582,6 +789,7 @@ class AnaLogger
582
789
  {
583
790
  this.writeLogToDom(context, text);
584
791
  }
792
+
585
793
  output = `%c${text}`;
586
794
  }
587
795
  else
@@ -607,11 +815,11 @@ class AnaLogger
607
815
 
608
816
  if (this.isBrowser())
609
817
  {
610
- this.realConsoleLog(output, `color: ${context.color}`);
818
+ this.#realConsoleLog(output, `color: ${context.color}`);
611
819
  }
612
820
  else
613
821
  {
614
- this.realConsoleLog(output);
822
+ this.#realConsoleLog(output);
615
823
  }
616
824
 
617
825
  this.errorTargetHandler(context, args);
@@ -644,7 +852,7 @@ class AnaLogger
644
852
  convertToContext(options, defaultContext)
645
853
  {
646
854
  defaultContext = defaultContext || this.generateDefaultContext();
647
- options = options || defaultContext;
855
+ options = options || defaultContext;
648
856
  let context = options;
649
857
  if (options.context && typeof options.context === "object")
650
858
  {
@@ -703,7 +911,7 @@ class AnaLogger
703
911
  {
704
912
  if (!this.options.hideHookMessage)
705
913
  {
706
- this.realConsoleLog("AnaLogger: Hook placed on console.error");
914
+ this.#realConsoleLog("AnaLogger: Hook placed on console.error");
707
915
  }
708
916
  console.error = this.onDisplayError.bind(this);
709
917
  }
@@ -712,7 +920,7 @@ class AnaLogger
712
920
  {
713
921
  if (!this.options.hideHookMessage)
714
922
  {
715
- this.realConsoleLog("AnaLogger: Hook placed on console.log");
923
+ this.#realConsoleLog("AnaLogger: Hook placed on console.log");
716
924
  }
717
925
 
718
926
  if (log)
@@ -738,24 +946,24 @@ class AnaLogger
738
946
 
739
947
  removeOverrideError()
740
948
  {
741
- console.warn = this.realConsoleError;
949
+ console.warn = this.#realConsoleError;
742
950
  }
743
951
 
744
952
  removeOverride({log = true, info = true, warn = true, error = false} = {})
745
953
  {
746
954
  if (log)
747
955
  {
748
- console.log = this.realConsoleLog;
956
+ console.log = this.#realConsoleLog;
749
957
  }
750
958
 
751
959
  if (info)
752
960
  {
753
- console.info = this.realConsoleInfo;
961
+ console.info = this.#realConsoleInfo;
754
962
  }
755
963
 
756
964
  if (warn)
757
965
  {
758
- console.warn = this.realConsoleWarn;
966
+ console.warn = this.#realConsoleWarn;
759
967
  }
760
968
 
761
969
  if (error)
@@ -775,6 +983,11 @@ class AnaLogger
775
983
  return this.log(...args);
776
984
  }
777
985
 
986
+ table(...args)
987
+ {
988
+ return this.buildTable(...args);
989
+ }
990
+
778
991
  alert(...args)
779
992
  {
780
993
  if (this.isNode())
@@ -831,5 +1044,6 @@ class AnaLogger
831
1044
 
832
1045
  }
833
1046
 
834
- export default new AnaLogger();
835
- export const anaLogger = new AnaLogger();
1047
+ export const anaLogger = new AnaLogger();
1048
+ export default anaLogger;
1049
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "analogger",
3
- "version": "1.9.0",
3
+ "version": "1.10.1",
4
4
  "description": "Js Logger",
5
5
  "main": "./src/cjs/ana-logger.cjs",
6
6
  "module": "./generated/browser/ana-logger.mjs",
@@ -34,7 +34,7 @@
34
34
  "*** In the Browser-2 ****": "# Generate Browser code",
35
35
  "*** In the Browser-3 ****": "# ----------------------------------------------------------------------------------------------------------",
36
36
  "build:esm:browser": "npm run clean:generated:browser && to-esm.cmd ./src/cjs/ana-logger.cjs --output generated/browser/ --config .toesm.cjs --target browser --update-all",
37
- "build:browser:demo": "npm run clean:generated:browser && to-esm.cmd example/cjs/demo.cjs --output=generated/browser/ --entrypoint=./src/cjs/ana-logger.cjs --config=\".toesm.cjs\" --target=browser --bundle=\"./dist/analogger-browser.min.mjs\"",
37
+ "build:browser:demo": "npm run clean:generated:browser && to-esm.cmd example/cjs/demo.cjs --output generated/browser/ --entrypoint ./src/cjs/ana-logger.cjs --config .toesm.cjs --target browser --bundle ./dist/analogger-browser.min.mjs",
38
38
  "demo:browser": "npm run build:browser:demo && node example/cjs/demo.cjs",
39
39
  "*** In the Browser with importmap-1 ****": "# ----------------------------------------------------------------------------------------------------------",
40
40
  "*** In the Browser with importmap-2 ****": "# Generate ESM code with import map",
@@ -90,12 +90,14 @@
90
90
  "chalk-cjs": "npm:chalk@^4.1.2",
91
91
  "color-convert": "^2.0.1",
92
92
  "color-convert-cjs": "npm:color-convert@^2.0.1",
93
+ "flatted": "^3.2.5",
93
94
  "js-beautify": "^1.10.1-rc2",
94
95
  "node_modules-path": "^2.0.5",
95
96
  "pretty-js": "^0.2.2",
96
97
  "rgb-hex": "^4.0.0",
97
98
  "rgb-hex-cjs": "npm:rgb-hex@^3.0.0",
98
99
  "to-ansi": "^1.0.5",
99
- "uglify-js": "^3.15.1"
100
+ "uglify-js": "^3.15.1",
101
+ "window-size": "^1.1.1"
100
102
  }
101
103
  }
@@ -1,18 +1,28 @@
1
+ let terminalSize = {};
2
+
1
3
  /** to-esm-browser: remove **/
2
4
  const path = require("path");
3
5
  const fs = require("fs");
4
6
  const os = require("os");
7
+ terminalSize = require("window-size");
5
8
  /** to-esm-browser: end-remove **/
6
9
 
10
+ /** to-esm-browser: add
11
+ terminalSize = {}
12
+ **/
13
+
7
14
  const toAnsi = require("to-ansi");
8
15
  const rgbHex = require("rgb-hex-cjs");
16
+
9
17
  const {COLOR_TABLE, SYSTEM} = require("./constants.cjs");
10
18
  const PREDEFINED_CONTEXT_NAMES = {
11
19
  "DEFAULT": "DEFAULT",
12
- "ERROR": "ERROR"
20
+ "ERROR" : "ERROR"
13
21
  };
14
22
 
15
- const EOL =`
23
+ const {stringify} = require("flatted");
24
+
25
+ const EOL = `
16
26
  `;
17
27
 
18
28
  class AnaLogger
@@ -39,6 +49,13 @@ class AnaLogger
39
49
  hideHookMessage: false
40
50
  };
41
51
 
52
+ #realConsoleLog = console.log;
53
+ #realConsoleInfo = console.info;
54
+ #realConsoleWarn = console.warn;
55
+ #realConsoleError = console.error;
56
+
57
+ isBrowser0 = null;
58
+
42
59
  static ALIGN = {
43
60
  LEFT : "LEFT",
44
61
  RIGHT: "RIGHT"
@@ -55,6 +72,7 @@ class AnaLogger
55
72
  {
56
73
  if (AnaLogger.Instance)
57
74
  {
75
+ /* istanbul ignore next */
58
76
  return AnaLogger.Instance;
59
77
  }
60
78
 
@@ -69,10 +87,26 @@ class AnaLogger
69
87
 
70
88
  this.setOptions(this.options);
71
89
 
72
- this.realConsoleLog = console.log;
73
- this.realConsoleInfo = console.info;
74
- this.realConsoleWarn = console.warn;
75
- this.realConsoleError = console.error;
90
+ this.rawLog = this.#realConsoleLog;
91
+ this.rawInfo = this.#realConsoleInfo;
92
+ this.rawWarn = this.#realConsoleWarn;
93
+ this.rawError = this.#realConsoleError;
94
+
95
+ console.rawLog = this.#realConsoleLog;
96
+ console.rawInfo = this.#realConsoleInfo;
97
+ console.rawWarn = this.#realConsoleWarn;
98
+ console.rawError = this.#realConsoleError;
99
+
100
+ console.table = this.table;
101
+ console.buildTable = this.buildTable;
102
+ console.isNode = this.isNode;
103
+ console.isBrowser = this.isBrowser;
104
+ console.truncateMessage = this.truncateMessage;
105
+ console.rawLog = this.rawLog;
106
+ console.rawInfo = this.rawInfo;
107
+ console.rawWarn = this.rawWarn;
108
+ console.rawError = this.rawError;
109
+ console.isBrowser0 = this.system === SYSTEM.BROWSER;
76
110
 
77
111
  this.ALIGN = AnaLogger.ALIGN;
78
112
  this.ENVIRONMENT_TYPE = AnaLogger.ENVIRONMENT_TYPE;
@@ -123,44 +157,34 @@ class AnaLogger
123
157
 
124
158
  resetLogger()
125
159
  {
126
- this.options = {
127
- contextLenMax : 10,
128
- idLenMax : 5,
129
- lidLenMax : 5,
130
- symbolLenMax : 2,
131
- messageLenMax : undefined,
132
- hideLog : undefined,
133
- hideError : undefined,
134
- hideHookMessage : undefined,
135
- hidePassingTests : undefined,
136
- logToDom : undefined,
137
- logToFile : undefined,
138
- oneConsolePerContext: undefined,
139
- silent : undefined
140
- };
141
- }
142
-
143
- resetOptions()
144
- {
160
+ this.options = {};
161
+ this.options.timeLenMax = 10;
145
162
  this.options.contextLenMax = 10;
146
163
  this.options.idLenMax = 5;
147
- this.options.lidLenMax = 5;
164
+ this.options.lidLenMax = 6;
148
165
  this.options.messageLenMax = undefined;
149
166
  this.options.symbolLenMax = 60;
150
- this.options.hideHookMessage = false;
151
- this.options.hidePassingTests = false;
152
- this.options.hideLog = false;
153
- this.options.hideError = false;
167
+ this.options.hideHookMessage = undefined;
168
+ this.options.hidePassingTests = undefined;
169
+ this.options.hideLog = undefined;
170
+ this.options.hideError = undefined;
154
171
  this.options.oneConsolePerContext = true;
155
172
  this.options.logToDom = undefined;
173
+ this.options.logToFile = undefined;
156
174
  this.options.logToDomlogToFile = undefined;
157
175
  this.options.silent = false;
176
+
177
+ }
178
+
179
+ resetOptions()
180
+ {
181
+ this.resetLogger();
158
182
  }
159
183
 
160
184
  setOptions({
161
185
  contextLenMax = 10,
162
186
  idLenMax = 5,
163
- lidLenMax = 5,
187
+ lidLenMax = 6,
164
188
  symbolLenMax = 2,
165
189
  messageLenMax = undefined,
166
190
  hideLog = undefined,
@@ -218,14 +242,14 @@ class AnaLogger
218
242
  /** to-esm-browser: remove **/
219
243
  // these require won't get compiled by to-esm
220
244
  this.options.logToFilePath = path.resolve(this.options.logToFile);
221
- this.logFile = fs.createWriteStream(this.options.logToFilePath, {flags : "a"});
245
+ this.logFile = fs.createWriteStream(this.options.logToFilePath, {flags: "a"});
222
246
  this.EOL = os.EOL;
223
247
  /** to-esm-browser: end-remove **/
224
248
  }
225
249
 
226
250
  /** to-esm-browser: add
227
- this.realConsoleLog("LogToFile is not supported in this environment. ")
228
- * **/
251
+ this.#realConsoleLog("LogToFile is not supported in this environment. ")
252
+ **/
229
253
 
230
254
  }
231
255
 
@@ -242,18 +266,164 @@ class AnaLogger
242
266
  return this.options;
243
267
  }
244
268
 
245
- truncateMessage(input = "", {fit = 0, align = AnaLogger.ALIGN.LEFT} = {})
269
+ truncateMessage(input = "", {fit = 0, align = AnaLogger.ALIGN.LEFT, ellipsis = "..."} = {})
246
270
  {
247
271
  input = "" + input;
248
- if (fit && input.length >= fit + 2)
272
+ if (fit && input.length > fit)
249
273
  {
250
- input = input.substring(0, fit - 3) + "...";
274
+ input = input.substring(0, fit - ellipsis.length) + ellipsis;
251
275
  }
252
276
 
253
277
  input = align === AnaLogger.ALIGN.LEFT ? input.padEnd(fit, " ") : input.padStart(fit, " ");
254
278
  return input;
255
279
  }
256
280
 
281
+ /**
282
+ * Display data
283
+ * @param {any[]} table
284
+ * @param ellipsis
285
+ * @param ColumnMinChars
286
+ * @param columnMaxChars
287
+ * @param verticalSeparator
288
+ * @param horizontalSeparator
289
+ * @param availableLength
290
+ */
291
+ buildTable(table, {
292
+ ellipsis = "...",
293
+ ColumnMinChars = 6,
294
+ columnMaxChars = 0,
295
+ verticalSeparator = " │ ",
296
+ horizontalSeparator = "─",
297
+ availableLength = 0
298
+ } = {})
299
+ {
300
+ let text = "";
301
+
302
+ const isArray = Array.isArray(table);
303
+ if (!isArray)
304
+ {
305
+ table = Object.values(Object.values(table));
306
+ }
307
+
308
+ if (!table || !table.length)
309
+ {
310
+ return "";
311
+ }
312
+
313
+ const firstLine = table[0];
314
+ const titles = Object.keys(firstLine);
315
+ table.unshift(titles);
316
+
317
+ horizontalSeparator = horizontalSeparator.repeat(100);
318
+
319
+ const fits = {};
320
+ for (let i = 1; i < table.length; ++i)
321
+ {
322
+ const line = table[i];
323
+ for (let ii = 0; ii < titles.length; ++ii)
324
+ {
325
+ const colName = titles[ii];
326
+ const colContent = line[colName];
327
+
328
+ fits[colName] = fits[colName] || 0;
329
+ let colLength;
330
+ try
331
+ {
332
+ colLength = JSON.stringify(colContent).length;
333
+ }
334
+ catch (e)
335
+ {
336
+ }
337
+
338
+ colLength = colLength || ColumnMinChars;
339
+ fits[colName] = Math.max(fits[colName], colLength, colName.length);
340
+ }
341
+ }
342
+
343
+ if (!this.isBrowser0)
344
+ {
345
+ terminalSize = terminalSize || {};
346
+
347
+ if (!availableLength)
348
+ {
349
+ availableLength = terminalSize.width || process.stdout.columns || 120 - verticalSeparator.length - 1 - 5;
350
+ }
351
+ }
352
+
353
+ availableLength = availableLength - 4;
354
+
355
+ let totalLength = Object.values(fits).reduce((a, b) => a + b, 0);
356
+ if (availableLength < totalLength)
357
+ {
358
+ const ratio = (availableLength) / totalLength;
359
+ for (let key in fits)
360
+ {
361
+ fits[key] = Math.floor(fits[key] * ratio) - 1;
362
+ if (ColumnMinChars && fits[key] < ColumnMinChars)
363
+ {
364
+ fits[key] = ColumnMinChars;
365
+ }
366
+
367
+ if (columnMaxChars && fits[key] > columnMaxChars)
368
+ {
369
+ fits[key] = columnMaxChars;
370
+ }
371
+
372
+ fits[key] = fits[key];
373
+ }
374
+
375
+ }
376
+
377
+ let strLine;
378
+
379
+ // Titles
380
+ strLine = "";
381
+ for (let i = 0; i < titles.length; ++i)
382
+ {
383
+ const colName = titles[i];
384
+ const fit = fits[colName];
385
+ strLine += this.truncateMessage(colName, {fit, ellipsis});
386
+ strLine += verticalSeparator;
387
+ }
388
+ text += this.truncateMessage(strLine, {fit: availableLength});
389
+ text += EOL;
390
+
391
+ // Separators
392
+ strLine = "";
393
+ const colContent = horizontalSeparator;
394
+ for (let i = 0; i < titles.length; ++i)
395
+ {
396
+ const colName = titles[i];
397
+ const fit = fits[colName];
398
+ strLine += this.truncateMessage(colContent, {fit, ellipsis: ""});
399
+ strLine += verticalSeparator;
400
+ }
401
+ text += this.truncateMessage(strLine, {fit: availableLength});
402
+ text += EOL;
403
+
404
+ // Content
405
+ for (let i = 1; i < table.length; ++i)
406
+ {
407
+ strLine = "";
408
+ const line = table[i];
409
+ for (let ii = 0; ii < titles.length; ++ii)
410
+ {
411
+ const colName = titles[ii];
412
+ const colContent = line[colName];
413
+ const fit = fits[colName];
414
+
415
+ strLine += this.truncateMessage(colContent, {fit, ellipsis});
416
+ strLine += verticalSeparator;
417
+ }
418
+ text += this.truncateMessage(strLine, {fit: availableLength});
419
+ text += EOL;
420
+ }
421
+
422
+ this.rawLog(text);
423
+
424
+ return text;
425
+ }
426
+
257
427
  /**
258
428
  * Format inputs
259
429
  * @see Override {@link setLogFormat}
@@ -271,9 +441,11 @@ class AnaLogger
271
441
  let time = ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2) + ":" + ("0" + date.getSeconds()).slice(-2);
272
442
 
273
443
  // Display content in columns
274
- time = this.truncateMessage(time, {fit: 7});
275
- contextName = this.truncateMessage(contextName, {fit: this.options.contextLenMax, align: AnaLogger.ALIGN.RIGHT});
276
- // id = this.truncateMessage(id, {fit: this.options.idLenMax})
444
+ time = this.truncateMessage(time, {fit: this.options.timeLenMax});
445
+ contextName = this.truncateMessage(contextName, {
446
+ fit : this.options.contextLenMax,
447
+ align: AnaLogger.ALIGN.RIGHT
448
+ });
277
449
  lid = this.truncateMessage(lid, {fit: this.options.lidLenMax});
278
450
 
279
451
  if (this.options.messageLenMax !== undefined)
@@ -531,7 +703,7 @@ class AnaLogger
531
703
  $line.setAttribute("data-log-counter", this.logCounter);
532
704
  $line.setAttribute("data-log-index", this.logIndex);
533
705
 
534
- this.setColumns($line ,context, text);
706
+ this.setColumns($line, context, text);
535
707
 
536
708
  $view.append($line);
537
709
  }
@@ -542,6 +714,44 @@ class AnaLogger
542
714
  this.logFile.write(text + this.EOL);
543
715
  }
544
716
 
717
+ convertArgumentsToText(args)
718
+ {
719
+ const strs = [];
720
+ let text;
721
+ const n = args.length;
722
+ for (let i = 0; i < n; ++i)
723
+ {
724
+ let str;
725
+ let arg = args[i];
726
+
727
+ try
728
+ {
729
+ str = JSON.stringify(arg);
730
+ }
731
+ catch (e)
732
+ {
733
+
734
+ }
735
+
736
+ if (!str)
737
+ {
738
+ try
739
+ {
740
+ str = stringify(arg);
741
+ }
742
+ catch (e)
743
+ {
744
+
745
+ }
746
+ }
747
+
748
+ strs.push(str);
749
+ }
750
+
751
+ text = strs.join("•");
752
+ return text;
753
+ }
754
+
545
755
  /**
546
756
  * Display log following template
547
757
  * @param context
@@ -550,6 +760,8 @@ class AnaLogger
550
760
  {
551
761
  try
552
762
  {
763
+ let message = "";
764
+
553
765
  if (!this.isTargetAllowed(context.target))
554
766
  {
555
767
  return;
@@ -558,10 +770,11 @@ class AnaLogger
558
770
  let args = Array.prototype.slice.call(arguments);
559
771
  args.shift();
560
772
 
561
- const message = args.join(" | ");
773
+ message = this.convertArgumentsToText(args);
562
774
 
563
775
  let output = "";
564
- const text = this.format({...context, message});
776
+ let text = "";
777
+ text = this.format({...context, message});
565
778
 
566
779
  ++this.logCounter;
567
780
 
@@ -572,6 +785,7 @@ class AnaLogger
572
785
  {
573
786
  this.writeLogToDom(context, text);
574
787
  }
788
+
575
789
  output = `%c${text}`;
576
790
  }
577
791
  else
@@ -597,11 +811,11 @@ class AnaLogger
597
811
 
598
812
  if (this.isBrowser())
599
813
  {
600
- this.realConsoleLog(output, `color: ${context.color}`);
814
+ this.#realConsoleLog(output, `color: ${context.color}`);
601
815
  }
602
816
  else
603
817
  {
604
- this.realConsoleLog(output);
818
+ this.#realConsoleLog(output);
605
819
  }
606
820
 
607
821
  this.errorTargetHandler(context, args);
@@ -634,7 +848,7 @@ class AnaLogger
634
848
  convertToContext(options, defaultContext)
635
849
  {
636
850
  defaultContext = defaultContext || this.generateDefaultContext();
637
- options = options || defaultContext;
851
+ options = options || defaultContext;
638
852
  let context = options;
639
853
  if (options.context && typeof options.context === "object")
640
854
  {
@@ -693,7 +907,7 @@ class AnaLogger
693
907
  {
694
908
  if (!this.options.hideHookMessage)
695
909
  {
696
- this.realConsoleLog("AnaLogger: Hook placed on console.error");
910
+ this.#realConsoleLog("AnaLogger: Hook placed on console.error");
697
911
  }
698
912
  console.error = this.onDisplayError.bind(this);
699
913
  }
@@ -702,7 +916,7 @@ class AnaLogger
702
916
  {
703
917
  if (!this.options.hideHookMessage)
704
918
  {
705
- this.realConsoleLog("AnaLogger: Hook placed on console.log");
919
+ this.#realConsoleLog("AnaLogger: Hook placed on console.log");
706
920
  }
707
921
 
708
922
  if (log)
@@ -728,24 +942,24 @@ class AnaLogger
728
942
 
729
943
  removeOverrideError()
730
944
  {
731
- console.warn = this.realConsoleError;
945
+ console.warn = this.#realConsoleError;
732
946
  }
733
947
 
734
948
  removeOverride({log = true, info = true, warn = true, error = false} = {})
735
949
  {
736
950
  if (log)
737
951
  {
738
- console.log = this.realConsoleLog;
952
+ console.log = this.#realConsoleLog;
739
953
  }
740
954
 
741
955
  if (info)
742
956
  {
743
- console.info = this.realConsoleInfo;
957
+ console.info = this.#realConsoleInfo;
744
958
  }
745
959
 
746
960
  if (warn)
747
961
  {
748
- console.warn = this.realConsoleWarn;
962
+ console.warn = this.#realConsoleWarn;
749
963
  }
750
964
 
751
965
  if (error)
@@ -765,6 +979,11 @@ class AnaLogger
765
979
  return this.log(...args);
766
980
  }
767
981
 
982
+ table(...args)
983
+ {
984
+ return this.buildTable(...args);
985
+ }
986
+
768
987
  alert(...args)
769
988
  {
770
989
  if (this.isNode())
@@ -821,5 +1040,6 @@ class AnaLogger
821
1040
 
822
1041
  }
823
1042
 
824
- module.exports = new AnaLogger();
825
- module.exports.anaLogger = new AnaLogger();
1043
+ const anaLogger = new AnaLogger();
1044
+ module.exports = anaLogger;
1045
+ module.exports.anaLogger = anaLogger;
@@ -1,37 +0,0 @@
1
- /**
2
- * DO NOT EDIT THIS FILE DIRECTLY.
3
- * This file is generated following the conversion of
4
- * [./src/cjs/constants.cjs]{@link ./src/cjs/constants.cjs}
5
- *
6
- **/
7
- const constants = {
8
- COLOR_TABLE: [
9
- "#d2466e", // Error context color
10
- "#FFA07A", // Default context color
11
- "#FF7F50",
12
- "#FF6347",
13
- "#FFE4B5",
14
- "#ADFF2F",
15
- "#808000",
16
- "#40E0D0",
17
- "#1E90FF",
18
- "#EE82EE",
19
- "#708090",
20
- "#DEB887",
21
- "#FE642E",
22
- "#210B61",
23
- "#088A4B",
24
- "#5E610B",
25
- "#FA8258",
26
- "#088A68",
27
- "#B40431",
28
- ],
29
- SYSTEM: {
30
- BROWSER: "BROWSER",
31
- NODE: "NODE"
32
- }
33
-
34
- };
35
-
36
- export const COLOR_TABLE = constants.COLOR_TABLE;
37
- export const SYSTEM = constants.SYSTEM;