@memlab/lens 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/dist/config/config.d.ts +22 -0
  3. package/dist/core/dom-observer.d.ts +10 -0
  4. package/dist/core/event-listener-tracker.d.ts +33 -0
  5. package/dist/core/react-fiber-analysis.d.ts +4 -0
  6. package/dist/core/react-memory-scan.d.ts +36 -0
  7. package/{src/core/types.ts → dist/core/types.d.ts} +56 -80
  8. package/{src/index.ts → dist/core/valid-component-name.d.ts} +2 -7
  9. package/dist/extensions/basic-extension.d.ts +30 -0
  10. package/dist/extensions/dom-visualization-extension.d.ts +17 -0
  11. package/dist/index.d.ts +1 -0
  12. package/dist/memlens.lib.bundle.js +1695 -0
  13. package/dist/memlens.lib.bundle.min.js +1 -0
  14. package/dist/memlens.lib.d.ts +12 -0
  15. package/dist/memlens.run.bundle.js +2673 -0
  16. package/dist/memlens.run.bundle.min.js +1 -0
  17. package/dist/memlens.run.d.ts +1 -0
  18. package/dist/tests/bundle/lib.bundle.test.d.ts +1 -0
  19. package/dist/tests/bundle/run.bundle.start.head.test.d.ts +1 -0
  20. package/dist/tests/bundle/run.bundle.start.test.d.ts +1 -0
  21. package/dist/tests/bundle/run.bundle.test.d.ts +1 -0
  22. package/dist/tests/fiber/dev.fiber.complex.dev.test.d.ts +1 -0
  23. package/dist/tests/fiber/dev.fiber.complex.list.dev.test.d.ts +1 -0
  24. package/dist/tests/fiber/dev.fiber.complex.prod.test.d.ts +1 -0
  25. package/dist/tests/fiber/dev.fiber.name.dev.test.d.ts +1 -0
  26. package/dist/tests/fiber/dev.fiber.name.prod.test.d.ts +1 -0
  27. package/dist/tests/utils/test-utils.d.ts +11 -0
  28. package/dist/utils/intersection-observer.d.ts +18 -0
  29. package/dist/utils/react-fiber-utils.d.ts +56 -0
  30. package/dist/utils/utils.d.ts +26 -0
  31. package/dist/utils/weak-ref-utils.d.ts +67 -0
  32. package/dist/visual/components/component-stack-panel.d.ts +11 -0
  33. package/dist/visual/components/control-widget.d.ts +13 -0
  34. package/dist/visual/components/overlay-rectangle.d.ts +11 -0
  35. package/dist/visual/components/status-text.d.ts +2 -0
  36. package/dist/visual/components/toggle-button.d.ts +3 -0
  37. package/dist/visual/components/visual-overlay.d.ts +1 -0
  38. package/dist/visual/dom-element-visualizer-interactive.d.ts +26 -0
  39. package/{src/core/valid-component-name.ts → dist/visual/dom-element-visualizer.d.ts} +5 -7
  40. package/dist/visual/visual-utils.d.ts +16 -0
  41. package/package.json +5 -1
  42. package/explainer.md +0 -54
  43. package/playwright.config.ts +0 -21
  44. package/src/config/config.ts +0 -32
  45. package/src/core/dom-observer.ts +0 -189
  46. package/src/core/event-listener-tracker.ts +0 -171
  47. package/src/core/react-fiber-analysis.ts +0 -123
  48. package/src/core/react-memory-scan.ts +0 -366
  49. package/src/extensions/basic-extension.ts +0 -41
  50. package/src/extensions/dom-visualization-extension.ts +0 -42
  51. package/src/memlens.lib.js.flow +0 -75
  52. package/src/memlens.lib.ts +0 -22
  53. package/src/memlens.run.ts +0 -21
  54. package/src/tests/bundle/lib.bundle.test.ts +0 -31
  55. package/src/tests/bundle/run.bundle.start.head.test.ts +0 -48
  56. package/src/tests/bundle/run.bundle.start.test.ts +0 -48
  57. package/src/tests/bundle/run.bundle.test.ts +0 -51
  58. package/src/tests/fiber/dev.fiber.complex.dev.test.ts +0 -92
  59. package/src/tests/fiber/dev.fiber.complex.list.dev.test.ts +0 -118
  60. package/src/tests/fiber/dev.fiber.complex.prod.test.ts +0 -92
  61. package/src/tests/fiber/dev.fiber.name.dev.test.ts +0 -77
  62. package/src/tests/fiber/dev.fiber.name.prod.test.ts +0 -79
  63. package/src/tests/lib/babel.prod.js +0 -4
  64. package/src/tests/lib/react-dom-v18.dev.js +0 -29926
  65. package/src/tests/lib/react-dom-v18.prod.js +0 -269
  66. package/src/tests/lib/react-v18.dev.js +0 -3345
  67. package/src/tests/lib/react-v18.prod.js +0 -33
  68. package/src/tests/manual/playwright-open-manual.js +0 -40
  69. package/src/tests/manual/todo-list/todo-with-run.bundle.html +0 -80
  70. package/src/tests/utils/test-utils.ts +0 -28
  71. package/src/utils/intersection-observer.ts +0 -65
  72. package/src/utils/react-fiber-utils.ts +0 -212
  73. package/src/utils/utils.ts +0 -201
  74. package/src/utils/weak-ref-utils.ts +0 -308
  75. package/src/visual/components/component-stack-panel.ts +0 -85
  76. package/src/visual/components/control-widget.ts +0 -96
  77. package/src/visual/components/overlay-rectangle.ts +0 -167
  78. package/src/visual/components/status-text.ts +0 -53
  79. package/src/visual/components/toggle-button.ts +0 -57
  80. package/src/visual/components/visual-overlay.ts +0 -19
  81. package/src/visual/dom-element-visualizer-interactive.ts +0 -358
  82. package/src/visual/dom-element-visualizer.ts +0 -130
  83. package/src/visual/visual-utils.ts +0 -89
  84. package/tsconfig.json +0 -18
  85. package/webpack.config.js +0 -105
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Meta Platforms, Inc. and affiliates.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import { Config } from '../core/types';
11
+ export declare const performanceConfig: {
12
+ scanIntervalMs: number;
13
+ maxComponentStackDepth: number;
14
+ memoryMeasurementIntervalMs: number;
15
+ };
16
+ export declare const featureFlags: {
17
+ enableMutationObserver: boolean;
18
+ enableMemoryTracking: boolean;
19
+ enableComponentStack: boolean;
20
+ enableConsoleLogs: any;
21
+ };
22
+ export declare const config: Config;
@@ -0,0 +1,10 @@
1
+ import { DOMElementStats, DOMObserveCallback } from './types';
2
+ export declare class DOMObserver {
3
+ #private;
4
+ constructor();
5
+ register(callback: DOMObserveCallback): void;
6
+ startMonitoring(): void;
7
+ stopMonitoring(): void;
8
+ getDOMElements(): Array<WeakRef<Element>>;
9
+ getStats(): DOMElementStats;
10
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import type { Fiber } from 'react-reconciler';
11
+ type EventListenerEntry = {
12
+ type: string;
13
+ cb: WeakRef<EventListenerOrEventListenerObject>;
14
+ options?: boolean | AddEventListenerOptions;
15
+ fiber?: WeakRef<Fiber>;
16
+ };
17
+ type DetachedListenerGroup = {
18
+ type: string;
19
+ count: number;
20
+ entries: WeakRef<EventListenerEntry>[];
21
+ };
22
+ export declare class EventListenerTracker {
23
+ #private;
24
+ private static instance;
25
+ private constructor();
26
+ static getInstance(): EventListenerTracker;
27
+ addListener(el: EventTarget, type: string, cb: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
28
+ removeListener(el: EventTarget, type: string, cb: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
29
+ scan(getComponentName: (elRef: WeakRef<Element>) => string): Map<string, DetachedListenerGroup[]>;
30
+ getDetachedListeners(): Map<string, DetachedListenerGroup[]>;
31
+ destroy(): void;
32
+ }
33
+ export {};
@@ -0,0 +1,4 @@
1
+ import { ScanResult } from './types';
2
+ export default class ReactFiberAnalyzer {
3
+ scan(elementWeakRefList: Array<WeakRef<Element>>, elementToComponentStack: WeakMap<Element, string[]>): ScanResult;
4
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import type { Fiber } from 'react-reconciler';
11
+ import type { AnalysisResultCallback, CreateOptions, DOMElementInfo, ScanResult } from './types';
12
+ import type { BasicExtension } from '../extensions/basic-extension';
13
+ export default class ReactMemoryScan {
14
+ #private;
15
+ static nextElementId: number;
16
+ constructor(options?: CreateOptions);
17
+ subscribe(callback: AnalysisResultCallback): () => void;
18
+ unsubscribe(callback: AnalysisResultCallback): void;
19
+ registerExtension(extension: BasicExtension): () => void;
20
+ unregisterExtension(extension: BasicExtension): void;
21
+ start(): void;
22
+ pause(): void;
23
+ stop(): void;
24
+ recordBoundingRectangles(elementRefs: Array<WeakRef<Element>>): void;
25
+ getDetachedDOMInfo(): Array<DOMElementInfo>;
26
+ isDevMode(): boolean;
27
+ getCachedComponentName(elementRef: WeakRef<Element>): string;
28
+ updateFiberNodes(fiberNodes: Array<WeakRef<Fiber>>): Array<WeakRef<Fiber>>;
29
+ packLeakedFibers(leakedFibers: Array<WeakRef<Fiber>>): Array<LeakedFiber>;
30
+ scan(): ScanResult;
31
+ }
32
+ declare class LeakedFiber {
33
+ leakedFiber: WeakRef<Fiber>;
34
+ constructor(fiber: WeakRef<Fiber>);
35
+ }
36
+ export {};
@@ -7,60 +7,49 @@
7
7
  * @format
8
8
  * @oncall memory_lab
9
9
  */
10
- import {Fiber} from 'react-reconciler';
11
- import type {BasicExtension} from '../extensions/basic-extension';
10
+ import { Fiber } from 'react-reconciler';
11
+ import type { BasicExtension } from '../extensions/basic-extension';
12
12
  import type ReactMemoryScan from './react-memory-scan';
13
-
14
13
  /** @internal */
15
- export type AnyValue = any; // eslint-disable-line @typescript-eslint/no-explicit-any
16
-
14
+ export type AnyValue = any;
17
15
  /** @internal */
18
- export type ObjectValue = {[key: string]: AnyValue};
19
-
16
+ export type ObjectValue = {
17
+ [key: string]: AnyValue;
18
+ };
20
19
  /** @internal */
21
- export type RecordValue =
22
- | string
23
- | number
24
- | boolean
25
- | null
26
- | RecordValue[]
27
- | {[key: string]: RecordValue};
28
-
20
+ export type RecordValue = string | number | boolean | null | RecordValue[] | {
21
+ [key: string]: RecordValue;
22
+ };
29
23
  /**
30
24
  * Given any type `T`, return the union type `T` and `null`
31
25
  * @typeParam T - The type that will be made nullable.
32
26
  */
33
27
  export type Nullable<T> = T | null;
34
-
35
28
  /**
36
29
  * Given any type `T`, return the union type `T`, `null`, and `undefined`.
37
30
  * @typeParam T - The type that will be made both nullable and undefinable.
38
31
  */
39
32
  export type Optional<T> = T | null | undefined;
40
-
41
33
  /**
42
34
  * Given any type `T`, return the union type `T` and `undefined`.
43
35
  * @typeParam T - The type that will be made undefinable.
44
36
  */
45
37
  export type Undefinable<T> = T | undefined;
46
-
47
38
  /** @internal */
48
39
  export type AnyRecord = Record<string, RecordValue>;
49
40
  /** @internal */
50
41
  export type StringRecord = Record<string, string>;
51
-
52
42
  /**
53
43
  * Options for creating a ReactMemoryScan instance
54
44
  * @property {boolean} [isDevMode] - When true, enables dev mode features
55
45
  */
56
46
  export type CreateOptions = {
57
- isDevMode?: boolean;
58
- subscribers?: Array<AnalysisResultCallback>;
59
- extensions?: Array<BasicExtension>;
60
- scanIntervalMs?: number;
61
- trackEventListenerLeaks?: boolean;
47
+ isDevMode?: boolean;
48
+ subscribers?: Array<AnalysisResultCallback>;
49
+ extensions?: Array<BasicExtension>;
50
+ scanIntervalMs?: number;
51
+ trackEventListenerLeaks?: boolean;
62
52
  };
63
-
64
53
  /**
65
54
  * Result of scanning react fiber tree and DOM elements
66
55
  * @property {Set<string>} components - Set of component names found in the fiber tree
@@ -70,39 +59,35 @@ export type CreateOptions = {
70
59
  * @property {Map<string, number>} detachedComponentToFiberNodeCount - Map of component names to their detached instance counts
71
60
  */
72
61
  export type EventListenerLeak = {
73
- type: string;
74
- componentName: string;
75
- count: number;
62
+ type: string;
63
+ componentName: string;
64
+ count: number;
76
65
  };
77
-
78
66
  export type ScanResult = {
79
- components: Set<string>;
80
- componentToFiberNodeCount: Map<string, number>;
81
- totalElements: number;
82
- totalDetachedElements: number;
83
- detachedComponentToFiberNodeCount: Map<string, number>;
84
- fiberNodes: Array<WeakRef<Fiber>>;
85
- leakedFibers: Array<WeakRef<Fiber>>;
86
- eventListenerLeaks?: EventListenerLeak[];
67
+ components: Set<string>;
68
+ componentToFiberNodeCount: Map<string, number>;
69
+ totalElements: number;
70
+ totalDetachedElements: number;
71
+ detachedComponentToFiberNodeCount: Map<string, number>;
72
+ fiberNodes: Array<WeakRef<Fiber>>;
73
+ leakedFibers: Array<WeakRef<Fiber>>;
74
+ eventListenerLeaks?: EventListenerLeak[];
87
75
  };
88
-
89
76
  /**
90
77
  * Result of analyzing React fiber nodes and DOM elements
91
78
  * @property {number} start - Start time of the analysis
92
79
  * @property {number} end - End time of the analysis
93
80
  */
94
81
  export type AnalysisResult = ScanResult & {
95
- start: number;
96
- end: number;
97
- scanner: ReactMemoryScan;
82
+ start: number;
83
+ end: number;
84
+ scanner: ReactMemoryScan;
98
85
  };
99
-
100
86
  /**
101
87
  * Callback function type for analysis results
102
88
  * @param {AnalysisResult} result - The analysis result
103
89
  */
104
90
  export type AnalysisResultCallback = (result: AnalysisResult) => void;
105
-
106
91
  /**
107
92
  * Represents the dimensions and position of an element's bounding box
108
93
  * @property {number} x - The x-coordinate of the element's left edge relative to the viewport
@@ -117,18 +102,17 @@ export type AnalysisResultCallback = (result: AnalysisResult) => void;
117
102
  * @property {number} scrollTop - The scroll distance from the top of the viewport to the element's top edge
118
103
  */
119
104
  export interface BoundingRect {
120
- x: number;
121
- y: number;
122
- width: number;
123
- height: number;
124
- top: number;
125
- right: number;
126
- bottom: number;
127
- left: number;
128
- scrollLeft: number;
129
- scrollTop: number;
105
+ x: number;
106
+ y: number;
107
+ width: number;
108
+ height: number;
109
+ top: number;
110
+ right: number;
111
+ bottom: number;
112
+ left: number;
113
+ scrollLeft: number;
114
+ scrollTop: number;
130
115
  }
131
-
132
116
  /**
133
117
  * Represents information about a DOM element
134
118
  * @property {WeakRef<Element>} element - A weak reference to the DOM element
@@ -136,45 +120,37 @@ export interface BoundingRect {
136
120
  * @property {Optional<string>} component - The react component name associated with the element
137
121
  */
138
122
  export type DOMElementInfo = {
139
- element: WeakRef<Element>;
140
- boundingRect: Optional<BoundingRect>;
141
- componentStack: Optional<string[]>;
123
+ element: WeakRef<Element>;
124
+ boundingRect: Optional<BoundingRect>;
125
+ componentStack: Optional<string[]>;
142
126
  };
143
-
144
127
  /** @internal */
145
128
  export type DOMElementStats = {
146
- elements: number;
147
- detachedElements: number;
129
+ elements: number;
130
+ detachedElements: number;
148
131
  };
149
-
150
132
  export type DOMObserveCallback = (list: Array<WeakRef<Element>>) => void;
151
-
152
133
  export type PerformanceConfig = {
153
- scanIntervalMs: number;
154
- maxComponentStackDepth: number;
155
- memoryMeasurementIntervalMs: number;
134
+ scanIntervalMs: number;
135
+ maxComponentStackDepth: number;
136
+ memoryMeasurementIntervalMs: number;
156
137
  };
157
-
158
138
  export type FeatureFlags = {
159
- enableMutationObserver: boolean;
160
- enableMemoryTracking: boolean;
161
- enableComponentStack: boolean;
162
- enableConsoleLogs: boolean;
139
+ enableMutationObserver: boolean;
140
+ enableMemoryTracking: boolean;
141
+ enableComponentStack: boolean;
142
+ enableConsoleLogs: boolean;
163
143
  };
164
-
165
144
  export type Config = {
166
- performance: PerformanceConfig;
167
- features: FeatureFlags;
145
+ performance: PerformanceConfig;
146
+ features: FeatureFlags;
168
147
  };
169
-
170
148
  export type Entry<K extends object, V> = {
171
- ref: WeakRef<K>;
172
- value: V;
149
+ ref: WeakRef<K>;
150
+ value: V;
173
151
  };
174
-
175
152
  export type FallbackMode = 'strong' | 'noop';
176
-
177
153
  export type WeakMapPlusOptions = {
178
- fallback?: FallbackMode;
179
- cleanupMs?: number;
154
+ fallback?: FallbackMode;
155
+ cleanupMs?: number;
180
156
  };
@@ -7,10 +7,5 @@
7
7
  * @format
8
8
  * @oncall memory_lab
9
9
  */
10
- import * as fs from 'fs';
11
- import * as path from 'path';
12
-
13
- export function getBundleContent(): string {
14
- const bundlePath = path.join(__dirname, 'memlens.run.bundle.min.js');
15
- return fs.readFileSync(bundlePath, 'utf-8');
16
- }
10
+ import { Optional } from './types';
11
+ export declare function isValidComponentName(name: Optional<string>): boolean;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import type ReactMemoryScan from '../core/react-memory-scan';
11
+ import type { AnalysisResult } from '../core/types';
12
+ /**
13
+ * Base class for React Memory Scanner extensions.
14
+ * Extensions can hook into the scanning process before and after analysis.
15
+ */
16
+ export declare abstract class BasicExtension {
17
+ protected readonly scanner: ReactMemoryScan;
18
+ constructor(scanner: ReactMemoryScan);
19
+ /**
20
+ * Hook that runs before the memory scan starts.
21
+ * Override this method to perform any setup or pre-scan operations.
22
+ */
23
+ beforeScan(): void;
24
+ /**
25
+ * Hook that runs after the memory scan completes.
26
+ * Override this method to process or modify the analysis results.
27
+ * @param analysisResult - The results from the memory scan
28
+ */
29
+ afterScan(_analysisResult: AnalysisResult): void;
30
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import type ReactMemoryScan from '../core/react-memory-scan';
11
+ import type { AnalysisResult } from '../core/types';
12
+ import { BasicExtension } from './basic-extension';
13
+ export declare class DOMVisualizationExtension extends BasicExtension {
14
+ #private;
15
+ constructor(scanner: ReactMemoryScan);
16
+ afterScan(_analysisResult: AnalysisResult): void;
17
+ }
@@ -0,0 +1 @@
1
+ export declare function getBundleContent(): string;