analogger 2.6.0 → 2.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.
package/README.md CHANGED
@@ -281,6 +281,74 @@ If the calls arrive out of sequence — for example, `API_123` (order 2) appeari
281
281
  > - Calls filtered out by `only`, targets, or log levels are not counted toward the sequence.
282
282
  > - Equal order values (non-decreasing) are always allowed; only strictly lower values trigger the warning.
283
283
 
284
+ ---
285
+
286
+ #### Example 8: The "maxSeen" option
287
+
288
+ ###### Limit how many times a given lid may be logged. Once the count exceeds `maxSeen`, every subsequent call emits a console warning. The limit and the counter are both tied to the lid string, so different lids track independently.
289
+
290
+ ```javascript
291
+ anaLogger.log({lid: "API", maxSeen: 1}, "I'm first"); // OK — seen 1 time
292
+ anaLogger.log({lid: "API", maxSeen: 1}, "I'm second"); // Warning — seen 2 times
293
+ anaLogger.log({lid: "API", maxSeen: 1}, "I'm third"); // Warning — seen 3 times
294
+ ```
295
+
296
+ When the limit is exceeded the following warning is printed to the console:
297
+
298
+ ```
299
+ ! MaxSeen exceeded: [API| maxSeen: 1] has been seen 2 time(s)
300
+ ! MaxSeen exceeded: [API| maxSeen: 1] has been seen 3 time(s)
301
+ ```
302
+
303
+ > **Notes:**
304
+ > - The counter is per-instance and per-lid — different lids each have their own count.
305
+ > - Calls filtered out by `only`, targets, or log levels are not counted.
306
+ > - `maxSeen` can be combined with `order` in the same context object.
307
+
308
+ ---
309
+
310
+ #### Example 9: The "test" option and `report()`
311
+
312
+ ###### Attach an inline assertion to any log call. Pass `test: false` (or a function that returns `false`) and AnaLogger records a failure and emits a warning immediately. Call `report()` at any point to print a summary of all pass/fail results.
313
+
314
+ ```javascript
315
+ anaLogger.log({lid: "API_1", test: false}, "I'm first"); // fails — boolean
316
+ anaLogger.log({lid: "API_2", test: () => false}, "I'm second"); // fails — function
317
+ anaLogger.log({lid: "API_3", test: true}, "I'm third"); // passes
318
+ anaLogger.log({lid: "API_4", test: () => true}, "I'm fourth"); // passes
319
+
320
+ anaLogger.report();
321
+ ```
322
+
323
+ Failing calls emit an immediate warning:
324
+
325
+ ```
326
+ ! Test failed: [API_1] I'm first
327
+ ! Test failed: [API_2] I'm second
328
+ ```
329
+
330
+ `report()` then prints a bordered summary. If any test failed the output is **bold red**; if all tests passed it is **bold green**:
331
+
332
+ ```
333
+ ================== ANALOGGER TEST RESULT ================
334
+ Total : 4
335
+ Passed : 2
336
+ Failed : 2
337
+ ==========================================================
338
+ ```
339
+
340
+ `report()` also returns the counts as an object, so you can assert on them programmatically:
341
+
342
+ ```javascript
343
+ const {total, passed, failed} = anaLogger.report();
344
+ ```
345
+
346
+ > **Notes:**
347
+ > - `test` accepts a plain boolean or a zero-argument function — both are resolved to a boolean.
348
+ > - Every call that carries a `test` key is recorded, whether it passes or fails.
349
+ > - Calls without a `test` key are completely transparent and never appear in the report.
350
+ > - Results accumulate across the lifetime of the instance. Call `anaLogger._testResults = []` to reset between suites if needed.
351
+
284
352
 
285
353
  ---
286
354
 
@@ -351,6 +419,8 @@ Display the browser native message box if run from it; otherwise, it displays th
351
419
  | forceLidOn | false | boolean | _Automatically generates a short hash LID if one isn't provided_ |
352
420
  | only | undefined | string/Regex/Array | Filter logs to show only those matching specific IDs or patterns |
353
421
  | order | undefined | number | _Enforce call order — emits a console warning if a log with a lower order value appears after one with a higher value_ |
