@buoy-gg/highlight-updates 7.0.41 → 7.0.43

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/README.md +11 -71
  2. package/lib/commonjs/highlight-updates/HighlightUpdatesOverlay.js +1 -281
  3. package/lib/commonjs/highlight-updates/components/HighlightFilterView.js +1 -1474
  4. package/lib/commonjs/highlight-updates/components/HighlightUpdatesModal.js +1 -641
  5. package/lib/commonjs/highlight-updates/components/IdentifierBadge.js +1 -273
  6. package/lib/commonjs/highlight-updates/components/IsolatedRenderList.js +1 -188
  7. package/lib/commonjs/highlight-updates/components/ModalHeaderContent.js +1 -293
  8. package/lib/commonjs/highlight-updates/components/RenderCauseBadge.js +1 -508
  9. package/lib/commonjs/highlight-updates/components/RenderDetailView.js +1 -846
  10. package/lib/commonjs/highlight-updates/components/RenderHistoryViewer.js +1 -915
  11. package/lib/commonjs/highlight-updates/components/RenderListItem.js +1 -235
  12. package/lib/commonjs/highlight-updates/components/RendersCopySettingsView.js +1 -469
  13. package/lib/commonjs/highlight-updates/components/StatsDisplay.js +1 -73
  14. package/lib/commonjs/highlight-updates/types/copySettings.js +1 -107
  15. package/lib/commonjs/highlight-updates/utils/CommitProfiler.js +1 -455
  16. package/lib/commonjs/highlight-updates/utils/HighlightUpdatesController.js +1 -1929
  17. package/lib/commonjs/highlight-updates/utils/PerformanceLogger.js +26 -359
  18. package/lib/commonjs/highlight-updates/utils/ProfilerInterceptor.js +1 -371
  19. package/lib/commonjs/highlight-updates/utils/RenderCauseDetector.js +5 -1840
  20. package/lib/commonjs/highlight-updates/utils/RenderTracker.js +1 -952
  21. package/lib/commonjs/highlight-updates/utils/ViewTypeMapper.js +1 -264
  22. package/lib/commonjs/highlight-updates/utils/copySettingsStorage.js +1 -32
  23. package/lib/commonjs/highlight-updates/utils/devtoolsComponentNames.js +1 -188
  24. package/lib/commonjs/highlight-updates/utils/namedComposite.js +1 -41
  25. package/lib/commonjs/highlight-updates/utils/ownStateChanged.js +1 -103
  26. package/lib/commonjs/highlight-updates/utils/rawEventEmitter.js +1 -50
  27. package/lib/commonjs/highlight-updates/utils/rawEventEmitter.web.js +1 -12
  28. package/lib/commonjs/highlight-updates/utils/renderExportFormatter.js +1 -58
  29. package/lib/commonjs/highlight-updates/utils/rendersExportFormatter.js +1 -485
  30. package/lib/commonjs/highlight-updates/utils/screenElements.js +1 -1269
  31. package/lib/commonjs/highlight-updates/utils/tapMatch.js +1 -83
  32. package/lib/commonjs/highlight-updates/utils/testIDs.js +1 -68
  33. package/lib/commonjs/highlight-updates/utils/touchCapture.js +1 -277
  34. package/lib/commonjs/index.js +1 -429
  35. package/lib/commonjs/preset.js +1 -278
  36. package/lib/commonjs/sync/highlightUpdatesSyncAdapter.js +1 -235
  37. package/lib/module/highlight-updates/HighlightUpdatesOverlay.js +1 -274
  38. package/lib/module/highlight-updates/components/HighlightFilterView.js +1 -1468
  39. package/lib/module/highlight-updates/components/HighlightUpdatesModal.js +1 -634
  40. package/lib/module/highlight-updates/components/IdentifierBadge.js +1 -265
  41. package/lib/module/highlight-updates/components/IsolatedRenderList.js +1 -183
  42. package/lib/module/highlight-updates/components/ModalHeaderContent.js +1 -288
  43. package/lib/module/highlight-updates/components/RenderCauseBadge.js +1 -499
  44. package/lib/module/highlight-updates/components/RenderDetailView.js +1 -840
  45. package/lib/module/highlight-updates/components/RenderHistoryViewer.js +1 -908
  46. package/lib/module/highlight-updates/components/RenderListItem.js +1 -230
  47. package/lib/module/highlight-updates/components/RendersCopySettingsView.js +1 -465
  48. package/lib/module/highlight-updates/components/StatsDisplay.js +1 -70
  49. package/lib/module/highlight-updates/types/copySettings.js +1 -102
  50. package/lib/module/highlight-updates/utils/CommitProfiler.js +1 -451
  51. package/lib/module/highlight-updates/utils/HighlightUpdatesController.js +1 -1925
  52. package/lib/module/highlight-updates/utils/PerformanceLogger.js +26 -353
  53. package/lib/module/highlight-updates/utils/ProfilerInterceptor.js +1 -358
  54. package/lib/module/highlight-updates/utils/RenderCauseDetector.js +5 -1830
  55. package/lib/module/highlight-updates/utils/RenderTracker.js +1 -949
  56. package/lib/module/highlight-updates/utils/ViewTypeMapper.js +1 -255
  57. package/lib/module/highlight-updates/utils/copySettingsStorage.js +1 -26
  58. package/lib/module/highlight-updates/utils/devtoolsComponentNames.js +1 -178
  59. package/lib/module/highlight-updates/utils/namedComposite.js +1 -36
  60. package/lib/module/highlight-updates/utils/ownStateChanged.js +1 -98
  61. package/lib/module/highlight-updates/utils/rawEventEmitter.js +1 -46
  62. package/lib/module/highlight-updates/utils/rawEventEmitter.web.js +1 -3
  63. package/lib/module/highlight-updates/utils/renderExportFormatter.js +1 -54
  64. package/lib/module/highlight-updates/utils/rendersExportFormatter.js +1 -478
  65. package/lib/module/highlight-updates/utils/screenElements.js +1 -1263
  66. package/lib/module/highlight-updates/utils/tapMatch.js +1 -76
  67. package/lib/module/highlight-updates/utils/testIDs.js +1 -60
  68. package/lib/module/highlight-updates/utils/touchCapture.js +1 -270
  69. package/lib/module/index.js +1 -130
  70. package/lib/module/preset.js +1 -272
  71. package/lib/module/sync/highlightUpdatesSyncAdapter.js +1 -230
  72. package/lib/web/index.mjs +28 -29
  73. package/package.json +7 -11
  74. package/lib/typescript/highlight-updates/HighlightUpdatesOverlay.d.ts.map +0 -1
  75. package/lib/typescript/highlight-updates/components/HighlightFilterView.d.ts.map +0 -1
  76. package/lib/typescript/highlight-updates/components/HighlightUpdatesModal.d.ts.map +0 -1
  77. package/lib/typescript/highlight-updates/components/IdentifierBadge.d.ts.map +0 -1
  78. package/lib/typescript/highlight-updates/components/IsolatedRenderList.d.ts.map +0 -1
  79. package/lib/typescript/highlight-updates/components/ModalHeaderContent.d.ts.map +0 -1
  80. package/lib/typescript/highlight-updates/components/RenderCauseBadge.d.ts.map +0 -1
  81. package/lib/typescript/highlight-updates/components/RenderDetailView.d.ts.map +0 -1
  82. package/lib/typescript/highlight-updates/components/RenderHistoryViewer.d.ts.map +0 -1
  83. package/lib/typescript/highlight-updates/components/RenderListItem.d.ts.map +0 -1
  84. package/lib/typescript/highlight-updates/components/RendersCopySettingsView.d.ts.map +0 -1
  85. package/lib/typescript/highlight-updates/components/StatsDisplay.d.ts.map +0 -1
  86. package/lib/typescript/highlight-updates/types/copySettings.d.ts.map +0 -1
  87. package/lib/typescript/highlight-updates/utils/CommitProfiler.d.ts.map +0 -1
  88. package/lib/typescript/highlight-updates/utils/HighlightUpdatesController.d.ts.map +0 -1
  89. package/lib/typescript/highlight-updates/utils/PerformanceLogger.d.ts.map +0 -1
  90. package/lib/typescript/highlight-updates/utils/ProfilerInterceptor.d.ts.map +0 -1
  91. package/lib/typescript/highlight-updates/utils/RenderCauseDetector.d.ts.map +0 -1
  92. package/lib/typescript/highlight-updates/utils/RenderTracker.d.ts.map +0 -1
  93. package/lib/typescript/highlight-updates/utils/ViewTypeMapper.d.ts.map +0 -1
  94. package/lib/typescript/highlight-updates/utils/copySettingsStorage.d.ts.map +0 -1
  95. package/lib/typescript/highlight-updates/utils/devtoolsComponentNames.d.ts.map +0 -1
  96. package/lib/typescript/highlight-updates/utils/namedComposite.d.ts.map +0 -1
  97. package/lib/typescript/highlight-updates/utils/ownStateChanged.d.ts.map +0 -1
  98. package/lib/typescript/highlight-updates/utils/rawEventEmitter.d.ts.map +0 -1
  99. package/lib/typescript/highlight-updates/utils/rawEventEmitter.web.d.ts.map +0 -1
  100. package/lib/typescript/highlight-updates/utils/renderExportFormatter.d.ts.map +0 -1
  101. package/lib/typescript/highlight-updates/utils/rendersExportFormatter.d.ts.map +0 -1
  102. package/lib/typescript/highlight-updates/utils/screenElements.d.ts.map +0 -1
  103. package/lib/typescript/highlight-updates/utils/tapMatch.d.ts.map +0 -1
  104. package/lib/typescript/highlight-updates/utils/testIDs.d.ts.map +0 -1
  105. package/lib/typescript/highlight-updates/utils/touchCapture.d.ts.map +0 -1
  106. package/lib/typescript/index.d.ts.map +0 -1
  107. package/lib/typescript/preset.d.ts.map +0 -1
  108. package/lib/typescript/sync/highlightUpdatesSyncAdapter.d.ts.map +0 -1
