slicejs-web-framework 3.4.2 β†’ 3.4.4

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.
Files changed (108) hide show
  1. package/.opencode/opencode.json +14 -14
  2. package/Slice/Components/Structural/ContextManager/ContextManager.js +422 -422
  3. package/Slice/Components/Structural/ContextManager/ContextManagerDebugger.js +468 -468
  4. package/Slice/Components/Structural/Controller/Controller.js +1271 -1198
  5. package/Slice/Components/Structural/Debugger/Debugger.js +1503 -1503
  6. package/Slice/Components/Structural/EventManager/EventManager.js +366 -366
  7. package/Slice/Components/Structural/Logger/LogViewer/LogViewer.js +126 -5
  8. package/Slice/Components/Structural/Logger/Logger.js +225 -225
  9. package/Slice/Components/Structural/Router/Router.js +775 -775
  10. package/Slice/Components/Structural/StylesManager/StylesManager.js +82 -82
  11. package/Slice/Components/Structural/StylesManager/ThemeManager/ThemeManager.js +106 -106
  12. package/Slice/Slice.js +650 -627
  13. package/Slice/tests/build-singleton.test.js +244 -244
  14. package/Slice/tests/bundle-v2-runtime-contract.test.js +738 -738
  15. package/Slice/tests/context-patch-use.test.js +95 -95
  16. package/Slice/tests/fixtures/real-runtime-loader.mjs +21 -21
  17. package/Slice/tests/public-env-typed-accessors.test.js +66 -66
  18. package/api/index.js +281 -281
  19. package/api/utils/publicEnvResolver.js +123 -123
  20. package/package.json +44 -44
  21. package/slicejs-cli/.github/workflows/ci.yml +43 -0
  22. package/slicejs-cli/LICENSE +21 -0
  23. package/slicejs-cli/assets/Slice.js-logo.png +0 -0
  24. package/slicejs-cli/client.js +740 -0
  25. package/slicejs-cli/commands/Print.js +164 -0
  26. package/slicejs-cli/commands/Validations.js +92 -0
  27. package/slicejs-cli/commands/build/build.js +40 -0
  28. package/slicejs-cli/commands/buildProduction/buildProduction.js +577 -0
  29. package/slicejs-cli/commands/bundle/bundle.js +236 -0
  30. package/slicejs-cli/commands/createComponent/VisualComponentTemplate.js +55 -0
  31. package/slicejs-cli/commands/createComponent/createComponent.js +128 -0
  32. package/slicejs-cli/commands/deleteComponent/deleteComponent.js +81 -0
  33. package/slicejs-cli/commands/doctor/doctor.js +516 -0
  34. package/slicejs-cli/commands/getComponent/getComponent.js +695 -0
  35. package/slicejs-cli/commands/init/init.js +473 -0
  36. package/slicejs-cli/commands/listComponents/listComponents.js +172 -0
  37. package/slicejs-cli/commands/startServer/startServer.js +240 -0
  38. package/slicejs-cli/commands/startServer/watchServer.js +66 -0
  39. package/slicejs-cli/commands/types/types.js +583 -0
  40. package/slicejs-cli/commands/utils/LocalCliDelegation.js +53 -0
  41. package/slicejs-cli/commands/utils/PackageManager.js +148 -0
  42. package/slicejs-cli/commands/utils/PathHelper.js +75 -0
  43. package/slicejs-cli/commands/utils/VersionChecker.js +169 -0
  44. package/slicejs-cli/commands/utils/bundling/BundleGenerator.js +2525 -0
  45. package/slicejs-cli/commands/utils/bundling/DependencyAnalyzer.js +933 -0
  46. package/slicejs-cli/commands/utils/loadConfig.js +31 -0
  47. package/slicejs-cli/commands/utils/sliceScripts.js +48 -0
  48. package/slicejs-cli/commands/utils/updateManager.js +471 -0
  49. package/slicejs-cli/package.json +71 -0
  50. package/slicejs-cli/playwright.config.js +51 -0
  51. package/slicejs-cli/pnpm-lock.yaml +1629 -0
  52. package/slicejs-cli/tests/build-command-integration.test.js +87 -0
  53. package/slicejs-cli/tests/build-mangling-e2e.test.js +290 -0
  54. package/slicejs-cli/tests/build-production-e2e.test.js +140 -0
  55. package/slicejs-cli/tests/builder-edge-cases.test.js +322 -0
  56. package/slicejs-cli/tests/bundle-generate-e2e.test.js +115 -0
  57. package/slicejs-cli/tests/bundle-generator.test.js +691 -0
  58. package/slicejs-cli/tests/bundle-v2-register-output.test.js +470 -0
  59. package/slicejs-cli/tests/bundling-dependency-edges.test.js +127 -0
  60. package/slicejs-cli/tests/bundling-imports-unit.test.js +267 -0
  61. package/slicejs-cli/tests/client-launcher-contract.test.js +211 -0
  62. package/slicejs-cli/tests/commands-component-crud.test.js +128 -0
  63. package/slicejs-cli/tests/commands-doctor.test.js +152 -0
  64. package/slicejs-cli/tests/commands-version-checker.test.js +37 -0
  65. package/slicejs-cli/tests/component-registry-parse.test.js +34 -0
  66. package/slicejs-cli/tests/dependency-analyzer.test.js +24 -0
  67. package/slicejs-cli/tests/e2e/bundles.spec.js +91 -0
  68. package/slicejs-cli/tests/e2e/dependency-scenarios.spec.js +56 -0
  69. package/slicejs-cli/tests/e2e/fixtures/components/Service/FetchManager/FetchManager.js +136 -0
  70. package/slicejs-cli/tests/e2e/fixtures/components/Service/IndexedDbManager/IndexedDbManager.js +149 -0
  71. package/slicejs-cli/tests/e2e/fixtures/components/Service/LocalStorageManager/LocalStorageManager.js +45 -0
  72. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Button/Button.css +106 -0
  73. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Button/Button.html +5 -0
  74. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Button/Button.js +158 -0
  75. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Link/Link.js +33 -0
  76. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Loading/Loading.css +56 -0
  77. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Loading/Loading.html +83 -0
  78. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Loading/Loading.js +164 -0
  79. package/slicejs-cli/tests/e2e/fixtures/components/Visual/MultiRoute/MultiRoute.js +167 -0
  80. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Navbar/Navbar.css +116 -0
  81. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Navbar/Navbar.html +44 -0
  82. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Navbar/Navbar.js +180 -0
  83. package/slicejs-cli/tests/e2e/fixtures/components/Visual/NotFound/NotFound.js +20 -0
  84. package/slicejs-cli/tests/e2e/fixtures/components/Visual/Route/Route.js +181 -0
  85. package/slicejs-cli/tests/e2e/fixtures/components/registry.json +12 -0
  86. package/slicejs-cli/tests/e2e/fixtures/vendor-components.mjs +65 -0
  87. package/slicejs-cli/tests/e2e/navigation.spec.js +44 -0
  88. package/slicejs-cli/tests/e2e/render.spec.js +34 -0
  89. package/slicejs-cli/tests/e2e/serve.mjs +264 -0
  90. package/slicejs-cli/tests/e2e/shared-deps.spec.js +61 -0
  91. package/slicejs-cli/tests/e2e/unminified.spec.js +33 -0
  92. package/slicejs-cli/tests/e2e-serve.test.js +148 -0
  93. package/slicejs-cli/tests/fixtures/components.js +8 -0
  94. package/slicejs-cli/tests/fixtures/sliceConfig.json +74 -0
  95. package/slicejs-cli/tests/getcomponent.test.js +435 -0
  96. package/slicejs-cli/tests/helpers/setup.js +102 -0
  97. package/slicejs-cli/tests/init-command-contract.test.js +101 -0
  98. package/slicejs-cli/tests/init-e2e.test.js +82 -0
  99. package/slicejs-cli/tests/init-project-isolation.test.js +98 -0
  100. package/slicejs-cli/tests/local-cli-delegation.test.js +81 -0
  101. package/slicejs-cli/tests/package-manager.test.js +127 -0
  102. package/slicejs-cli/tests/path-helper.test.js +206 -0
  103. package/slicejs-cli/tests/perf-budget.test.js +84 -0
  104. package/slicejs-cli/tests/postinstall-command.test.js +103 -0
  105. package/slicejs-cli/tests/property-mangling-regression.test.js +182 -0
  106. package/slicejs-cli/tests/types-breakage.test.js +491 -0
  107. package/slicejs-cli/tests/types-generator-errors.test.js +361 -0
  108. package/slicejs-cli/tests/types-generator.test.js +348 -0
