@memlab/cli 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseCommand.d.ts +1 -1
- package/dist/BaseCommand.js +1 -1
- package/dist/CommandLoader.d.ts +1 -1
- package/dist/CommandLoader.js +1 -1
- package/dist/Dispatcher.d.ts +1 -1
- package/dist/Dispatcher.js +1 -1
- package/dist/TypesThirdParty.d.ts +1 -1
- package/dist/TypesThirdParty.js +1 -1
- package/dist/commands/CleanLoggerDataCommand.d.ts +1 -1
- package/dist/commands/CleanLoggerDataCommand.js +1 -1
- package/dist/commands/CleanRunDataCommand.d.ts +1 -1
- package/dist/commands/CleanRunDataCommand.js +1 -1
- package/dist/commands/GetVersionCommand.d.ts +1 -1
- package/dist/commands/GetVersionCommand.js +1 -1
- package/dist/commands/InitDirectoryCommand.d.ts +1 -1
- package/dist/commands/InitDirectoryCommand.js +1 -1
- package/dist/commands/ListScenariosCommand.d.ts +1 -1
- package/dist/commands/ListScenariosCommand.js +1 -1
- package/dist/commands/MemLabRunCommand.d.ts +1 -1
- package/dist/commands/MemLabRunCommand.js +1 -1
- package/dist/commands/PrintSummaryCommand.d.ts +1 -1
- package/dist/commands/PrintSummaryCommand.js +1 -1
- package/dist/commands/ResetDirectoryCommand.d.ts +1 -1
- package/dist/commands/ResetDirectoryCommand.js +1 -1
- package/dist/commands/RunMeasureCommand.d.ts +1 -1
- package/dist/commands/RunMeasureCommand.js +1 -1
- package/dist/commands/WarmupAppCommand.d.ts +1 -1
- package/dist/commands/WarmupAppCommand.js +1 -1
- package/dist/commands/heap/CheckLeakCommand.d.ts +1 -1
- package/dist/commands/heap/CheckLeakCommand.js +1 -1
- package/dist/commands/heap/GetRetainerTraceCommand.d.ts +1 -1
- package/dist/commands/heap/GetRetainerTraceCommand.js +1 -1
- package/dist/commands/heap/HeapAnalysisCommand.d.ts +1 -1
- package/dist/commands/heap/HeapAnalysisCommand.js +1 -1
- package/dist/commands/heap/HeapAnalysisSubCommandWrapper.d.ts +1 -1
- package/dist/commands/heap/HeapAnalysisSubCommandWrapper.js +1 -1
- package/dist/commands/heap/interactive/InteractiveCommandLoader.d.ts +1 -1
- package/dist/commands/heap/interactive/InteractiveCommandLoader.js +1 -1
- package/dist/commands/heap/interactive/InteractiveHeapCommand.d.ts +6 -1
- package/dist/commands/heap/interactive/InteractiveHeapCommand.js +54 -15
- package/dist/commands/heap/interactive/InteractiveHeapExploreCommand.d.ts +26 -0
- package/dist/commands/heap/interactive/InteractiveHeapExploreCommand.js +145 -0
- package/dist/commands/heap/interactive/ui-components/CliScreen.d.ts +38 -0
- package/dist/commands/heap/interactive/ui-components/CliScreen.js +234 -0
- package/dist/commands/heap/interactive/ui-components/HeapViewController.d.ts +58 -0
- package/dist/commands/heap/interactive/ui-components/HeapViewController.js +251 -0
- package/dist/commands/heap/interactive/ui-components/HeapViewUtils.d.ts +29 -0
- package/dist/commands/heap/interactive/ui-components/HeapViewUtils.js +84 -0
- package/dist/commands/heap/interactive/ui-components/ListComponent.d.ts +62 -0
- package/dist/commands/heap/interactive/ui-components/ListComponent.js +220 -0
- package/dist/commands/helper/GenerateCLIDocCommand.d.ts +1 -1
- package/dist/commands/helper/GenerateCLIDocCommand.js +1 -1
- package/dist/commands/helper/HelperCommand.d.ts +1 -1
- package/dist/commands/helper/HelperCommand.js +1 -1
- package/dist/commands/helper/lib/CommandOrder.d.ts +1 -1
- package/dist/commands/helper/lib/CommandOrder.js +1 -1
- package/dist/commands/helper/lib/Types.d.ts +1 -1
- package/dist/commands/helper/lib/Types.js +1 -1
- package/dist/commands/query/QueryDefaultWorkDirCommand.d.ts +1 -1
- package/dist/commands/query/QueryDefaultWorkDirCommand.js +1 -1
- package/dist/commands/snapshot/CheckXvfbSupportCommand.d.ts +1 -1
- package/dist/commands/snapshot/CheckXvfbSupportCommand.js +1 -1
- package/dist/commands/snapshot/Snapshot.d.ts +1 -1
- package/dist/commands/snapshot/Snapshot.js +1 -1
- package/dist/commands/snapshot/TakeSnapshotCommand.d.ts +1 -1
- package/dist/commands/snapshot/TakeSnapshotCommand.js +1 -1
- package/dist/commands/snapshot/WarmupAndSnapshotCommand.d.ts +1 -1
- package/dist/commands/snapshot/WarmupAndSnapshotCommand.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/options/AppOption.d.ts +1 -1
- package/dist/options/AppOption.js +1 -1
- package/dist/options/DebugOption.d.ts +1 -1
- package/dist/options/DebugOption.js +1 -1
- package/dist/options/DisableXvfbOption.d.ts +1 -1
- package/dist/options/DisableXvfbOption.js +1 -1
- package/dist/options/FullExecutionOption.d.ts +1 -1
- package/dist/options/FullExecutionOption.js +1 -1
- package/dist/options/HeadfulBrowserOption.d.ts +1 -1
- package/dist/options/HeadfulBrowserOption.js +1 -1
- package/dist/options/HeapNodeIdOption.d.ts +1 -1
- package/dist/options/HeapNodeIdOption.js +1 -1
- package/dist/options/HelperOption.d.ts +1 -1
- package/dist/options/HelperOption.js +1 -1
- package/dist/options/InteractionOption.d.ts +1 -1
- package/dist/options/InteractionOption.js +1 -1
- package/dist/options/MLClusteringLinkageMaxDistanceOption.d.ts +1 -1
- package/dist/options/MLClusteringLinkageMaxDistanceOption.js +1 -1
- package/dist/options/MLClusteringMaxDFOption.d.ts +1 -1
- package/dist/options/MLClusteringMaxDFOption.js +1 -1
- package/dist/options/MLClusteringOption.d.ts +1 -1
- package/dist/options/MLClusteringOption.js +1 -1
- package/dist/options/NumberOfRunsOption.d.ts +1 -1
- package/dist/options/NumberOfRunsOption.js +1 -1
- package/dist/options/RemoteBrowserDebugOption.d.ts +1 -1
- package/dist/options/RemoteBrowserDebugOption.js +1 -1
- package/dist/options/RunningModeOption.d.ts +1 -1
- package/dist/options/RunningModeOption.js +1 -1
- package/dist/options/ScenarioFileOption.d.ts +1 -1
- package/dist/options/ScenarioFileOption.js +1 -1
- package/dist/options/SetContinuousTestOption.d.ts +1 -1
- package/dist/options/SetContinuousTestOption.js +1 -1
- package/dist/options/SetDeviceOption.d.ts +1 -1
- package/dist/options/SetDeviceOption.js +1 -1
- package/dist/options/SetWorkingDirectoryOption.d.ts +1 -1
- package/dist/options/SetWorkingDirectoryOption.js +1 -1
- package/dist/options/SilentOption.d.ts +1 -1
- package/dist/options/SilentOption.js +1 -1
- package/dist/options/SkipExtraOperationOption.d.ts +1 -1
- package/dist/options/SkipExtraOperationOption.js +1 -1
- package/dist/options/SkipGCOption.d.ts +1 -1
- package/dist/options/SkipGCOption.js +1 -1
- package/dist/options/SkipScreenshotOption.d.ts +1 -1
- package/dist/options/SkipScreenshotOption.js +1 -1
- package/dist/options/SkipScrollOption.d.ts +1 -1
- package/dist/options/SkipScrollOption.js +1 -1
- package/dist/options/SkipSnapshotOption.d.ts +1 -1
- package/dist/options/SkipSnapshotOption.js +1 -1
- package/dist/options/SkipWarmupOption.d.ts +1 -1
- package/dist/options/SkipWarmupOption.js +1 -1
- package/dist/options/VerboseOption.d.ts +1 -1
- package/dist/options/VerboseOption.js +1 -1
- package/dist/options/heap/BaselineFileOption.d.ts +1 -1
- package/dist/options/heap/BaselineFileOption.js +1 -1
- package/dist/options/heap/FinalFileOption.d.ts +1 -1
- package/dist/options/heap/FinalFileOption.js +1 -1
- package/dist/options/heap/JSEngineOption.d.ts +1 -1
- package/dist/options/heap/JSEngineOption.js +1 -1
- package/dist/options/heap/LeakClusterSizeThresholdOption.d.ts +1 -1
- package/dist/options/heap/LeakClusterSizeThresholdOption.js +1 -1
- package/dist/options/heap/LogTraceAsClusterOption.d.ts +1 -1
- package/dist/options/heap/LogTraceAsClusterOption.js +1 -1
- package/dist/options/heap/OversizeThresholdOption.d.ts +1 -1
- package/dist/options/heap/OversizeThresholdOption.js +1 -1
- package/dist/options/heap/SnapshotDirectoryOption.d.ts +1 -1
- package/dist/options/heap/SnapshotDirectoryOption.js +1 -1
- package/dist/options/heap/SnapshotFileOption.d.ts +1 -1
- package/dist/options/heap/SnapshotFileOption.js +1 -1
- package/dist/options/heap/TargetFileOption.d.ts +1 -1
- package/dist/options/heap/TargetFileOption.js +1 -1
- package/dist/options/heap/TraceAllObjectsOption.d.ts +1 -1
- package/dist/options/heap/TraceAllObjectsOption.js +1 -1
- package/dist/options/heap/leak-filter/LeakFilterFileOption.d.ts +1 -1
- package/dist/options/heap/leak-filter/LeakFilterFileOption.js +1 -1
- package/dist/options/heap/leak-filter/examples/FilterLib.d.ts +1 -1
- package/dist/options/heap/leak-filter/examples/FilterLib.js +1 -1
- package/dist/options/heap/leak-filter/examples/dup-string-as-leak.example-1.d.ts +1 -1
- package/dist/options/heap/leak-filter/examples/dup-string-as-leak.example-1.js +1 -1
- package/dist/options/heap/leak-filter/examples/dup-string-as-leak.example-2.d.ts +1 -1
- package/dist/options/heap/leak-filter/examples/dup-string-as-leak.example-2.js +1 -1
- package/dist/options/lib/UniversalOptions.d.ts +1 -1
- package/dist/options/lib/UniversalOptions.js +1 -1
- package/dist/runner.d.ts +1 -1
- package/dist/runner.js +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
* @oncall ws_labs
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
35
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
36
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
37
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
38
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
39
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
40
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
44
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
45
|
+
};
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
48
|
+
const BaseCommand_1 = __importStar(require("../../../BaseCommand"));
|
|
49
|
+
const core_1 = require("@memlab/core");
|
|
50
|
+
const SnapshotFileOption_1 = __importDefault(require("../../../options/heap/SnapshotFileOption"));
|
|
51
|
+
const JSEngineOption_1 = __importDefault(require("../../../options/heap/JSEngineOption"));
|
|
52
|
+
const core_2 = require("@memlab/core");
|
|
53
|
+
const heap_analysis_1 = require("@memlab/heap-analysis");
|
|
54
|
+
const CliScreen_1 = __importDefault(require("./ui-components/CliScreen"));
|
|
55
|
+
const HeapNodeIdOption_1 = __importDefault(require("../../../options/HeapNodeIdOption"));
|
|
56
|
+
class InteractiveHeapViewCommand extends BaseCommand_1.default {
|
|
57
|
+
getCommandName() {
|
|
58
|
+
return 'view-heap';
|
|
59
|
+
}
|
|
60
|
+
getDescription() {
|
|
61
|
+
return 'interactive command to view a single heap snapshot';
|
|
62
|
+
}
|
|
63
|
+
getCategory() {
|
|
64
|
+
return BaseCommand_1.CommandCategory.COMMON;
|
|
65
|
+
}
|
|
66
|
+
getExamples() {
|
|
67
|
+
return ['--snapshot <HEAP_SNAPSHOT_FILE>'];
|
|
68
|
+
}
|
|
69
|
+
getOptions() {
|
|
70
|
+
return [
|
|
71
|
+
new SnapshotFileOption_1.default(),
|
|
72
|
+
new JSEngineOption_1.default(),
|
|
73
|
+
new HeapNodeIdOption_1.default(),
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
// get the heap snapshot to view
|
|
77
|
+
getHeap(options) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
// load single heap snapshot
|
|
80
|
+
heap_analysis_1.heapConfig.isCliInteractiveMode = true;
|
|
81
|
+
yield (0, heap_analysis_1.loadHeapSnapshot)({ args: options.cliArgs });
|
|
82
|
+
// get heap
|
|
83
|
+
const heap = heap_analysis_1.heapConfig.currentHeap;
|
|
84
|
+
if (!heap) {
|
|
85
|
+
throw core_1.utils.haltOrThrow('heap snapshot not found, please specify a heap snapshot ' +
|
|
86
|
+
`via --${new SnapshotFileOption_1.default().getOptionName()}`);
|
|
87
|
+
}
|
|
88
|
+
return heap;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
getNodesToFocus(heap) {
|
|
92
|
+
const nodes = this.getNodesWithLargestRetainedSize(heap);
|
|
93
|
+
nodes.push(...this.getDetachedNodes(heap));
|
|
94
|
+
return nodes;
|
|
95
|
+
}
|
|
96
|
+
getDetachedNodes(heap) {
|
|
97
|
+
const ret = [];
|
|
98
|
+
heap.nodes.forEach(node => {
|
|
99
|
+
if (core_1.utils.isDetachedDOMNode(node) || core_1.utils.isDetachedFiberNode(node)) {
|
|
100
|
+
ret.push({ tag: 'Detached', heapObject: node });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return ret;
|
|
104
|
+
}
|
|
105
|
+
getNodesWithLargestRetainedSize(heap) {
|
|
106
|
+
const sizeThreshold = 2 * 1024 * 1024; // 2MB
|
|
107
|
+
const ret = [];
|
|
108
|
+
heap.nodes.forEach(node => {
|
|
109
|
+
if (node.retainedSize >= sizeThreshold && !core_1.utils.isRootNode(node)) {
|
|
110
|
+
ret.push({
|
|
111
|
+
tag: `${core_1.utils.getReadableBytes(node.retainedSize)}`,
|
|
112
|
+
heapObject: node,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
return ret;
|
|
117
|
+
}
|
|
118
|
+
// get heap node to focus on
|
|
119
|
+
getHeapNodes(heap) {
|
|
120
|
+
if (core_1.config.focusFiberNodeId >= 0) {
|
|
121
|
+
const node = heap.getNodeById(core_1.config.focusFiberNodeId);
|
|
122
|
+
if (node) {
|
|
123
|
+
return [{ heapObject: node }];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const nodes = this.getNodesToFocus(heap);
|
|
127
|
+
if (nodes.length === 0) {
|
|
128
|
+
throw core_1.utils.haltOrThrow('please specify a heap node ' +
|
|
129
|
+
`via --${new HeapNodeIdOption_1.default().getOptionName()}`);
|
|
130
|
+
}
|
|
131
|
+
return nodes;
|
|
132
|
+
}
|
|
133
|
+
run(options) {
|
|
134
|
+
var _a;
|
|
135
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
136
|
+
const workDir = (_a = options.configFromOptions) === null || _a === void 0 ? void 0 : _a.workDir;
|
|
137
|
+
const reportOutDir = core_2.fileManager.getReportOutDir({ workDir });
|
|
138
|
+
fs_extra_1.default.emptyDirSync(reportOutDir);
|
|
139
|
+
const heap = yield this.getHeap(options);
|
|
140
|
+
const nodes = this.getHeapNodes(heap);
|
|
141
|
+
new CliScreen_1.default('memlab heap viewer', heap, nodes).start();
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.default = InteractiveHeapViewCommand;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { IHeapSnapshot } from '@memlab/core';
|
|
2
|
+
import { ComponentDataItem } from './HeapViewUtils';
|
|
3
|
+
export default class CliScreen {
|
|
4
|
+
private screen;
|
|
5
|
+
private objectBox;
|
|
6
|
+
private parentObjectBox;
|
|
7
|
+
private referrerBox;
|
|
8
|
+
private referenceBox;
|
|
9
|
+
private objectPropertyBox;
|
|
10
|
+
private retainerTraceBox;
|
|
11
|
+
private currentFocuseKey;
|
|
12
|
+
private keyToComponent;
|
|
13
|
+
private heapController;
|
|
14
|
+
constructor(title: string, heap: IHeapSnapshot, nodes: ComponentDataItem[]);
|
|
15
|
+
private initScreen;
|
|
16
|
+
private initCallbacks;
|
|
17
|
+
start(): void;
|
|
18
|
+
private registerEvents;
|
|
19
|
+
private registerScreenResize;
|
|
20
|
+
private updateComponentSize;
|
|
21
|
+
private registerKeys;
|
|
22
|
+
private addComponentToFocusKeyMap;
|
|
23
|
+
private getNextFocusKey;
|
|
24
|
+
private getLabel;
|
|
25
|
+
private initParentObjectBox;
|
|
26
|
+
private getParentObjectBoxSize;
|
|
27
|
+
private initReferrerBox;
|
|
28
|
+
private getReferrerBoxSize;
|
|
29
|
+
private initObjectBox;
|
|
30
|
+
private getObjectBoxSize;
|
|
31
|
+
private initObjectPropertyBox;
|
|
32
|
+
private getObjectPropertyBoxSize;
|
|
33
|
+
private initReferenceBox;
|
|
34
|
+
private getReferenceBoxSize;
|
|
35
|
+
private initRetainerTraceBox;
|
|
36
|
+
private getRetainerTraceBoxSize;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=CliScreen.d.ts.map
|
|
@@ -0,0 +1,234 @@
|
|
|
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 HeapViewUtils_1 = require("./HeapViewUtils");
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const blessed_1 = __importDefault(require("blessed"));
|
|
9
|
+
const ListComponent_1 = __importDefault(require("./ListComponent"));
|
|
10
|
+
const HeapViewController_1 = __importDefault(require("./HeapViewController"));
|
|
11
|
+
function positionToNumber(info) {
|
|
12
|
+
return parseInt(`${info}`);
|
|
13
|
+
}
|
|
14
|
+
/*
|
|
15
|
+
* The CliScreen component managers the screen layout
|
|
16
|
+
* all the UI components in CLI.
|
|
17
|
+
*
|
|
18
|
+
* Screen Layout:
|
|
19
|
+
* ┌─Referrers of [*] ─┐┌─Objects ──────────┐┌─References ───────┐
|
|
20
|
+
* │ ││ ││ │
|
|
21
|
+
* │ ││ ││ │
|
|
22
|
+
* │ ││ ││ │
|
|
23
|
+
* │ ││ ││ │
|
|
24
|
+
* │ ││ │└───────────────────┘
|
|
25
|
+
* │ ││ │┌─Retainer Trace ───┐
|
|
26
|
+
* │ ││ ││ │
|
|
27
|
+
* │ ││ ││ │
|
|
28
|
+
* └───────────────────┘│ ││ │
|
|
29
|
+
* ┌─Referrers ────────┐│ ││ │
|
|
30
|
+
* │ ││ ││ │
|
|
31
|
+
* │ │└───────────────────┘│ │
|
|
32
|
+
* │ │┌─Object Detail ────┐│ │
|
|
33
|
+
* │ ││ ││ │
|
|
34
|
+
* │ ││ ││ │
|
|
35
|
+
* │ ││ ││ │
|
|
36
|
+
* │ ││ ││ │
|
|
37
|
+
* │ ││ ││ │
|
|
38
|
+
* └───────────────────┘└───────────────────┘└───────────────────┘
|
|
39
|
+
*/
|
|
40
|
+
class CliScreen {
|
|
41
|
+
constructor(title, heap, nodes) {
|
|
42
|
+
this.currentFocuseKey = 1;
|
|
43
|
+
this.heapController = new HeapViewController_1.default(heap, nodes);
|
|
44
|
+
this.screen = this.initScreen(title);
|
|
45
|
+
const callbacks = this.initCallbacks(this.heapController, this.screen);
|
|
46
|
+
this.keyToComponent = new Map();
|
|
47
|
+
this.referrerBox = this.initReferrerBox(callbacks);
|
|
48
|
+
this.heapController.setReferrerBox(this.referrerBox);
|
|
49
|
+
this.parentObjectBox = this.initParentObjectBox(callbacks);
|
|
50
|
+
this.heapController.setParentBox(this.parentObjectBox);
|
|
51
|
+
this.objectBox = this.initObjectBox(callbacks);
|
|
52
|
+
this.heapController.setObjectBox(this.objectBox);
|
|
53
|
+
this.referenceBox = this.initReferenceBox(callbacks);
|
|
54
|
+
this.heapController.setReferenceBox(this.referenceBox);
|
|
55
|
+
this.objectPropertyBox = this.initObjectPropertyBox(callbacks);
|
|
56
|
+
this.heapController.setObjectPropertyBox(this.objectPropertyBox);
|
|
57
|
+
this.retainerTraceBox = this.initRetainerTraceBox(callbacks);
|
|
58
|
+
this.heapController.setRetainerTraceBox(this.retainerTraceBox);
|
|
59
|
+
this.registerEvents();
|
|
60
|
+
this.heapController.setCurrentHeapObject((0, HeapViewUtils_1.getHeapObjectAt)(nodes, 0));
|
|
61
|
+
}
|
|
62
|
+
initScreen(title) {
|
|
63
|
+
return blessed_1.default.screen({
|
|
64
|
+
smartCSR: true,
|
|
65
|
+
title: title,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
initCallbacks(controller, screen) {
|
|
69
|
+
const selectDebounce = (0, HeapViewUtils_1.debounce)(150);
|
|
70
|
+
const selectCallback = (componentId, index, content, selectInfo) => {
|
|
71
|
+
if (selectInfo.keyName === 'enter') {
|
|
72
|
+
selectDebounce(() => {
|
|
73
|
+
controller.setCurrentHeapObjectFromComponent(componentId, index);
|
|
74
|
+
screen.render();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else if (selectInfo.keyName === 'up' || selectInfo.keyName === 'down') {
|
|
78
|
+
selectDebounce(() => {
|
|
79
|
+
controller.setSelectedHeapObjectFromComponent(componentId, index);
|
|
80
|
+
screen.render();
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
selectCallback,
|
|
86
|
+
render: () => screen.render(),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
start() {
|
|
90
|
+
this.screen.render();
|
|
91
|
+
}
|
|
92
|
+
registerEvents() {
|
|
93
|
+
this.registerKeys();
|
|
94
|
+
this.registerScreenResize();
|
|
95
|
+
}
|
|
96
|
+
registerScreenResize() {
|
|
97
|
+
const screen = this.screen;
|
|
98
|
+
screen.on('resize', () => {
|
|
99
|
+
// all boxes/lists needs to resize
|
|
100
|
+
this.updateComponentSize(this.parentObjectBox, this.getParentObjectBoxSize());
|
|
101
|
+
this.updateComponentSize(this.referrerBox, this.getReferrerBoxSize());
|
|
102
|
+
this.updateComponentSize(this.objectBox, this.getObjectBoxSize());
|
|
103
|
+
this.updateComponentSize(this.objectPropertyBox, this.getObjectPropertyBoxSize());
|
|
104
|
+
this.updateComponentSize(this.referenceBox, this.getReferenceBoxSize());
|
|
105
|
+
this.updateComponentSize(this.retainerTraceBox, this.getRetainerTraceBoxSize());
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
updateComponentSize(component, size) {
|
|
109
|
+
component.element.width = size.width;
|
|
110
|
+
component.element.height = size.height;
|
|
111
|
+
component.element.top = size.top;
|
|
112
|
+
component.element.left = size.left;
|
|
113
|
+
}
|
|
114
|
+
registerKeys() {
|
|
115
|
+
const screen = this.screen;
|
|
116
|
+
// Quit on Escape, q, or Control-C.
|
|
117
|
+
screen.key(['escape', 'q', 'C-c'], () => process.exit(0));
|
|
118
|
+
const keyToComponent = this.keyToComponent;
|
|
119
|
+
const heapController = this.heapController;
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
121
|
+
const callback = (char, key) => {
|
|
122
|
+
if (keyToComponent.has(char)) {
|
|
123
|
+
// focus on the selected element
|
|
124
|
+
const component = keyToComponent.get(char);
|
|
125
|
+
if (component) {
|
|
126
|
+
heapController.focusOnComponent(component.id);
|
|
127
|
+
screen.render();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
screen.on('keypress', callback);
|
|
132
|
+
}
|
|
133
|
+
addComponentToFocusKeyMap(component) {
|
|
134
|
+
const key = `${this.currentFocuseKey++}`;
|
|
135
|
+
this.keyToComponent.set(key, component);
|
|
136
|
+
return key;
|
|
137
|
+
}
|
|
138
|
+
getNextFocusKey() {
|
|
139
|
+
return `${this.currentFocuseKey}`;
|
|
140
|
+
}
|
|
141
|
+
getLabel(text, key) {
|
|
142
|
+
return `${text}` + chalk_1.default.grey(` (press ${chalk_1.default.inverse(key)} to focus)`);
|
|
143
|
+
}
|
|
144
|
+
initParentObjectBox(callbacks) {
|
|
145
|
+
const box = new ListComponent_1.default([], callbacks, Object.assign(Object.assign({}, this.getParentObjectBoxSize()), { label: this.getLabel('Referrers of Current', this.getNextFocusKey()) }));
|
|
146
|
+
this.screen.append(box.element);
|
|
147
|
+
this.addComponentToFocusKeyMap(box);
|
|
148
|
+
return box;
|
|
149
|
+
}
|
|
150
|
+
getParentObjectBoxSize() {
|
|
151
|
+
return {
|
|
152
|
+
width: Math.floor(positionToNumber(this.screen.width) / 3),
|
|
153
|
+
height: positionToNumber(this.screen.height) -
|
|
154
|
+
Math.floor(positionToNumber(this.screen.height) / 2),
|
|
155
|
+
top: Math.floor(positionToNumber(this.screen.height) / 2),
|
|
156
|
+
left: 0,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
initReferrerBox(callbacks) {
|
|
160
|
+
const box = new ListComponent_1.default([], callbacks, Object.assign(Object.assign({}, this.getReferrerBoxSize()), { label: this.getLabel('Referrers', this.getNextFocusKey()) }));
|
|
161
|
+
this.screen.append(box.element);
|
|
162
|
+
this.addComponentToFocusKeyMap(box);
|
|
163
|
+
return box;
|
|
164
|
+
}
|
|
165
|
+
getReferrerBoxSize() {
|
|
166
|
+
return {
|
|
167
|
+
width: Math.floor(positionToNumber(this.screen.width) / 3),
|
|
168
|
+
height: Math.floor(positionToNumber(this.screen.height) / 2),
|
|
169
|
+
top: 0,
|
|
170
|
+
left: 0,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
initObjectBox(callbacks) {
|
|
174
|
+
const box = new ListComponent_1.default([], callbacks, Object.assign(Object.assign({}, this.getObjectBoxSize()), { label: this.getLabel('Objects', this.getNextFocusKey()) }));
|
|
175
|
+
this.screen.append(box.element);
|
|
176
|
+
this.addComponentToFocusKeyMap(box);
|
|
177
|
+
return box;
|
|
178
|
+
}
|
|
179
|
+
getObjectBoxSize() {
|
|
180
|
+
return {
|
|
181
|
+
width: Math.floor(positionToNumber(this.screen.width) / 3),
|
|
182
|
+
height: Math.floor((2 * positionToNumber(this.screen.height)) / 3),
|
|
183
|
+
top: 0,
|
|
184
|
+
left: Math.floor(positionToNumber(this.screen.width) / 3),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
initObjectPropertyBox(callbacks) {
|
|
188
|
+
const box = new ListComponent_1.default([], callbacks, Object.assign(Object.assign({}, this.getObjectPropertyBoxSize()), { label: this.getLabel('Object Detail', this.getNextFocusKey()) }));
|
|
189
|
+
this.screen.append(box.element);
|
|
190
|
+
this.addComponentToFocusKeyMap(box);
|
|
191
|
+
return box;
|
|
192
|
+
}
|
|
193
|
+
getObjectPropertyBoxSize() {
|
|
194
|
+
return {
|
|
195
|
+
width: Math.floor(positionToNumber(this.screen.width) / 3),
|
|
196
|
+
height: positionToNumber(this.screen.height) -
|
|
197
|
+
Math.floor((2 * positionToNumber(this.screen.height)) / 3),
|
|
198
|
+
top: Math.floor((2 * positionToNumber(this.screen.height)) / 3),
|
|
199
|
+
left: Math.floor(positionToNumber(this.screen.width) / 3),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
initReferenceBox(callbacks) {
|
|
203
|
+
const box = new ListComponent_1.default([], callbacks, Object.assign(Object.assign({}, this.getReferenceBoxSize()), { label: this.getLabel('References', this.getNextFocusKey()) }));
|
|
204
|
+
this.screen.append(box.element);
|
|
205
|
+
this.addComponentToFocusKeyMap(box);
|
|
206
|
+
return box;
|
|
207
|
+
}
|
|
208
|
+
getReferenceBoxSize() {
|
|
209
|
+
return {
|
|
210
|
+
width: positionToNumber(this.screen.width) -
|
|
211
|
+
Math.floor((2 * positionToNumber(this.screen.width)) / 3),
|
|
212
|
+
height: Math.floor(positionToNumber(this.screen.height) / 3),
|
|
213
|
+
top: 0,
|
|
214
|
+
left: Math.floor((2 * positionToNumber(this.screen.width)) / 3),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
initRetainerTraceBox(callbacks) {
|
|
218
|
+
const box = new ListComponent_1.default([], callbacks, Object.assign(Object.assign({}, this.getRetainerTraceBoxSize()), { label: this.getLabel('Retainer Trace', this.getNextFocusKey()) }));
|
|
219
|
+
this.screen.append(box.element);
|
|
220
|
+
this.addComponentToFocusKeyMap(box);
|
|
221
|
+
return box;
|
|
222
|
+
}
|
|
223
|
+
getRetainerTraceBoxSize() {
|
|
224
|
+
return {
|
|
225
|
+
width: positionToNumber(this.screen.width) -
|
|
226
|
+
Math.floor((2 * positionToNumber(this.screen.width)) / 3),
|
|
227
|
+
height: positionToNumber(this.screen.height) -
|
|
228
|
+
Math.floor(positionToNumber(this.screen.height) / 3),
|
|
229
|
+
top: Math.floor(positionToNumber(this.screen.height) / 3),
|
|
230
|
+
left: Math.floor((2 * positionToNumber(this.screen.width)) / 3),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
exports.default = CliScreen;
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* HeapViewController managers all the data associated with each
|
|
21
|
+
* UI components in CLI and coordinates the events/interaction
|
|
22
|
+
* among all UI components.
|
|
23
|
+
*/
|
|
24
|
+
export default class HeapViewController {
|
|
25
|
+
private currentHeapObject;
|
|
26
|
+
private selectedHeapObject;
|
|
27
|
+
private currentHeapObjectsInfo;
|
|
28
|
+
private componentIdToDataMap;
|
|
29
|
+
private componentIdToComponentMap;
|
|
30
|
+
private heap;
|
|
31
|
+
private parentBox;
|
|
32
|
+
private referrerBox;
|
|
33
|
+
private objectBox;
|
|
34
|
+
private referenceBox;
|
|
35
|
+
private objectPropertyBox;
|
|
36
|
+
private retainerTracePropertyBox;
|
|
37
|
+
constructor(heap: IHeapSnapshot, nodes: ComponentDataItem[]);
|
|
38
|
+
getContent(componentId: number): string[];
|
|
39
|
+
setParentBox(component: ListComponent): void;
|
|
40
|
+
setReferrerBox(component: ListComponent): void;
|
|
41
|
+
getReferrerBoxData(node?: IHeapNode): ComponentData;
|
|
42
|
+
setObjectBox(component: ListComponent): void;
|
|
43
|
+
getObjectBoxData(): ComponentData;
|
|
44
|
+
setReferenceBox(component: ListComponent): void;
|
|
45
|
+
getReferenceBoxData(): ComponentData;
|
|
46
|
+
setObjectPropertyBox(component: ListComponent): void;
|
|
47
|
+
getObjectPropertyData(): ComponentData;
|
|
48
|
+
private getKeyValuePairString;
|
|
49
|
+
setRetainerTraceBox(component: ListComponent): void;
|
|
50
|
+
getRetainerTraceData(): ComponentData;
|
|
51
|
+
setCurrentHeapObjectFromComponent(componentId: number, itemIndex: number): void;
|
|
52
|
+
setCurrentHeapObject(node: IHeapNode): void;
|
|
53
|
+
focusOnComponent(componentId: number): void;
|
|
54
|
+
setSelectedHeapObjectFromComponent(componentId: number, itemIndex: number): void;
|
|
55
|
+
setSelectedHeapObject(node: IHeapNode, options?: SelectHeapObjectOption): void;
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=HeapViewController.d.ts.map
|