analogger 1.7.0 → 1.8.2

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,805 @@
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 "./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 : undefined,
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 = undefined;
148
+ this.options.symbolLenMax = 60;
149
+ this.options.hideHookMessage = false;
150
+ this.options.hidePassingTests = false;
151
+ this.options.hideLog = false;
152
+ this.options.hideError = false;
153
+ this.options.oneConsolePerContext = true;
154
+ this.options.logToDom = undefined;
155
+ this.options.logToDomlogToFile = undefined;
156
+ this.options.silent = false;
157
+ }
158
+
159
+ setOptions({
160
+ contextLenMax = 10,
161
+ idLenMax = 5,
162
+ lidLenMax = 5,
163
+ symbolLenMax = 2,
164
+ messageLenMax = undefined,
165
+ hideLog = undefined,
166
+ hideError = undefined,
167
+ hideHookMessage = undefined,
168
+ hidePassingTests = undefined,
169
+ logToDom = undefined,
170
+ logToFile = undefined,
171
+ oneConsolePerContext = undefined,
172
+ silent = undefined
173
+ } = null)
174
+ {
175
+ this.options.contextLenMax = contextLenMax;
176
+ this.options.idLenMax = idLenMax;
177
+ this.options.lidLenMax = lidLenMax;
178
+ this.options.messageLenMax = messageLenMax;
179
+ this.options.symbolLenMax = symbolLenMax;
180
+
181
+ if (hidePassingTests !== undefined)
182
+ {
183
+ this.options.hidePassingTests = !!hidePassingTests;
184
+ }
185
+
186
+ if (hideHookMessage !== undefined)
187
+ {
188
+ this.options.hideHookMessage = !!hideHookMessage;
189
+ }
190
+
191
+ if (hideLog !== undefined)
192
+ {
193
+ this.options.hideLog = !!hideLog;
194
+ }
195
+
196
+ if (hideError !== undefined)
197
+ {
198
+ this.options.hideError = !!hideError;
199
+ }
200
+
201
+ if (oneConsolePerContext !== undefined)
202
+ {
203
+ this.options.oneConsolePerContext = !!oneConsolePerContext;
204
+ }
205
+
206
+ if (logToDom !== undefined)
207
+ {
208
+ this.options.logToDom = logToDom || "#analogger";
209
+ }
210
+
211
+ if (logToFile !== undefined)
212
+ {
213
+ if (!this.isBrowser())
214
+ {
215
+ this.options.logToFile = logToFile || "./analogger.log";
216
+
217
+
218
+ }
219
+
220
+
221
+ this.realConsoleLog("LogToFile is not supported in this environment. ")
222
+
223
+
224
+ }
225
+
226
+ if (silent !== undefined)
227
+ {
228
+ this.options.silent = !!silent;
229
+ this.options.hideLog = this.options.silent;
230
+ }
231
+
232
+ }
233
+
234
+ getOptions()
235
+ {
236
+ return this.options;
237
+ }
238
+
239
+ truncateMessage(input = "", {fit = 0, align = AnaLogger.ALIGN.LEFT} = {})
240
+ {
241
+ input = "" + input;
242
+ if (fit && input.length >= fit + 2)
243
+ {
244
+ input = input.substring(0, fit - 3) + "...";
245
+ }
246
+
247
+ input = align === AnaLogger.ALIGN.LEFT ? input.padEnd(fit, " ") : input.padStart(fit, " ");
248
+ return input;
249
+ }
250
+
251
+ /**
252
+ * Format inputs
253
+ * @see Override {@link setLogFormat}
254
+ * @param contextName
255
+ * @param id
256
+ * @param message
257
+ * @param lid
258
+ * @param symbol
259
+ * @returns {string}
260
+ */
261
+ onBuildLog({contextName, message = "", lid = "", symbol = ""} = {})
262
+ {
263
+ // Time
264
+ const date = new Date();
265
+ let time = ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2) + ":" + ("0" + date.getSeconds()).slice(-2);
266
+
267
+ // Display content in columns
268
+ time = this.truncateMessage(time, {fit: 7});
269
+ contextName = this.truncateMessage(contextName, {fit: this.options.contextLenMax, align: AnaLogger.ALIGN.RIGHT});
270
+ // id = this.truncateMessage(id, {fit: this.options.idLenMax})
271
+ lid = this.truncateMessage(lid, {fit: this.options.lidLenMax});
272
+
273
+ if (this.options.messageLenMax !== undefined)
274
+ {
275
+ message = this.truncateMessage(message, {fit: this.options.messageLenMax});
276
+ }
277
+
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") ||
609
+ options.hasOwnProperty("target") ||
610
+ options.hasOwnProperty("color") ||
611
+ options.hasOwnProperty("lid");
612
+ }
613
+
614
+ convertToContext(options, defaultContext)
615
+ {
616
+ defaultContext = defaultContext || this.generateDefaultContext();
617
+ options = options || defaultContext;
618
+ let context = options;
619
+ if (options.context && typeof options.context === "object")
620
+ {
621
+ const moreOptions = Object.assign({}, options);
622
+ delete moreOptions.context;
623
+ context = Object.assign({}, options.context, moreOptions);
624
+ }
625
+
626
+ context = Object.assign({}, defaultContext, context);
627
+ delete context.context;
628
+
629
+ return context;
630
+ }
631
+
632
+ /**
633
+ * console.log with options set on the first parameter to dictate console log behaviours
634
+ * @param options
635
+ * @param args
636
+ */
637
+ log(options, ...args)
638
+ {
639
+ if (!this.isExtendedOptionsPassed(options))
640
+ {
641
+ const defaultContext = this.generateDefaultContext();
642
+ this.processOutput.apply(this, [defaultContext, options, ...args]);
643
+ return;
644
+ }
645
+
646
+ let context = this.convertToContext(options);
647
+
648
+ this.processOutput.apply(this, [context, ...args]);
649
+ }
650
+
651
+ error(options, ...args)
652
+ {
653
+ if (this.options.hideError)
654
+ {
655
+ return;
656
+ }
657
+
658
+ if (!this.isExtendedOptionsPassed(options))
659
+ {
660
+ const defaultContext = this.generateErrorContext();
661
+ this.processOutput.apply(this, [defaultContext, options, ...args]);
662
+ return;
663
+ }
664
+
665
+ const errorContext = this.generateErrorContext();
666
+ let context = this.convertToContext(options, errorContext);
667
+
668
+ let args0 = Array.prototype.slice.call(arguments, 1);
669
+ this.log(context, ...args0);
670
+ }
671
+
672
+ overrideError()
673
+ {
674
+ if (!this.options.hideHookMessage)
675
+ {
676
+ this.realConsoleLog("AnaLogger: Hook placed on console.error");
677
+ }
678
+ console.error = this.onDisplayError.bind(this);
679
+ }
680
+
681
+ overrideConsole({log = true, info = true, warn = true, error = false} = {})
682
+ {
683
+ if (!this.options.hideHookMessage)
684
+ {
685
+ this.realConsoleLog("AnaLogger: Hook placed on console.log");
686
+ }
687
+
688
+ if (log)
689
+ {
690
+ console.log = this.onDisplayLog.bind(this);
691
+ }
692
+
693
+ if (info)
694
+ {
695
+ console.info = this.onDisplayLog.bind(this);
696
+ }
697
+
698
+ if (warn)
699
+ {
700
+ console.warn = this.onDisplayLog.bind(this);
701
+ }
702
+
703
+ if (error)
704
+ {
705
+ this.overrideError();
706
+ }
707
+ }
708
+
709
+ removeOverrideError()
710
+ {
711
+ console.warn = this.realConsoleError;
712
+ }
713
+
714
+ removeOverride({log = true, info = true, warn = true, error = false} = {})
715
+ {
716
+ if (log)
717
+ {
718
+ console.log = this.realConsoleLog;
719
+ }
720
+
721
+ if (info)
722
+ {
723
+ console.info = this.realConsoleInfo;
724
+ }
725
+
726
+ if (warn)
727
+ {
728
+ console.warn = this.realConsoleWarn;
729
+ }
730
+
731
+ if (error)
732
+ {
733
+ this.removeOverrideError();
734
+ }
735
+
736
+ }
737
+
738
+ info(...args)
739
+ {
740
+ return this.log(...args);
741
+ }
742
+
743
+ warn(...args)
744
+ {
745
+ return this.log(...args);
746
+ }
747
+
748
+ alert(...args)
749
+ {
750
+ if (this.isNode())
751
+ {
752
+ return this.log(...args);
753
+ }
754
+
755
+ const message = args.join(" | ");
756
+
757
+ alert(message);
758
+ }
759
+
760
+ assert(condition, expected = true, ...args)
761
+ {
762
+ let result;
763
+
764
+ try
765
+ {
766
+ if (typeof condition === "function")
767
+ {
768
+ result = condition(...args);
769
+ if (result !== expected)
770
+ {
771
+ this.error("Asset failed");
772
+ return false;
773
+ }
774
+
775
+ if (!this.options.hidePassingTests)
776
+ {
777
+ this.log("SUCCESS: Assert passed");
778
+ }
779
+ return true;
780
+ }
781
+
782
+ if (condition !== expected)
783
+ {
784
+ this.error("Assert failed");
785
+ return false;
786
+ }
787
+
788
+ if (!this.options.hidePassingTests)
789
+ {
790
+ this.log("SUCCESS: Assert passed");
791
+ }
792
+ return true;
793
+ }
794
+ catch (e)
795
+ {
796
+ this.error("Unexpected error in assert");
797
+ }
798
+
799
+ return false;
800
+ }
801
+
802
+ }
803
+
804
+ export default new AnaLogger();
805
+ export const anaLogger = new AnaLogger();