analogger 1.6.2 → 1.8.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.
@@ -0,0 +1,800 @@
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 : 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.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 = 60,
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
+ message = this.truncateMessage(message, {fit: this.options.messageLenMax});
273
+ symbol = this.truncateMessage(symbol, {fit: this.options.symbolLenMax});
274
+
275
+ return `[${time}] ${contextName}: (${lid}) ${symbol} ${message}`;
276
+ }
277
+
278
+ onErrorForUserTarget(context, ...args)
279
+ {
280
+ this.errorUserTargetHandler(context, ...args);
281
+ }
282
+
283
+ onError(context, ...args)
284
+ {
285
+ if (context.target === this.targets.USER)
286
+ {
287
+ this.onErrorForUserTarget(context, ...args);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Forward input to real console log
293
+ * @param args
294
+ */
295
+ onDisplayLog(...args)
296
+ {
297
+ this.log(...args);
298
+ }
299
+
300
+ /**
301
+ * Forward input to real console log
302
+ * @param args
303
+ */
304
+ onDisplayError(...args)
305
+ {
306
+ this.error(...args);
307
+ }
308
+
309
+ /**
310
+ * Set log template
311
+ * @param format
312
+ */
313
+ setLogFormat(format)
314
+ {
315
+ if (typeof format !== "function")
316
+ {
317
+ console.error("Invalid parameter for setFormat. It is expecting a function or method.");
318
+ return false;
319
+ }
320
+ this.format = format.bind(this);
321
+ }
322
+
323
+ resetLogFormatter()
324
+ {
325
+ this.format = this.originalFormatFunction;
326
+ }
327
+
328
+ setErrorHandler(handler)
329
+ {
330
+ this.errorTargetHandler = handler.bind(this);
331
+ }
332
+
333
+ setErrorHandlerForUserTarget(handler)
334
+ {
335
+ this.errorUserTargetHandler = handler.bind(this);
336
+ }
337
+
338
+ // ------------------------------------------------
339
+ // Color
340
+ // ------------------------------------------------
341
+
342
+ // ------------------------------------------------
343
+ // Log Contexts
344
+ // ------------------------------------------------
345
+ isContextValid(context)
346
+ {
347
+ if (
348
+ !(typeof context === "object" &&
349
+ !Array.isArray(context) &&
350
+ context !== null)
351
+ )
352
+ {
353
+ return false;
354
+ }
355
+ return (context.hasOwnProperty("contextName") && context.hasOwnProperty("target"));
356
+ }
357
+
358
+ generateDefaultContext()
359
+ {
360
+ const defaultContext = {
361
+ name : "DEFAULT",
362
+ contextName: "DEFAULT",
363
+ target : "ALL",
364
+ symbol : "⚡"
365
+ };
366
+
367
+ defaultContext.id = this.logIndex++;
368
+ defaultContext.color = COLOR_TABLE[1];
369
+ return defaultContext;
370
+ }
371
+
372
+ generateNewContext()
373
+ {
374
+ const newContext = this.generateDefaultContext();
375
+ newContext.color = COLOR_TABLE[(this.indexColor++) % (COLOR_TABLE.length - 3) + 2];
376
+ newContext.symbol = "";
377
+ return newContext;
378
+ }
379
+
380
+ generateErrorContext()
381
+ {
382
+ const errorContext = this.generateDefaultContext();
383
+ errorContext.color = COLOR_TABLE[0];
384
+ errorContext.symbol = "v";
385
+ errorContext.error = true;
386
+ return errorContext;
387
+ }
388
+
389
+ #allegeProperties(entry)
390
+ {
391
+ let converted = entry;
392
+
393
+ const defaultContext = this.generateNewContext();
394
+
395
+ converted = Object.assign({}, defaultContext, converted);
396
+
397
+ if (converted.color.toLowerCase().indexOf("rgb") > -1)
398
+ {
399
+ converted.color = "#" + rgbHex(converted.color);
400
+ }
401
+ else if (converted.color.indexOf("#") === -1)
402
+ {
403
+ const colorConvert = null;
404
+ if (colorConvert)
405
+ {
406
+ converted.color = "#" + colorConvert.keyword.hex(converted.color);
407
+ }
408
+ }
409
+
410
+ return converted;
411
+ }
412
+
413
+ /**
414
+ * Load the context names that should be available to the environment.
415
+ * They are defined by the user.
416
+ * @see Context definitions {@link ./example/cjs/contexts-def.cjs}
417
+ * @param contextTable
418
+ */
419
+ setContexts(contextTable)
420
+ {
421
+ const arr = Object.keys(contextTable);
422
+ contextTable["DEFAULT"] = this.contexts["DEFAULT"] = this.generateDefaultContext();
423
+ contextTable["ERROR"] = this.contexts["ERROR"] = this.generateErrorContext();
424
+ arr.forEach((key) =>
425
+ {
426
+ const contextPassed = contextTable[key] || {};
427
+ contextPassed.contextName = key;
428
+ contextPassed.name = key;
429
+ this.contexts[key] = this.#allegeProperties(contextPassed);
430
+ contextTable[key] = this.contexts[key];
431
+ });
432
+ }
433
+
434
+ setTargets(targetTable = {})
435
+ {
436
+ this.targets = Object.assign({}, targetTable, {ALL: "ALL", USER: "USER"});
437
+ }
438
+
439
+ setActiveTarget(target)
440
+ {
441
+ this.activeTarget = target;
442
+ }
443
+
444
+ isTargetAllowed(target)
445
+ {
446
+ if (!target || !this.activeTarget)
447
+ {
448
+ return true;
449
+ }
450
+
451
+ if (target === this.targets.ALL)
452
+ {
453
+ return true;
454
+ }
455
+
456
+ return this.activeTarget === target;
457
+ }
458
+
459
+
460
+ // ------------------------------------------------
461
+ // Logging methods
462
+ // ------------------------------------------------
463
+ setColumns($line, context, text)
464
+ {
465
+ let index = 0;
466
+ for (let columnName in context)
467
+ {
468
+ if ("name" === columnName)
469
+ {
470
+ continue;
471
+ }
472
+
473
+ const colContent = context[columnName];
474
+ const $col = document.createElement("span");
475
+ $col.classList.add("analogger-col", `analogger-col-${columnName}`, `analogger-col-${index}`);
476
+ ++index;
477
+ $col.textContent = colContent;
478
+ $line.append($col);
479
+ }
480
+
481
+ const $col = document.createElement("span");
482
+ $col.classList.add("analogger-col", "analogger-col-text", `analogger-col-${index}`);
483
+ $col.textContent = text;
484
+ $line.append($col);
485
+ }
486
+
487
+ writeLogToDom(context, text)
488
+ {
489
+ this.$containers = this.$containers || document.querySelectorAll(this.options.logToDom);
490
+
491
+ for (let i = 0; i < this.$containers.length; ++i)
492
+ {
493
+ const $container = this.$containers[i];
494
+
495
+ let $view = $container.querySelector(".analogger-view");
496
+ if (!$view)
497
+ {
498
+ $view = document.createElement("div");
499
+ $view.classList.add("analogger-view");
500
+ $container.append($view);
501
+ }
502
+
503
+ const $line = document.createElement("div");
504
+ $line.classList.add("to-esm-line");
505
+ $line.style.color = context.color;
506
+ $line.setAttribute("data-log-counter", this.logCounter);
507
+ $line.setAttribute("data-log-index", this.logIndex);
508
+
509
+ this.setColumns($line ,context, text);
510
+
511
+ $view.append($line);
512
+ }
513
+ }
514
+
515
+ writeLogToFile(text)
516
+ {
517
+ this.logFile.write(text + this.EOL);
518
+ }
519
+
520
+ /**
521
+ * Display log following template
522
+ * @param context
523
+ */
524
+ processOutput(context = {})
525
+ {
526
+ try
527
+ {
528
+ if (!this.isTargetAllowed(context.target))
529
+ {
530
+ return;
531
+ }
532
+
533
+ let args = Array.prototype.slice.call(arguments);
534
+ args.shift();
535
+
536
+ const message = args.join(" | ");
537
+
538
+ let output = "";
539
+ const text = this.format({...context, message});
540
+
541
+ ++this.logCounter;
542
+
543
+ if (this.isBrowser())
544
+ {
545
+ context.environnment = AnaLogger.ENVIRONMENT_TYPE.BROWSER;
546
+ if (this.options.logToDom)
547
+ {
548
+ this.writeLogToDom(context, text);
549
+ }
550
+ output = `%c${text}`;
551
+ }
552
+ else
553
+ {
554
+ context.environnment = AnaLogger.ENVIRONMENT_TYPE.NODE;
555
+ output = toAnsi.getTextFromHex(text, {fg: context.color});
556
+
557
+ if (this.options.logToFile)
558
+ {
559
+ this.writeLogToFile(text);
560
+ }
561
+ }
562
+
563
+ if (this.keepLog)
564
+ {
565
+ this.logHistory.push(output);
566
+ }
567
+
568
+ if (this.options.hideLog)
569
+ {
570
+ return;
571
+ }
572
+
573
+ if (this.isBrowser())
574
+ {
575
+ this.realConsoleLog(output, `color: ${context.color}`);
576
+ }
577
+ else
578
+ {
579
+ this.realConsoleLog(output);
580
+ }
581
+
582
+ this.errorTargetHandler(context, args);
583
+ }
584
+ catch (e)
585
+ {
586
+ /* istanbul ignore next */
587
+ console.error("AnaLogger:", e.message);
588
+ }
589
+ }
590
+
591
+ /**
592
+ * Check that a parameter (should be the first) uses the expected format.
593
+ * @param options
594
+ * @returns {boolean}
595
+ */
596
+ isExtendedOptionsPassed(options)
597
+ {
598
+ if (typeof options !== "object")
599
+ {
600
+ return false;
601
+ }
602
+
603
+ return options.hasOwnProperty("context") ||
604
+ options.hasOwnProperty("target") ||
605
+ options.hasOwnProperty("color") ||
606
+ options.hasOwnProperty("lid");
607
+ }
608
+
609
+ convertToContext(options, defaultContext)
610
+ {
611
+ defaultContext = defaultContext || this.generateDefaultContext();
612
+ options = options || defaultContext;
613
+ let context = options;
614
+ if (options.context && typeof options.context === "object")
615
+ {
616
+ const moreOptions = Object.assign({}, options);
617
+ delete moreOptions.context;
618
+ context = Object.assign({}, options.context, moreOptions);
619
+ }
620
+
621
+ context = Object.assign({}, defaultContext, context);
622
+ delete context.context;
623
+
624
+ return context;
625
+ }
626
+
627
+ /**
628
+ * console.log with options set on the first parameter to dictate console log behaviours
629
+ * @param options
630
+ * @param args
631
+ */
632
+ log(options, ...args)
633
+ {
634
+ if (!this.isExtendedOptionsPassed(options))
635
+ {
636
+ const defaultContext = this.generateDefaultContext();
637
+ this.processOutput.apply(this, [defaultContext, options, ...args]);
638
+ return;
639
+ }
640
+
641
+ let context = this.convertToContext(options);
642
+
643
+ this.processOutput.apply(this, [context, ...args]);
644
+ }
645
+
646
+ error(options, ...args)
647
+ {
648
+ if (this.options.hideError)
649
+ {
650
+ return;
651
+ }
652
+
653
+ if (!this.isExtendedOptionsPassed(options))
654
+ {
655
+ const defaultContext = this.generateErrorContext();
656
+ this.processOutput.apply(this, [defaultContext, options, ...args]);
657
+ return;
658
+ }
659
+
660
+ const errorContext = this.generateErrorContext();
661
+ let context = this.convertToContext(options, errorContext);
662
+
663
+ let args0 = Array.prototype.slice.call(arguments, 1);
664
+ this.log(context, ...args0);
665
+ }
666
+
667
+ overrideError()
668
+ {
669
+ if (!this.options.hideHookMessage)
670
+ {
671
+ this.realConsoleLog("AnaLogger: Hook placed on console.error");
672
+ }
673
+ console.error = this.onDisplayError.bind(this);
674
+ }
675
+
676
+ overrideConsole({log = true, info = true, warn = true, error = false} = {})
677
+ {
678
+ if (!this.options.hideHookMessage)
679
+ {
680
+ this.realConsoleLog("AnaLogger: Hook placed on console.log");
681
+ }
682
+
683
+ if (log)
684
+ {
685
+ console.log = this.onDisplayLog.bind(this);
686
+ }
687
+
688
+ if (info)
689
+ {
690
+ console.info = this.onDisplayLog.bind(this);
691
+ }
692
+
693
+ if (warn)
694
+ {
695
+ console.warn = this.onDisplayLog.bind(this);
696
+ }
697
+
698
+ if (error)
699
+ {
700
+ this.overrideError();
701
+ }
702
+ }
703
+
704
+ removeOverrideError()
705
+ {
706
+ console.warn = this.realConsoleError;
707
+ }
708
+
709
+ removeOverride({log = true, info = true, warn = true, error = false} = {})
710
+ {
711
+ if (log)
712
+ {
713
+ console.log = this.realConsoleLog;
714
+ }
715
+
716
+ if (info)
717
+ {
718
+ console.info = this.realConsoleInfo;
719
+ }
720
+
721
+ if (warn)
722
+ {
723
+ console.warn = this.realConsoleWarn;
724
+ }
725
+
726
+ if (error)
727
+ {
728
+ this.removeOverrideError();
729
+ }
730
+
731
+ }
732
+
733
+ info(...args)
734
+ {
735
+ return this.log(...args);
736
+ }
737
+
738
+ warn(...args)
739
+ {
740
+ return this.log(...args);
741
+ }
742
+
743
+ alert(...args)
744
+ {
745
+ if (this.isNode())
746
+ {
747
+ return this.log(...args);
748
+ }
749
+
750
+ const message = args.join(" | ");
751
+
752
+ alert(message);
753
+ }
754
+
755
+ assert(condition, expected = true, ...args)
756
+ {
757
+ let result;
758
+
759
+ try
760
+ {
761
+ if (typeof condition === "function")
762
+ {
763
+ result = condition(...args);
764
+ if (result !== expected)
765
+ {
766
+ this.error("Asset failed");
767
+ return false;
768
+ }
769
+
770
+ if (!this.options.hidePassingTests)
771
+ {
772
+ this.log("SUCCESS: Assert passed");
773
+ }
774
+ return true;
775
+ }
776
+
777
+ if (condition !== expected)
778
+ {
779
+ this.error("Assert failed");
780
+ return false;
781
+ }
782
+
783
+ if (!this.options.hidePassingTests)
784
+ {
785
+ this.log("SUCCESS: Assert passed");
786
+ }
787
+ return true;
788
+ }
789
+ catch (e)
790
+ {
791
+ this.error("Unexpected error in assert");
792
+ }
793
+
794
+ return false;
795
+ }
796
+
797
+ }
798
+
799
+ export default new AnaLogger();
800
+ export const anaLogger = new AnaLogger();