@@ -31,10 +31,14 @@ export default class LogViewer extends HTMLElement {
31
31
  this.$header = this.querySelector('.lv__header');
32
32
  this.$body = this.querySelector('[data-body]');
33
33
  this.$count = this.querySelector('[data-count]');
34
+ this.$componentSelect = this.querySelector('[data-component-select]');
35
+ this.$queryInput = this.querySelector('[data-query-input]');
34
36
 
35
37
  this._isOpen = false;
36
38
  this._logCount = 0;
37
39
  this._filters = new Set();
40
+ this._componentFilter = '';
41
+ this._queryFilter = '';
38
42
  this._dragState = null;
39
43
  this._logHandler = null;
40
44
  }
@@ -45,6 +49,8 @@ export default class LogViewer extends HTMLElement {
45
49
  this._attachClear();
46
50
  this._attachMinimize();
47
51
  this._attachBodyClick();
52
+ this._attachComponentSelect();
53
+ this._attachQueryInput();
48
54
  this._render();
49
55
  this._subscribeLogger();
50
56
  }
@@ -165,6 +171,28 @@ export default class LogViewer extends HTMLElement {
165
171
  });
166
172
  }
167
173
 
174
+ /* -- component select -- */
175
+ _attachComponentSelect() {
176
+ if (!this.$componentSelect) return;
177
+ this.$componentSelect.addEventListener('change', () => {
178
+ this._componentFilter = this.$componentSelect.value;
179
+ this._render();
180
+ });
181
+ }
182
+
183
+ /* -- query text input (debounced) -- */
184
+ _attachQueryInput() {
185
+ if (!this.$queryInput) return;
186
+ let timer;
187
+ this.$queryInput.addEventListener('input', () => {
188
+ clearTimeout(timer);
189
+ timer = setTimeout(() => {
190
+ this._queryFilter = this.$queryInput.value.trim().toLowerCase();
191
+ this._render();
192
+ }, 150);
193
+ });
194
+ }
195
+
168
196
  /* -- real-time subscription via logger.onLog -- */
