@memlab/cli 1.0.7 → 1.0.11

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 (156) hide show
  1. package/bin/{memlab → memlab.js} +5 -3
  2. package/dist/BaseCommand.d.ts +1 -1
  3. package/dist/BaseCommand.js +1 -1
  4. package/dist/CommandLoader.d.ts +8 -7
  5. package/dist/CommandLoader.js +8 -1
  6. package/dist/Dispatcher.d.ts +8 -3
  7. package/dist/Dispatcher.js +13 -6
  8. package/dist/TypesThirdParty.d.ts +1 -1
  9. package/dist/TypesThirdParty.js +1 -1
  10. package/dist/commands/CleanLoggerDataCommand.d.ts +1 -1
  11. package/dist/commands/CleanLoggerDataCommand.js +1 -1
  12. package/dist/commands/CleanRunDataCommand.d.ts +1 -1
  13. package/dist/commands/CleanRunDataCommand.js +1 -1
  14. package/dist/commands/GetVersionCommand.d.ts +1 -1
  15. package/dist/commands/GetVersionCommand.js +2 -2
  16. package/dist/commands/InitDirectoryCommand.d.ts +1 -1
  17. package/dist/commands/InitDirectoryCommand.js +1 -1
  18. package/dist/commands/ListScenariosCommand.d.ts +1 -1
  19. package/dist/commands/ListScenariosCommand.js +1 -1
  20. package/dist/commands/MemLabRunCommand.d.ts +1 -1
  21. package/dist/commands/MemLabRunCommand.js +1 -1
  22. package/dist/commands/PrintSummaryCommand.d.ts +1 -1
  23. package/dist/commands/PrintSummaryCommand.js +1 -1
  24. package/dist/commands/ResetDirectoryCommand.d.ts +1 -1
  25. package/dist/commands/ResetDirectoryCommand.js +1 -1
  26. package/dist/commands/RunMeasureCommand.d.ts +1 -1
  27. package/dist/commands/RunMeasureCommand.js +1 -1
  28. package/dist/commands/WarmupAppCommand.d.ts +1 -1
  29. package/dist/commands/WarmupAppCommand.js +1 -1
  30. package/dist/commands/heap/CheckLeakCommand.d.ts +1 -1
  31. package/dist/commands/heap/CheckLeakCommand.js +3 -1
  32. package/dist/commands/heap/GetRetainerTraceCommand.d.ts +1 -1
  33. package/dist/commands/heap/GetRetainerTraceCommand.js +1 -1
  34. package/dist/commands/heap/HeapAnalysisCommand.d.ts +1 -1
  35. package/dist/commands/heap/HeapAnalysisCommand.js +1 -1
  36. package/dist/commands/heap/HeapAnalysisSubCommandWrapper.d.ts +1 -1
  37. package/dist/commands/heap/HeapAnalysisSubCommandWrapper.js +1 -1
  38. package/dist/commands/heap/interactive/InteractiveCommandLoader.d.ts +16 -0
  39. package/dist/commands/heap/interactive/InteractiveCommandLoader.js +33 -0
  40. package/dist/commands/heap/interactive/InteractiveHeapCommand.d.ts +28 -0
  41. package/dist/commands/heap/interactive/InteractiveHeapCommand.js +166 -0
  42. package/dist/commands/heap/interactive/InteractiveHeapExploreCommand.d.ts +25 -0
  43. package/dist/commands/heap/interactive/InteractiveHeapExploreCommand.js +169 -0
  44. package/dist/commands/heap/interactive/ui-components/CliScreen.d.ts +38 -0
  45. package/dist/commands/heap/interactive/ui-components/CliScreen.js +253 -0
  46. package/dist/commands/heap/interactive/ui-components/HeapViewController.d.ts +73 -0
  47. package/dist/commands/heap/interactive/ui-components/HeapViewController.js +358 -0
  48. package/dist/commands/heap/interactive/ui-components/HeapViewUtils.d.ts +32 -0
  49. package/dist/commands/heap/interactive/ui-components/HeapViewUtils.js +205 -0
  50. package/dist/commands/heap/interactive/ui-components/ListComponent.d.ts +65 -0
  51. package/dist/commands/heap/interactive/ui-components/ListComponent.js +237 -0
  52. package/dist/commands/helper/GenerateCLIDocCommand.d.ts +1 -1
  53. package/dist/commands/helper/GenerateCLIDocCommand.js +1 -1
  54. package/dist/commands/helper/HelperCommand.d.ts +1 -1
  55. package/dist/commands/helper/HelperCommand.js +17 -5
  56. package/dist/commands/helper/lib/CommandOrder.d.ts +1 -1
  57. package/dist/commands/helper/lib/CommandOrder.js +1 -1
  58. package/dist/commands/helper/lib/Types.d.ts +1 -1
  59. package/dist/commands/helper/lib/Types.js +1 -1
  60. package/dist/commands/query/QueryDefaultWorkDirCommand.d.ts +1 -1
  61. package/dist/commands/query/QueryDefaultWorkDirCommand.js +1 -1
  62. package/dist/commands/snapshot/CheckXvfbSupportCommand.d.ts +1 -1
  63. package/dist/commands/snapshot/CheckXvfbSupportCommand.js +1 -1
  64. package/dist/commands/snapshot/Snapshot.d.ts +1 -1
  65. package/dist/commands/snapshot/Snapshot.js +1 -1
  66. package/dist/commands/snapshot/TakeSnapshotCommand.d.ts +1 -1
  67. package/dist/commands/snapshot/TakeSnapshotCommand.js +1 -1
  68. package/dist/commands/snapshot/WarmupAndSnapshotCommand.d.ts +1 -1
  69. package/dist/commands/snapshot/WarmupAndSnapshotCommand.js +1 -1
  70. package/dist/index.d.ts +1 -1
  71. package/dist/index.js +1 -1
  72. package/dist/options/AppOption.d.ts +1 -1
  73. package/dist/options/AppOption.js +1 -1
  74. package/dist/options/DebugOption.d.ts +1 -1
  75. package/dist/options/DebugOption.js +1 -1
  76. package/dist/options/DisableXvfbOption.d.ts +1 -1
  77. package/dist/options/DisableXvfbOption.js +1 -1
  78. package/dist/options/FullExecutionOption.d.ts +1 -1
  79. package/dist/options/FullExecutionOption.js +1 -1
  80. package/dist/options/HeadfulBrowserOption.d.ts +1 -1
  81. package/dist/options/HeadfulBrowserOption.js +1 -1
  82. package/dist/options/HeapNodeIdOption.d.ts +1 -1
  83. package/dist/options/HeapNodeIdOption.js +1 -1
  84. package/dist/options/HelperOption.d.ts +1 -1
  85. package/dist/options/HelperOption.js +1 -1
  86. package/dist/options/InteractionOption.d.ts +1 -1
  87. package/dist/options/InteractionOption.js +1 -1
  88. package/dist/options/MLClusteringLinkageMaxDistanceOption.d.ts +1 -1
  89. package/dist/options/MLClusteringLinkageMaxDistanceOption.js +1 -1
  90. package/dist/options/MLClusteringMaxDFOption.d.ts +18 -0
  91. package/dist/options/MLClusteringMaxDFOption.js +47 -0
  92. package/dist/options/MLClusteringOption.d.ts +1 -1
  93. package/dist/options/MLClusteringOption.js +1 -1
  94. package/dist/options/NumberOfRunsOption.d.ts +1 -1
  95. package/dist/options/NumberOfRunsOption.js +1 -1
  96. package/dist/options/RemoteBrowserDebugOption.d.ts +1 -1
  97. package/dist/options/RemoteBrowserDebugOption.js +1 -1
  98. package/dist/options/RunningModeOption.d.ts +1 -1
  99. package/dist/options/RunningModeOption.js +1 -1
  100. package/dist/options/ScenarioFileOption.d.ts +1 -1
  101. package/dist/options/ScenarioFileOption.js +1 -1
  102. package/dist/options/SetContinuousTestOption.d.ts +1 -1
  103. package/dist/options/SetContinuousTestOption.js +1 -1
  104. package/dist/options/SetDeviceOption.d.ts +1 -1
  105. package/dist/options/SetDeviceOption.js +1 -1
  106. package/dist/options/SetWorkingDirectoryOption.d.ts +1 -1
  107. package/dist/options/SetWorkingDirectoryOption.js +1 -1
  108. package/dist/options/SilentOption.d.ts +1 -1
  109. package/dist/options/SilentOption.js +1 -1
  110. package/dist/options/SkipExtraOperationOption.d.ts +1 -1
  111. package/dist/options/SkipExtraOperationOption.js +1 -1
  112. package/dist/options/SkipGCOption.d.ts +1 -1
  113. package/dist/options/SkipGCOption.js +1 -1
  114. package/dist/options/SkipScreenshotOption.d.ts +1 -1
  115. package/dist/options/SkipScreenshotOption.js +1 -1
  116. package/dist/options/SkipScrollOption.d.ts +1 -1
  117. package/dist/options/SkipScrollOption.js +1 -1
  118. package/dist/options/SkipSnapshotOption.d.ts +1 -1
  119. package/dist/options/SkipSnapshotOption.js +1 -1
  120. package/dist/options/SkipWarmupOption.d.ts +1 -1
  121. package/dist/options/SkipWarmupOption.js +1 -1
  122. package/dist/options/VerboseOption.d.ts +1 -1
  123. package/dist/options/VerboseOption.js +1 -1
  124. package/dist/options/heap/BaselineFileOption.d.ts +1 -1
  125. package/dist/options/heap/BaselineFileOption.js +1 -1
  126. package/dist/options/heap/FinalFileOption.d.ts +1 -1
  127. package/dist/options/heap/FinalFileOption.js +1 -1
  128. package/dist/options/heap/JSEngineOption.d.ts +1 -1
  129. package/dist/options/heap/JSEngineOption.js +1 -1
  130. package/dist/options/heap/LeakClusterSizeThresholdOption.d.ts +1 -1
  131. package/dist/options/heap/LeakClusterSizeThresholdOption.js +1 -1
  132. package/dist/options/heap/LogTraceAsClusterOption.d.ts +1 -1
  133. package/dist/options/heap/LogTraceAsClusterOption.js +1 -1
  134. package/dist/options/heap/OversizeThresholdOption.d.ts +1 -1
  135. package/dist/options/heap/OversizeThresholdOption.js +1 -1
  136. package/dist/options/heap/SnapshotDirectoryOption.d.ts +1 -1
  137. package/dist/options/heap/SnapshotDirectoryOption.js +1 -1
  138. package/dist/options/heap/SnapshotFileOption.d.ts +1 -1
  139. package/dist/options/heap/SnapshotFileOption.js +1 -1
  140. package/dist/options/heap/TargetFileOption.d.ts +1 -1
  141. package/dist/options/heap/TargetFileOption.js +1 -1
  142. package/dist/options/heap/TraceAllObjectsOption.d.ts +1 -1
  143. package/dist/options/heap/TraceAllObjectsOption.js +1 -1
  144. package/dist/options/heap/leak-filter/LeakFilterFileOption.d.ts +1 -1
  145. package/dist/options/heap/leak-filter/LeakFilterFileOption.js +1 -1
  146. package/dist/options/heap/leak-filter/examples/FilterLib.d.ts +1 -1
  147. package/dist/options/heap/leak-filter/examples/FilterLib.js +1 -1
  148. package/dist/options/heap/leak-filter/examples/dup-string-as-leak.example-1.d.ts +1 -1
  149. package/dist/options/heap/leak-filter/examples/dup-string-as-leak.example-1.js +1 -1
  150. package/dist/options/heap/leak-filter/examples/dup-string-as-leak.example-2.d.ts +1 -1
  151. package/dist/options/heap/leak-filter/examples/dup-string-as-leak.example-2.js +1 -1
  152. package/dist/options/lib/UniversalOptions.d.ts +1 -1
  153. package/dist/options/lib/UniversalOptions.js +1 -1
  154. package/dist/runner.d.ts +1 -1
  155. package/dist/runner.js +1 -1
  156. package/package.json +8 -6