@@ -1,952 +1 @@
1
- /**
2
- * RenderTracker
3
- *
4
- * Singleton that tracks component render history for the Highlight Updates modal.
5
- * Stores information about each tracked component including render counts,
6
- * timestamps, and identifying props (testID, nativeID, etc.)
7
- */
8
-
9
- "use strict";
10
-
11
- Object.defineProperty(exports, "__esModule", {
12
- value: true
13
- });
14
- exports.default = exports.RenderTracker = void 0;
15
- var _ViewTypeMapper = require("./ViewTypeMapper");
16
- var _PerformanceLogger = require("./PerformanceLogger");
17
- var _namedComposite = require("./namedComposite");
18
- /**
19
- * Debug logging levels for render cause detection.
20
- * Controls verbosity of console output for debugging "Why Did You Render" feature.
21
- *
22
- * - "off": No debug logging (default, best for production)
23
- * - "minimal": Only log state/hook value changes (e.g., "useState: 3334 → 3335")
24
- * - "verbose": Log component info + cause + value changes
25
- * - "all": Full fiber dump with everything (native fiber, component fiber, hooks, batch context)
26
- */
27
-
28
- // Render cause types - why did a component render?
29
-
30
- // Could not determine
31
-
32
- // Component-level cause - why did the React component re-render?
33
-
34
- // Could not determine
35
-
36
- /**
37
- * Represents a change in a single hook's state
38
- * Used to show meaningful before/after values for debugging
39
- */
40
-
41
- /**
42
- * A single render event in the history
43
- * Captures everything about one render occurrence
44
- */
45
-
46
- /** Callback for individual render events (for unified events integration) */
47
-
48
- // Maximum number of tracked components to prevent memory issues
49
- const MAX_TRACKED_COMPONENTS = 200;
50
-
51
- // Default batch size for highlight rendering
52
- const DEFAULT_BATCH_SIZE = 150;
53
- class RenderTrackerSingleton {
54
- renders = new Map();
55
- listeners = new Set();
56
- stateListeners = new Set();
57
- settingsListeners = new Set();
58
- filterListeners = new Set();
59
- /** Callbacks for individual render events (unified events integration) */
60
- renderEventCallbacks = new Set();
61
- isTracking = false;
62
- isPaused = false;
63
- settings = {
64
- batchSize: DEFAULT_BATCH_SIZE,
65
- showRenderCount: true,
66
- performanceLogging: false,
67
- trackRenderCauses: false,
68
- // History is opt-in (memory + perf overhead). JSDoc default: false.
69
- enableRenderHistory: false,
70
- maxRenderHistoryPerComponent: 20,
71
- capturePropsOnRender: false,
72
- captureStateOnRender: false,
73
- // Debug settings
74
- debugLogLevel: "off",
75
- // Dev tools visibility - exclude by default
76
- excludeDevTools: true,
77
- showHostViews: false
78
- };
79
-
80
- // Batch mode: defer notifyListeners until endBatch is called
81
- isBatchMode = false;
82
- batchDirty = false;
83
- filters = {
84
- includeTestID: new Set(),
85
- includeNativeID: new Set(),
86
- includeViewType: new Set(),
87
- includeComponent: new Set(),
88
- excludeTestID: new Set(),
89
- excludeNativeID: new Set(),
90
- excludeViewType: new Set(),
91
- excludeComponent: new Set(),
92
- includePatterns: [],
93
- excludePatterns: []
94
- };
95
-
96
- /**
97
- * Track a component render
98
- */
99
- trackRender(data) {
100
- if (this.isPaused) return;
101
- const id = String(data.nativeTag);
102
- const now = Date.now();
103
- const existing = this.renders.get(id);
104
- if (existing) {
105
- // Mutate in place to keep Map entry correct
106
- existing.renderCount = data.count;
107
- existing.lastRenderTime = now;
108
- existing.color = data.color;
109
- if (data.measurements) {
110
- existing.measurements = data.measurements;
111
- }
112
- // Update props if they weren't set before
113
- if (data.testID && !existing.testID) existing.testID = data.testID;
114
- if (data.nativeID && !existing.nativeID) existing.nativeID = data.nativeID;
115
- if (data.accessibilityLabel && !existing.accessibilityLabel) {
116
- existing.accessibilityLabel = data.accessibilityLabel;
117
- }
118
- if (data.componentName && !existing.componentName) {
119
- existing.componentName = data.componentName;
120
- }
121
- // Update render cause if provided
122
- if (data.renderCause) {
123
- existing.lastRenderCause = data.renderCause;
124
- }
125
-
126
- // Add to render history if enabled (create minimal cause if not provided)
127
- if (this.settings.enableRenderHistory) {
128
- const cause = data.renderCause || {
129
- type: "unknown",
130
- timestamp: now
131
- };
132
- this.addRenderEvent(existing, cause, data.capturedProps, data.capturedState);
133
- }
134
- } else {
135
- // Add new render
136
- const newRender = {
137
- id,
138
- nativeTag: data.nativeTag,
139
- viewType: data.viewType,
140
- displayName: (0, _ViewTypeMapper.getComponentDisplayName)(data.viewType),
141
- testID: data.testID,
142
- nativeID: data.nativeID,
143
- accessibilityLabel: data.accessibilityLabel,
144
- componentName: data.componentName,
145
- renderCount: data.count,
146
- firstRenderTime: now,
147
- lastRenderTime: now,
148
- measurements: data.measurements,
149
- color: data.color,
150
- lastRenderCause: data.renderCause
151
- };
152
-
153
- // Initialize render history if enabled (create minimal cause if not provided)
154
- if (this.settings.enableRenderHistory) {
155
- newRender.renderHistory = [];
156
- const cause = data.renderCause || {
157
- type: data.count === 1 ? "mount" : "unknown",
158
- timestamp: now
159
- };
160
- this.addRenderEvent(newRender, cause, data.capturedProps, data.capturedState);
161
- }
162
- this.renders.set(id, newRender);
163
-
164
- // Enforce max limit - remove oldest renders
165
- if (this.renders.size > MAX_TRACKED_COMPONENTS) {
166
- const sorted = Array.from(this.renders.values()).sort((a, b) => a.lastRenderTime - b.lastRenderTime);
167
- const toRemove = sorted.slice(0, this.renders.size - MAX_TRACKED_COMPONENTS);
168
- for (const render of toRemove) {
169
- this.renders.delete(render.id);
170
- }
171
- }
172
- }
173
-
174
- // In batch mode, defer notification until endBatch()
175
- if (this.isBatchMode) {
176
- this.batchDirty = true;
177
- } else {
178
- this.notifyListeners();
179
- }
180
- }
181
-
182
- /**
183
- * Add a render event to a component's history (circular buffer)
184
- */
185
- addRenderEvent(render, cause, capturedProps, capturedState) {
186
- // Initialize history array if needed
187
- if (!render.renderHistory) {
188
- render.renderHistory = [];
189
- }
190
- const event = {
191
- id: `${render.nativeTag}-${cause.timestamp}`,
192
- timestamp: cause.timestamp,
193
- cause,
194
- renderNumber: render.renderCount,
195
- // Only include captured data if settings allow and data is provided
196
- capturedProps: this.settings.capturePropsOnRender ? capturedProps : undefined,
197
- capturedState: this.settings.captureStateOnRender ? capturedState : undefined
198
- };
199
- render.renderHistory.push(event);
200
-
201
- // Enforce max history size (circular buffer behavior)
202
- const maxHistory = Math.max(5, Math.min(50, this.settings.maxRenderHistoryPerComponent));
203
- if (render.renderHistory.length > maxHistory) {
204
- // Remove oldest events
205
- render.renderHistory = render.renderHistory.slice(-maxHistory);
206
- }
207
-
208
- // Notify render event callbacks (for unified events integration)
209
- this.notifyRenderEventCallbacks(event, render);
210
- }
211
-
212
- /**
213
- * Notify all render event callbacks
214
- */
215
- notifyRenderEventCallbacks(event, render) {
216
- this.renderEventCallbacks.forEach(callback => {
217
- try {
218
- callback(event, render);
219
- } catch {
220
- // Silently ignore callback errors
221
- }
222
- });
223
- }
224
-
225
- /**
226
- * Emit a render event to callbacks only (without storing in the render list).
227
- * Used by Events tool when visual highlights are off - we want events but not list updates.
228
- */
229
- emitRenderEvent(data) {
230
- if (this.renderEventCallbacks.size === 0) return;
231
- const now = Date.now();
232
- const cause = data.renderCause || {
233
- type: "unknown",
234
- timestamp: now
235
- };
236
-
237
- // Create a minimal TrackedRender for the event (not stored)
238
- const render = {
239
- id: String(data.nativeTag),
240
- nativeTag: data.nativeTag,
241
- viewType: data.viewType,
242
- displayName: (0, _ViewTypeMapper.getComponentDisplayName)(data.viewType),
243
- testID: data.testID,
244
- nativeID: data.nativeID,
245
- accessibilityLabel: data.accessibilityLabel,
246
- componentName: data.componentName,
247
- renderCount: data.count,
248
- firstRenderTime: now,
249
- lastRenderTime: now,
250
- measurements: data.measurements,
251
- color: data.color,
252
- lastRenderCause: cause,
253
- renderHistory: []
254
- };
255
-
256
- // Create the event
257
- const event = {
258
- id: `${data.nativeTag}-${now}-${data.count}`,
259
- timestamp: now,
260
- renderNumber: data.count,
261
- cause,
262
- capturedProps: undefined,
263
- capturedState: undefined
264
- };
265
-
266
- // Notify callbacks only (no storage, no list listeners)
267
- this.notifyRenderEventCallbacks(event, render);
268
- }
269
-
270
- /**
271
- * Start batch mode - defers listener notifications until endBatch() is called.
272
- * Use this when tracking multiple renders in a loop to avoid O(n²) notifications.
273
- */
274
- startBatch() {
275
- this.isBatchMode = true;
276
- this.batchDirty = false;
277
- }
278
-
279
- /**
280
- * End batch mode and notify listeners if any renders were tracked.
281
- */
282
- endBatch() {
283
- this.isBatchMode = false;
284
- if (this.batchDirty) {
285
- this.batchDirty = false;
286
- this.notifyListeners();
287
- }
288
- }
289
-
290
- /**
291
- * Get all tracked renders
292
- * Creates new object copies to trigger React.memo re-renders
293
- */
294
- getRenders() {
295
- return Array.from(this.renders.values()).map(r => ({
296
- ...r
297
- }));
298
- }
299
-
300
- /**
301
- * Check if a component passes all active filters.
302
- * Used by both the modal list and the overlay to filter components.
303
- *
304
- * @param info Component info to check (can be TrackedRender or extracted component info)
305
- * @returns true if the component passes all filters, false if it should be hidden
306
- */
307
- passesFilters(info) {
308
- // Check new unified include patterns (if any are set, must match at least one)
309
- if (this.filters.includePatterns.length > 0) {
310
- const matchesInclude = this.matchesAnyPatternForInfo(info, this.filters.includePatterns);
311
- if (!matchesInclude) return false;
312
- }
313
-
314
- // Check new unified exclude patterns
315
- if (this.filters.excludePatterns.length > 0) {
316
- const matchesExclude = this.matchesAnyPatternForInfo(info, this.filters.excludePatterns);
317
- if (matchesExclude) return false;
318
- }
319
-
320
- // Legacy filter support (for backwards compatibility)
321
- // Include filters: if any are set, component must match at least one
322
- if (this.filters.includeViewType.size > 0) {
323
- const viewType = info.viewType || '';
324
- const displayName = info.displayName || '';
325
- if (!this.matchesPattern(viewType, this.filters.includeViewType) && !this.matchesPattern(displayName, this.filters.includeViewType)) {
326
- return false;
327
- }
328
- }
329
- if (this.filters.includeTestID.size > 0) {
330
- if (!info.testID || !this.matchesPattern(info.testID, this.filters.includeTestID)) {
331
- return false;
332
- }
333
- }
334
- if (this.filters.includeNativeID.size > 0) {
335
- if (!info.nativeID || !this.matchesPattern(info.nativeID, this.filters.includeNativeID)) {
336
- return false;
337
- }
338
- }
339
- if (this.filters.includeComponent.size > 0) {
340
- if (!info.componentName || !this.matchesPattern(info.componentName, this.filters.includeComponent)) {
341
- return false;
342
- }
343
- }
344
-
345
- // Exclude filters: if component matches any, it should be hidden
346
- if (this.filters.excludeViewType.size > 0) {
347
- const viewType = info.viewType || '';
348
- const displayName = info.displayName || '';
349
- if (this.matchesPattern(viewType, this.filters.excludeViewType) || this.matchesPattern(displayName, this.filters.excludeViewType)) {
350
- return false;
351
- }
352
- }
353
- if (this.filters.excludeTestID.size > 0) {
354
- if (info.testID && this.matchesPattern(info.testID, this.filters.excludeTestID)) {
355
- return false;
356
- }
357
- }
358
- if (this.filters.excludeNativeID.size > 0) {
359
- if (info.nativeID && this.matchesPattern(info.nativeID, this.filters.excludeNativeID)) {
360
- return false;
361
- }
362
- }
363
- if (this.filters.excludeComponent.size > 0) {
364
- if (info.componentName && this.matchesPattern(info.componentName, this.filters.excludeComponent)) {
365
- return false;
366
- }
367
- }
368
- return true;
369
- }
370
-
371
- /**
372
- * Check if component info matches any of the given patterns
373
- */
374
- matchesAnyPatternForInfo(info, patterns) {
375
- for (const pattern of patterns) {
376
- const lowerValue = pattern.value.toLowerCase();
377
- switch (pattern.type) {
378
- case "any":
379
- // Match against all fields
380
- if (info.viewType.toLowerCase().includes(lowerValue) || info.displayName?.toLowerCase().includes(lowerValue) || info.testID?.toLowerCase().includes(lowerValue) || info.nativeID?.toLowerCase().includes(lowerValue) || info.componentName?.toLowerCase().includes(lowerValue) || info.accessibilityLabel?.toLowerCase().includes(lowerValue)) {
381
- return true;
382
- }
383
- break;
384
- case "viewType":
385
- if (info.viewType.toLowerCase().includes(lowerValue) || info.displayName?.toLowerCase().includes(lowerValue)) {
386
- return true;
387
- }
388
- break;
389
- case "testID":
390
- if (info.testID?.toLowerCase().includes(lowerValue)) {
391
- return true;
392
- }
393
- break;
394
- case "nativeID":
395
- if (info.nativeID?.toLowerCase().includes(lowerValue)) {
396
- return true;
397
- }
398
- break;
399
- case "component":
400
- if (info.componentName?.toLowerCase().includes(lowerValue)) {
401
- return true;
402
- }
403
- break;
404
- case "accessibilityLabel":
405
- if (info.accessibilityLabel?.toLowerCase().includes(lowerValue)) {
406
- return true;
407
- }
408
- break;
409
- }
410
- }
411
- return false;
412
- }
413
-
414
- /**
415
- * Check if any filters are currently active
416
- */
417
- hasActiveFilters() {
418
- return this.filters.includePatterns.length > 0 || this.filters.excludePatterns.length > 0 || this.filters.includeViewType.size > 0 || this.filters.includeTestID.size > 0 || this.filters.includeNativeID.size > 0 || this.filters.includeComponent.size > 0 || this.filters.excludeViewType.size > 0 || this.filters.excludeTestID.size > 0 || this.filters.excludeNativeID.size > 0 || this.filters.excludeComponent.size > 0 || this.filters.minRenderCount !== undefined || this.filters.maxRenderCount !== undefined;
419
- }
420
-
421
- /**
422
- * Get filtered renders based on current filter config
423
- */
424
- getFilteredRenders(searchText = "") {
425
- let renders = this.getRenders();
426
- if (!this.settings.showHostViews) {
427
- renders = renders.filter(_namedComposite.isNamedComposite);
428
- }
429
-
430
- // Apply search filter
431
- if (searchText.trim()) {
432
- const search = searchText.toLowerCase();
433
- renders = renders.filter(r => {
434
- return r.viewType.toLowerCase().includes(search) || r.displayName.toLowerCase().includes(search) || r.testID?.toLowerCase().includes(search) || r.nativeID?.toLowerCase().includes(search) || r.accessibilityLabel?.toLowerCase().includes(search) || r.componentName?.toLowerCase().includes(search) || String(r.nativeTag).includes(search);
435
- });
436
- }
437
-
438
- // Apply filters using the shared passesFilters method
439
- renders = renders.filter(r => this.passesFilters(r));
440
-
441
- // Apply render count range filter
442
- if (this.filters.minRenderCount !== undefined) {
443
- renders = renders.filter(r => r.renderCount >= this.filters.minRenderCount);
444
- }
445
- if (this.filters.maxRenderCount !== undefined) {
446
- renders = renders.filter(r => r.renderCount <= this.filters.maxRenderCount);
447
- }
448
-
449
- // Sort by last render time (most recent first)
450
- return renders.sort((a, b) => b.lastRenderTime - a.lastRenderTime);
451
- }
452
-
453
- /**
454
- * Check if a value matches any pattern in the set
455
- */
456
- matchesPattern(value, patterns) {
457
- const lowerValue = value.toLowerCase();
458
- for (const pattern of patterns) {
459
- const lowerPattern = pattern.toLowerCase();
460
- if (lowerValue.includes(lowerPattern)) {
461
- return true;
462
- }
463
- }
464
- return false;
465
- }
466
-
467
- /**
468
- * Get a single render by id
469
- */
470
- getRender(id) {
471
- return this.renders.get(id);
472
- }
473
-
474
- /**
475
- * Clear all tracked renders
476
- */
477
- clear() {
478
- this.renders.clear();
479
- this.notifyListeners();
480
- }
481
-
482
- /**
483
- * Reset render count for a specific component
484
- */
485
- resetRenderCount(id) {
486
- const render = this.renders.get(id);
487
- if (render) {
488
- render.renderCount = 0;
489
- this.notifyListeners();
490
- }
491
- }
492
-
493
- /**
494
- * Start tracking
495
- */
496
- start() {
497
- this.isTracking = true;
498
- this.isPaused = false;
499
- this.notifyStateListeners();
500
- }
501
-
502
- /**
503
- * Stop tracking
504
- */
505
- stop() {
506
- this.isTracking = false;
507
- this.isPaused = false;
508
- this.notifyStateListeners();
509
- }
510
-
511
- /**
512
- * Pause tracking (keeps state but stops adding new renders)
513
- */
514
- pause() {
515
- this.isPaused = true;
516
- this.notifyStateListeners();
517
- }
518
-
519
- /**
520
- * Resume tracking
521
- */
522
- resume() {
523
- this.isPaused = false;
524
- this.notifyStateListeners();
525
- }
526
-
527
- /**
528
- * Toggle pause state
529
- */
530
- togglePause() {
531
- this.isPaused = !this.isPaused;
532
- this.notifyStateListeners();
533
- }
534
-
535
- /**
536
- * Get current tracking state
537
- */
538
- getState() {
539
- return {
540
- isTracking: this.isTracking,
541
- isPaused: this.isPaused
542
- };
543
- }
544
-
545
- /**
546
- * Replace all tracked renders (and optionally tracking state) from a
547
- * synced device snapshot. Remote mirror mode only (desktop dashboard) —
548
- * nothing tracks locally there, so this is the sole data source. Filters
549
- * and search stay local: they apply at read time via getFilteredRenders.
550
- */
551
- replaceRenders(renders, state) {
552
- // Preserve history a remote mirror already hydrated — wire-form snapshots
553
- // omit renderHistory, and a later snapshot must not blank the detail pane.
554
- const hydratedHistory = new Map();
555
- for (const [id, existing] of this.renders) {
556
- if (existing.renderHistory && existing.renderHistory.length > 0) {
557
- hydratedHistory.set(id, existing.renderHistory);
558
- }
559
- }
560
- this.renders = new Map(renders.map(render => {
561
- const kept = hydratedHistory.get(render.id);
562
- const next = kept && !(render.renderHistory && render.renderHistory.length > 0) ? {
563
- ...render,
564
- renderHistory: kept
565
- } : render;
566
- return [next.id, next];
567
- }));
568
- if (state && (this.isTracking !== state.isTracking || this.isPaused !== state.isPaused)) {
569
- this.isTracking = state.isTracking;
570
- this.isPaused = state.isPaused;
571
- this.notifyStateListeners();
572
- }
573
- this.notifyListeners();
574
- }
575
-
576
- /**
577
- * Hydrate one mirrored render with on-demand detail (history / cause
578
- * values) fetched via the adapter's `getRenderDetail`. Remote-mirror only.
579
- */
580
- hydrateRender(render) {
581
- const existing = this.renders.get(render.id);
582
- this.renders.set(render.id, existing ? {
583
- ...existing,
584
- ...render
585
- } : render);
586
- this.notifyListeners();
587
- }
588
-
589
- /**
590
- * Get filter config
591
- */
592
- getFilters() {
593
- return this.filters;
594
- }
595
-
596
- /**
597
- * Update filter config
598
- */
599
- setFilters(filters) {
600
- this.filters = {
601
- ...this.filters,
602
- ...filters
603
- };
604
- this.notifyListeners();
605
- this.notifyFilterListeners();
606
- }
607
-
608
- /**
609
- * Add an include pattern
610
- */
611
- addIncludePattern(type, pattern) {
612
- const key = `include${type.charAt(0).toUpperCase() + type.slice(1)}`;
613
- this.filters[key].add(pattern);
614
- this.notifyListeners();
615
- }
616
-
617
- /**
618
- * Remove an include pattern
619
- */
620
- removeIncludePattern(type, pattern) {
621
- const key = `include${type.charAt(0).toUpperCase() + type.slice(1)}`;
622
- this.filters[key].delete(pattern);
623
- this.notifyListeners();
624
- }
625
-
626
- /**
627
- * Add an exclude pattern
628
- */
629
- addExcludePattern(type, pattern) {
630
- const key = `exclude${type.charAt(0).toUpperCase() + type.slice(1)}`;
631
- this.filters[key].add(pattern);
632
- this.notifyListeners();
633
- }
634
-
635
- /**
636
- * Remove an exclude pattern
637
- */
638
- removeExcludePattern(type, pattern) {
639
- const key = `exclude${type.charAt(0).toUpperCase() + type.slice(1)}`;
640
- this.filters[key].delete(pattern);
641
- this.notifyListeners();
642
- }
643
-
644
- /**
645
- * Clear all filters
646
- */
647
- clearFilters() {
648
- this.filters = {
649
- includeTestID: new Set(),
650
- includeNativeID: new Set(),
651
- includeViewType: new Set(),
652
- includeComponent: new Set(),
653
- excludeTestID: new Set(),
654
- excludeNativeID: new Set(),
655
- excludeViewType: new Set(),
656
- excludeComponent: new Set(),
657
- includePatterns: [],
658
- excludePatterns: [],
659
- minRenderCount: undefined,
660
- maxRenderCount: undefined
661
- };
662
- this.notifyListeners();
663
- }
664
-
665
- /**
666
- * Get available prop values from tracked renders
667
- */
668
- getAvailableProps() {
669
- const viewTypes = new Set();
670
- const testIDs = new Set();
671
- const nativeIDs = new Set();
672
- const componentNames = new Set();
673
- const accessibilityLabels = new Set();
674
- for (const render of this.renders.values()) {
675
- if (render.viewType) viewTypes.add(render.viewType);
676
- if (render.testID) testIDs.add(render.testID);
677
- if (render.nativeID) nativeIDs.add(render.nativeID);
678
- if (render.componentName) componentNames.add(render.componentName);
679
- if (render.accessibilityLabel) accessibilityLabels.add(render.accessibilityLabel);
680
- }
681
- return {
682
- viewTypes: Array.from(viewTypes).sort(),
683
- testIDs: Array.from(testIDs).sort(),
684
- nativeIDs: Array.from(nativeIDs).sort(),
685
- componentNames: Array.from(componentNames).sort(),
686
- accessibilityLabels: Array.from(accessibilityLabels).sort()
687
- };
688
- }
689
-
690
- /**
691
- * Get summary stats
692
- */
693
- getStats() {
694
- let totalRenders = 0;
695
- for (const render of this.renders.values()) {
696
- totalRenders += render.renderCount;
697
- }
698
- return {
699
- totalComponents: this.renders.size,
700
- totalRenders
701
- };
702
- }
703
-
704
- /**
705
- * Subscribe to render updates
706
- */
707
- subscribe(listener) {
708
- this.listeners.add(listener);
709
- // Immediately notify with current state
710
- listener(this.getRenders());
711
- return () => {
712
- this.listeners.delete(listener);
713
- };
714
- }
715
-
716
- /**
717
- * Subscribe to state changes (tracking/paused)
718
- */
719
- subscribeToState(listener) {
720
- this.stateListeners.add(listener);
721
- // Immediately notify with current state
722
- listener(this.getState());
723
- return () => {
724
- this.stateListeners.delete(listener);
725
- };
726
- }
727
-
728
- /**
729
- * Subscribe to settings changes
730
- */
731
- subscribeToSettings(listener) {
732
- this.settingsListeners.add(listener);
733
- // Immediately notify with current settings
734
- listener(this.settings);
735
- return () => {
736
- this.settingsListeners.delete(listener);
737
- };
738
- }
739
-
740
- /**
741
- * Subscribe to filter changes
742
- */
743
- subscribeToFilters(listener) {
744
- this.filterListeners.add(listener);
745
- // Immediately notify with current filters
746
- listener(this.filters);
747
- return () => {
748
- this.filterListeners.delete(listener);
749
- };
750
- }
751
-
752
- /**
753
- * Subscribe to individual render events as they occur.
754
- * Used by unified events system to integrate render events into the timeline.
755
- *
756
- * @param callback - Called for each render event with the event and component info
757
- * @returns Unsubscribe function
758
- */
759
- onRenderEvent(callback) {
760
- this.renderEventCallbacks.add(callback);
761
- return () => {
762
- this.renderEventCallbacks.delete(callback);
763
- };
764
- }
765
-
766
- /**
767
- * Get the number of render event callbacks (for debugging)
768
- */
769
- getRenderEventCallbackCount() {
770
- return this.renderEventCallbacks.size;
771
- }
772
-
773
- /**
774
- * Check if a render should be visible based on current filters
775
- * Used by the overlay to filter frozen highlights
776
- */
777
- shouldShowRender(render) {
778
- const filters = this.filters;
779
-
780
- // Check new pattern-based filters first
781
- if (filters.includePatterns.length > 0) {
782
- if (!this.matchesAnyPatternForInfo(render, filters.includePatterns)) {
783
- return false;
784
- }
785
- }
786
- if (filters.excludePatterns.length > 0) {
787
- if (this.matchesAnyPatternForInfo(render, filters.excludePatterns)) {
788
- return false;
789
- }
790
- }
791
-
792
- // Legacy set-based filters
793
- const hasLegacyIncludeFilters = filters.includeViewType.size > 0 || filters.includeTestID.size > 0 || filters.includeNativeID.size > 0 || filters.includeComponent.size > 0;
794
- if (hasLegacyIncludeFilters) {
795
- const matchesInclude = filters.includeViewType.size > 0 && filters.includeViewType.has(render.viewType) || filters.includeTestID.size > 0 && render.testID && filters.includeTestID.has(render.testID) || filters.includeNativeID.size > 0 && render.nativeID && filters.includeNativeID.has(render.nativeID) || filters.includeComponent.size > 0 && render.componentName && filters.includeComponent.has(render.componentName);
796
- if (!matchesInclude) {
797
- return false;
798
- }
799
- }
800
-
801
- // Check exclude filters
802
- if (filters.excludeViewType.has(render.viewType)) return false;
803
- if (render.testID && filters.excludeTestID.has(render.testID)) return false;
804
- if (render.nativeID && filters.excludeNativeID.has(render.nativeID)) return false;
805
- if (render.componentName && filters.excludeComponent.has(render.componentName)) return false;
806
- return true;
807
- }
808
-
809
- /**
810
- * Get current settings
811
- */
812
- getSettings() {
813
- return {
814
- ...this.settings
815
- };
816
- }
817
-
818
- /**
819
- * Update settings
820
- */
821
- setSettings(newSettings) {
822
- // Validate batchSize
823
- if (newSettings.batchSize !== undefined) {
824
- newSettings.batchSize = Math.max(10, Math.min(500, newSettings.batchSize));
825
- }
826
-
827
- // Validate maxRenderHistoryPerComponent
828
- if (newSettings.maxRenderHistoryPerComponent !== undefined) {
829
- newSettings.maxRenderHistoryPerComponent = Math.max(5, Math.min(50, newSettings.maxRenderHistoryPerComponent));
830
- }
831
-
832
- // If enabling render history, also enable trackRenderCauses
833
- if (newSettings.enableRenderHistory && !this.settings.trackRenderCauses) {
834
- newSettings.trackRenderCauses = true;
835
- }
836
-
837
- // If disabling trackRenderCauses, also disable render history
838
- if (newSettings.trackRenderCauses === false && this.settings.enableRenderHistory) {
839
- newSettings.enableRenderHistory = false;
840
- }
841
- this.settings = {
842
- ...this.settings,
843
- ...newSettings
844
- };
845
-
846
- // Sync performance logging with PerformanceLogger
847
- if (newSettings.performanceLogging !== undefined) {
848
- _PerformanceLogger.PerformanceLogger.setEnabled(newSettings.performanceLogging);
849
- }
850
- this.notifySettingsListeners();
851
- }
852
-
853
- /**
854
- * Clear render history for all components
855
- */
856
- clearAllRenderHistory() {
857
- for (const render of this.renders.values()) {
858
- render.renderHistory = [];
859
- }
860
- this.notifyListeners();
861
- }
862
-
863
- /**
864
- * Clear render history for a specific component
865
- */
866
- clearRenderHistory(id) {
867
- const render = this.renders.get(id);
868
- if (render) {
869
- render.renderHistory = [];
870
- this.notifyListeners();
871
- }
872
- }
873
-
874
- /**
875
- * Get render history stats for debugging
876
- */
877
- getRenderHistoryStats() {
878
- let totalEvents = 0;
879
- let componentsWithHistory = 0;
880
- for (const render of this.renders.values()) {
881
- if (render.renderHistory && render.renderHistory.length > 0) {
882
- totalEvents += render.renderHistory.length;
883
- componentsWithHistory++;
884
- }
885
- }
886
- return {
887
- totalEvents,
888
- componentsWithHistory,
889
- averageEventsPerComponent: componentsWithHistory > 0 ? totalEvents / componentsWithHistory : 0
890
- };
891
- }
892
-
893
- /**
894
- * Get batch size (convenience method)
895
- */
896
- getBatchSize() {
897
- return this.settings.batchSize;
898
- }
899
-
900
- /**
901
- * Set batch size (convenience method)
902
- */
903
- setBatchSize(size) {
904
- this.setSettings({
905
- batchSize: size
906
- });
907
- }
908
- notifyListeners() {
909
- const renders = this.getRenders();
910
- for (const listener of this.listeners) {
911
- try {
912
- listener(renders);
913
- } catch (error) {
914
- console.error("[RenderTracker] Error in listener:", error);
915
- }
916
- }
917
- }
918
- notifyStateListeners() {
919
- const state = this.getState();
920
- for (const listener of this.stateListeners) {
921
- try {
922
- listener(state);
923
- } catch (error) {
924
- console.error("[RenderTracker] Error in state listener:", error);
925
- }
926
- }
927
- }
928
- notifySettingsListeners() {
929
- const settings = this.getSettings();
930
- for (const listener of this.settingsListeners) {
931
- try {
932
- listener(settings);
933
- } catch (error) {
934
- console.error("[RenderTracker] Error in settings listener:", error);
935
- }
936
- }
937
- }
938
- notifyFilterListeners() {
939
- const filters = this.getFilters();
940
- for (const listener of this.filterListeners) {
941
- try {
942
- listener(filters);
943
- } catch (error) {
944
- console.error("[RenderTracker] Error in filter listener:", error);
945
- }
946
- }
947
- }
948
- }
949
-
950
- // Export singleton instance
951
- const RenderTracker = exports.RenderTracker = new RenderTrackerSingleton();
952
- var _default = exports.default = RenderTracker;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=exports.RenderTracker=void 0;var _ViewTypeMapper=require("./ViewTypeMapper");var _PerformanceLogger=require("./PerformanceLogger");var _namedComposite=require("./namedComposite");const MAX_TRACKED_COMPONENTS=200;const DEFAULT_BATCH_SIZE=150;class RenderTrackerSingleton{renders=new Map;listeners=new Set;stateListeners=new Set;settingsListeners=new Set;filterListeners=new Set;renderEventCallbacks=new Set;isTracking=false;isPaused=false;settings={batchSize:DEFAULT_BATCH_SIZE,showRenderCount:true,performanceLogging:false,trackRenderCauses:false,enableRenderHistory:false,maxRenderHistoryPerComponent:20,capturePropsOnRender:false,captureStateOnRender:false,debugLogLevel:"off",excludeDevTools:true,showHostViews:false};isBatchMode=false;batchDirty=false;filters={includeTestID:new Set,includeNativeID:new Set,includeViewType:new Set,includeComponent:new Set,excludeTestID:new Set,excludeNativeID:new Set,excludeViewType:new Set,excludeComponent:new Set,includePatterns:[],excludePatterns:[]};trackRender(e){if(this.isPaused)return;const t=String(e.nativeTag);const s=Date.now();const i=this.renders.get(t);if(i){i.renderCount=e.count;i.lastRenderTime=s;i.color=e.color;if(e.measurements){i.measurements=e.measurements}if(e.testID&&!i.testID)i.testID=e.testID;if(e.nativeID&&!i.nativeID)i.nativeID=e.nativeID;if(e.accessibilityLabel&&!i.accessibilityLabel){i.accessibilityLabel=e.accessibilityLabel}if(e.componentName&&!i.componentName){i.componentName=e.componentName}if(e.renderCause){i.lastRenderCause=e.renderCause}if(this.settings.enableRenderHistory){const r=e.renderCause||{type:"unknown",timestamp:s};this.addRenderEvent(i,r,e.capturedProps,e.capturedState)}}else{const r={id:t,nativeTag:e.nativeTag,viewType:e.viewType,displayName:(0,_ViewTypeMapper.getComponentDisplayName)(e.viewType),testID:e.testID,nativeID:e.nativeID,accessibilityLabel:e.accessibilityLabel,componentName:e.componentName,renderCount:e.count,firstRenderTime:s,lastRenderTime:s,measurements:e.measurements,color:e.color,lastRenderCause:e.renderCause};if(this.settings.enableRenderHistory){r.renderHistory=[];const n=e.renderCause||{type:e.count===1?"mount":"unknown",timestamp:s};this.addRenderEvent(r,n,e.capturedProps,e.capturedState)}this.renders.set(t,r);if(this.renders.size>MAX_TRACKED_COMPONENTS){const n=Array.from(this.renders.values()).sort((a,l)=>a.lastRenderTime-l.lastRenderTime);const o=n.slice(0,this.renders.size-MAX_TRACKED_COMPONENTS);for(const a of o){this.renders.delete(a.id)}}}if(this.isBatchMode){this.batchDirty=true}else{this.notifyListeners()}}addRenderEvent(e,t,s,i){if(!e.renderHistory){e.renderHistory=[]}const r={id:`${e.nativeTag}-${t.timestamp}`,timestamp:t.timestamp,cause:t,renderNumber:e.renderCount,capturedProps:this.settings.capturePropsOnRender?s:void 0,capturedState:this.settings.captureStateOnRender?i:void 0};e.renderHistory.push(r);const n=Math.max(5,Math.min(50,this.settings.maxRenderHistoryPerComponent));if(e.renderHistory.length>n){e.renderHistory=e.renderHistory.slice(-n)}this.notifyRenderEventCallbacks(r,e)}notifyRenderEventCallbacks(e,t){this.renderEventCallbacks.forEach(s=>{try{s(e,t)}catch{}})}emitRenderEvent(e){if(this.renderEventCallbacks.size===0)return;const t=Date.now();const s=e.renderCause||{type:"unknown",timestamp:t};const i={id:String(e.nativeTag),nativeTag:e.nativeTag,viewType:e.viewType,displayName:(0,_ViewTypeMapper.getComponentDisplayName)(e.viewType),testID:e.testID,nativeID:e.nativeID,accessibilityLabel:e.accessibilityLabel,componentName:e.componentName,renderCount:e.count,firstRenderTime:t,lastRenderTime:t,measurements:e.measurements,color:e.color,lastRenderCause:s,renderHistory:[]};const r={id:`${e.nativeTag}-${t}-${e.count}`,timestamp:t,renderNumber:e.count,cause:s,capturedProps:void 0,capturedState:void 0};this.notifyRenderEventCallbacks(r,i)}startBatch(){this.isBatchMode=true;this.batchDirty=false}endBatch(){this.isBatchMode=false;if(this.batchDirty){this.batchDirty=false;this.notifyListeners()}}getRenders(){return Array.from(this.renders.values()).map(e=>({...e}))}passesFilters(e){if(this.filters.includePatterns.length>0){const t=this.matchesAnyPatternForInfo(e,this.filters.includePatterns);if(!t)return false}if(this.filters.excludePatterns.length>0){const t=this.matchesAnyPatternForInfo(e,this.filters.excludePatterns);if(t)return false}if(this.filters.includeViewType.size>0){const t=e.viewType||"";const s=e.displayName||"";if(!this.matchesPattern(t,this.filters.includeViewType)&&!this.matchesPattern(s,this.filters.includeViewType)){return false}}if(this.filters.includeTestID.size>0){if(!e.testID||!this.matchesPattern(e.testID,this.filters.includeTestID)){return false}}if(this.filters.includeNativeID.size>0){if(!e.nativeID||!this.matchesPattern(e.nativeID,this.filters.includeNativeID)){return false}}if(this.filters.includeComponent.size>0){if(!e.componentName||!this.matchesPattern(e.componentName,this.filters.includeComponent)){return false}}if(this.filters.excludeViewType.size>0){const t=e.viewType||"";const s=e.displayName||"";if(this.matchesPattern(t,this.filters.excludeViewType)||this.matchesPattern(s,this.filters.excludeViewType)){return false}}if(this.filters.excludeTestID.size>0){if(e.testID&&this.matchesPattern(e.testID,this.filters.excludeTestID)){return false}}if(this.filters.excludeNativeID.size>0){if(e.nativeID&&this.matchesPattern(e.nativeID,this.filters.excludeNativeID)){return false}}if(this.filters.excludeComponent.size>0){if(e.componentName&&this.matchesPattern(e.componentName,this.filters.excludeComponent)){return false}}return true}matchesAnyPatternForInfo(e,t){for(const s of t){const i=s.value.toLowerCase();switch(s.type){case"any":if(e.viewType.toLowerCase().includes(i)||e.displayName?.toLowerCase().includes(i)||e.testID?.toLowerCase().includes(i)||e.nativeID?.toLowerCase().includes(i)||e.componentName?.toLowerCase().includes(i)||e.accessibilityLabel?.toLowerCase().includes(i)){return true}break;case"viewType":if(e.viewType.toLowerCase().includes(i)||e.displayName?.toLowerCase().includes(i)){return true}break;case"testID":if(e.testID?.toLowerCase().includes(i)){return true}break;case"nativeID":if(e.nativeID?.toLowerCase().includes(i)){return true}break;case"component":if(e.componentName?.toLowerCase().includes(i)){return true}break;case"accessibilityLabel":if(e.accessibilityLabel?.toLowerCase().includes(i)){return true}break}}return false}hasActiveFilters(){return this.filters.includePatterns.length>0||this.filters.excludePatterns.length>0||this.filters.includeViewType.size>0||this.filters.includeTestID.size>0||this.filters.includeNativeID.size>0||this.filters.includeComponent.size>0||this.filters.excludeViewType.size>0||this.filters.excludeTestID.size>0||this.filters.excludeNativeID.size>0||this.filters.excludeComponent.size>0||this.filters.minRenderCount!==void 0||this.filters.maxRenderCount!==void 0}getFilteredRenders(e=""){let t=this.getRenders();if(!this.settings.showHostViews){t=t.filter(_namedComposite.isNamedComposite)}if(e.trim()){const s=e.toLowerCase();t=t.filter(i=>{return i.viewType.toLowerCase().includes(s)||i.displayName.toLowerCase().includes(s)||i.testID?.toLowerCase().includes(s)||i.nativeID?.toLowerCase().includes(s)||i.accessibilityLabel?.toLowerCase().includes(s)||i.componentName?.toLowerCase().includes(s)||String(i.nativeTag).includes(s)})}t=t.filter(s=>this.passesFilters(s));if(this.filters.minRenderCount!==void 0){t=t.filter(s=>s.renderCount>=this.filters.minRenderCount)}if(this.filters.maxRenderCount!==void 0){t=t.filter(s=>s.renderCount<=this.filters.maxRenderCount)}return t.sort((s,i)=>i.lastRenderTime-s.lastRenderTime)}matchesPattern(e,t){const s=e.toLowerCase();for(const i of t){const r=i.toLowerCase();if(s.includes(r)){return true}}return false}getRender(e){return this.renders.get(e)}clear(){this.renders.clear();this.notifyListeners()}resetRenderCount(e){const t=this.renders.get(e);if(t){t.renderCount=0;this.notifyListeners()}}start(){this.isTracking=true;this.isPaused=false;this.notifyStateListeners()}stop(){this.isTracking=false;this.isPaused=false;this.notifyStateListeners()}pause(){this.isPaused=true;this.notifyStateListeners()}resume(){this.isPaused=false;this.notifyStateListeners()}togglePause(){this.isPaused=!this.isPaused;this.notifyStateListeners()}getState(){return{isTracking:this.isTracking,isPaused:this.isPaused}}replaceRenders(e,t){const s=new Map;for(const[i,r]of this.renders){if(r.renderHistory&&r.renderHistory.length>0){s.set(i,r.renderHistory)}}this.renders=new Map(e.map(i=>{const r=s.get(i.id);const n=r&&!(i.renderHistory&&i.renderHistory.length>0)?{...i,renderHistory:r}:i;return[n.id,n]}));if(t&&(this.isTracking!==t.isTracking||this.isPaused!==t.isPaused)){this.isTracking=t.isTracking;this.isPaused=t.isPaused;this.notifyStateListeners()}this.notifyListeners()}hydrateRender(e){const t=this.renders.get(e.id);this.renders.set(e.id,t?{...t,...e}:e);this.notifyListeners()}getFilters(){return this.filters}setFilters(e){this.filters={...this.filters,...e};this.notifyListeners();this.notifyFilterListeners()}addIncludePattern(e,t){const s=`include${e.charAt(0).toUpperCase()+e.slice(1)}`;this.filters[s].add(t);this.notifyListeners()}removeIncludePattern(e,t){const s=`include${e.charAt(0).toUpperCase()+e.slice(1)}`;this.filters[s].delete(t);this.notifyListeners()}addExcludePattern(e,t){const s=`exclude${e.charAt(0).toUpperCase()+e.slice(1)}`;this.filters[s].add(t);this.notifyListeners()}removeExcludePattern(e,t){const s=`exclude${e.charAt(0).toUpperCase()+e.slice(1)}`;this.filters[s].delete(t);this.notifyListeners()}clearFilters(){this.filters={includeTestID:new Set,includeNativeID:new Set,includeViewType:new Set,includeComponent:new Set,excludeTestID:new Set,excludeNativeID:new Set,excludeViewType:new Set,excludeComponent:new Set,includePatterns:[],excludePatterns:[],minRenderCount:void 0,maxRenderCount:void 0};this.notifyListeners()}getAvailableProps(){const e=new Set;const t=new Set;const s=new Set;const i=new Set;const r=new Set;for(const n of this.renders.values()){if(n.viewType)e.add(n.viewType);if(n.testID)t.add(n.testID);if(n.nativeID)s.add(n.nativeID);if(n.componentName)i.add(n.componentName);if(n.accessibilityLabel)r.add(n.accessibilityLabel)}return{viewTypes:Array.from(e).sort(),testIDs:Array.from(t).sort(),nativeIDs:Array.from(s).sort(),componentNames:Array.from(i).sort(),accessibilityLabels:Array.from(r).sort()}}getStats(){let e=0;for(const t of this.renders.values()){e+=t.renderCount}return{totalComponents:this.renders.size,totalRenders:e}}subscribe(e){this.listeners.add(e);e(this.getRenders());return()=>{this.listeners.delete(e)}}subscribeToState(e){this.stateListeners.add(e);e(this.getState());return()=>{this.stateListeners.delete(e)}}subscribeToSettings(e){this.settingsListeners.add(e);e(this.settings);return()=>{this.settingsListeners.delete(e)}}subscribeToFilters(e){this.filterListeners.add(e);e(this.filters);return()=>{this.filterListeners.delete(e)}}onRenderEvent(e){this.renderEventCallbacks.add(e);return()=>{this.renderEventCallbacks.delete(e)}}getRenderEventCallbackCount(){return this.renderEventCallbacks.size}shouldShowRender(e){const t=this.filters;if(t.includePatterns.length>0){if(!this.matchesAnyPatternForInfo(e,t.includePatterns)){return false}}if(t.excludePatterns.length>0){if(this.matchesAnyPatternForInfo(e,t.excludePatterns)){return false}}const s=t.includeViewType.size>0||t.includeTestID.size>0||t.includeNativeID.size>0||t.includeComponent.size>0;if(s){const i=t.includeViewType.size>0&&t.includeViewType.has(e.viewType)||t.includeTestID.size>0&&e.testID&&t.includeTestID.has(e.testID)||t.includeNativeID.size>0&&e.nativeID&&t.includeNativeID.has(e.nativeID)||t.includeComponent.size>0&&e.componentName&&t.includeComponent.has(e.componentName);if(!i){return false}}if(t.excludeViewType.has(e.viewType))return false;if(e.testID&&t.excludeTestID.has(e.testID))return false;if(e.nativeID&&t.excludeNativeID.has(e.nativeID))return false;if(e.componentName&&t.excludeComponent.has(e.componentName))return false;return true}getSettings(){return{...this.settings}}setSettings(e){if(e.batchSize!==void 0){e.batchSize=Math.max(10,Math.min(500,e.batchSize))}if(e.maxRenderHistoryPerComponent!==void 0){e.maxRenderHistoryPerComponent=Math.max(5,Math.min(50,e.maxRenderHistoryPerComponent))}if(e.enableRenderHistory&&!this.settings.trackRenderCauses){e.trackRenderCauses=true}if(e.trackRenderCauses===false&&this.settings.enableRenderHistory){e.enableRenderHistory=false}this.settings={...this.settings,...e};if(e.performanceLogging!==void 0){_PerformanceLogger.PerformanceLogger.setEnabled(e.performanceLogging)}this.notifySettingsListeners()}clearAllRenderHistory(){for(const e of this.renders.values()){e.renderHistory=[]}this.notifyListeners()}clearRenderHistory(e){const t=this.renders.get(e);if(t){t.renderHistory=[];this.notifyListeners()}}getRenderHistoryStats(){let e=0;let t=0;for(const s of this.renders.values()){if(s.renderHistory&&s.renderHistory.length>0){e+=s.renderHistory.length;t++}}return{totalEvents:e,componentsWithHistory:t,averageEventsPerComponent:t>0?e/t:0}}getBatchSize(){return this.settings.batchSize}setBatchSize(e){this.setSettings({batchSize:e})}notifyListeners(){const e=this.getRenders();for(const t of this.listeners){try{t(e)}catch(s){console.error("[RenderTracker] Error in listener:",s)}}}notifyStateListeners(){const e=this.getState();for(const t of this.stateListeners){try{t(e)}catch(s){console.error("[RenderTracker] Error in state listener:",s)}}}notifySettingsListeners(){const e=this.getSettings();for(const t of this.settingsListeners){try{t(e)}catch(s){console.error("[RenderTracker] Error in settings listener:",s)}}}notifyFilterListeners(){const e=this.getFilters();for(const t of this.filterListeners){try{t(e)}catch(s){console.error("[RenderTracker] Error in filter listener:",s)}}}}const RenderTracker=exports.RenderTracker=new RenderTrackerSingleton;var _default=exports.default=RenderTracker;