169
197
  _subscribeLogger() {
170
198
  const logger = slice.logger;
@@ -192,11 +220,25 @@ export default class LogViewer extends HTMLElement {
192
220
 
193
221
  const filters = this._filters;
194
222
  const hasFilters = filters.size > 0;
223
+ const hasComponent = this._componentFilter !== '';
224
+ const hasQuery = this._queryFilter !== '';
195
225
 
196
226
  if (this.$count) {
197
227
  this.$count.textContent = logs.length;
198
228
  }
199
229
 
230
+ /* refresh component select options */
231
+ if (this.$componentSelect) {
232
+ const currentVal = this.$componentSelect.value;
233
+ const components = [...new Set(logs.map(l => l.componentSliceId).filter(Boolean))].sort();
234
+ let opts = '<option value="">All components</option>';
235
+ for (const c of components) {
236
+ const sel = c === currentVal ? ' selected' : '';
237
+ opts += `<option value="${escapeHtml(c)}"${sel}>${escapeHtml(c)}</option>`;
238
+ }
239
+ this.$componentSelect.innerHTML = opts;
240
+ }
241
+
200
242
  if (!this.$body) return;
201
243
 
202
244
  if (logs.length === 0) {
@@ -204,9 +246,19 @@ export default class LogViewer extends HTMLElement {
204
246
  return;
205
247
  }
206
248
 
207
- const filtered = hasFilters ? logs.filter((log) => filters.has(log.logType)) : logs;
249
+ let filtered = logs;
250
+ if (hasFilters) filtered = filtered.filter((log) => filters.has(log.logType));
251
+ if (hasComponent) filtered = filtered.filter((log) => log.componentSliceId === this._componentFilter);
252
+ if (hasQuery) filtered = filtered.filter((log) => (log.message || '').toLowerCase().includes(this._queryFilter));
208
253
  const reversed = [...filtered].reverse();
209
254
 
255
+ if (reversed.length === 0) {
256
+ this.$body.innerHTML = '<div class="lv__empty"><span class="lv__empty-icon">&#128269;</span><span>No matches</span></div>';
257
+ return;
258
+ }
259
+
260
+ const prevScrollTop = this.$body.scrollTop;
261
+
210
262
  let html = '';
211
263
  for (const log of reversed) {
212
264
  const type = log.logType || 'info';
@@ -233,9 +285,8 @@ export default class LogViewer extends HTMLElement {
233
285
  }
234
286
 
235
287
  this.$body.innerHTML = html;
236
- if (this.$body.scrollTop < 20) {
237
- this.$body.scrollTop = 0;
238
- }
288
+ /* preserve scroll β€” if user was at top (newest), stay at top */
289
+ this.$body.scrollTop = prevScrollTop === 0 ? 0 : Math.min(prevScrollTop, this.$body.scrollHeight);
239
290
  }
240
291
  }
241
292
 
@@ -286,6 +337,7 @@ slice-log-viewer[data-minimized] {
286
337
  min-height: 0;
287
338
  }
288
339
 
340
+ slice-log-viewer[data-minimized] .lv__toolbar,
289
341
  slice-log-viewer[data-minimized] .lv__body {
290
342
  display: none;
291
343
  }
@@ -390,10 +442,73 @@ slice-log-viewer[data-minimized] .lv__body {
390
442
  padding: 3px 8px 4px;
391
443
  }
392
444
 
445
+ .lv__toolbar {
446
+ display: flex;
447
+ align-items: center;
448
+ gap: 6px;
449
+ padding: 5px 10px;
450
+ background: color-mix(in srgb, var(--si-surface, #1e1e2e) 98%, #000);
451
+ border-bottom: 1px solid color-mix(in srgb, var(--si-border, #555) 18%, transparent);
452
+ }
453
+
454
+ .lv__component-select {
455
+ all: unset;
456
+ flex: 0 0 auto;
457
+ max-width: 160px;
458
+ font-size: 10px;
459
+ font-weight: 600;
460
+ font-family: inherit;
461
+ color: var(--si-text, #cdd6f4);
462
+ background: color-mix(in srgb, var(--si-border, #555) 20%, transparent);
463
+ padding: 3px 20px 3px 7px;
464
+ border-radius: 6px;
465
+ cursor: pointer;
466
+ white-space: nowrap;
467
+ overflow: hidden;
468
+ text-overflow: ellipsis;
469
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath fill='%23a6adc8' d='M2 2.5l2 2 2-2'/%3E%3C/svg%3E");
470
+ background-repeat: no-repeat;
471
+ background-position: right 6px center;
472
+ appearance: none;
473
+ -webkit-appearance: none;
474
+ }
475
+
476
+ .lv__component-select:hover {
477
+ background-color: color-mix(in srgb, var(--si-border, #555) 35%, transparent);
478
+ }
479
+
480
+ .lv__component-select option {
481
+ background: var(--si-surface, #1e1e2e);
482
+ color: var(--si-text, #cdd6f4);
483
+ font-size: 10px;
484
+ }
485
+
486
+ .lv__query-input {
487
+ all: unset;
488
+ flex: 1;
489
+ min-width: 0;
490
+ font-size: 10px;
491
+ font-family: inherit;
492
+ color: var(--si-text, #cdd6f4);
493
+ background: color-mix(in srgb, var(--si-border, #555) 15%, transparent);
494
+ padding: 3px 7px;
495
+ border-radius: 6px;
496
+ transition: background .12s ease;
497
+ }
498
+
499
+ .lv__query-input::placeholder {
500
+ color: color-mix(in srgb, var(--si-dim, #a6adc8) 45%, transparent);
501
+ }
502
+
503
+ .lv__query-input:focus {
504
+ background: color-mix(in srgb, var(--si-border, #555) 25%, transparent);
505
+ outline: 1px solid color-mix(in srgb, var(--si-accent, #6ee7ff) 30%, transparent);
506
+ }
507
+
393
508
  .lv__body {
394
509
  overflow-y: auto;
395
510
  overflow-x: hidden;
396
- height: calc(100% - 38px);
511
+ height: calc(100% - 76px);
397
512
  padding: 4px 0;
398
513
  cursor: auto;
399
514
  }
@@ -536,6 +651,12 @@ function productionOnlyHtml() {
536
651
  <button class="lv__close" title="Close">&times;</button>
537
652
  </div>
538
653
  </div>
654
+ <div class="lv__toolbar">
655
+ <select class="lv__component-select" data-component-select>
656
+ <option value="">All components</option>
657
+ </select>
658
+ <input class="lv__query-input" data-query-input type="text" placeholder="Search logs..." />
659
+ </div>
539
660
  <div class="lv__body" data-body></div>
540
661
  </div>`;
541
662
  }
@@ -1,225 +1,225 @@
1
- import Log from './Log.js';
2
-
3
- const logTypes = {
4
- ERROR: 'error',
5
- WARN: 'warn',
6
- INFO: 'info',
7
- DEBUG: 'debug',
8
- };
9
-
10
- export default class Logger {
11
- constructor() {
12
- this.logs = [];
13
- this._logListeners = new Set();
14
- this.logEnabled = slice.loggerConfig.enabled;
15
- this.showLogsConfig = slice.loggerConfig.showLogs;
16
-
17
- this.showLog = function showLog(log) {
18
- if (!this.showLogsConfig) return;
19
-
20
- const logType = log.logType;
21
-
22
- Object.keys(this.showLogsConfig).forEach((logConfig) => {
23
- if (this.showLogsConfig[logConfig][logType] === true) {
24
- switch (logConfig) {
25
- case 'console':
26
- switch (logType) {
27
- case logTypes.ERROR:
28
- console.error(
29
- `\x1b[31mERROR\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`,
30
- log.error
31
- );
32
- break;
33
- case logTypes.WARN:
34
- if (log.error) {
35
- console.warn(
36
- `\x1b[33m⚠ WARN\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`,
37
- log.error
38
- );
39
- } else {
40
- console.warn(
41
- `\x1b[33m⚠ WARN\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`
42
- );
43
- }
44
- break;
45
- case logTypes.INFO:
46
- if (log.error) {
47
- console.log(
48
- `\x1b[32mβœ” INFO\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`,
49
- log.error
50
- );
51
- } else {
52
- console.log(
53
- `\x1b[32mβœ” INFO\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`
54
- );
55
- }
56
- break;
57
- case logTypes.DEBUG:
58
- if (log.error) {
59
- console.debug(
60
- `\x1b[36mπŸ” DEBUG\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`,
61
- log.error
62
- );
63
- } else {
64
- console.debug(
65
- `\x1b[36mπŸ” DEBUG\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`
66
- );
67
- }
68
- break;
69
- default:
70
- console.log(
71
- `\x1b[37mUNKNOWN\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`
72
- );
73
- }
74
- break;
75
- }
76
- }
77
- });
78
- };
79
- }
80
-
81
- createLog(logType, componentSliceId, message, error = null) {
82
- if (!this.logEnabled) return;
83
- let componentName;
84
-
85
- try {
86
- componentName = slice.controller.activeComponents.get(componentSliceId).constructor.name;
87
- } catch (_err) {
88
- componentName = componentSliceId;
89
- }
90
-
91
- let componentCategory = slice.controller.getComponentCategory(componentName);
92
- if (componentSliceId === 'Slice' || componentSliceId === 'ThemeManager') componentCategory = 'Structural';
93
- const log = new Log(logType, componentCategory, componentSliceId, message, error);
94
- this.logs.push(log);
95
- this.showLog(log);
96
- for (const listener of this._logListeners) {
97
- try { listener(log); } catch (_) { }
98
- }
99
- }
100
-
101
- /**
102
- * Log an error message.
103
- * @param {string} componentSliceId
104
- * @param {string} message
105
- * @param {any} [error]
106
- * @returns {void}
107
- */
108
- error(componentSliceId, message, error) {
109
- this.createLog(logTypes.ERROR, componentSliceId, message, error);
110
- }
111
-
112
- /**
113
- * Log a warning message.
114
- * @param {string} componentSliceId
115
- * @param {string} message
116
- * @param {any} [error]
117
- * @returns {void}
118
- */
119
- warn(componentSliceId, message, error) {
120
- this.createLog(logTypes.WARN, componentSliceId, message, error);
121
- }
122
-
123
- /**
124
- * Log an info message.
125
- * @param {string} componentSliceId
126
- * @param {string} message
127
- * @param {any} [error]
128
- * @returns {void}
129
- */
130
- info(componentSliceId, message, error) {
131
- this.createLog(logTypes.INFO, componentSliceId, message, error);
132
- }
133
-
134
- /**
135
- * Log a debug message.
136
- * @param {string} componentSliceId
137
- * @param {string} message
138
- * @param {any} [error]
139
- * @returns {void}
140
- */
141
- debug(componentSliceId, message, error) {
142
- this.createLog(logTypes.DEBUG, componentSliceId, message, error);
143
- }
144
-
145
- // ── Retrocompatibilidad: mΓ©todos antiguos redirigen a los nuevos ──
146
-
147
- /** @deprecated Use .error() instead */
148
- logError(componentSliceId, message, error) {
149
- this.error(componentSliceId, message, error);
150
- }
151
-
152
- /** @deprecated Use .warn() instead */
153
- logWarning(componentSliceId, message, error) {
154
- this.warn(componentSliceId, message, error);
155
- }
156
-
157
- /** @deprecated Use .info() instead */
158
- logInfo(componentSliceId, message, error) {
159
- this.info(componentSliceId, message, error);
160
- }
161
-
162
- /**
163
- * Subscribe to new log entries in real time.
164
- * @param {Function} callback β€” receives the Log instance
165
- * @returns {Function} the same callback (for passing to offLog)
166
- */
167
- onLog(callback) {
168
- if (typeof callback === 'function') {
169
- this._logListeners.add(callback);
170
- }
171
- return callback;
172
- }
173
-
174
- /**
175
- * Unsubscribe a previously registered listener.
176
- * @param {Function} callback
177
- * @returns {void}
178
- */
179
- offLog(callback) {
180
- this._logListeners.delete(callback);
181
- }
182
-
183
- /**
184
- * Get all logs.
185
- * @returns {Array}
186
- */
187
- getLogs() {
188
- return this.logs;
189
- }
190
-
191
- /**
192
- * Clear all logs.
193
- * @returns {void}
194
- */
195
- clearLogs() {
196
- this.logs = [];
197
- }
198
-
199
- /**
200
- * Filter logs by type.
201
- * @param {string} type
202
- * @returns {Array}
203
- */
204
- getLogsByLogType(type) {
205
- return this.logs.filter((log) => log.logType === type);
206
- }
207
-
208
- /**
209
- * Filter logs by component category.
210
- * @param {string} componentCategory
211
- * @returns {Array}
212
- */
213
- getLogsByComponentCategory(componentCategory) {
214
- return this.logs.filter((log) => log.componentCategory === componentCategory);
215
- }
216
-
217
- /**
218
- * Filter logs by component sliceId.
219
- * @param {string} componentSliceId
220
- * @returns {Array}
221
- */
222
- getLogsByComponent(componentSliceId) {
223
- return this.logs.filter((log) => log.componentSliceId === componentSliceId);
224
- }
225
- }
1
+ import Log from './Log.js';
2
+
3
+ const logTypes = {
4
+ ERROR: 'error',
5
+ WARN: 'warn',
6
+ INFO: 'info',
7
+ DEBUG: 'debug',
8
+ };
9
+
10
+ export default class Logger {
11
+ constructor() {
12
+ this.logs = [];
13
+ this._logListeners = new Set();
14
+ this.logEnabled = slice.loggerConfig.enabled;
15
+ this.showLogsConfig = slice.loggerConfig.showLogs;
16
+
17
+ this.showLog = function showLog(log) {
18
+ if (!this.showLogsConfig) return;
19
+
20
+ const logType = log.logType;
21
+
22
+ Object.keys(this.showLogsConfig).forEach((logConfig) => {
23
+ if (this.showLogsConfig[logConfig][logType] === true) {
24
+ switch (logConfig) {
25
+ case 'console':
26
+ switch (logType) {
27
+ case logTypes.ERROR:
28
+ console.error(
29
+ `\x1b[31mERROR\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`,
30
+ log.error
31
+ );
32
+ break;
33
+ case logTypes.WARN:
34
+ if (log.error) {
35
+ console.warn(
36
+ `\x1b[33m⚠ WARN\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`,
37
+ log.error
38
+ );
39
+ } else {
40
+ console.warn(
41
+ `\x1b[33m⚠ WARN\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`
42
+ );
43
+ }
44
+ break;
45
+ case logTypes.INFO:
46
+ if (log.error) {
47
+ console.log(
48
+ `\x1b[32mβœ” INFO\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`,
49
+ log.error
50
+ );
51
+ } else {
52
+ console.log(
53
+ `\x1b[32mβœ” INFO\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`
54
+ );
55
+ }
56
+ break;
57
+ case logTypes.DEBUG:
58
+ if (log.error) {
59
+ console.debug(
60
+ `\x1b[36mπŸ” DEBUG\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`,
61
+ log.error
62
+ );
63
+ } else {
64
+ console.debug(
65
+ `\x1b[36mπŸ” DEBUG\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`
66
+ );
67
+ }
68
+ break;
69
+ default:
70
+ console.log(
71
+ `\x1b[37mUNKNOWN\x1b[0m - ${log.componentCategory} - ${log.componentSliceId} - ${log.message}`
72
+ );
73
+ }
74
+ break;
75
+ }
76
+ }
77
+ });
78
+ };
79
+ }
80
+
81
+ createLog(logType, componentSliceId, message, error = null) {
82
+ if (!this.logEnabled) return;
83
+ let componentName;
84
+
85
+ try {
86
+ componentName = slice.controller.activeComponents.get(componentSliceId).constructor.name;
87
+ } catch (_err) {
88
+ componentName = componentSliceId;
89
+ }
90
+
91
+ let componentCategory = slice.controller.getComponentCategory(componentName);
92
+ if (componentSliceId === 'Slice' || componentSliceId === 'ThemeManager') componentCategory = 'Structural';
93
+ const log = new Log(logType, componentCategory, componentSliceId, message, error);
94
+ this.logs.push(log);
95
+ this.showLog(log);
96
+ for (const listener of this._logListeners) {
97
+ try { listener(log); } catch (_) { }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Log an error message.
103
+ * @param {string} componentSliceId
104
+ * @param {string} message
105
+ * @param {any} [error]
106
+ * @returns {void}
107
+ */
108
+ error(componentSliceId, message, error) {
109
+ this.createLog(logTypes.ERROR, componentSliceId, message, error);
110
+ }
111
+
112
+ /**
113
+ * Log a warning message.
114
+ * @param {string} componentSliceId
115
+ * @param {string} message
116
+ * @param {any} [error]
117
+ * @returns {void}
118
+ */
119
+ warn(componentSliceId, message, error) {
120
+ this.createLog(logTypes.WARN, componentSliceId, message, error);
121
+ }
122
+
123
+ /**
124
+ * Log an info message.
125
+ * @param {string} componentSliceId
126
+ * @param {string} message
127
+ * @param {any} [error]
128
+ * @returns {void}
129
+ */
130
+ info(componentSliceId, message, error) {
131
+ this.createLog(logTypes.INFO, componentSliceId, message, error);
132
+ }
133
+
134
+ /**
135
+ * Log a debug message.
136
+ * @param {string} componentSliceId
137
+ * @param {string} message
138
+ * @param {any} [error]
139
+ * @returns {void}
140
+ */
141
+ debug(componentSliceId, message, error) {
142
+ this.createLog(logTypes.DEBUG, componentSliceId, message, error);
143
+ }
144
+
145
+ // ── Retrocompatibilidad: mΓ©todos antiguos redirigen a los nuevos ──
146
+
147
+ /** @deprecated Use .error() instead */
148
+ logError(componentSliceId, message, error) {
149
+ this.error(componentSliceId, message, error);
150
+ }
151
+
152
+ /** @deprecated Use .warn() instead */
153
+ logWarning(componentSliceId, message, error) {
154
+ this.warn(componentSliceId, message, error);
155
+ }
156
+
157
+ /** @deprecated Use .info() instead */
158
+ logInfo(componentSliceId, message, error) {
159
+ this.info(componentSliceId, message, error);
160
+ }
161
+
162
+ /**
163
+ * Subscribe to new log entries in real time.
164
+ * @param {Function} callback β€” receives the Log instance
165
+ * @returns {Function} the same callback (for passing to offLog)
166
+ */
167
+ onLog(callback) {
168
+ if (typeof callback === 'function') {
169
+ this._logListeners.add(callback);
170
+ }
171
+ return callback;
172
+ }
173
+
174
+ /**
175
+ * Unsubscribe a previously registered listener.
176
+ * @param {Function} callback
177
+ * @returns {void}
178
+ */
179
+ offLog(callback) {
180
+ this._logListeners.delete(callback);
181
+ }
182
+
183
+ /**
184
+ * Get all logs.
185
+ * @returns {Array}
186
+ */
187
+ getLogs() {
188
+ return this.logs;
189
+ }
190
+
191
+ /**
192
+ * Clear all logs.
193
+ * @returns {void}
194
+ */
195
+ clearLogs() {
196
+ this.logs = [];
197
+ }
198
+
199
+ /**
200
+ * Filter logs by type.
201
+ * @param {string} type
202
+ * @returns {Array}
203
+ */
204
+ getLogsByLogType(type) {
205
+ return this.logs.filter((log) => log.logType === type);
206
+ }
207
+
208
+ /**
209
+ * Filter logs by component category.
210
+ * @param {string} componentCategory
211
+ * @returns {Array}
212
+ */
213
+ getLogsByComponentCategory(componentCategory) {
214
+ return this.logs.filter((log) => log.componentCategory === componentCategory);
215
+ }
216
+
217
+ /**
218
+ * Filter logs by component sliceId.
219
+ * @param {string} componentSliceId
220
+ * @returns {Array}
221
+ */
222
+ getLogsByComponent(componentSliceId) {
223
+ return this.logs.filter((log) => log.componentSliceId === componentSliceId);
224
+ }
225
+ }