analogger 1.7.0 → 1.8.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.
@@ -0,0 +1,802 @@
1
+ /**
2
+ * DO NOT EDIT THIS FILE DIRECTLY.
3
+ * This file is generated following the conversion of
4
+ * [./src/cjs/ana-logger.cjs]{@link ./src/cjs/ana-logger.cjs}
5
+ *
6
+ **/
7
+ import toAnsi from "./node_modules/to-ansi/index.mjs";
8
+ import rgbHex from "./node_modules/rgb-hex/index.mjs";
9
+ import {COLOR_TABLE, SYSTEM} from "./src/cjs/constants.mjs";
10
+
11
+
12
+
13
+
14
+ const EOL =`
15
+ `;
16
+
17
+ class AnaLogger
18
+ {
19
+ system = "";
20
+
21
+ logIndex = 0;
22
+ logCounter = 0;
23
+ contexts = [];
24
+ targets = {};
25
+
26
+ activeTarget = null;
27
+
28
+ indexColor = 0;
29
+
30
+ format = "";
31
+
32
+ keepLog = false;
33
+ logHistory = [];
34
+
35
+ $containers = null;
36
+
37
+ options = {
38
+ hideHookMessage: false
39
+ };
40
+
41
+ static ALIGN = {
42
+ LEFT : "LEFT",
43
+ RIGHT: "RIGHT"
44
+ };
45
+
46
+ static ENVIRONMENT_TYPE = {
47
+ BROWSER: "BROWSER",
48
+ NODE : "NODE",
49
+ OTHER : "OTHER"
50
+ };
51
+ originalFormatFunction;
52
+
53
+ constructor()
54
+ {
55
+ if (AnaLogger.Instance)
56
+ {
57
+ return AnaLogger.Instance;
58
+ }
59
+
60
+ AnaLogger.Instance = this;
61
+
62
+ this.system = (typeof process === "object") ? SYSTEM.NODE : SYSTEM.BROWSER;
63
+ this.format = this.onBuildLog.bind(this);
64
+ this.originalFormatFunction = this.format;
65
+
66
+ this.errorTargetHandler = this.onError.bind(this);
67
+ this.errorUserTargetHandler = this.onErrorForUserTarget.bind(this);
68
+
69
+ this.setOptions(this.options);
70
+
71
+ this.realConsoleLog = console.log;
72
+ this.realConsoleInfo = console.info;
73
+ this.realConsoleWarn = console.warn;
74
+ this.realConsoleError = console.error;
75
+
76
+ this.ALIGN = AnaLogger.ALIGN;
77
+ this.ENVIRONMENT_TYPE = AnaLogger.ENVIRONMENT_TYPE;
78
+ }
79
+
80
+ keepLogHistory()
81
+ {
82
+ this.keepLog = true;
83
+ }
84
+
85
+ releaseLogHistory()
86
+ {
87
+ this.keepLog = false;
88
+ }
89
+
90
+ resetLogHistory()
91
+ {
92
+ this.logHistory = [];
93
+ }
94
+
95
+ getLogHistory(join = true, symbol = EOL)
96
+ {
97
+ const history = JSON.parse(JSON.stringify(this.logHistory.slice(0)));
98
+ if (!join)
99
+ {
100
+ return history;
101
+ }
102
+ return history.join(symbol);
103
+ }
104
+
105
+ /**
106
+ * Tell whether we are in a Node environment
107
+ * @returns {boolean}
108
+ */
109
+ isNode()
110
+ {
111
+ return this.system === SYSTEM.NODE;
112
+ }
113
+
114
+ /**
115
+ * Tell whether the logger runs from a browser
116
+ * @returns {boolean}
117
+ */
118
+ isBrowser()
119
+ {
120
+ return !this.isNode();
121
+ }
122
+
123
+ resetLogger()
124
+ {
125
+ this.options = {
126
+ contextLenMax : 10,
127
+ idLenMax : 5,
128
+ lidLenMax : 5,
129
+ symbolLenMax : 2,
130
+ messageLenMax : 60,
131
+ hideLog : undefined,
132
+ hideError : undefined,
133
+ hideHookMessage : undefined,
134
+ hidePassingTests : undefined,
135
+ logToDom : undefined,
136
+ logToFile : undefined,
137
+ oneConsolePerContext: undefined,
138
+ silent : undefined
139
+ };
140
+ }
141
+
142
+ resetOptions()
143
+ {
144
+ this.options.contextLenMax = 10;
145
+ this.options.idLenMax = 5;
146
+ this.options.lidLenMax = 5;
147
+ this.options.messageLenMax = 2;
148
+ this.options.symbolLenMax = 60;
149
+ this.options.hideHookMessage = false;
150
+ this.options.hidePassingTests = false;
151
+ this.options.hideHookMessage = false;
152
+ this.options.hideLog = false;
153
+ this.options.hideError = false;
154
+ this.options.oneConsolePerContext = true;
155
+ this.options.logToDom = undefined;
156
+ this.options.logToDomlogToFile = undefined;
157
+ this.options.silent = false;
158
+ }
159
+
160
+ setOptions({
161
+ contextLenMax = 10,
162
+ idLenMax = 5,
163
+ lidLenMax = 5,
164
+ symbolLenMax = 2,
165
+ messageLenMax = 60,
166
+ hideLog = undefined,
167
+ hideError = undefined,
168
+ hideHookMessage = undefined,
169
+ hidePassingTests = undefined,
170
+ logToDom = undefined,
171
+ logToFile = undefined,
172
+ oneConsolePerContext = undefined,
173
+ silent = undefined
174
+ } = null)
175
+ {
176
+ this.options.contextLenMax = contextLenMax;
177
+ this.options.idLenMax = idLenMax;
178
+ this.options.lidLenMax = lidLenMax;
179
+ this.options.messageLenMax = messageLenMax;
180
+ this.options.symbolLenMax = symbolLenMax;
181
+ this.options.hideHookMessage = !!hideHookMessage;
182
+
183
+ if (hidePassingTests !== undefined)
184
+ {
185
+ this.options.hidePassingTests = !!hidePassingTests;
186
+ }
187
+
188
+ if (hideHookMessage !== undefined)
189
+ {
190
+ this.options.hideHookMessage = !!hideHookMessage;
191
+ }
192
+
193
+ if (hideLog !== undefined)
194
+ {
195
+ this.options.hideLog = !!hideLog;
196
+ }
197
+
198
+ if (hideError !== undefined)
199
+ {
200
+ this.options.hideError = !!hideError;
201
+ }
202
+
203
+ if (oneConsolePerContext !== undefined)
204
+ {
205
+ this.options.oneConsolePerContext = !!oneConsolePerContext;
206
+ }
207
+
208
+ if (logToDom !== undefined)
209
+ {
210
+ this.options.logToDom = logToDom || "#analogger";
211
+ }
212
+
213
+ if (logToFile !== undefined)
214
+ {
215
+ if (!this.isBrowser())
216
+ {
217
+ this.options.logToFile = logToFile || "./analogger.log";
218
+
219
+
220
+ }
221
+
222
+
223
+ this.realConsoleLog("LogToFile is not supported in this environment. ")
224
+
225
+
226
+ }
227
+
228
+ if (silent !== undefined)
229
+ {
230
+ this.options.silent = !!silent;
231
+
232
+ this.options.hideLog = this.options.silent;
233
+ this.options.hideHookMessage = this.options.silent;
234
+ this.options.silent = this.options.silent;
235
+ }
236
+
237
+ }
238
+
239
+ getOptions()
240
+ {
241
+ return this.options;
242
+ }
243
+
244
+ truncateMessage(input = "", {fit = 0, align = AnaLogger.ALIGN.LEFT})
245
+ {
246
+ input = "" + input;
247
+ if (fit && input.length >= fit + 2)
248
+ {
249
+ input = input.substring(0, fit - 3) + "...";
250
+ }
251
+
252
+ input = align === AnaLogger.ALIGN.LEFT ? input.padEnd(fit + 1, " ") : input.padStart(fit + 1, " ");
253
+ return input;
254
+ }
255
+
256
+ /**
257
+ * Format inputs
258
+ * @see Override {@link setLogFormat}
259
+ * @param contextName
260
+ * @param id
261
+ * @param message
262
+ * @param lid
263
+ * @param symbol
264
+ * @returns {string}
265
+ */
266
+ onBuildLog({contextName, message = "", lid = "", symbol = ""} = {})
267
+ {
268
+ // Time
269
+ const date = new Date();
270
+ let time = ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2) + ":" + ("0" + date.getSeconds()).slice(-2);
271
+
272
+ // Display content in columns
273
+ time = this.truncateMessage(time, {fit: 7});
274
+ contextName = this.truncateMessage(contextName, {fit: this.options.contextLenMax, align: AnaLogger.ALIGN.RIGHT});
275
+ // id = this.truncateMessage(id, {fit: this.options.idLenMax})
276
+ lid = this.truncateMessage(lid, {fit: this.options.lidLenMax});
277
+ message = this.truncateMessage(message, {fit: this.options.messageLenMax});
278
+ symbol = this.truncateMessage(symbol, {fit: this.options.symbolLenMax});
279
+
280
+ return `[${time}] ${contextName}: (${lid}) ${symbol} ${message}`;
281
+ }
282
+
283
+ onErrorForUserTarget(context, ...args)
284
+ {
285
+ this.errorUserTargetHandler(context, ...args);
286
+ }
287
+
288
+ onError(context, ...args)
289
+ {
290
+ if (context.target === this.targets.USER)
291
+ {
292
+ this.onErrorForUserTarget(context, ...args);
293
+ }
294
+ }
295
+
296
+ /**
297
+ * Forward input to real console log
298
+ * @param args
299
+ */
300
+ onDisplayLog(...args)
301
+ {
302
+ this.log(...args);
303
+ }
304
+
305
+ /**
306
+ * Forward input to real console log
307
+ * @param args
308
+ */
309
+ onDisplayError(...args)
310
+ {
311
+ this.error(...args);
312
+ }
313
+
314
+ /**
315
+ * Set log template
316
+ * @param format
317
+ */
318
+ setLogFormat(format)
319
+ {
320
+ if (typeof format !== "function")
321
+ {
322
+ console.error("Invalid parameter for setFormat. It is expecting a function or method.");
323
+ return false;
324
+ }
325
+ this.format = format.bind(this);
326
+ }
327
+
328
+ resetLogFormatter()
329
+ {
330
+ this.format = this.originalFormatFunction;
331
+ }
332
+
333
+ setErrorHandler(handler)
334
+ {
335
+ this.errorTargetHandler = handler.bind(this);
336
+ }
337
+
338
+ setErrorHandlerForUserTarget(handler)
339
+ {
340
+ this.errorUserTargetHandler = handler.bind(this);
341
+ }
342
+
343
+ // ------------------------------------------------
344
+ // Color
345
+ // ------------------------------------------------
346
+
347
+ // ------------------------------------------------
348
+ // Log Contexts
349
+ // ------------------------------------------------
350
+ isContextValid(context)
351
+ {
352
+ if (
353
+ !(typeof context === "object" &&
354
+ !Array.isArray(context) &&
355
+ context !== null)
356
+ )
357
+ {
358
+ return false;
359
+ }
360
+ return (context.hasOwnProperty("contextName") && context.hasOwnProperty("target"));
361
+ }
362
+
363
+ generateDefaultContext()
364
+ {
365
+ const defaultContext = {
366
+ name : "DEFAULT",
367
+ contextName: "DEFAULT",
368
+ target : "ALL",
369
+ symbol : "⚡"
370
+ };
371
+
372
+ defaultContext.id = this.logIndex++;
373
+ defaultContext.color = COLOR_TABLE[1];
374
+ return defaultContext;
375
+ }
376
+
377
+ generateNewContext()
378
+ {
379
+ const newContext = this.generateDefaultContext();
380
+ newContext.color = COLOR_TABLE[(this.indexColor++) % (COLOR_TABLE.length - 3) + 2];
381
+ newContext.symbol = "";
382
+ return newContext;
383
+ }
384
+
385
+ generateErrorContext()
386
+ {
387
+ const errorContext = this.generateDefaultContext();
388
+ errorContext.color = COLOR_TABLE[0];
389
+ errorContext.symbol = "v";
390
+ errorContext.error = true;
391
+ return errorContext;
392
+ }
393
+
394
+ #allegeProperties(entry)
395
+ {
396
+ let converted = entry;
397
+
398
+ const defaultContext = this.generateNewContext();
399
+
400
+ converted = Object.assign({}, defaultContext, converted);
401
+
402
+ if (converted.color.toLowerCase().indexOf("rgb") > -1)
403
+ {
404
+ converted.color = "#" + rgbHex(converted.color);
405
+ }
406
+ else if (converted.color.indexOf("#") === -1)
407
+ {
408
+ const colorConvert = null;
409
+ if (colorConvert)
410
+ {
411
+ converted.color = "#" + colorConvert.keyword.hex(converted.color);
412
+ }
413
+ }
414
+
415
+ return converted;
416
+ }
417
+
418
+ /**
419
+ * Load the context names that should be available to the environment.
420
+ * They are defined by the user.
421
+ * @see Context definitions {@link ./example/cjs/contexts-def.cjs}
422
+ * @param contextTable
423
+ */
424
+ setContexts(contextTable)
425
+ {
426
+ const arr = Object.keys(contextTable);
427
+ contextTable["DEFAULT"] = this.contexts["DEFAULT"] = this.generateDefaultContext();
428
+ contextTable["ERROR"] = this.contexts["ERROR"] = this.generateErrorContext();
429
+ arr.forEach((key) =>
430
+ {
431
+ const contextPassed = contextTable[key] || {};
432
+ contextPassed.contextName = key;
433
+ contextPassed.name = key;
434
+ this.contexts[key] = this.#allegeProperties(contextPassed);
435
+ contextTable[key] = this.contexts[key];
436
+ });
437
+ }
438
+
439
+ setTargets(targetTable = {})
440
+ {
441
+ this.targets = Object.assign({}, targetTable, {ALL: "ALL", USER: "USER"});
442
+ }
443
+
444
+ setActiveTarget(target)
445
+ {
446
+ this.activeTarget = target;
447
+ }
448
+
449
+ isTargetAllowed(target)
450
+ {
451
+ if (!target || !this.activeTarget)
452
+ {
453
+ return true;
454
+ }
455
+
456
+ if (target === this.targets.ALL)
457
+ {
458
+ return true;
459
+ }
460
+
461
+ return this.activeTarget === target;
462
+ }
463
+
464
+
465
+ // ------------------------------------------------
466
+ // Logging methods
467
+ // ------------------------------------------------
468
+ setColumns($line, context, text)
469
+ {
470
+ let index = 0;
471
+ for (let columnName in context)
472
+ {
473
+ if ("name" === columnName)
474
+ {
475
+ continue;
476
+ }
477
+
478
+ const colContent = context[columnName];
479
+ const $col = document.createElement("span");
480
+ $col.classList.add("analogger-col", `analogger-col-${columnName}`, `analogger-col-${index}`);
481
+ ++index;
482
+ $col.textContent = colContent;
483
+ $line.append($col);
484
+ }
485
+
486
+ const $col = document.createElement("span");
487
+ $col.classList.add("analogger-col", "analogger-col-text", `analogger-col-${index}`);
488
+ $col.textContent = text;
489
+ $line.append($col);
490
+ }
491
+
492
+ writeLogToDom(context, text)
493
+ {
494
+ this.$containers = this.$containers || document.querySelectorAll(this.options.logToDom);
495
+
496
+ for (let i = 0; i < this.$containers.length; ++i)
497
+ {
498
+ const $container = this.$containers[i];
499
+
500
+ let $view = $container.querySelector(".analogger-view");
501
+ if (!$view)
502
+ {
503
+ $view = document.createElement("div");
504
+ $view.classList.add("analogger-view");
505
+ $container.append($view);
506
+ }
507
+
508
+ const $line = document.createElement("div");
509
+ $line.classList.add("to-esm-line");
510
+ $line.style.color = context.color;
511
+ $line.setAttribute("data-log-counter", this.logCounter);
512
+ $line.setAttribute("data-log-index", this.logIndex);
513
+
514
+ this.setColumns($line ,context, text);
515
+
516
+ $view.append($line);
517
+ }
518
+ }
519
+
520
+ writeLogToFile(text)
521
+ {
522
+ this.logFile.write(text + this.EOL);
523
+ }
524
+
525
+ /**
526
+ * Display log following template
527
+ * @param context
528
+ */
529
+ processOutput(context = {})
530
+ {
531
+ try
532
+ {
533
+ if (!this.isTargetAllowed(context.target))
534
+ {
535
+ return;
536
+ }
537
+
538
+ let args = Array.prototype.slice.call(arguments);
539
+ args.shift();
540
+
541
+ const message = args.join(" | ");
542
+
543
+ let output = "";
544
+ const text = this.format({...context, message});
545
+
546
+ ++this.logCounter;
547
+
548
+ if (this.isBrowser())
549
+ {
550
+ context.environnment = AnaLogger.ENVIRONMENT_TYPE.BROWSER;
551
+ if (this.options.logToDom)
552
+ {
553
+ this.writeLogToDom(context, text);
554
+ }
555
+ output = `%c${text}`;
556
+ }
557
+ else
558
+ {
559
+ context.environnment = AnaLogger.ENVIRONMENT_TYPE.NODE;
560
+ output = toAnsi.getTextFromHex(text, {fg: context.color});
561
+
562
+ if (this.options.logToFile)
563
+ {
564
+ this.writeLogToFile(text);
565
+ }
566
+ }
567
+
568
+ if (this.keepLog)
569
+ {
570
+ this.logHistory.push(output);
571
+ }
572
+
573
+ if (this.options.hideLog)
574
+ {
575
+ return;
576
+ }
577
+
578
+ if (this.isBrowser())
579
+ {
580
+ this.realConsoleLog(output, `color: ${context.color}`);
581
+ }
582
+ else
583
+ {
584
+ this.realConsoleLog(output);
585
+ }
586
+
587
+ this.errorTargetHandler(context, args);
588
+ }
589
+ catch (e)
590
+ {
591
+ /* istanbul ignore next */
592
+ console.error("AnaLogger:", e.message);
593
+ }
594
+ }
595
+
596
+ /**
597
+ * Check that a parameter (should be the first) uses the expected format.
598
+ * @param options
599
+ * @returns {boolean}
600
+ */
601
+ isExtendedOptionsPassed(options)
602
+ {
603
+ if (typeof options !== "object")
604
+ {
605
+ return false;
606
+ }
607
+
608
+ return options.hasOwnProperty("context") || options.hasOwnProperty("target");
609
+ }
610
+
611
+ convertToContext(options, defaultContext)
612
+ {
613
+ defaultContext = defaultContext || this.generateDefaultContext();
614
+ options = options || defaultContext;
615
+ let context = options;
616
+ if (options.context && typeof options.context === "object")
617
+ {
618
+ const moreOptions = Object.assign({}, options);
619
+ delete moreOptions.context;
620
+ context = Object.assign({}, options.context, moreOptions);
621
+ }
622
+
623
+ context = Object.assign({}, defaultContext, context);
624
+ delete context.context;
625
+
626
+ return context;
627
+ }
628
+
629
+ /**
630
+ * console.log with options set on the first parameter to dictate console log behaviours
631
+ * @param options
632
+ * @param args
633
+ */
634
+ log(options, ...args)
635
+ {
636
+ if (!this.isExtendedOptionsPassed(options))
637
+ {
638
+ const defaultContext = this.generateDefaultContext();
639
+ this.processOutput.apply(this, [defaultContext, options, ...args]);
640
+ return;
641
+ }
642
+
643
+ let context = this.convertToContext(options);
644
+
645
+ this.processOutput.apply(this, [context, ...args]);
646
+ }
647
+
648
+ error(options, ...args)
649
+ {
650
+ if (this.options.hideError)
651
+ {
652
+ return;
653
+ }
654
+
655
+ if (!this.isExtendedOptionsPassed(options))
656
+ {
657
+ const defaultContext = this.generateErrorContext();
658
+ this.processOutput.apply(this, [defaultContext, options, ...args]);
659
+ return;
660
+ }
661
+
662
+ const errorContext = this.generateErrorContext();
663
+ let context = this.convertToContext(options, errorContext);
664
+
665
+ let args0 = Array.prototype.slice.call(arguments);
666
+ this.log(context, ...args0);
667
+ }
668
+
669
+ overrideError()
670
+ {
671
+ if (!this.options.hideHookMessage)
672
+ {
673
+ this.realConsoleLog("AnaLogger: Hook placed on console.error");
674
+ }
675
+ console.error = this.onDisplayError.bind(this);
676
+ }
677
+
678
+ overrideConsole({log = true, info = true, warn = true, error = false} = {})
679
+ {
680
+ if (!this.options.hideHookMessage)
681
+ {
682
+ this.realConsoleLog("AnaLogger: Hook placed on console.log");
683
+ }
684
+
685
+ if (log)
686
+ {
687
+ console.log = this.onDisplayLog.bind(this);
688
+ }
689
+
690
+ if (info)
691
+ {
692
+ console.info = this.onDisplayLog.bind(this);
693
+ }
694
+
695
+ if (warn)
696
+ {
697
+ console.warn = this.onDisplayLog.bind(this);
698
+ }
699
+
700
+ if (error)
701
+ {
702
+ this.overrideError();
703
+ }
704
+ }
705
+
706
+ removeOverrideError()
707
+ {
708
+ console.warn = this.realConsoleError;
709
+ }
710
+
711
+ removeOverride({log = true, info = true, warn = true, error = false} = {})
712
+ {
713
+ if (log)
714
+ {
715
+ console.log = this.realConsoleLog;
716
+ }
717
+
718
+ if (info)
719
+ {
720
+ console.info = this.realConsoleInfo;
721
+ }
722
+
723
+ if (warn)
724
+ {
725
+ console.warn = this.realConsoleWarn;
726
+ }
727
+
728
+ if (error)
729
+ {
730
+ this.removeOverrideError();
731
+ }
732
+
733
+ }
734
+
735
+ info(...args)
736
+ {
737
+ return this.log(...args);
738
+ }
739
+
740
+ warn(...args)
741
+ {
742
+ return this.log(...args);
743
+ }
744
+
745
+ alert(...args)
746
+ {
747
+ if (this.isNode())
748
+ {
749
+ return this.log(...args);
750
+ }
751
+
752
+ const message = args.join(" | ");
753
+
754
+ alert(message);
755
+ }
756
+
757
+ assert(condition, expected = true, ...args)
758
+ {
759
+ let result;
760
+
761
+ try
762
+ {
763
+ if (typeof condition === "function")
764
+ {
765
+ result = condition(...args);
766
+ if (result !== expected)
767
+ {
768
+ this.error("Asset failed");
769
+ return false;
770
+ }
771
+
772
+ if (!this.options.hidePassingTests)
773
+ {
774
+ this.log("SUCCESS: Assert passed");
775
+ }
776
+ return true;
777
+ }
778
+
779
+ if (condition !== expected)
780
+ {
781
+ this.error("Assert failed");
782
+ return false;
783
+ }
784
+
785
+ if (!this.options.hidePassingTests)
786
+ {
787
+ this.log("SUCCESS: Assert passed");
788
+ }
789
+ return true;
790
+ }
791
+ catch (e)
792
+ {
793
+ this.error("Unexpected error in assert");
794
+ }
795
+
796
+ return false;
797
+ }
798
+
799
+ }
800
+
801
+ export default new AnaLogger();
802
+ export const anaLogger = new AnaLogger();