422
+ | maxSeen | undefined | number | _Emits a console warning when the same lid is logged more times than this limit_ |
423
+ | test | undefined | boolean / () => boolean | _Records a pass/fail result for the log call; emits a warning immediately on failure. Use_ `report()` _to see the full summary_ |
354
424
 
355
425
  <br/>
356
426
 
@@ -1373,6 +1443,8 @@ anaLogger.log("lid: USR_LOGIN, color: purple", "User logged in");
1373
1443
  * Make the alert method display the lid when detected
1374
1444
  * Keep format when displaying multiple lines for one entry
1375
1445
  * Add `order` option to detect and warn on out-of-sequence log calls
1446
+ * Add `maxSeen` option to warn when a lid is logged more times than allowed
1447
+ * Add `test` context option and `report()` method for inline assertions and test summaries
1376
1448
 
1377
1449
 
1378
1450
  ##### 1.23.2:
package/ana-logger.d.cts CHANGED
@@ -81,6 +81,8 @@ declare class ____AnaLogger {
81
81
  lid: any;
82
82
  order: any;
83
83
  };
84
+ _seenCount: {};
85
+ _testResults: any[];
84
86
  getName(): string;
85
87
  getId(): string;
86
88
  /**
@@ -317,6 +319,23 @@ declare class ____AnaLogger {
317
319
  checkOnLogging(context: any, data: any, extras: any, callbackName: any): any;
318
320
  isContextMessagePattern(str: any): boolean;
319
321
  transformContextMessage(template: any, data: any): any;
322
+ /**
323
+ * Print a summary of all test results collected via the "test" context option.
324
+ * If any test failed the banner and counts are printed in bold red (Node) or
325
+ * red CSS (browser); otherwise they are printed in green.
326
+ *
327
+ * Output format:
328
+ * ================== ANALOGGER TEST RESULT ================
329
+ * Total : N
330
+ * Passed : N
331
+ * Failed : N
332
+ * ==========================================================
333
+ */
334
+ report(): {
335
+ total: number;
336
+ passed: number;
337
+ failed: number;
338
+ };
320
339
  /**
321
340
  * Display log following template
322
341
  * @param context
@@ -730,6 +730,14 @@ class ____AnaLogger
730
730
 
731
731
  // Tracks the last seen "order" entry { lid, order } for order-mismatch detection.
732
732
  this._lastOrderEntry = null;
733
+
734
+ // Tracks how many times each lid has been seen, keyed by lid string.
735
+ // Used by the "maxSeen" context option.
736
+ this._seenCount = {};
737
+
738
+ // Accumulates test results recorded by the "test" context option.
739
+ // Each entry is { lid, passed, message }.
740
+ this._testResults = [];
733
741
  }
734
742
 
735
743
  getName()
@@ -2289,6 +2297,8 @@ class ____AnaLogger
2289
2297
  if (context) {
2290
2298
  context.symbol = "floppy_disk";
2291
2299
  delete context.order;
2300
+ delete context.maxSeen;
2301
+ delete context.test;
2292
2302
  }
2293
2303
  this.processOutput(context, ...args);
2294
2304
  });
@@ -2627,6 +2637,112 @@ class ____AnaLogger
2627
2637
  this._lastOrderEntry = {lid: currentLid, order: currentOrder};
2628
2638
  }
2629
2639
 
2640
+ /**
2641
+ * Check that a lid is not logged more times than its maxSeen limit.
2642
+ * When the count exceeds the limit a warning is emitted:
2643
+ * ! MaxSeen exceeded: [API| maxSeen: 1] has been seen 2 time(s)
2644
+ *
2645
+ * @param {object} context
2646
+ */
2647
+ #checkMaxSeen(context)
2648
+ {
2649
+ if (context.maxSeen === undefined || context.maxSeen === null)
2650
+ {
2651
+ return;
2652
+ }
2653
+
2654
+ const lid = context.lid || "";
2655
+ const maxSeen = context.maxSeen;
2656
+
2657
+ this._seenCount[lid] = (this._seenCount[lid] || 0) + 1;
2658
+ const count = this._seenCount[lid];
2659
+
2660
+ if (count > maxSeen)
2661
+ {
2662
+ const msg = `! MaxSeen exceeded: [${lid}| maxSeen: ${maxSeen}] has been seen ${count} time(s)`;
2663
+ ____AnaLogger.Console.warn(msg);
2664
+ }
2665
+ }
2666
+
2667
+ /**
2668
+ * Evaluate the "test" context option and record the result.
2669
+ * - If test is a function, it is called with no arguments and its return value is used.
2670
+ * - If the resolved value is falsy a console warning is emitted immediately.
2671
+ * - Every call (pass or fail) is appended to this._testResults for report().
2672
+ *
2673
+ * @param {object} context
2674
+ * @param {string} message — the log message, used in the test record
2675
+ */
2676
+ #checkTest(context, message)
2677
+ {
2678
+ if (!context.hasOwnProperty("test"))
2679
+ {
2680
+ return;
2681
+ }
2682
+
2683
+ const lid = context.lid || "";
2684
+ const testVal = context.test;
2685
+ const passed = typeof testVal === "function" ? !!testVal() : !!testVal;
2686
+
2687
+ this._testResults.push({lid, passed, message});
2688
+
2689
+ if (!passed)
2690
+ {
2691
+ ____AnaLogger.Console.warn(`! Test failed: [${lid}] ${message}`);
2692
+ }
2693
+ }
2694
+
2695
+ /**
2696
+ * Print a summary of all test results collected via the "test" context option.
2697
+ * If any test failed the banner and counts are printed in bold red (Node) or
2698
+ * red CSS (browser); otherwise they are printed in green.
2699
+ *
2700
+ * Output format:
2701
+ * ================== ANALOGGER TEST RESULT ================
2702
+ * Total : N
2703
+ * Passed : N
2704
+ * Failed : N
2705
+ * ==========================================================
2706
+ */
2707
+ report()
2708
+ {
2709
+ const total = this._testResults.length;
2710
+ const passed = this._testResults.filter((r) => r.passed).length;
2711
+ const failed = total - passed;
2712
+ const hasFailed = failed > 0;
2713
+
2714
+ const BORDER = "================== ANALOGGER TEST RESULT ================";
2715
+ const BORDER2 = "==========================================================";
2716
+ const lines = [
2717
+ BORDER,
2718
+ ` Total : ${total}`,
2719
+ ` Passed : ${passed}`,
2720
+ ` Failed : ${failed}`,
2721
+ BORDER2,
2722
+ ];
2723
+
2724
+ if (this.isBrowser())
2725
+ {
2726
+ const style = hasFailed
2727
+ ? "color: red; font-weight: bold;"
2728
+ : "color: green; font-weight: bold;";
2729
+ lines.forEach((line) => ____AnaLogger.Console.log(`%c${line}`, style));
2730
+ }
2731
+ else
2732
+ {
2733
+ lines.forEach((line) =>
2734
+ {
2735
+ const styled = toAnsi.getTextFromColor(line, {
2736
+ fg : hasFailed ? "#FF0000" : "#00CC44",
2737
+ isBold: true,
2738
+ });
2739
+ ____AnaLogger.Console.log(styled);
2740
+ });
2741
+ }
2742
+
2743
+ return {total, passed, failed};
2744
+ }
2745
+
2630
2746
  /**
2631
2747
  * Handle the local "only" option on a log context.
2632
2748
  *
@@ -2835,6 +2951,9 @@ class ____AnaLogger
2835
2951
  // Check that "order" values are non-decreasing across calls.
2836
2952
  this.#checkOrder(context);
2837
2953
 
2954
+ // Check that a lid is not logged more times than its maxSeen limit.
2955
+ this.#checkMaxSeen(context);
2956
+
2838
2957
  const newMessages = this.checkOnLogging(context, argsWithoutContext[0], arguments,"onMessage");
2839
2958
  if (newMessages !== undefined) {
2840
2959
  arguments[1] = newMessages;
@@ -2844,6 +2963,9 @@ class ____AnaLogger
2844
2963
 
2845
2964
  message = this.convertArgumentsToText(args);
2846
2965
 
2966
+ // Evaluate the "test" option and record the pass/fail result.
2967
+ this.#checkTest(context, message);
2968
+
2847
2969
  // Ensure UID is set early so it's available in history/context when requested
2848
2970
  if (this.options.logUidToRemote)
2849
2971
  {