@tachui/devtools 0.8.0-alpha
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/LICENSE +363 -0
- package/README.md +189 -0
- package/dist/build-time/detection.d.ts +32 -0
- package/dist/build-time/detection.d.ts.map +1 -0
- package/dist/build-time/index.d.ts +84 -0
- package/dist/build-time/index.d.ts.map +1 -0
- package/dist/build-time/plugins.d.ts +75 -0
- package/dist/build-time/plugins.d.ts.map +1 -0
- package/dist/build-time/rules.d.ts +73 -0
- package/dist/build-time/rules.d.ts.map +1 -0
- package/dist/build-time/transformer.d.ts +23 -0
- package/dist/build-time/transformer.d.ts.map +1 -0
- package/dist/build-time/types.d.ts +212 -0
- package/dist/build-time/types.d.ts.map +1 -0
- package/dist/debug/advanced-debugging.d.ts +327 -0
- package/dist/debug/advanced-debugging.d.ts.map +1 -0
- package/dist/debug/debug.d.ts +61 -0
- package/dist/debug/debug.d.ts.map +1 -0
- package/dist/debug/developer-experience.d.ts +261 -0
- package/dist/debug/developer-experience.d.ts.map +1 -0
- package/dist/debug/development-warnings.d.ts +42 -0
- package/dist/debug/development-warnings.d.ts.map +1 -0
- package/dist/debug/documentation-integration.d.ts +269 -0
- package/dist/debug/documentation-integration.d.ts.map +1 -0
- package/dist/debug/enhanced-errors.d.ts +176 -0
- package/dist/debug/enhanced-errors.d.ts.map +1 -0
- package/dist/debug/enhanced-types.d.ts +284 -0
- package/dist/debug/enhanced-types.d.ts.map +1 -0
- package/dist/debug/ide-integration.d.ts +328 -0
- package/dist/debug/ide-integration.d.ts.map +1 -0
- package/dist/debug/index.d.ts +12 -0
- package/dist/debug/index.d.ts.map +1 -0
- package/dist/debug/index.js +1251 -0
- package/dist/debug/index.js.map +1 -0
- package/dist/debug/validation-debug-tools.d.ts +228 -0
- package/dist/debug/validation-debug-tools.d.ts.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +216229 -0
- package/dist/index.js.map +1 -0
- package/dist/inspector/index.d.ts +232 -0
- package/dist/inspector/index.d.ts.map +1 -0
- package/dist/inspector/index.js +525 -0
- package/dist/inspector/index.js.map +1 -0
- package/dist/plugins/simplified-error-handler.d.ts +83 -0
- package/dist/plugins/simplified-error-handler.d.ts.map +1 -0
- package/dist/profiler/index.d.ts +21 -0
- package/dist/profiler/index.d.ts.map +1 -0
- package/dist/profiler/index.js +519 -0
- package/dist/profiler/index.js.map +1 -0
- package/dist/profiler/performance-optimizer.d.ts +115 -0
- package/dist/profiler/performance-optimizer.d.ts.map +1 -0
- package/dist/profiler/production-monitoring.d.ts +150 -0
- package/dist/profiler/production-monitoring.d.ts.map +1 -0
- package/dist/runtime/error-boundary.d.ts +302 -0
- package/dist/runtime/error-boundary.d.ts.map +1 -0
- package/dist/runtime/error-recovery.d.ts +267 -0
- package/dist/runtime/error-recovery.d.ts.map +1 -0
- package/dist/runtime/error-reporting.d.ts +287 -0
- package/dist/runtime/error-reporting.d.ts.map +1 -0
- package/dist/runtime/error-utils.d.ts +204 -0
- package/dist/runtime/error-utils.d.ts.map +1 -0
- package/dist/runtime/performance.d.ts +217 -0
- package/dist/runtime/performance.d.ts.map +1 -0
- package/dist/testing/index.d.ts +29 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +47 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/validation/debug-tools-stub.d.ts +67 -0
- package/dist/validation/debug-tools-stub.d.ts.map +1 -0
- package/dist/validation/enhanced-runtime.d.ts +310 -0
- package/dist/validation/enhanced-runtime.d.ts.map +1 -0
- package/dist/validation/error-reporting.d.ts +186 -0
- package/dist/validation/error-reporting.d.ts.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,1251 @@
|
|
|
1
|
+
class DebugManager {
|
|
2
|
+
config = {
|
|
3
|
+
enabled: false,
|
|
4
|
+
showLabels: false,
|
|
5
|
+
showBounds: false,
|
|
6
|
+
logComponentTree: false
|
|
7
|
+
};
|
|
8
|
+
componentTree = [];
|
|
9
|
+
/**
|
|
10
|
+
* Enable debug mode with optional configuration
|
|
11
|
+
*/
|
|
12
|
+
enable(options = {}) {
|
|
13
|
+
this.config = {
|
|
14
|
+
enabled: true,
|
|
15
|
+
showLabels: true,
|
|
16
|
+
showBounds: true,
|
|
17
|
+
logComponentTree: true,
|
|
18
|
+
...options
|
|
19
|
+
};
|
|
20
|
+
if (this.config.enabled) {
|
|
21
|
+
this.injectDebugStyles();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Disable debug mode
|
|
26
|
+
*/
|
|
27
|
+
disable() {
|
|
28
|
+
this.config.enabled = false;
|
|
29
|
+
this.removeDebugStyles();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if debug mode is enabled
|
|
33
|
+
*/
|
|
34
|
+
isEnabled() {
|
|
35
|
+
return this.config.enabled;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get current debug configuration
|
|
39
|
+
*/
|
|
40
|
+
getConfig() {
|
|
41
|
+
return { ...this.config };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Add debug attributes to DOM element
|
|
45
|
+
*/
|
|
46
|
+
addDebugAttributes(element, componentType, debugLabel) {
|
|
47
|
+
if (!this.config.enabled) return;
|
|
48
|
+
element.setAttribute("data-tachui-component", componentType);
|
|
49
|
+
if (debugLabel) {
|
|
50
|
+
element.setAttribute("data-tachui-label", debugLabel);
|
|
51
|
+
}
|
|
52
|
+
if (this.config.showLabels || this.config.showBounds) {
|
|
53
|
+
element.classList.add("tachui-debug");
|
|
54
|
+
}
|
|
55
|
+
if (this.config.showLabels && debugLabel) {
|
|
56
|
+
element.classList.add("tachui-debug-labeled");
|
|
57
|
+
}
|
|
58
|
+
if (this.config.showBounds) {
|
|
59
|
+
element.classList.add("tachui-debug-bounds");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Log component to tree (for hierarchical debugging)
|
|
64
|
+
*/
|
|
65
|
+
logComponent(type, label, depth = 0) {
|
|
66
|
+
if (!this.config.enabled || !this.config.logComponentTree) return;
|
|
67
|
+
this.componentTree.push({
|
|
68
|
+
label: label || `<${type}>`,
|
|
69
|
+
type,
|
|
70
|
+
depth
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Print component tree to console
|
|
75
|
+
*/
|
|
76
|
+
printComponentTree() {
|
|
77
|
+
if (!this.config.enabled || !this.config.logComponentTree) return;
|
|
78
|
+
console.group("🌳 TachUI Component Tree:");
|
|
79
|
+
this.componentTree.forEach(({ label, type, depth }) => {
|
|
80
|
+
const indent = " ".repeat(depth);
|
|
81
|
+
const icon = this.getComponentIcon(type);
|
|
82
|
+
console.log(`${indent}${icon} ${type}: "${label}"`);
|
|
83
|
+
});
|
|
84
|
+
console.groupEnd();
|
|
85
|
+
this.componentTree = [];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get icon for component type
|
|
89
|
+
*/
|
|
90
|
+
getComponentIcon(type) {
|
|
91
|
+
const icons = {
|
|
92
|
+
VStack: "📚",
|
|
93
|
+
HStack: "➡️",
|
|
94
|
+
ZStack: "📑",
|
|
95
|
+
Button: "🔘",
|
|
96
|
+
Text: "📝",
|
|
97
|
+
Image: "🖼️",
|
|
98
|
+
ScrollView: "📜",
|
|
99
|
+
List: "📋",
|
|
100
|
+
Form: "📋",
|
|
101
|
+
Section: "📁",
|
|
102
|
+
default: "🧩"
|
|
103
|
+
};
|
|
104
|
+
return icons[type] || icons.default;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Inject debug CSS styles
|
|
108
|
+
*/
|
|
109
|
+
injectDebugStyles() {
|
|
110
|
+
if (document.getElementById("tachui-debug-styles")) return;
|
|
111
|
+
const styles = `
|
|
112
|
+
/* TachUI Debug Styles */
|
|
113
|
+
.tachui-debug {
|
|
114
|
+
position: relative;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.tachui-debug-bounds {
|
|
118
|
+
outline: 1px dashed rgba(255, 0, 0, 0.3) !important;
|
|
119
|
+
outline-offset: -1px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.tachui-debug-labeled::before {
|
|
123
|
+
content: attr(data-tachui-label);
|
|
124
|
+
position: absolute;
|
|
125
|
+
top: -1px;
|
|
126
|
+
left: -1px;
|
|
127
|
+
background: rgba(255, 0, 0, 0.9);
|
|
128
|
+
color: white;
|
|
129
|
+
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
|
|
130
|
+
font-size: 10px;
|
|
131
|
+
font-weight: bold;
|
|
132
|
+
line-height: 1;
|
|
133
|
+
padding: 2px 4px;
|
|
134
|
+
border-radius: 2px;
|
|
135
|
+
z-index: 9999;
|
|
136
|
+
pointer-events: none;
|
|
137
|
+
white-space: nowrap;
|
|
138
|
+
max-width: 200px;
|
|
139
|
+
overflow: hidden;
|
|
140
|
+
text-overflow: ellipsis;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.tachui-debug-labeled:hover::before {
|
|
144
|
+
background: rgba(255, 0, 0, 1);
|
|
145
|
+
max-width: none;
|
|
146
|
+
white-space: normal;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* Component type indicators */
|
|
150
|
+
[data-tachui-component="VStack"] {
|
|
151
|
+
border-left: 2px solid rgba(0, 255, 0, 0.5) !important;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
[data-tachui-component="HStack"] {
|
|
155
|
+
border-top: 2px solid rgba(0, 0, 255, 0.5) !important;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
[data-tachui-component="Button"] {
|
|
159
|
+
box-shadow: inset 0 0 0 1px rgba(255, 165, 0, 0.5) !important;
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
const styleElement = document.createElement("style");
|
|
163
|
+
styleElement.id = "tachui-debug-styles";
|
|
164
|
+
styleElement.textContent = styles;
|
|
165
|
+
document.head.appendChild(styleElement);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Remove debug CSS styles
|
|
169
|
+
*/
|
|
170
|
+
removeDebugStyles() {
|
|
171
|
+
const styleElement = document.getElementById("tachui-debug-styles");
|
|
172
|
+
if (styleElement) {
|
|
173
|
+
styleElement.remove();
|
|
174
|
+
}
|
|
175
|
+
document.querySelectorAll(".tachui-debug").forEach((el) => {
|
|
176
|
+
el.classList.remove(
|
|
177
|
+
"tachui-debug",
|
|
178
|
+
"tachui-debug-labeled",
|
|
179
|
+
"tachui-debug-bounds"
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const debugManager = new DebugManager();
|
|
185
|
+
const enableDebug = (options) => debugManager.enable(options);
|
|
186
|
+
const disableDebug = () => debugManager.disable();
|
|
187
|
+
const isDebugEnabled = () => debugManager.isEnabled();
|
|
188
|
+
if (typeof window !== "undefined") {
|
|
189
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
190
|
+
const debugParam = urlParams.get("debug");
|
|
191
|
+
if (debugParam === "true" || debugParam === "1") {
|
|
192
|
+
debugManager.enable({
|
|
193
|
+
enabled: true,
|
|
194
|
+
showLabels: true,
|
|
195
|
+
showBounds: true,
|
|
196
|
+
logComponentTree: true
|
|
197
|
+
});
|
|
198
|
+
console.log("🔧 TachUI Debug Mode: Enabled via URL parameter (?debug=true)");
|
|
199
|
+
} else if (debugParam === "labels") {
|
|
200
|
+
debugManager.enable({
|
|
201
|
+
enabled: true,
|
|
202
|
+
showLabels: true,
|
|
203
|
+
showBounds: false,
|
|
204
|
+
logComponentTree: false
|
|
205
|
+
});
|
|
206
|
+
console.log("🔧 TachUI Debug Mode: Labels only (?debug=labels)");
|
|
207
|
+
} else if (debugParam === "bounds") {
|
|
208
|
+
debugManager.enable({
|
|
209
|
+
enabled: true,
|
|
210
|
+
showLabels: false,
|
|
211
|
+
showBounds: true,
|
|
212
|
+
logComponentTree: false
|
|
213
|
+
});
|
|
214
|
+
console.log("🔧 TachUI Debug Mode: Bounds only (?debug=bounds)");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
class DeveloperErrorFactory {
|
|
218
|
+
/**
|
|
219
|
+
* Create modifier validation error
|
|
220
|
+
*/
|
|
221
|
+
static modifierValidationError(modifier, issue, component) {
|
|
222
|
+
const componentName = component?.type || "Unknown";
|
|
223
|
+
const error = new Error(
|
|
224
|
+
`Invalid modifier usage: ${modifier} - ${issue}`
|
|
225
|
+
);
|
|
226
|
+
error.code = "MODIFIER_VALIDATION_ERROR";
|
|
227
|
+
error.category = "modifier";
|
|
228
|
+
error.severity = "error";
|
|
229
|
+
error.component = componentName;
|
|
230
|
+
error.suggestion = DeveloperErrorFactory.getModifierSuggestion(
|
|
231
|
+
modifier,
|
|
232
|
+
issue
|
|
233
|
+
);
|
|
234
|
+
error.documentation = `https://docs.tachui.dev/modifiers/${modifier.toLowerCase()}`;
|
|
235
|
+
error.examples = DeveloperErrorFactory.getModifierExamples(modifier);
|
|
236
|
+
return error;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Create component validation error
|
|
240
|
+
*/
|
|
241
|
+
static componentValidationError(componentType, prop, expectedType, actualValue) {
|
|
242
|
+
const actualType = Array.isArray(actualValue) ? `array[${actualValue.length}]` : typeof actualValue;
|
|
243
|
+
const error = new Error(
|
|
244
|
+
`Component validation failed: ${componentType}.${prop} expected ${expectedType}, got ${actualType}`
|
|
245
|
+
);
|
|
246
|
+
error.code = "COMPONENT_VALIDATION_ERROR";
|
|
247
|
+
error.category = "component";
|
|
248
|
+
error.severity = "error";
|
|
249
|
+
error.component = componentType;
|
|
250
|
+
error.suggestion = `Ensure ${prop} is of type ${expectedType}. ${DeveloperErrorFactory.getTypeConversionSuggestion(expectedType, actualValue)}`;
|
|
251
|
+
error.documentation = `https://docs.tachui.dev/components/${componentType.toLowerCase()}`;
|
|
252
|
+
error.examples = DeveloperErrorFactory.getComponentExamples(
|
|
253
|
+
componentType,
|
|
254
|
+
prop
|
|
255
|
+
);
|
|
256
|
+
return error;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Create reactive system error
|
|
260
|
+
*/
|
|
261
|
+
static reactiveSystemError(operation, issue, context) {
|
|
262
|
+
const error = new Error(
|
|
263
|
+
`Reactive system error: ${operation} - ${issue}`
|
|
264
|
+
);
|
|
265
|
+
error.code = "REACTIVE_SYSTEM_ERROR";
|
|
266
|
+
error.category = "reactive";
|
|
267
|
+
error.severity = "error";
|
|
268
|
+
error.suggestion = DeveloperErrorFactory.getReactiveSuggestion(
|
|
269
|
+
operation,
|
|
270
|
+
issue
|
|
271
|
+
);
|
|
272
|
+
error.documentation = "https://docs.tachui.dev/reactive/signals";
|
|
273
|
+
error.examples = DeveloperErrorFactory.getReactiveExamples(operation);
|
|
274
|
+
if (context) {
|
|
275
|
+
error.message += ` (Context: ${context})`;
|
|
276
|
+
}
|
|
277
|
+
return error;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Create runtime error
|
|
281
|
+
*/
|
|
282
|
+
static runtimeError(operation, issue, component) {
|
|
283
|
+
const error = new Error(
|
|
284
|
+
`Runtime error: ${operation} - ${issue}`
|
|
285
|
+
);
|
|
286
|
+
error.code = "RUNTIME_ERROR";
|
|
287
|
+
error.category = "runtime";
|
|
288
|
+
error.severity = "fatal";
|
|
289
|
+
error.component = component;
|
|
290
|
+
error.suggestion = DeveloperErrorFactory.getRuntimeSuggestion(
|
|
291
|
+
operation,
|
|
292
|
+
issue
|
|
293
|
+
);
|
|
294
|
+
error.documentation = "https://docs.tachui.dev/runtime/renderer";
|
|
295
|
+
return error;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Get modifier-specific suggestion
|
|
299
|
+
*/
|
|
300
|
+
static getModifierSuggestion(modifier, issue) {
|
|
301
|
+
const suggestions = {
|
|
302
|
+
padding: {
|
|
303
|
+
"conflicting properties": "Use either .padding(number) for all sides, or .padding({ horizontal, vertical }) for symmetric padding, or individual directional functions like .paddingTop()",
|
|
304
|
+
"invalid value": "Padding values must be numbers (pixels) or valid CSS length strings",
|
|
305
|
+
"negative padding": "Negative padding values are not recommended and may cause layout issues"
|
|
306
|
+
},
|
|
307
|
+
frame: {
|
|
308
|
+
"missing dimensions": "Frame modifier requires at least width or height: .frame(width, height) or .frame({ width: 100 })",
|
|
309
|
+
"invalid dimensions": "Frame dimensions must be positive numbers or valid CSS length values"
|
|
310
|
+
},
|
|
311
|
+
backgroundColor: {
|
|
312
|
+
"invalid color": "Use valid color formats: hex (#ff0000), rgb (rgb(255,0,0)), or named colors (red)",
|
|
313
|
+
"asset not found": "Color asset not found. Check your asset definitions or use getColor() to verify"
|
|
314
|
+
},
|
|
315
|
+
onTap: {
|
|
316
|
+
"not a function": "onTap requires a function: .onTap(() => { /* your code */ })",
|
|
317
|
+
"missing parameter": "onTap handler will receive a MouseEvent: .onTap((event) => { /* handle event */ })"
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const modifierSuggestions = suggestions[modifier];
|
|
321
|
+
return modifierSuggestions?.[issue] || `Check the ${modifier} modifier documentation for proper usage`;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Get modifier examples
|
|
325
|
+
*/
|
|
326
|
+
static getModifierExamples(modifier) {
|
|
327
|
+
const examples = {
|
|
328
|
+
padding: [
|
|
329
|
+
".padding(16)",
|
|
330
|
+
".padding({ horizontal: 20, vertical: 12 })",
|
|
331
|
+
".paddingTop(8).paddingHorizontal(16)",
|
|
332
|
+
".paddingLeading(20) // SwiftUI-style"
|
|
333
|
+
],
|
|
334
|
+
frame: [
|
|
335
|
+
".frame(100, 200)",
|
|
336
|
+
".frame({ width: 100, height: 200 })",
|
|
337
|
+
".frame({ minWidth: 50, maxWidth: 200 })"
|
|
338
|
+
],
|
|
339
|
+
backgroundColor: [
|
|
340
|
+
'.backgroundColor("#ff0000")',
|
|
341
|
+
'.backgroundColor("rgb(255, 0, 0)")',
|
|
342
|
+
".backgroundColor(Colors.primary) // Asset"
|
|
343
|
+
],
|
|
344
|
+
onTap: [
|
|
345
|
+
'.onTap(() => console.log("Tapped!"))',
|
|
346
|
+
".onTap((event) => handleTap(event))"
|
|
347
|
+
]
|
|
348
|
+
};
|
|
349
|
+
return examples[modifier] || [];
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Get component examples
|
|
353
|
+
*/
|
|
354
|
+
static getComponentExamples(componentType, prop) {
|
|
355
|
+
const examples = {
|
|
356
|
+
Text: {
|
|
357
|
+
children: ['Text("Hello World")', "Text(() => dynamicText())"],
|
|
358
|
+
style: [
|
|
359
|
+
'Text("Hello").fontSize(16)',
|
|
360
|
+
'Text("Hello").foregroundColor("red")'
|
|
361
|
+
]
|
|
362
|
+
},
|
|
363
|
+
Button: {
|
|
364
|
+
children: [
|
|
365
|
+
'Button({ children: "Click me" })',
|
|
366
|
+
"Button({ children: () => buttonText() })"
|
|
367
|
+
],
|
|
368
|
+
onPress: ["Button({ onPress: () => handlePress() })"]
|
|
369
|
+
},
|
|
370
|
+
VStack: {
|
|
371
|
+
children: [
|
|
372
|
+
'VStack([Text("Item 1"), Text("Item 2")])',
|
|
373
|
+
"VStack({ children: childComponents })"
|
|
374
|
+
],
|
|
375
|
+
spacing: [
|
|
376
|
+
"VStack({ spacing: 16 })",
|
|
377
|
+
"VStack({ spacing: 8, children: items })"
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
const componentExamples = examples[componentType];
|
|
382
|
+
return componentExamples?.[prop] || [
|
|
383
|
+
`${componentType}({ ${prop}: /* your value */ })`
|
|
384
|
+
];
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Get type conversion suggestion
|
|
388
|
+
*/
|
|
389
|
+
static getTypeConversionSuggestion(expectedType, actualValue) {
|
|
390
|
+
if (expectedType.includes("string") && typeof actualValue === "number") {
|
|
391
|
+
return `Convert number to string: "${actualValue}"`;
|
|
392
|
+
}
|
|
393
|
+
if (expectedType.includes("number") && typeof actualValue === "string") {
|
|
394
|
+
const parsed = parseFloat(actualValue);
|
|
395
|
+
if (!Number.isNaN(parsed)) {
|
|
396
|
+
return `Convert string to number: ${parsed}`;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (expectedType.includes("array") && !Array.isArray(actualValue)) {
|
|
400
|
+
return `Wrap value in array: [${JSON.stringify(actualValue)}]`;
|
|
401
|
+
}
|
|
402
|
+
if (expectedType.includes("function") && typeof actualValue !== "function") {
|
|
403
|
+
return "Provide a function: () => { /* your code */ }";
|
|
404
|
+
}
|
|
405
|
+
return `Expected ${expectedType}, ensure the value matches this type`;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Get reactive system suggestion
|
|
409
|
+
*/
|
|
410
|
+
static getReactiveSuggestion(operation, issue) {
|
|
411
|
+
const suggestions = {
|
|
412
|
+
createSignal: {
|
|
413
|
+
"invalid initial value": "Signal initial value should match the expected type",
|
|
414
|
+
"mutation attempt": "Signals are immutable. Use the setter function: const [value, setValue] = createSignal(0); setValue(newValue)"
|
|
415
|
+
},
|
|
416
|
+
createEffect: {
|
|
417
|
+
"missing dependencies": "Effect will only run when accessed signals change. Ensure all dependencies are accessed within the effect",
|
|
418
|
+
"infinite loop": "Effect creates infinite loop. Avoid setting signals that the effect depends on"
|
|
419
|
+
},
|
|
420
|
+
createComputed: {
|
|
421
|
+
"side effects": "Computed values should be pure. Avoid side effects like console.log or API calls",
|
|
422
|
+
"circular dependency": "Computed value depends on itself, creating circular dependency"
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
const operationSuggestions = suggestions[operation];
|
|
426
|
+
return operationSuggestions?.[issue] || `Check reactive system documentation for ${operation} usage`;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Get reactive examples
|
|
430
|
+
*/
|
|
431
|
+
static getReactiveExamples(operation) {
|
|
432
|
+
const examples = {
|
|
433
|
+
createSignal: [
|
|
434
|
+
"const [count, setCount] = createSignal(0)",
|
|
435
|
+
'const [text, setText] = createSignal("Hello")',
|
|
436
|
+
"const [user, setUser] = createSignal<User | null>(null)"
|
|
437
|
+
],
|
|
438
|
+
createEffect: [
|
|
439
|
+
'createEffect(() => { console.log("Count:", count()) })',
|
|
440
|
+
'createEffect(() => { localStorage.setItem("count", count().toString()) })'
|
|
441
|
+
],
|
|
442
|
+
createComputed: [
|
|
443
|
+
"const doubled = createComputed(() => count() * 2)",
|
|
444
|
+
"const fullName = createComputed(() => `${firstName()} ${lastName()}`)"
|
|
445
|
+
]
|
|
446
|
+
};
|
|
447
|
+
return examples[operation] || [];
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Get runtime suggestion
|
|
451
|
+
*/
|
|
452
|
+
static getRuntimeSuggestion(operation, issue) {
|
|
453
|
+
const suggestions = {
|
|
454
|
+
render: "Ensure all components return valid virtual DOM nodes",
|
|
455
|
+
mount: "Check that the mount target element exists in the DOM",
|
|
456
|
+
update: "Verify component state and props are valid before updating"
|
|
457
|
+
};
|
|
458
|
+
return suggestions[operation] || `Runtime issue in ${operation}: ${issue}`;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
class DeveloperWarnings {
|
|
462
|
+
static warningsSeen = /* @__PURE__ */ new Set();
|
|
463
|
+
/**
|
|
464
|
+
* Warn about deprecated API usage
|
|
465
|
+
*/
|
|
466
|
+
static deprecation(oldAPI, newAPI, component, willBeRemovedIn) {
|
|
467
|
+
const key = `deprecation:${oldAPI}:${component || "global"}`;
|
|
468
|
+
if (DeveloperWarnings.warningsSeen.has(key)) return;
|
|
469
|
+
DeveloperWarnings.warningsSeen.add(key);
|
|
470
|
+
const componentContext = component ? ` in ${component}` : "";
|
|
471
|
+
const removalVersion = willBeRemovedIn ? ` (will be removed in ${willBeRemovedIn})` : "";
|
|
472
|
+
console.warn(
|
|
473
|
+
`🟡 TachUI Deprecation Warning${componentContext}: "${oldAPI}" is deprecated. Use "${newAPI}" instead${removalVersion}.
|
|
474
|
+
See: https://docs.tachui.dev/migration/deprecations`
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Warn about performance issues
|
|
479
|
+
*/
|
|
480
|
+
static performance(issue, suggestion, component) {
|
|
481
|
+
const key = `performance:${issue}:${component || "global"}`;
|
|
482
|
+
if (DeveloperWarnings.warningsSeen.has(key)) return;
|
|
483
|
+
DeveloperWarnings.warningsSeen.add(key);
|
|
484
|
+
const componentContext = component ? ` in ${component}` : "";
|
|
485
|
+
console.warn(
|
|
486
|
+
`⚡ TachUI Performance Warning${componentContext}: ${issue}
|
|
487
|
+
💡 Suggestion: ${suggestion}
|
|
488
|
+
See: https://docs.tachui.dev/performance/optimization`
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Warn about accessibility issues
|
|
493
|
+
*/
|
|
494
|
+
static accessibility(issue, suggestion, component) {
|
|
495
|
+
const key = `a11y:${issue}:${component || "global"}`;
|
|
496
|
+
if (DeveloperWarnings.warningsSeen.has(key)) return;
|
|
497
|
+
DeveloperWarnings.warningsSeen.add(key);
|
|
498
|
+
const componentContext = component ? ` in ${component}` : "";
|
|
499
|
+
console.warn(
|
|
500
|
+
`♿ TachUI Accessibility Warning${componentContext}: ${issue}
|
|
501
|
+
💡 Suggestion: ${suggestion}
|
|
502
|
+
See: https://docs.tachui.dev/accessibility/guidelines`
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Clear warning cache (for testing)
|
|
507
|
+
*/
|
|
508
|
+
static clearWarnings() {
|
|
509
|
+
DeveloperWarnings.warningsSeen.clear();
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Get count of unique warnings shown
|
|
513
|
+
*/
|
|
514
|
+
static getWarningCount() {
|
|
515
|
+
return DeveloperWarnings.warningsSeen.size;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
class TypeValidation {
|
|
519
|
+
/**
|
|
520
|
+
* Validate component props with enhanced error messages
|
|
521
|
+
*/
|
|
522
|
+
static validateComponentProps(componentType, props, schema) {
|
|
523
|
+
for (const [prop, config] of Object.entries(schema)) {
|
|
524
|
+
const value = props[prop];
|
|
525
|
+
if (config.required && (value === void 0 || value === null)) {
|
|
526
|
+
throw DeveloperErrorFactory.componentValidationError(
|
|
527
|
+
componentType,
|
|
528
|
+
prop,
|
|
529
|
+
`${config.type} (required)`,
|
|
530
|
+
value
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
if (value === void 0 && !config.required) continue;
|
|
534
|
+
if (!TypeValidation.validateType(value, config.type)) {
|
|
535
|
+
throw DeveloperErrorFactory.componentValidationError(
|
|
536
|
+
componentType,
|
|
537
|
+
prop,
|
|
538
|
+
config.type,
|
|
539
|
+
value
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
if (config.validator && !config.validator(value)) {
|
|
543
|
+
const error = DeveloperErrorFactory.componentValidationError(
|
|
544
|
+
componentType,
|
|
545
|
+
prop,
|
|
546
|
+
config.type,
|
|
547
|
+
value
|
|
548
|
+
);
|
|
549
|
+
if (config.message) {
|
|
550
|
+
error.suggestion = config.message;
|
|
551
|
+
}
|
|
552
|
+
throw error;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Validate type
|
|
558
|
+
*/
|
|
559
|
+
static validateType(value, type) {
|
|
560
|
+
switch (type) {
|
|
561
|
+
case "string":
|
|
562
|
+
return typeof value === "string";
|
|
563
|
+
case "number":
|
|
564
|
+
return typeof value === "number" && !Number.isNaN(value);
|
|
565
|
+
case "boolean":
|
|
566
|
+
return typeof value === "boolean";
|
|
567
|
+
case "function":
|
|
568
|
+
return typeof value === "function";
|
|
569
|
+
case "array":
|
|
570
|
+
return Array.isArray(value);
|
|
571
|
+
case "object":
|
|
572
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
573
|
+
case "ComponentInstance":
|
|
574
|
+
return value && typeof value === "object" && "type" in value;
|
|
575
|
+
case "Signal":
|
|
576
|
+
return typeof value === "function" && "peek" in value;
|
|
577
|
+
default:
|
|
578
|
+
if (type.includes("|")) {
|
|
579
|
+
return type.split("|").some((t) => TypeValidation.validateType(value, t.trim()));
|
|
580
|
+
}
|
|
581
|
+
return true;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Validate modifier combination
|
|
586
|
+
*/
|
|
587
|
+
static validateModifierCombination(modifiers) {
|
|
588
|
+
const conflicts = [
|
|
589
|
+
{
|
|
590
|
+
types: ["padding", "padding"],
|
|
591
|
+
message: "Multiple padding modifiers detected. Combine into single .padding() call or use specific directional functions"
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
types: ["size", "size"],
|
|
595
|
+
message: "Multiple size modifiers detected. Combine into single .size() call"
|
|
596
|
+
}
|
|
597
|
+
];
|
|
598
|
+
for (const conflict of conflicts) {
|
|
599
|
+
const matchingModifiers = modifiers.filter(
|
|
600
|
+
(m) => conflict.types.includes(m.type)
|
|
601
|
+
);
|
|
602
|
+
if (matchingModifiers.length > 1) {
|
|
603
|
+
DeveloperWarnings.performance(
|
|
604
|
+
"Redundant modifiers detected",
|
|
605
|
+
conflict.message
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
class DeveloperExperienceUtils {
|
|
612
|
+
/**
|
|
613
|
+
* Format error message for better developer experience
|
|
614
|
+
*/
|
|
615
|
+
static formatError(error) {
|
|
616
|
+
return {
|
|
617
|
+
code: error.code,
|
|
618
|
+
message: error.message,
|
|
619
|
+
suggestion: error.suggestion,
|
|
620
|
+
severity: error.severity,
|
|
621
|
+
component: error.component,
|
|
622
|
+
documentation: error.documentation,
|
|
623
|
+
examples: error.examples
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Get statistics about developer experience features
|
|
628
|
+
*/
|
|
629
|
+
static getStatistics() {
|
|
630
|
+
return {
|
|
631
|
+
errorCount: 0,
|
|
632
|
+
warningCount: 0,
|
|
633
|
+
suggestionCount: 0
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Get suggestions for a diagnostic
|
|
638
|
+
*/
|
|
639
|
+
static getSuggestions(_code, _data) {
|
|
640
|
+
return [];
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Test developer experience features
|
|
644
|
+
*/
|
|
645
|
+
static async test() {
|
|
646
|
+
console.log("🛠️ Developer Experience Utils test completed");
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
const devMode = {
|
|
650
|
+
/**
|
|
651
|
+
* Enable enhanced error reporting in development
|
|
652
|
+
*/
|
|
653
|
+
enableEnhancedErrors() {
|
|
654
|
+
const originalError = console.error;
|
|
655
|
+
console.error = (...args) => {
|
|
656
|
+
const firstArg = args[0];
|
|
657
|
+
if (firstArg && typeof firstArg === "object" && "code" in firstArg) {
|
|
658
|
+
const error = firstArg;
|
|
659
|
+
console.group(
|
|
660
|
+
`🚨 TachUI ${error.severity.toUpperCase()}: ${error.code}`
|
|
661
|
+
);
|
|
662
|
+
console.error(error.message);
|
|
663
|
+
if (error.component) console.log(`📦 Component: ${error.component}`);
|
|
664
|
+
console.log(`💡 Suggestion: ${error.suggestion}`);
|
|
665
|
+
if (error.documentation) console.log(`📖 Docs: ${error.documentation}`);
|
|
666
|
+
if (error.examples?.length) {
|
|
667
|
+
console.group("💻 Examples:");
|
|
668
|
+
error.examples.forEach((example) => console.log(` ${example}`));
|
|
669
|
+
console.groupEnd();
|
|
670
|
+
}
|
|
671
|
+
console.groupEnd();
|
|
672
|
+
} else {
|
|
673
|
+
originalError(...args);
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
},
|
|
677
|
+
/**
|
|
678
|
+
* Log component tree for debugging
|
|
679
|
+
*/
|
|
680
|
+
logComponentTree(root, depth = 0) {
|
|
681
|
+
const indent = " ".repeat(depth);
|
|
682
|
+
const modifierCount = root.modifiers?.length || 0;
|
|
683
|
+
const modifierInfo = modifierCount > 0 ? ` (${modifierCount} modifiers)` : "";
|
|
684
|
+
console.log(`${indent}${root.type}${modifierInfo}`);
|
|
685
|
+
if ("children" in root.props && Array.isArray(root.props.children)) {
|
|
686
|
+
root.props.children.forEach((child) => {
|
|
687
|
+
if (child && typeof child === "object" && "type" in child) {
|
|
688
|
+
this.logComponentTree(child, depth + 1);
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
class DevelopmentWarnings {
|
|
695
|
+
static warningsShown = /* @__PURE__ */ new Set();
|
|
696
|
+
/**
|
|
697
|
+
* Warn about element tag overrides in development
|
|
698
|
+
*/
|
|
699
|
+
static warnElementOverride(componentType, originalTag, overrideTag) {
|
|
700
|
+
if (process.env.NODE_ENV === "production") return;
|
|
701
|
+
const warningKey = `${componentType}-${originalTag}-${overrideTag}`;
|
|
702
|
+
if (this.warningsShown.has(warningKey)) return;
|
|
703
|
+
this.warningsShown.add(warningKey);
|
|
704
|
+
console.warn(
|
|
705
|
+
`[tachUI] ${componentType} (${originalTag}) overridden to <${overrideTag}>. Ensure this maintains expected behavior and accessibility.`
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Error for invalid HTML tags
|
|
710
|
+
*/
|
|
711
|
+
static errorInvalidTag(tag, componentType) {
|
|
712
|
+
if (process.env.NODE_ENV === "production") return;
|
|
713
|
+
console.error(
|
|
714
|
+
`[tachUI] Invalid HTML tag '${tag}' specified for ${componentType}. Using tag as-is - ensure this is intentional.`
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Info message for semantic role application
|
|
719
|
+
*/
|
|
720
|
+
static infoSemanticRole(tag, role) {
|
|
721
|
+
if (process.env.NODE_ENV !== "development") return;
|
|
722
|
+
console.info(`[tachUI] Applied semantic role '${role}' to <${tag}> element`);
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Warn about potentially problematic tag combinations
|
|
726
|
+
*/
|
|
727
|
+
static warnProblematicCombination(componentType, tag, issue, severity = "warning") {
|
|
728
|
+
if (process.env.NODE_ENV === "production") return;
|
|
729
|
+
const warningKey = `${componentType}-${tag}-${issue}`;
|
|
730
|
+
if (this.warningsShown.has(warningKey)) return;
|
|
731
|
+
this.warningsShown.add(warningKey);
|
|
732
|
+
const logFunction = severity === "warning" ? console.warn : console.info;
|
|
733
|
+
logFunction(`[tachUI] ${componentType}: ${issue}`);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Warn about accessibility concerns
|
|
737
|
+
*/
|
|
738
|
+
static warnAccessibility(componentType, tag, accessibilityIssue) {
|
|
739
|
+
if (process.env.NODE_ENV === "production") return;
|
|
740
|
+
const warningKey = `a11y-${componentType}-${tag}-${accessibilityIssue}`;
|
|
741
|
+
if (this.warningsShown.has(warningKey)) return;
|
|
742
|
+
this.warningsShown.add(warningKey);
|
|
743
|
+
console.warn(
|
|
744
|
+
`[tachUI A11y] ${componentType} with <${tag}>: ${accessibilityIssue}. Consider using appropriate ARIA attributes or different semantic structure.`
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Clear all shown warnings (useful for testing)
|
|
749
|
+
*/
|
|
750
|
+
static clearWarnings() {
|
|
751
|
+
this.warningsShown.clear();
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Check if a warning has been shown
|
|
755
|
+
*/
|
|
756
|
+
static hasWarningBeenShown(warningKey) {
|
|
757
|
+
return this.warningsShown.has(warningKey);
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Get count of unique warnings shown
|
|
761
|
+
*/
|
|
762
|
+
static getWarningCount() {
|
|
763
|
+
return this.warningsShown.size;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
const performanceMonitor = {
|
|
767
|
+
getSnapshot: () => ({
|
|
768
|
+
memory: 0,
|
|
769
|
+
timing: {},
|
|
770
|
+
validationOverhead: 0,
|
|
771
|
+
cacheEfficiency: 0.85
|
|
772
|
+
})
|
|
773
|
+
};
|
|
774
|
+
class ValidationDebugger {
|
|
775
|
+
static instance;
|
|
776
|
+
sessions = /* @__PURE__ */ new Map();
|
|
777
|
+
currentSession = null;
|
|
778
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
779
|
+
componentRegistry = /* @__PURE__ */ new Map();
|
|
780
|
+
static getInstance() {
|
|
781
|
+
if (!this.instance) {
|
|
782
|
+
this.instance = new ValidationDebugger();
|
|
783
|
+
}
|
|
784
|
+
return this.instance;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Start a debugging session
|
|
788
|
+
*/
|
|
789
|
+
startSession(sessionId) {
|
|
790
|
+
const id = sessionId || `debug-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
791
|
+
const session = {
|
|
792
|
+
id,
|
|
793
|
+
startTime: Date.now(),
|
|
794
|
+
validationEvents: [],
|
|
795
|
+
components: [],
|
|
796
|
+
errors: [],
|
|
797
|
+
performance: performanceMonitor.getSnapshot()
|
|
798
|
+
};
|
|
799
|
+
this.sessions.set(id, session);
|
|
800
|
+
this.currentSession = session;
|
|
801
|
+
this.logEvent("validation-start", `Debug session ${id} started`);
|
|
802
|
+
if (process.env.NODE_ENV !== "production") {
|
|
803
|
+
console.info(`🔍 TachUI Debug Session Started: ${id}`);
|
|
804
|
+
}
|
|
805
|
+
return id;
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* End the current debugging session
|
|
809
|
+
*/
|
|
810
|
+
endSession() {
|
|
811
|
+
if (!this.currentSession) {
|
|
812
|
+
console.warn("No active debug session to end");
|
|
813
|
+
return null;
|
|
814
|
+
}
|
|
815
|
+
this.currentSession.endTime = Date.now();
|
|
816
|
+
this.logEvent(
|
|
817
|
+
"validation-end",
|
|
818
|
+
`Debug session ${this.currentSession.id} ended`
|
|
819
|
+
);
|
|
820
|
+
const session = this.currentSession;
|
|
821
|
+
this.currentSession = null;
|
|
822
|
+
if (process.env.NODE_ENV !== "production") {
|
|
823
|
+
console.info(`🔍 TachUI Debug Session Ended: ${session.id}`);
|
|
824
|
+
this.printSessionSummary(session);
|
|
825
|
+
}
|
|
826
|
+
return session;
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Log a debug event
|
|
830
|
+
*/
|
|
831
|
+
logEvent(type, message, data) {
|
|
832
|
+
if (!this.currentSession) return;
|
|
833
|
+
const event = {
|
|
834
|
+
id: `event-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`,
|
|
835
|
+
type,
|
|
836
|
+
timestamp: Date.now(),
|
|
837
|
+
message,
|
|
838
|
+
data,
|
|
839
|
+
stackTrace: process.env.NODE_ENV !== "production" ? new Error().stack : void 0
|
|
840
|
+
};
|
|
841
|
+
this.currentSession.validationEvents.push(event);
|
|
842
|
+
const listeners = this.eventListeners.get(type) || [];
|
|
843
|
+
listeners.forEach((listener) => {
|
|
844
|
+
try {
|
|
845
|
+
listener(event);
|
|
846
|
+
} catch (error) {
|
|
847
|
+
console.error("Debug event listener error:", error);
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Register component for debugging
|
|
853
|
+
*/
|
|
854
|
+
registerComponent(_component, type, props) {
|
|
855
|
+
const componentId = `${type}-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`;
|
|
856
|
+
const debugInfo = {
|
|
857
|
+
type,
|
|
858
|
+
id: componentId,
|
|
859
|
+
props,
|
|
860
|
+
lifecycle: {
|
|
861
|
+
created: Date.now()
|
|
862
|
+
},
|
|
863
|
+
validation: {
|
|
864
|
+
passed: true,
|
|
865
|
+
errors: [],
|
|
866
|
+
warnings: [],
|
|
867
|
+
lastCheck: Date.now()
|
|
868
|
+
},
|
|
869
|
+
performance: {
|
|
870
|
+
updateTimes: [],
|
|
871
|
+
validationTime: 0
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
this.componentRegistry.set(componentId, debugInfo);
|
|
875
|
+
if (this.currentSession) {
|
|
876
|
+
this.currentSession.components.push(debugInfo);
|
|
877
|
+
this.logEvent("component-mount", `Component ${type} registered`, {
|
|
878
|
+
componentId,
|
|
879
|
+
props
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
return componentId;
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Update component debug info
|
|
886
|
+
*/
|
|
887
|
+
updateComponent(componentId, phase, data) {
|
|
888
|
+
const debugInfo = this.componentRegistry.get(componentId);
|
|
889
|
+
if (!debugInfo) return;
|
|
890
|
+
const timestamp = Date.now();
|
|
891
|
+
switch (phase) {
|
|
892
|
+
case "mount":
|
|
893
|
+
debugInfo.lifecycle.mounted = timestamp;
|
|
894
|
+
if (data?.performance) {
|
|
895
|
+
debugInfo.performance.mountTime = data.performance.duration;
|
|
896
|
+
}
|
|
897
|
+
this.logEvent(
|
|
898
|
+
"component-mount",
|
|
899
|
+
`Component ${debugInfo.type} mounted`,
|
|
900
|
+
{ componentId, data }
|
|
901
|
+
);
|
|
902
|
+
break;
|
|
903
|
+
case "update":
|
|
904
|
+
debugInfo.lifecycle.lastUpdate = timestamp;
|
|
905
|
+
if (data?.performance) {
|
|
906
|
+
debugInfo.performance.updateTimes.push(data.performance.duration);
|
|
907
|
+
}
|
|
908
|
+
if (data?.props) {
|
|
909
|
+
debugInfo.props = { ...data.props };
|
|
910
|
+
}
|
|
911
|
+
this.logEvent(
|
|
912
|
+
"component-update",
|
|
913
|
+
`Component ${debugInfo.type} updated`,
|
|
914
|
+
{ componentId, data }
|
|
915
|
+
);
|
|
916
|
+
break;
|
|
917
|
+
case "unmount":
|
|
918
|
+
debugInfo.lifecycle.unmounted = timestamp;
|
|
919
|
+
this.logEvent(
|
|
920
|
+
"component-unmount",
|
|
921
|
+
`Component ${debugInfo.type} unmounted`,
|
|
922
|
+
{ componentId }
|
|
923
|
+
);
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Record validation error for debugging
|
|
929
|
+
*/
|
|
930
|
+
recordValidationError(error, componentId) {
|
|
931
|
+
if (this.currentSession) {
|
|
932
|
+
this.currentSession.errors.push(error);
|
|
933
|
+
this.logEvent("validation-error", `Validation error: ${error.message}`, {
|
|
934
|
+
error,
|
|
935
|
+
componentId
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
if (componentId) {
|
|
939
|
+
const debugInfo = this.componentRegistry.get(componentId);
|
|
940
|
+
if (debugInfo) {
|
|
941
|
+
debugInfo.validation.passed = false;
|
|
942
|
+
debugInfo.validation.errors.push(error.message);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* Record validation recovery for debugging
|
|
948
|
+
*/
|
|
949
|
+
recordValidationRecovery(originalError, recoveryStrategy, componentId) {
|
|
950
|
+
this.logEvent(
|
|
951
|
+
"validation-recovery",
|
|
952
|
+
`Recovered from validation error using ${recoveryStrategy}`,
|
|
953
|
+
{ originalError, recoveryStrategy, componentId }
|
|
954
|
+
);
|
|
955
|
+
if (componentId) {
|
|
956
|
+
const debugInfo = this.componentRegistry.get(componentId);
|
|
957
|
+
if (debugInfo) {
|
|
958
|
+
debugInfo.validation.warnings.push(`Recovered from: ${originalError}`);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Add event listener for debug events
|
|
964
|
+
*/
|
|
965
|
+
addEventListener(type, listener) {
|
|
966
|
+
if (!this.eventListeners.has(type)) {
|
|
967
|
+
this.eventListeners.set(type, []);
|
|
968
|
+
}
|
|
969
|
+
this.eventListeners.get(type).push(listener);
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Remove event listener
|
|
973
|
+
*/
|
|
974
|
+
removeEventListener(type, listener) {
|
|
975
|
+
const listeners = this.eventListeners.get(type);
|
|
976
|
+
if (listeners) {
|
|
977
|
+
const index = listeners.indexOf(listener);
|
|
978
|
+
if (index > -1) {
|
|
979
|
+
listeners.splice(index, 1);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Get debug session by ID
|
|
985
|
+
*/
|
|
986
|
+
getSession(sessionId) {
|
|
987
|
+
return this.sessions.get(sessionId);
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Get current active session
|
|
991
|
+
*/
|
|
992
|
+
getCurrentSession() {
|
|
993
|
+
return this.currentSession;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Get all debug sessions
|
|
997
|
+
*/
|
|
998
|
+
getAllSessions() {
|
|
999
|
+
return Array.from(this.sessions.values());
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Search debug events by criteria
|
|
1003
|
+
*/
|
|
1004
|
+
searchEvents(criteria) {
|
|
1005
|
+
if (!this.currentSession) return [];
|
|
1006
|
+
return this.currentSession.validationEvents.filter((event) => {
|
|
1007
|
+
if (criteria.type && event.type !== criteria.type) return false;
|
|
1008
|
+
if (criteria.componentType && event.componentType !== criteria.componentType)
|
|
1009
|
+
return false;
|
|
1010
|
+
if (criteria.timeRange) {
|
|
1011
|
+
if (event.timestamp < criteria.timeRange.start || event.timestamp > criteria.timeRange.end)
|
|
1012
|
+
return false;
|
|
1013
|
+
}
|
|
1014
|
+
if (criteria.messageContains && !event.message.includes(criteria.messageContains))
|
|
1015
|
+
return false;
|
|
1016
|
+
return true;
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Analyze component performance
|
|
1021
|
+
*/
|
|
1022
|
+
analyzeComponent(componentId) {
|
|
1023
|
+
const debugInfo = this.componentRegistry.get(componentId);
|
|
1024
|
+
if (!debugInfo) return null;
|
|
1025
|
+
if (debugInfo.performance.updateTimes.length > 0) {
|
|
1026
|
+
const average = debugInfo.performance.updateTimes.reduce((sum, time) => sum + time, 0) / debugInfo.performance.updateTimes.length;
|
|
1027
|
+
console.info(
|
|
1028
|
+
`📊 Component ${debugInfo.type} average update time: ${average.toFixed(2)}ms`
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
const age = Date.now() - debugInfo.lifecycle.created;
|
|
1032
|
+
console.info(`📊 Component ${debugInfo.type} age: ${age}ms`);
|
|
1033
|
+
return debugInfo;
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Generate performance report
|
|
1037
|
+
*/
|
|
1038
|
+
generatePerformanceReport() {
|
|
1039
|
+
if (!this.currentSession) return "No active debug session";
|
|
1040
|
+
const components = this.currentSession.components;
|
|
1041
|
+
const totalValidationTime = components.reduce(
|
|
1042
|
+
(sum, comp) => sum + comp.performance.validationTime,
|
|
1043
|
+
0
|
|
1044
|
+
);
|
|
1045
|
+
const averageValidationTime = components.length > 0 ? totalValidationTime / components.length : 0;
|
|
1046
|
+
const report = [
|
|
1047
|
+
"🔍 TachUI Validation Performance Report",
|
|
1048
|
+
`Session ID: ${this.currentSession.id}`,
|
|
1049
|
+
`Duration: ${this.currentSession.endTime ? this.currentSession.endTime - this.currentSession.startTime : "Ongoing"}ms`,
|
|
1050
|
+
`Components: ${components.length}`,
|
|
1051
|
+
`Validation Events: ${this.currentSession.validationEvents.length}`,
|
|
1052
|
+
`Errors: ${this.currentSession.errors.length}`,
|
|
1053
|
+
`Average Validation Time: ${averageValidationTime.toFixed(2)}ms`,
|
|
1054
|
+
"",
|
|
1055
|
+
"Component Performance:",
|
|
1056
|
+
...components.map((comp) => {
|
|
1057
|
+
const updateCount = comp.performance.updateTimes.length;
|
|
1058
|
+
const avgUpdateTime = updateCount > 0 ? comp.performance.updateTimes.reduce(
|
|
1059
|
+
(sum, time) => sum + time,
|
|
1060
|
+
0
|
|
1061
|
+
) / updateCount : 0;
|
|
1062
|
+
return ` ${comp.type} (${comp.id}): ${comp.performance.validationTime}ms validation, ${avgUpdateTime.toFixed(2)}ms avg update, ${updateCount} updates`;
|
|
1063
|
+
})
|
|
1064
|
+
].join("\n");
|
|
1065
|
+
return report;
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Clear all debug data
|
|
1069
|
+
*/
|
|
1070
|
+
clearDebugData() {
|
|
1071
|
+
this.sessions.clear();
|
|
1072
|
+
this.currentSession = null;
|
|
1073
|
+
this.componentRegistry.clear();
|
|
1074
|
+
this.eventListeners.clear();
|
|
1075
|
+
console.info("🔍 Debug data cleared");
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Export debug data for external analysis
|
|
1079
|
+
*/
|
|
1080
|
+
exportDebugData() {
|
|
1081
|
+
const data = {
|
|
1082
|
+
sessions: Array.from(this.sessions.entries()),
|
|
1083
|
+
currentSession: this.currentSession,
|
|
1084
|
+
components: Array.from(this.componentRegistry.entries()),
|
|
1085
|
+
timestamp: Date.now()
|
|
1086
|
+
};
|
|
1087
|
+
return JSON.stringify(data, null, 2);
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Import debug data from external source
|
|
1091
|
+
*/
|
|
1092
|
+
importDebugData(jsonData) {
|
|
1093
|
+
try {
|
|
1094
|
+
const data = JSON.parse(jsonData);
|
|
1095
|
+
if (data.sessions) {
|
|
1096
|
+
this.sessions = new Map(data.sessions);
|
|
1097
|
+
}
|
|
1098
|
+
if (data.components) {
|
|
1099
|
+
this.componentRegistry = new Map(data.components);
|
|
1100
|
+
}
|
|
1101
|
+
if (data.currentSession) {
|
|
1102
|
+
this.currentSession = data.currentSession;
|
|
1103
|
+
}
|
|
1104
|
+
console.info("🔍 Debug data imported successfully");
|
|
1105
|
+
} catch (error) {
|
|
1106
|
+
console.error("Failed to import debug data:", error);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Print session summary to console
|
|
1111
|
+
*/
|
|
1112
|
+
printSessionSummary(session) {
|
|
1113
|
+
const duration = session.endTime ? session.endTime - session.startTime : 0;
|
|
1114
|
+
const errorCount = session.errors.length;
|
|
1115
|
+
const componentCount = session.components.length;
|
|
1116
|
+
const eventCount = session.validationEvents.length;
|
|
1117
|
+
console.group(`📊 Debug Session Summary: ${session.id}`);
|
|
1118
|
+
console.info(`Duration: ${duration}ms`);
|
|
1119
|
+
console.info(`Components: ${componentCount}`);
|
|
1120
|
+
console.info(`Events: ${eventCount}`);
|
|
1121
|
+
console.info(`Errors: ${errorCount}`);
|
|
1122
|
+
if (errorCount > 0) {
|
|
1123
|
+
console.warn(
|
|
1124
|
+
"Errors encountered:",
|
|
1125
|
+
session.errors.map((e) => e.message)
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
const performanceEvents = session.validationEvents.filter(
|
|
1129
|
+
(e) => e.type === "performance-warning"
|
|
1130
|
+
);
|
|
1131
|
+
if (performanceEvents.length > 0) {
|
|
1132
|
+
console.warn(`Performance warnings: ${performanceEvents.length}`);
|
|
1133
|
+
}
|
|
1134
|
+
console.groupEnd();
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
const validationDebugger = ValidationDebugger.getInstance();
|
|
1138
|
+
const ValidationDebugUtils = {
|
|
1139
|
+
/**
|
|
1140
|
+
* Start debugging session
|
|
1141
|
+
*/
|
|
1142
|
+
startSession: (sessionId) => validationDebugger.startSession(sessionId),
|
|
1143
|
+
/**
|
|
1144
|
+
* End debugging session
|
|
1145
|
+
*/
|
|
1146
|
+
endSession: () => validationDebugger.endSession(),
|
|
1147
|
+
/**
|
|
1148
|
+
* Log debug event
|
|
1149
|
+
*/
|
|
1150
|
+
logEvent: (type, message, data) => validationDebugger.logEvent(type, message, data),
|
|
1151
|
+
/**
|
|
1152
|
+
* Register component for debugging
|
|
1153
|
+
*/
|
|
1154
|
+
registerComponent: (component, type, props) => validationDebugger.registerComponent(component, type, props),
|
|
1155
|
+
/**
|
|
1156
|
+
* Record validation error
|
|
1157
|
+
*/
|
|
1158
|
+
recordError: (error, componentId) => validationDebugger.recordValidationError(error, componentId),
|
|
1159
|
+
/**
|
|
1160
|
+
* Record validation recovery
|
|
1161
|
+
*/
|
|
1162
|
+
recordRecovery: (originalError, strategy, componentId) => validationDebugger.recordValidationRecovery(
|
|
1163
|
+
originalError,
|
|
1164
|
+
strategy,
|
|
1165
|
+
componentId
|
|
1166
|
+
),
|
|
1167
|
+
/**
|
|
1168
|
+
* Get performance report
|
|
1169
|
+
*/
|
|
1170
|
+
getPerformanceReport: () => validationDebugger.generatePerformanceReport(),
|
|
1171
|
+
/**
|
|
1172
|
+
* Search events
|
|
1173
|
+
*/
|
|
1174
|
+
searchEvents: (criteria) => validationDebugger.searchEvents(criteria),
|
|
1175
|
+
/**
|
|
1176
|
+
* Export debug data
|
|
1177
|
+
*/
|
|
1178
|
+
export: () => validationDebugger.exportDebugData(),
|
|
1179
|
+
/**
|
|
1180
|
+
* Import debug data
|
|
1181
|
+
*/
|
|
1182
|
+
import: (data) => validationDebugger.importDebugData(data),
|
|
1183
|
+
/**
|
|
1184
|
+
* Clear all debug data
|
|
1185
|
+
*/
|
|
1186
|
+
clear: () => validationDebugger.clearDebugData(),
|
|
1187
|
+
/**
|
|
1188
|
+
* Test debugging system
|
|
1189
|
+
*/
|
|
1190
|
+
test: () => {
|
|
1191
|
+
console.group("🔍 Validation Debug System Test");
|
|
1192
|
+
try {
|
|
1193
|
+
const sessionId = validationDebugger.startSession("test-session");
|
|
1194
|
+
console.info("✅ Debug session started:", sessionId);
|
|
1195
|
+
const componentId = validationDebugger.registerComponent(
|
|
1196
|
+
{},
|
|
1197
|
+
"TestComponent",
|
|
1198
|
+
{ prop: "value" }
|
|
1199
|
+
);
|
|
1200
|
+
console.info("✅ Test component registered:", componentId);
|
|
1201
|
+
validationDebugger.logEvent("validation-start", "Test validation started");
|
|
1202
|
+
validationDebugger.logEvent("cache-hit", "Test cache hit", {
|
|
1203
|
+
key: "test-key"
|
|
1204
|
+
});
|
|
1205
|
+
validationDebugger.logEvent("validation-end", "Test validation completed");
|
|
1206
|
+
validationDebugger.updateComponent(componentId, "mount", {
|
|
1207
|
+
performance: { duration: 5 }
|
|
1208
|
+
});
|
|
1209
|
+
validationDebugger.updateComponent(componentId, "update", {
|
|
1210
|
+
props: { updated: true }
|
|
1211
|
+
});
|
|
1212
|
+
validationDebugger.recordValidationError(
|
|
1213
|
+
new Error("Test error"),
|
|
1214
|
+
componentId
|
|
1215
|
+
);
|
|
1216
|
+
validationDebugger.recordValidationRecovery(
|
|
1217
|
+
"Test error",
|
|
1218
|
+
"fallback",
|
|
1219
|
+
componentId
|
|
1220
|
+
);
|
|
1221
|
+
const _report = validationDebugger.generatePerformanceReport();
|
|
1222
|
+
console.info("✅ Performance report generated");
|
|
1223
|
+
const errorEvents = validationDebugger.searchEvents({
|
|
1224
|
+
type: "validation-error"
|
|
1225
|
+
});
|
|
1226
|
+
console.info("✅ Event search:", errorEvents.length, "error events found");
|
|
1227
|
+
const session = validationDebugger.endSession();
|
|
1228
|
+
console.info("✅ Debug session ended:", session?.id);
|
|
1229
|
+
console.info("✅ Validation debugging system is working correctly");
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
console.error("❌ Validation debugging test failed:", error);
|
|
1232
|
+
}
|
|
1233
|
+
console.groupEnd();
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
export {
|
|
1237
|
+
DeveloperErrorFactory,
|
|
1238
|
+
DeveloperExperienceUtils,
|
|
1239
|
+
DeveloperWarnings,
|
|
1240
|
+
DevelopmentWarnings,
|
|
1241
|
+
TypeValidation,
|
|
1242
|
+
ValidationDebugUtils,
|
|
1243
|
+
ValidationDebugger,
|
|
1244
|
+
debugManager,
|
|
1245
|
+
devMode,
|
|
1246
|
+
disableDebug,
|
|
1247
|
+
enableDebug,
|
|
1248
|
+
isDebugEnabled,
|
|
1249
|
+
validationDebugger
|
|
1250
|
+
};
|
|
1251
|
+
//# sourceMappingURL=index.js.map
|