@@ -0,0 +1,73 @@
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 ws_labs
9
+ */
10
+ import type { IHeapSnapshot, IHeapNode } from '@memlab/core';
11
+ import type ListComponent from './ListComponent';
12
+ import { ComponentDataItem, ComponentData } from './HeapViewUtils';
13
+ declare type SelectHeapObjectOption = {
14
+ noChangeInReferenceBox?: boolean;
15
+ noChangeInReferrerBox?: boolean;
16
+ noChangeInRetainerTraceBox?: boolean;
17
+ noChangeInObjectPropertyBox?: boolean;
18
+ componentDataItem?: ComponentDataItem;
19
+ };
20
+ export declare type ObjectCategory = Map<string, ComponentDataItem[]>;
21
+ /**
22
+ * HeapViewController managers all the data associated with each
23
+ * UI components in CLI and coordinates the events/interaction
24
+ * among all UI components.
25
+ */
26
+ export default class HeapViewController {
27
+ private currentHeapObject;
28
+ private selectedHeapObject;
29
+ private currentHeapObjectsInfo;
30
+ private currentClusteredObjectsInfo;
31
+ private componentIdToDataMap;
32
+ private componentIdToComponentMap;
33
+ private heap;
34
+ private clusteredBox;
35
+ private referrerBox;
36
+ private objectBox;
37
+ private referenceBox;
38
+ private objectPropertyBox;
39
+ private retainerTracePropertyBox;
40
+ constructor(heap: IHeapSnapshot, objectCategory: ObjectCategory);
41
+ private getFlattenHeapObjectsInfo;
42
+ private getFlattenClusteredObjectsInfo;
43
+ private shouldClusterCategory;
44
+ private clusterComponentDataItems;
45
+ getContent(componentId: number): string[];
46
+ setClusteredBox(component: ListComponent): void;
47
+ getClusteredBoxData(): ComponentData;
48
+ setReferrerBox(component: ListComponent): void;
49
+ getReferrerBoxData(node?: IHeapNode): ComponentData;
50
+ setObjectBox(component: ListComponent): void;
51
+ getObjectBoxData(): ComponentData;
52
+ setReferenceBox(component: ListComponent): void;
53
+ getReferenceBoxData(): ComponentData;
54
+ setObjectPropertyBox(component: ListComponent): void;
55
+ getObjectPropertyData(options?: {
56
+ details?: Map<string, string>;
57
+ }): ComponentData;
58
+ private getReadableString;
59
+ private getKeyValuePairString;
60
+ setRetainerTraceBox(component: ListComponent): void;
61
+ getRetainerTraceData(): ComponentData;
62
+ setCurrentHeapObjectFromComponent(componentId: number, itemIndex: number, options?: {
63
+ skipFocus?: boolean;
64
+ }): void;
65
+ setCurrentHeapObject(node: IHeapNode, options?: {
66
+ skipFocus?: boolean;
67
+ }): void;
68
+ focusOnComponent(componentId: number): void;
69
+ setSelectedHeapObjectFromComponent(componentId: number, itemIndex: number): void;
70
+ setSelectedHeapObject(node: IHeapNode, options?: SelectHeapObjectOption): void;
71
+ }
72
+ export {};
73
+ //# sourceMappingURL=HeapViewController.d.ts.map
@@ -0,0 +1,358 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const chalk_1 = __importDefault(require("chalk"));
7
+ const core_1 = require("@memlab/core");
8
+ const HeapViewUtils_1 = require("./HeapViewUtils");
9
+ /**
10
+ * HeapViewController managers all the data associated with each
11
+ * UI components in CLI and coordinates the events/interaction
12
+ * among all UI components.
13
+ */
14
+ class HeapViewController {
15
+ constructor(heap, objectCategory) {
16
+ this.heap = heap;
17
+ this.currentHeapObjectsInfo =
18
+ this.getFlattenHeapObjectsInfo(objectCategory);
19
+ this.currentClusteredObjectsInfo =
20
+ this.getFlattenClusteredObjectsInfo(objectCategory);
21
+ this.currentHeapObject = (0, HeapViewUtils_1.getHeapObjectAt)(this.currentHeapObjectsInfo, 0);
22
+ this.componentIdToDataMap = new Map();
23
+ this.componentIdToComponentMap = new Map();
24
+ }
25
+ getFlattenHeapObjectsInfo(objectCategory) {
26
+ let ret = [];
27
+ for (const category of objectCategory.keys()) {
28
+ const nodes = objectCategory.get(category);
29
+ ret = [...ret, ...nodes];
30
+ }
31
+ return ret;
32
+ }
33
+ getFlattenClusteredObjectsInfo(objectCategory) {
34
+ let ret = [];
35
+ for (const category of objectCategory.keys()) {
36
+ let nodes = objectCategory.get(category);
37
+ if (this.shouldClusterCategory(category)) {
38
+ nodes = this.clusterComponentDataItems(nodes);
39
+ }
40
+ ret = [...ret, ...nodes];
41
+ }
42
+ return ret;
43
+ }
44
+ shouldClusterCategory(category) {
45
+ return category === 'detached';
46
+ }
47
+ clusterComponentDataItems(nodes) {
48
+ const ret = [];
49
+ const nodeIds = new Set(nodes
50
+ .filter(node => node.heapObject)
51
+ .map(node => { var _a, _b; return (_b = (_a = node.heapObject) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : -1; }));
52
+ const clusters = core_1.analysis.clusterHeapObjects(nodeIds, this.heap);
53
+ clusters.forEach(cluster => {
54
+ var _a;
55
+ const id = (_a = cluster.id) !== null && _a !== void 0 ? _a : -1;
56
+ let node = null;
57
+ node = this.heap.getNodeById(id);
58
+ const details = new Map();
59
+ if (cluster.count) {
60
+ details.set('# of clusters', `${cluster.count}`);
61
+ }
62
+ if (cluster.retainedSize) {
63
+ details.set('aggregated retained size', `${core_1.utils.getReadableBytes(cluster.retainedSize)}`);
64
+ }
65
+ ret.push({ tag: 'Cluster', heapObject: node, details });
66
+ });
67
+ return ret;
68
+ }
69
+ getContent(componentId) {
70
+ const ret = [];
71
+ const data = this.componentIdToDataMap.get(componentId);
72
+ if (data) {
73
+ for (const item of data.items) {
74
+ ret.push(HeapViewUtils_1.ComponentDataItem.getTextForDisplay(item));
75
+ }
76
+ }
77
+ return ret;
78
+ }
79
+ setClusteredBox(component) {
80
+ this.componentIdToComponentMap.set(component.id, component);
81
+ this.clusteredBox = component;
82
+ this.componentIdToDataMap.set(component.id, new HeapViewUtils_1.ComponentData());
83
+ }
84
+ getClusteredBoxData() {
85
+ const data = new HeapViewUtils_1.ComponentData();
86
+ data.selectedIdx = 0;
87
+ data.items = this.currentClusteredObjectsInfo;
88
+ return data;
89
+ }
90
+ setReferrerBox(component) {
91
+ this.componentIdToComponentMap.set(component.id, component);
92
+ this.referrerBox = component;
93
+ this.componentIdToDataMap.set(component.id, new HeapViewUtils_1.ComponentData());
94
+ }
95
+ getReferrerBoxData(node = this.selectedHeapObject) {
96
+ const data = new HeapViewUtils_1.ComponentData();
97
+ node.forEachReferrer(ref => {
98
+ var _a, _b;
99
+ const tag = ref.fromNode.id === ((_b = (_a = node.pathEdge) === null || _a === void 0 ? void 0 : _a.fromNode) === null || _b === void 0 ? void 0 : _b.id) ? { tag: '<-' } : {};
100
+ data.items.push(Object.assign({ heapObject: ref.fromNode, referenceEdge: ref }, tag));
101
+ return { stop: false };
102
+ });
103
+ data.selectedIdx = data.items.length > 0 ? 0 : -1;
104
+ return data;
105
+ }
106
+ setObjectBox(component) {
107
+ this.componentIdToComponentMap.set(component.id, component);
108
+ this.objectBox = component;
109
+ this.componentIdToDataMap.set(component.id, new HeapViewUtils_1.ComponentData());
110
+ }
111
+ getObjectBoxData() {
112
+ const data = new HeapViewUtils_1.ComponentData();
113
+ const index = this.currentHeapObjectsInfo.findIndex(item => { var _a; return ((_a = item.heapObject) === null || _a === void 0 ? void 0 : _a.id) === this.currentHeapObject.id; });
114
+ if (index >= 0) {
115
+ data.selectedIdx = index;
116
+ }
117
+ else {
118
+ data.selectedIdx = 0;
119
+ this.currentHeapObjectsInfo.unshift({
120
+ tag: 'Chosen',
121
+ heapObject: this.currentHeapObject,
122
+ });
123
+ }
124
+ data.items = this.currentHeapObjectsInfo;
125
+ return data;
126
+ }
127
+ setReferenceBox(component) {
128
+ this.componentIdToComponentMap.set(component.id, component);
129
+ this.referenceBox = component;
130
+ this.componentIdToDataMap.set(component.id, new HeapViewUtils_1.ComponentData());
131
+ }
132
+ getReferenceBoxData() {
133
+ const data = new HeapViewUtils_1.ComponentData();
134
+ this.selectedHeapObject.forEachReference(ref => {
135
+ data.items.push({ referrerEdge: ref, heapObject: ref.toNode });
136
+ return { stop: false };
137
+ });
138
+ data.items.sort((i1, i2) => { var _a, _b, _c, _d; return ((_b = (_a = i2.heapObject) === null || _a === void 0 ? void 0 : _a.retainedSize) !== null && _b !== void 0 ? _b : 0) - ((_d = (_c = i1.heapObject) === null || _c === void 0 ? void 0 : _c.retainedSize) !== null && _d !== void 0 ? _d : 0); });
139
+ data.selectedIdx = data.items.length > 0 ? 0 : -1;
140
+ return data;
141
+ }
142
+ setObjectPropertyBox(component) {
143
+ this.componentIdToComponentMap.set(component.id, component);
144
+ this.objectPropertyBox = component;
145
+ this.componentIdToDataMap.set(component.id, new HeapViewUtils_1.ComponentData());
146
+ }
147
+ getObjectPropertyData(options = {}) {
148
+ var _a, _b;
149
+ const data = new HeapViewUtils_1.ComponentData();
150
+ const node = this.selectedHeapObject;
151
+ data.items.push({
152
+ stringContent: this.getKeyValuePairString('id', `@${node.id}`),
153
+ });
154
+ data.items.push({
155
+ stringContent: this.getKeyValuePairString('name', node.name),
156
+ });
157
+ data.items.push({
158
+ stringContent: this.getKeyValuePairString('type', node.type),
159
+ });
160
+ data.items.push({
161
+ stringContent: this.getKeyValuePairString('self size', core_1.utils.getReadableBytes(node.self_size)),
162
+ });
163
+ data.items.push({
164
+ stringContent: this.getKeyValuePairString('retained size', core_1.utils.getReadableBytes(node.retainedSize)),
165
+ });
166
+ data.items.push({
167
+ stringContent: this.getKeyValuePairString('# of references', node.edge_count),
168
+ });
169
+ data.items.push({
170
+ stringContent: this.getKeyValuePairString('# of referrers', node.referrers.length),
171
+ });
172
+ if (node.dominatorNode) {
173
+ data.items.push({
174
+ stringContent: 'dominator node' + chalk_1.default.grey(': '),
175
+ heapObject: node.dominatorNode,
176
+ });
177
+ }
178
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
179
+ const self = this;
180
+ (_a = options.details) === null || _a === void 0 ? void 0 : _a.forEach((value, key) => data.items.push({
181
+ stringContent: self.getKeyValuePairString(key, value),
182
+ }));
183
+ // inject additional node information
184
+ if (node.isString) {
185
+ const stringNode = node.toStringNode();
186
+ if (stringNode) {
187
+ const value = this.getReadableString(stringNode.stringValue);
188
+ data.items.push({
189
+ stringContent: this.getKeyValuePairString('string value', value),
190
+ });
191
+ }
192
+ }
193
+ if (node.type === 'number') {
194
+ data.items.push({
195
+ stringContent: this.getKeyValuePairString('numeric value', (_b = core_1.utils.getNumberNodeValue(node)) !== null && _b !== void 0 ? _b : '<error>'),
196
+ });
197
+ }
198
+ if (node.type === 'closure') {
199
+ const contextNode = node.getReferenceNode('context', 'internal');
200
+ if (contextNode) {
201
+ contextNode.forEachReference(edge => {
202
+ data.items.push({
203
+ tag: chalk_1.default.grey('Scope Variable'),
204
+ referrerEdge: edge,
205
+ heapObject: edge.toNode,
206
+ });
207
+ });
208
+ }
209
+ }
210
+ data.selectedIdx = data.items.length > 0 ? 0 : -1;
211
+ return data;
212
+ }
213
+ getReadableString(value) {
214
+ return value.length > 300
215
+ ? value.substring(0, 300) + chalk_1.default.grey('...')
216
+ : value;
217
+ }
218
+ getKeyValuePairString(key, value) {
219
+ return key + chalk_1.default.grey(': ') + chalk_1.default.green(value);
220
+ }
221
+ setRetainerTraceBox(component) {
222
+ this.componentIdToComponentMap.set(component.id, component);
223
+ this.retainerTracePropertyBox = component;
224
+ this.componentIdToDataMap.set(component.id, new HeapViewUtils_1.ComponentData());
225
+ }
226
+ getRetainerTraceData() {
227
+ var _a;
228
+ const data = new HeapViewUtils_1.ComponentData();
229
+ const node = this.selectedHeapObject;
230
+ let curNode = node;
231
+ while (curNode && !core_1.utils.isRootNode(curNode)) {
232
+ if (!curNode.pathEdge) {
233
+ curNode = null;
234
+ break;
235
+ }
236
+ data.items.unshift({ referrerEdge: curNode.pathEdge, heapObject: curNode });
237
+ curNode = (_a = curNode.pathEdge) === null || _a === void 0 ? void 0 : _a.fromNode;
238
+ }
239
+ if (curNode) {
240
+ data.items.unshift({ heapObject: curNode });
241
+ }
242
+ data.selectedIdx = data.items.length > 0 ? 0 : -1;
243
+ return data;
244
+ }
245
+ setCurrentHeapObjectFromComponent(componentId, itemIndex, options = {}) {
246
+ const data = this.componentIdToDataMap.get(componentId);
247
+ if (!data) {
248
+ return;
249
+ }
250
+ const item = data.items[itemIndex];
251
+ if (!item) {
252
+ return;
253
+ }
254
+ const heapObject = item.heapObject;
255
+ if (!heapObject) {
256
+ return;
257
+ }
258
+ this.setCurrentHeapObject(heapObject, options);
259
+ }
260
+ setCurrentHeapObject(node, options = {}) {
261
+ this.currentHeapObject = node;
262
+ // set parent box's data and content
263
+ const clusteredBoxData = this.getClusteredBoxData();
264
+ this.componentIdToDataMap.set(this.clusteredBox.id, clusteredBoxData);
265
+ this.clusteredBox.setContent(this.getContent(this.clusteredBox.id));
266
+ this.clusteredBox.selectIndex(clusteredBoxData.selectedIdx);
267
+ // set object box's data and content
268
+ const objectBoxData = this.getObjectBoxData();
269
+ this.componentIdToDataMap.set(this.objectBox.id, objectBoxData);
270
+ this.objectBox.setContent(this.getContent(this.objectBox.id));
271
+ this.objectBox.selectIndex(objectBoxData.selectedIdx);
272
+ this.setSelectedHeapObject(node);
273
+ if (!options.skipFocus) {
274
+ this.focusOnComponent(this.objectBox.id);
275
+ }
276
+ }
277
+ focusOnComponent(componentId) {
278
+ var _a;
279
+ for (const component of this.componentIdToComponentMap.values()) {
280
+ if (component.id === componentId) {
281
+ component.focus();
282
+ const data = this.componentIdToDataMap.get(componentId);
283
+ const selectIndex = (_a = (data && data.selectedIdx)) !== null && _a !== void 0 ? _a : -1;
284
+ this.setSelectedHeapObjectFromComponent(componentId, selectIndex);
285
+ }
286
+ else {
287
+ component.loseFocus();
288
+ }
289
+ }
290
+ }
291
+ setSelectedHeapObjectFromComponent(componentId, itemIndex) {
292
+ const data = this.componentIdToDataMap.get(componentId);
293
+ if (!data) {
294
+ return;
295
+ }
296
+ data.selectedIdx = itemIndex;
297
+ const item = data.items[itemIndex];
298
+ if (!item) {
299
+ return;
300
+ }
301
+ const heapObject = item.heapObject;
302
+ if (!heapObject) {
303
+ return;
304
+ }
305
+ // if selecting in a specific box, do not update content in that box
306
+ const noChangeInReferenceBox = componentId === this.referenceBox.id;
307
+ const noChangeInReferrerBox = componentId === this.referrerBox.id;
308
+ const noChangeInRetainerTraceBox = componentId === this.retainerTracePropertyBox.id;
309
+ const noChangeInObjectPropertyBox = componentId === this.objectPropertyBox.id;
310
+ this.setSelectedHeapObject(heapObject, {
311
+ noChangeInReferenceBox,
312
+ noChangeInReferrerBox,
313
+ noChangeInRetainerTraceBox,
314
+ noChangeInObjectPropertyBox,
315
+ componentDataItem: item,
316
+ });
317
+ }
318
+ setSelectedHeapObject(node, options = {}) {
319
+ var _a;
320
+ this.selectedHeapObject = node;
321
+ // set referrer box's data and content
322
+ if (!options.noChangeInReferrerBox) {
323
+ const data = this.getReferrerBoxData();
324
+ this.componentIdToDataMap.set(this.referrerBox.id, data);
325
+ this.referrerBox.setContent(this.getContent(this.referrerBox.id));
326
+ this.referrerBox.selectIndex(data.selectedIdx);
327
+ this.referrerBox.setLabel(`Referrers of @${node.id}`);
328
+ }
329
+ // set reference box's data and content
330
+ if (!options.noChangeInReferenceBox) {
331
+ const data = this.getReferenceBoxData();
332
+ this.componentIdToDataMap.set(this.referenceBox.id, data);
333
+ this.referenceBox.setContent(this.getContent(this.referenceBox.id));
334
+ this.referenceBox.selectIndex(data.selectedIdx);
335
+ this.referenceBox.setLabel(`References of @${node.id}`);
336
+ }
337
+ // set object property box's data and content
338
+ if (!options.noChangeInObjectPropertyBox) {
339
+ const propertyOption = ((_a = options === null || options === void 0 ? void 0 : options.componentDataItem) === null || _a === void 0 ? void 0 : _a.details)
340
+ ? { details: options.componentDataItem.details }
341
+ : {};
342
+ const data = this.getObjectPropertyData(propertyOption);
343
+ this.componentIdToDataMap.set(this.objectPropertyBox.id, data);
344
+ this.objectPropertyBox.setContent(this.getContent(this.objectPropertyBox.id));
345
+ this.objectPropertyBox.selectIndex(data.selectedIdx);
346
+ this.objectPropertyBox.setLabel(`Object: @${node.id}`);
347
+ }
348
+ // set retainer trace box's data and content
349
+ if (!options.noChangeInRetainerTraceBox) {
350
+ const data = this.getRetainerTraceData();
351
+ this.componentIdToDataMap.set(this.retainerTracePropertyBox.id, data);
352
+ this.retainerTracePropertyBox.setContent(this.getContent(this.retainerTracePropertyBox.id));
353
+ this.retainerTracePropertyBox.selectIndex(data.selectedIdx);
354
+ this.retainerTracePropertyBox.setLabel(`Retainer Trace of @${node.id}`);
355
+ }
356
+ }
357
+ }
358
+ exports.default = HeapViewController;
@@ -0,0 +1,32 @@
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 ws_labs
9
+ */
10
+ import type { IHeapEdge, IHeapNode } from '@memlab/core';
11
+ export declare class ComponentDataItem {
12
+ stringContent?: string;
13
+ tag?: string;
14
+ referrerEdge?: IHeapEdge;
15
+ heapObject?: IHeapNode;
16
+ referenceEdge?: IHeapEdge;
17
+ type?: string;
18
+ details?: Map<string, string>;
19
+ static getTextForDisplay(data: ComponentDataItem): string;
20
+ private static getTextContent;
21
+ }
22
+ export declare class ComponentData {
23
+ selectedIdx: number;
24
+ items: ComponentDataItem[];
25
+ }
26
+ export declare function throwIfNodesEmpty(nodes: ComponentDataItem[]): boolean;
27
+ export declare function getHeapObjectAt(nodes: ComponentDataItem[], index: number): IHeapNode;
28
+ export declare function substringWithColor(input: string, begin: number): string;
29
+ export declare type DebounceCallback = () => void;
30
+ export declare type DebounceFunction = (callback: DebounceCallback) => void;
31
+ export declare function debounce(timeInMs: number): DebounceFunction;
32
+ //# sourceMappingURL=HeapViewUtils.d.ts.map
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.debounce = exports.substringWithColor = exports.getHeapObjectAt = exports.throwIfNodesEmpty = exports.ComponentData = exports.ComponentDataItem = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const core_1 = require("@memlab/core");
9
+ const lessUsefulEdgeTypeForDebugging = new Set([
10
+ 'internal',
11
+ 'hidden',
12
+ 'shortcut',
13
+ 'weak',
14
+ ]);
15
+ const reactEdgeNames = new Set([
16
+ 'alternate',
17
+ 'firstEffect',
18
+ 'lastEffect',
19
+ 'concurrentQueues',
20
+ 'child',
21
+ 'return',
22
+ 'sibling',
23
+ ]);
24
+ function isUsefulEdgeForDebugging(edge) {
25
+ if (lessUsefulEdgeTypeForDebugging.has(edge.type)) {
26
+ return false;
27
+ }
28
+ const edgeStr = `${edge.name_or_index}`;
29
+ if (reactEdgeNames.has(edgeStr)) {
30
+ if (core_1.utils.isFiberNode(edge.fromNode) || core_1.utils.isFiberNode(edge.toNode)) {
31
+ return false;
32
+ }
33
+ }
34
+ if (edgeStr.startsWith('__reactProps$')) {
35
+ return false;
36
+ }
37
+ return true;
38
+ }
39
+ const lessUsefulObjectTypeForDebugging = new Set([
40
+ 'native',
41
+ 'hidden',
42
+ 'array',
43
+ 'code',
44
+ 'synthetic',
45
+ ]);
46
+ function isUsefulObjectForDebugging(object) {
47
+ if (lessUsefulObjectTypeForDebugging.has(object.type)) {
48
+ return false;
49
+ }
50
+ return !core_1.utils.isFiberNode(object);
51
+ }
52
+ class ComponentDataItem {
53
+ static getTextForDisplay(data) {
54
+ const content = ComponentDataItem.getTextContent(data);
55
+ if (data.referrerEdge && isUsefulEdgeForDebugging(data.referrerEdge)) {
56
+ return content;
57
+ }
58
+ if (data.referenceEdge && isUsefulEdgeForDebugging(data.referenceEdge)) {
59
+ return content;
60
+ }
61
+ if (data.heapObject && isUsefulObjectForDebugging(data.heapObject)) {
62
+ return content;
63
+ }
64
+ if (!data.referenceEdge && !data.heapObject && !data.referrerEdge) {
65
+ return content;
66
+ }
67
+ return chalk_1.default.grey(content);
68
+ }
69
+ static getTextContent(data) {
70
+ let ret = '';
71
+ if (data.tag) {
72
+ ret += `[${data.tag}] `;
73
+ }
74
+ if (data.stringContent) {
75
+ ret += data.stringContent;
76
+ }
77
+ const arrowPrefix = chalk_1.default.grey('--');
78
+ const arrowSuffix = chalk_1.default.grey('---') + '>';
79
+ if (data.referrerEdge) {
80
+ const edgeType = chalk_1.default.grey(`(${data.referrerEdge.type})`);
81
+ const edgeName = data.referrerEdge.name_or_index;
82
+ ret += `${arrowPrefix}${edgeName}${edgeType}${arrowSuffix} `;
83
+ }
84
+ if (data.heapObject) {
85
+ const objectType = chalk_1.default.grey(`(${data.heapObject.type})`);
86
+ const objectId = chalk_1.default.grey(` @${data.heapObject.id}`);
87
+ const size = core_1.utils.getReadableBytes(data.heapObject.retainedSize);
88
+ const sizeInfo = chalk_1.default.grey(' [') + chalk_1.default.bold(chalk_1.default.blue(size)) + chalk_1.default.grey(']');
89
+ ret +=
90
+ chalk_1.default.green('[') +
91
+ (isUsefulObjectForDebugging(data.heapObject)
92
+ ? chalk_1.default.green(data.heapObject.name)
93
+ : chalk_1.default.bold(chalk_1.default.grey(data.heapObject.name))) +
94
+ chalk_1.default.green(']') +
95
+ objectType +
96
+ objectId +
97
+ sizeInfo;
98
+ }
99
+ if (data.referenceEdge) {
100
+ const edgeType = chalk_1.default.grey(`(${data.referenceEdge.type})`);
101
+ const edgeName = data.referenceEdge.name_or_index;
102
+ ret += ` ${arrowPrefix}${edgeName}${edgeType}${arrowSuffix} `;
103
+ }
104
+ return ret === '' ? chalk_1.default.grey('<undefinied>') : ret;
105
+ }
106
+ }
107
+ exports.ComponentDataItem = ComponentDataItem;
108
+ class ComponentData {
109
+ constructor() {
110
+ this.selectedIdx = -1;
111
+ this.items = [];
112
+ }
113
+ }
114
+ exports.ComponentData = ComponentData;
115
+ function throwIfNodesEmpty(nodes) {
116
+ if (nodes.length === 0) {
117
+ throw core_1.utils.haltOrThrow('no heap node specified');
118
+ }
119
+ for (let i = 0; i < nodes.length; ++i) {
120
+ if (!nodes[i].heapObject) {
121
+ throw core_1.utils.haltOrThrow('heap node missing in ComponentDataItem[]');
122
+ }
123
+ }
124
+ return true;
125
+ }
126
+ exports.throwIfNodesEmpty = throwIfNodesEmpty;
127
+ function getHeapObjectAt(nodes, index) {
128
+ throwIfNodesEmpty(nodes);
129
+ if (index < 0 || index >= nodes.length) {
130
+ throw core_1.utils.haltOrThrow('index is outside of nodes range');
131
+ }
132
+ return nodes[index].heapObject;
133
+ }
134
+ exports.getHeapObjectAt = getHeapObjectAt;
135
+ // eslint-disable-next-line no-control-regex
136
+ const colorBegin = /^\u001b\[(\d+)m/;
137
+ // eslint-disable-next-line no-control-regex
138
+ const colorEnd = /^\u001b\](\d+)m/;
139
+ function stripColorCodeIfAny(input) {
140
+ const matchBegin = input.match(colorBegin);
141
+ const matchEnd = input.match(colorEnd);
142
+ const match = matchBegin || matchEnd;
143
+ if (!match) {
144
+ return { str: input, code: -1, isBegin: false };
145
+ }
146
+ const isBegin = !!matchBegin;
147
+ const code = parseInt(match[1], 10);
148
+ const str = input.substring(match[0].length);
149
+ return { str, code, isBegin };
150
+ }
151
+ function toColorControlChar(code, isBegin) {
152
+ const colorSpecialChar = '\u001b';
153
+ return colorSpecialChar + (isBegin ? '[' : ']') + code + 'm';
154
+ }
155
+ function substringWithColor(input, begin) {
156
+ const codeQueue = [];
157
+ let curIndex = 0;
158
+ let curStr = input;
159
+ while (curIndex < begin) {
160
+ // enqueue all control characters
161
+ let strip;
162
+ do {
163
+ strip = stripColorCodeIfAny(curStr);
164
+ curStr = strip.str;
165
+ if (strip.code >= 0) {
166
+ // pop if control begin meets control ends
167
+ const last = codeQueue[codeQueue.length - 1];
168
+ if (!last ||
169
+ last.code !== strip.code ||
170
+ strip.isBegin === true ||
171
+ last.isBegin === false) {
172
+ codeQueue.push({ code: strip.code, isBegin: strip.isBegin });
173
+ }
174
+ else {
175
+ codeQueue.pop();
176
+ }
177
+ }
178
+ } while (strip.code >= 0);
179
+ // strip one actual content character
180
+ curStr = curStr.substring(1);
181
+ ++curIndex;
182
+ }
183
+ // prepend control characters
184
+ while (codeQueue.length > 0) {
185
+ const last = codeQueue.pop();
186
+ if (last) {
187
+ curStr = toColorControlChar(last === null || last === void 0 ? void 0 : last.code, last === null || last === void 0 ? void 0 : last.isBegin) + curStr;
188
+ }
189
+ }
190
+ return curStr;
191
+ }
192
+ exports.substringWithColor = substringWithColor;
193
+ function debounce(timeInMs) {
194
+ let id = null;
195
+ return (callback) => {
196
+ if (id) {
197
+ clearTimeout(id);
198
+ }
199
+ id = setTimeout(() => {
200
+ callback();
201
+ id = null;
202
+ }, timeInMs);
203
+ };
204
+ }
205
+ exports.debounce = debounce;