@memlab/cli 1.0.17 → 1.0.20
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/bin/memlab.js +1 -1
- package/dist/commands/RunMeasureCommand.js +2 -0
- package/dist/commands/WarmupAppCommand.js +2 -0
- package/dist/commands/heap/interactive/ui-components/CliScreen.js +13 -1
- package/dist/commands/heap/interactive/ui-components/HeapViewController.d.ts +7 -10
- package/dist/commands/heap/interactive/ui-components/HeapViewController.js +70 -19
- package/dist/commands/heap/interactive/ui-components/ListComponent.d.ts +8 -1
- package/dist/commands/heap/interactive/ui-components/ListComponent.js +28 -3
- package/dist/commands/heap/interactive/worker/LocateClosureSourceWorker.d.ts +11 -0
- package/dist/commands/heap/interactive/worker/LocateClosureSourceWorker.js +69 -0
- package/dist/commands/snapshot/TakeSnapshotCommand.js +2 -0
- package/dist/options/DebugOption.js +6 -2
- package/dist/options/HelperOption.js +6 -2
- package/dist/options/MLClusteringLinkageMaxDistanceOption.js +9 -3
- package/dist/options/MLClusteringMaxDFOption.js +9 -3
- package/dist/options/MLClusteringOption.js +7 -2
- package/dist/options/NumberOfRunsOption.js +5 -1
- package/dist/options/SetContinuousTestOption.js +7 -2
- package/dist/options/SetWorkingDirectoryOption.js +5 -1
- package/dist/options/SilentOption.js +6 -2
- package/dist/options/VerboseOption.js +6 -2
- package/dist/options/constant.d.ts +50 -0
- package/dist/options/constant.js +52 -0
- package/dist/options/e2e/AppOption.js +9 -5
- package/dist/options/e2e/DisableWebSecurityOption.js +5 -1
- package/dist/options/e2e/DisableXvfbOption.js +6 -2
- package/dist/options/e2e/EnableJSInterceptOption.d.ts +18 -0
- package/dist/options/e2e/EnableJSInterceptOption.js +42 -0
- package/dist/options/e2e/EnableJSRewriteOption.js +8 -1
- package/dist/options/e2e/FullExecutionOption.js +6 -2
- package/dist/options/e2e/HeadfulBrowserOption.js +6 -2
- package/dist/options/e2e/InteractionOption.js +9 -5
- package/dist/options/e2e/RemoteBrowserDebugOption.js +6 -2
- package/dist/options/e2e/RunningModeOption.js +6 -2
- package/dist/options/e2e/ScenarioFileOption.js +9 -3
- package/dist/options/e2e/SetDeviceOption.js +9 -3
- package/dist/options/e2e/SetUserAgentOption.js +5 -1
- package/dist/options/e2e/SkipExtraOperationOption.js +7 -2
- package/dist/options/e2e/SkipGCOption.js +5 -1
- package/dist/options/e2e/SkipScreenshotOption.js +6 -2
- package/dist/options/e2e/SkipScrollOption.js +6 -2
- package/dist/options/e2e/SkipSnapshotOption.js +6 -2
- package/dist/options/e2e/SkipWarmupOption.js +5 -1
- package/dist/options/heap/BaselineFileOption.js +5 -3
- package/dist/options/heap/FinalFileOption.js +5 -3
- package/dist/options/heap/HeapNodeIdOption.js +5 -1
- package/dist/options/heap/JSEngineOption.js +8 -3
- package/dist/options/heap/LeakClusterSizeThresholdOption.js +5 -1
- package/dist/options/heap/LogTraceAsClusterOption.js +5 -1
- package/dist/options/heap/OversizeThresholdOption.js +5 -1
- package/dist/options/heap/SnapshotDirectoryOption.js +5 -3
- package/dist/options/heap/SnapshotFileOption.js +5 -3
- package/dist/options/heap/TargetFileOption.js +5 -3
- package/dist/options/heap/TraceAllObjectsOption.js +5 -1
- package/dist/options/heap/leak-filter/LeakFilterFileOption.js +5 -1
- package/dist/options/lib/OptionConstant.d.ts +116 -0
- package/dist/options/lib/OptionConstant.js +67 -0
- package/package.json +2 -2
package/bin/memlab.js
CHANGED
|
@@ -44,6 +44,7 @@ const NumberOfRunsOption_1 = __importDefault(require("../options/NumberOfRunsOpt
|
|
|
44
44
|
const HeadfulBrowserOption_1 = __importDefault(require("../options/e2e/HeadfulBrowserOption"));
|
|
45
45
|
const DisableWebSecurityOption_1 = __importDefault(require("../options/e2e/DisableWebSecurityOption"));
|
|
46
46
|
const EnableJSRewriteOption_1 = __importDefault(require("../options/e2e/EnableJSRewriteOption"));
|
|
47
|
+
const EnableJSInterceptOption_1 = __importDefault(require("../options/e2e/EnableJSInterceptOption"));
|
|
47
48
|
class RunMeasureCommand extends BaseCommand_1.default {
|
|
48
49
|
getCommandName() {
|
|
49
50
|
return 'measure';
|
|
@@ -81,6 +82,7 @@ class RunMeasureCommand extends BaseCommand_1.default {
|
|
|
81
82
|
new DisableXvfbOption_1.default(),
|
|
82
83
|
new DisableWebSecurityOption_1.default(),
|
|
83
84
|
new EnableJSRewriteOption_1.default(),
|
|
85
|
+
new EnableJSInterceptOption_1.default(),
|
|
84
86
|
];
|
|
85
87
|
}
|
|
86
88
|
run(options) {
|
|
@@ -37,6 +37,7 @@ const CheckXvfbSupportCommand_1 = __importDefault(require("./snapshot/CheckXvfbS
|
|
|
37
37
|
const HeadfulBrowserOption_1 = __importDefault(require("../options/e2e/HeadfulBrowserOption"));
|
|
38
38
|
const DisableWebSecurityOption_1 = __importDefault(require("../options/e2e/DisableWebSecurityOption"));
|
|
39
39
|
const EnableJSRewriteOption_1 = __importDefault(require("../options/e2e/EnableJSRewriteOption"));
|
|
40
|
+
const EnableJSInterceptOption_1 = __importDefault(require("../options/e2e/EnableJSInterceptOption"));
|
|
40
41
|
class FBWarmupAppCommand extends BaseCommand_1.default {
|
|
41
42
|
getCommandName() {
|
|
42
43
|
return 'warmup';
|
|
@@ -67,6 +68,7 @@ class FBWarmupAppCommand extends BaseCommand_1.default {
|
|
|
67
68
|
new DisableWebSecurityOption_1.default(),
|
|
68
69
|
new SkipWarmupOption_1.default(),
|
|
69
70
|
new EnableJSRewriteOption_1.default(),
|
|
71
|
+
new EnableJSInterceptOption_1.default(),
|
|
70
72
|
];
|
|
71
73
|
}
|
|
72
74
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -85,7 +85,13 @@ class CliScreen {
|
|
|
85
85
|
initCallbacks(controller, screen) {
|
|
86
86
|
const selectDebounce = (0, HeapViewUtils_1.debounce)(150);
|
|
87
87
|
const selectCallback = (componentId, index, content, selectInfo) => {
|
|
88
|
-
if (selectInfo.keyName === '
|
|
88
|
+
if (selectInfo.keyName === 'd' || selectInfo.keyName === 'D') {
|
|
89
|
+
selectDebounce(() => {
|
|
90
|
+
controller.displaySourceCode(componentId, index);
|
|
91
|
+
screen.render();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else if (selectInfo.keyName === 'enter') {
|
|
89
95
|
selectDebounce(() => {
|
|
90
96
|
controller.setCurrentHeapObjectFromComponent(componentId, index);
|
|
91
97
|
screen.render();
|
|
@@ -161,6 +167,7 @@ class CliScreen {
|
|
|
161
167
|
}
|
|
162
168
|
initClusteredObjectBox(callbacks) {
|
|
163
169
|
const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getClusteredObjectBoxSize()));
|
|
170
|
+
box.setController(this.heapController);
|
|
164
171
|
box.setFocusKey(this.getNextFocusKey());
|
|
165
172
|
box.setLabel('Clustered Objects');
|
|
166
173
|
this.screen.append(box.element);
|
|
@@ -177,6 +184,7 @@ class CliScreen {
|
|
|
177
184
|
}
|
|
178
185
|
initReferrerBox(callbacks) {
|
|
179
186
|
const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getReferrerBoxSize()));
|
|
187
|
+
box.setController(this.heapController);
|
|
180
188
|
box.setFocusKey(this.getNextFocusKey());
|
|
181
189
|
box.setLabel('Referrers');
|
|
182
190
|
this.screen.append(box.element);
|
|
@@ -193,6 +201,7 @@ class CliScreen {
|
|
|
193
201
|
}
|
|
194
202
|
initObjectBox(callbacks) {
|
|
195
203
|
const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getObjectBoxSize()));
|
|
204
|
+
box.setController(this.heapController);
|
|
196
205
|
box.setFocusKey(this.getNextFocusKey());
|
|
197
206
|
box.setLabel('Objects');
|
|
198
207
|
this.screen.append(box.element);
|
|
@@ -211,6 +220,7 @@ class CliScreen {
|
|
|
211
220
|
}
|
|
212
221
|
initObjectPropertyBox(callbacks) {
|
|
213
222
|
const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getObjectPropertyBoxSize()));
|
|
223
|
+
box.setController(this.heapController);
|
|
214
224
|
box.setFocusKey(this.getNextFocusKey());
|
|
215
225
|
box.setLabel('Objects Detail');
|
|
216
226
|
this.screen.append(box.element);
|
|
@@ -229,6 +239,7 @@ class CliScreen {
|
|
|
229
239
|
}
|
|
230
240
|
initReferenceBox(callbacks) {
|
|
231
241
|
const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getReferenceBoxSize()));
|
|
242
|
+
box.setController(this.heapController);
|
|
232
243
|
box.setFocusKey(this.getNextFocusKey());
|
|
233
244
|
box.setLabel('References');
|
|
234
245
|
this.screen.append(box.element);
|
|
@@ -246,6 +257,7 @@ class CliScreen {
|
|
|
246
257
|
}
|
|
247
258
|
initRetainerTraceBox(callbacks) {
|
|
248
259
|
const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getRetainerTraceBoxSize()));
|
|
260
|
+
box.setController(this.heapController);
|
|
249
261
|
box.setFocusKey(this.getNextFocusKey());
|
|
250
262
|
box.setLabel('Retainer Trace');
|
|
251
263
|
this.screen.append(box.element);
|
|
@@ -1,13 +1,4 @@
|
|
|
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 web_perf_infra
|
|
9
|
-
*/
|
|
10
|
-
import type { IHeapSnapshot, IHeapNode } from '@memlab/core';
|
|
1
|
+
import type { IHeapSnapshot, IHeapNode, Nullable } from '@memlab/core';
|
|
11
2
|
import type ListComponent from './ListComponent';
|
|
12
3
|
import { ComponentDataItem, ComponentData } from './HeapViewUtils';
|
|
13
4
|
declare type SelectHeapObjectOption = {
|
|
@@ -37,11 +28,13 @@ export default class HeapViewController {
|
|
|
37
28
|
private referenceBox;
|
|
38
29
|
private objectPropertyBox;
|
|
39
30
|
private retainerTracePropertyBox;
|
|
31
|
+
private scriptManager;
|
|
40
32
|
constructor(heap: IHeapSnapshot, objectCategory: ObjectCategory);
|
|
41
33
|
private getFlattenHeapObjectsInfo;
|
|
42
34
|
private getFlattenClusteredObjectsInfo;
|
|
43
35
|
private shouldClusterCategory;
|
|
44
36
|
private clusterComponentDataItems;
|
|
37
|
+
getComponentDataById(componentId: number): Nullable<ComponentData>;
|
|
45
38
|
getContent(componentId: number): string[];
|
|
46
39
|
setClusteredBox(component: ListComponent): void;
|
|
47
40
|
getClusteredBoxData(): ComponentData;
|
|
@@ -59,6 +52,10 @@ export default class HeapViewController {
|
|
|
59
52
|
private getKeyValuePairString;
|
|
60
53
|
setRetainerTraceBox(component: ListComponent): void;
|
|
61
54
|
getRetainerTraceData(): ComponentData;
|
|
55
|
+
private getHeapObject;
|
|
56
|
+
displaySourceCode(componentId: number, itemIndex: number): void;
|
|
57
|
+
private displayClosureInfo;
|
|
58
|
+
private getClosureNodeScopeVarEdges;
|
|
62
59
|
setCurrentHeapObjectFromComponent(componentId: number, itemIndex: number, options?: {
|
|
63
60
|
skipFocus?: boolean;
|
|
64
61
|
}): void;
|
|
@@ -3,8 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const path_1 = __importDefault(require("path"));
|
|
6
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const worker_threads_1 = require("worker_threads");
|
|
7
9
|
const core_1 = require("@memlab/core");
|
|
10
|
+
const e2e_1 = require("@memlab/e2e");
|
|
8
11
|
const HeapViewUtils_1 = require("./HeapViewUtils");
|
|
9
12
|
/**
|
|
10
13
|
* HeapViewController managers all the data associated with each
|
|
@@ -21,6 +24,8 @@ class HeapViewController {
|
|
|
21
24
|
this.currentHeapObject = (0, HeapViewUtils_1.getHeapObjectAt)(this.currentHeapObjectsInfo, 0);
|
|
22
25
|
this.componentIdToDataMap = new Map();
|
|
23
26
|
this.componentIdToComponentMap = new Map();
|
|
27
|
+
this.scriptManager = new e2e_1.ScriptManager();
|
|
28
|
+
this.scriptManager.loadFromFiles();
|
|
24
29
|
}
|
|
25
30
|
getFlattenHeapObjectsInfo(objectCategory) {
|
|
26
31
|
let ret = [];
|
|
@@ -66,6 +71,10 @@ class HeapViewController {
|
|
|
66
71
|
});
|
|
67
72
|
return ret;
|
|
68
73
|
}
|
|
74
|
+
getComponentDataById(componentId) {
|
|
75
|
+
var _a;
|
|
76
|
+
return (_a = this.componentIdToDataMap.get(componentId)) !== null && _a !== void 0 ? _a : null;
|
|
77
|
+
}
|
|
69
78
|
getContent(componentId) {
|
|
70
79
|
const ret = [];
|
|
71
80
|
const data = this.componentIdToDataMap.get(componentId);
|
|
@@ -178,12 +187,6 @@ class HeapViewController {
|
|
|
178
187
|
// if the node has associated location info
|
|
179
188
|
const location = node.location;
|
|
180
189
|
if (location) {
|
|
181
|
-
const url = core_1.utils.getClosureSourceUrl(node);
|
|
182
|
-
if (url) {
|
|
183
|
-
data.items.push({
|
|
184
|
-
stringContent: this.getKeyValuePairString('code link', url),
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
190
|
data.items.push({
|
|
188
191
|
stringContent: this.getKeyValuePairString('script id', location.script_id),
|
|
189
192
|
});
|
|
@@ -215,16 +218,18 @@ class HeapViewController {
|
|
|
215
218
|
});
|
|
216
219
|
}
|
|
217
220
|
if (node.type === 'closure') {
|
|
218
|
-
const
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
tag: chalk_1.default.grey('Scope Variable'),
|
|
223
|
-
referrerEdge: edge,
|
|
224
|
-
heapObject: edge.toNode,
|
|
225
|
-
});
|
|
221
|
+
const url = core_1.utils.getClosureSourceUrl(node);
|
|
222
|
+
if (url) {
|
|
223
|
+
data.items.push({
|
|
224
|
+
stringContent: this.getKeyValuePairString('code link', url),
|
|
226
225
|
});
|
|
227
226
|
}
|
|
227
|
+
const closureVars = this.getClosureNodeScopeVarEdges(node);
|
|
228
|
+
closureVars.forEach(edge => data.items.push({
|
|
229
|
+
tag: chalk_1.default.grey('Outer Scope Var'),
|
|
230
|
+
referrerEdge: edge,
|
|
231
|
+
heapObject: edge.toNode,
|
|
232
|
+
}));
|
|
228
233
|
}
|
|
229
234
|
data.selectedIdx = data.items.length > 0 ? 0 : -1;
|
|
230
235
|
return data;
|
|
@@ -261,33 +266,79 @@ class HeapViewController {
|
|
|
261
266
|
data.selectedIdx = data.items.length > 0 ? 0 : -1;
|
|
262
267
|
return data;
|
|
263
268
|
}
|
|
264
|
-
|
|
269
|
+
getHeapObject(componentId, itemIndex) {
|
|
265
270
|
const data = this.componentIdToDataMap.get(componentId);
|
|
266
271
|
if (!data) {
|
|
267
|
-
return;
|
|
272
|
+
return null;
|
|
268
273
|
}
|
|
269
274
|
const item = data.items[itemIndex];
|
|
270
275
|
if (!item) {
|
|
271
|
-
return;
|
|
276
|
+
return null;
|
|
272
277
|
}
|
|
273
278
|
const heapObject = item.heapObject;
|
|
274
279
|
if (!heapObject) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
return heapObject;
|
|
283
|
+
}
|
|
284
|
+
displaySourceCode(componentId, itemIndex) {
|
|
285
|
+
const node = this.getHeapObject(componentId, itemIndex);
|
|
286
|
+
if (node && node.type === 'closure') {
|
|
287
|
+
this.displayClosureInfo(node);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// locate and display source code of a closure node
|
|
291
|
+
// in a worker thread
|
|
292
|
+
displayClosureInfo(node) {
|
|
293
|
+
const url = core_1.utils.getClosureSourceUrl(node);
|
|
294
|
+
if (!url) {
|
|
275
295
|
return;
|
|
276
296
|
}
|
|
277
|
-
this.
|
|
297
|
+
const closureVars = this.getClosureNodeScopeVarEdges(node).map(edge => `${edge.name_or_index}`);
|
|
298
|
+
const workerData = {
|
|
299
|
+
url,
|
|
300
|
+
closureVars,
|
|
301
|
+
};
|
|
302
|
+
new worker_threads_1.Worker(path_1.default.join(__dirname, '..', 'worker', 'LocateClosureSourceWorker.js'), { workerData });
|
|
303
|
+
}
|
|
304
|
+
getClosureNodeScopeVarEdges(node) {
|
|
305
|
+
const internalReferences = new Set(['map', 'scope_info', 'previous']);
|
|
306
|
+
const contextNode = node.getReferenceNode('context', 'internal');
|
|
307
|
+
const ret = [];
|
|
308
|
+
if (contextNode) {
|
|
309
|
+
contextNode.forEachReference(edge => {
|
|
310
|
+
const name = `${edge.name_or_index}`;
|
|
311
|
+
if (!internalReferences.has(name)) {
|
|
312
|
+
ret.push(edge);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
return ret;
|
|
317
|
+
}
|
|
318
|
+
setCurrentHeapObjectFromComponent(componentId, itemIndex, options = {}) {
|
|
319
|
+
const heapObject = this.getHeapObject(componentId, itemIndex);
|
|
320
|
+
if (heapObject) {
|
|
321
|
+
this.setCurrentHeapObject(heapObject, options);
|
|
322
|
+
}
|
|
278
323
|
}
|
|
279
324
|
setCurrentHeapObject(node, options = {}) {
|
|
280
325
|
this.currentHeapObject = node;
|
|
281
|
-
// set
|
|
326
|
+
// set clustered box's data and content
|
|
282
327
|
const clusteredBoxData = this.getClusteredBoxData();
|
|
283
328
|
this.componentIdToDataMap.set(this.clusteredBox.id, clusteredBoxData);
|
|
284
329
|
this.clusteredBox.setContent(this.getContent(this.clusteredBox.id));
|
|
285
330
|
this.clusteredBox.selectIndex(clusteredBoxData.selectedIdx);
|
|
331
|
+
// must set label here again so the additional label info
|
|
332
|
+
// can render with updated component data
|
|
333
|
+
this.clusteredBox.setLabel('Clustered Objects');
|
|
286
334
|
// set object box's data and content
|
|
287
335
|
const objectBoxData = this.getObjectBoxData();
|
|
288
336
|
this.componentIdToDataMap.set(this.objectBox.id, objectBoxData);
|
|
289
337
|
this.objectBox.setContent(this.getContent(this.objectBox.id));
|
|
290
338
|
this.objectBox.selectIndex(objectBoxData.selectedIdx);
|
|
339
|
+
// must set label here again so the additional label info
|
|
340
|
+
// can render with updated component data
|
|
341
|
+
this.objectBox.setLabel('Objects');
|
|
291
342
|
this.setSelectedHeapObject(node);
|
|
292
343
|
if (!options.skipFocus) {
|
|
293
344
|
this.focusOnComponent(this.objectBox.id);
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @oncall web_perf_infra
|
|
9
9
|
*/
|
|
10
10
|
import type { Widgets } from 'blessed';
|
|
11
|
+
import type HeapViewController from './HeapViewController';
|
|
11
12
|
export declare type ListComponentOption = {
|
|
12
13
|
width: number;
|
|
13
14
|
height: number;
|
|
@@ -18,6 +19,9 @@ export declare type ListComponentOption = {
|
|
|
18
19
|
export declare type ListItemSelectInfo = {
|
|
19
20
|
keyName: string;
|
|
20
21
|
};
|
|
22
|
+
export declare type LabelOption = {
|
|
23
|
+
nextTick?: boolean;
|
|
24
|
+
};
|
|
21
25
|
export declare type ListCallbacks = {
|
|
22
26
|
selectCallback?: (componentId: number, index: number, content: string[], selectInfo: ListItemSelectInfo) => void;
|
|
23
27
|
updateContent?: (oldContent: string[], newContent: string[]) => void;
|
|
@@ -32,6 +36,8 @@ export declare type ListCallbacks = {
|
|
|
32
36
|
export default class ListComponent {
|
|
33
37
|
element: Widgets.ListElement;
|
|
34
38
|
id: number;
|
|
39
|
+
private labelText;
|
|
40
|
+
private controller;
|
|
35
41
|
private listIndex;
|
|
36
42
|
private content;
|
|
37
43
|
private callbacks;
|
|
@@ -44,6 +50,7 @@ export default class ListComponent {
|
|
|
44
50
|
private static nextComponentId;
|
|
45
51
|
private static nextId;
|
|
46
52
|
constructor(content: string[], callbacks: ListCallbacks, options: ListComponentOption);
|
|
53
|
+
setController(controller: HeapViewController): void;
|
|
47
54
|
private render;
|
|
48
55
|
private static createEntryForMore;
|
|
49
56
|
protected registerKeys(): void;
|
|
@@ -53,7 +60,7 @@ export default class ListComponent {
|
|
|
53
60
|
loseFocus(): void;
|
|
54
61
|
selectIndex(index: number): void;
|
|
55
62
|
setFocusKey(key: string): void;
|
|
56
|
-
setLabel(label: string): void;
|
|
63
|
+
setLabel(label: string, option?: LabelOption): void;
|
|
57
64
|
setContent(content: string[]): void;
|
|
58
65
|
loadMoreContent(): void;
|
|
59
66
|
private removeDisplayMoreEntry;
|
|
@@ -14,6 +14,8 @@ const HeapViewUtils_1 = require("./HeapViewUtils");
|
|
|
14
14
|
*/
|
|
15
15
|
class ListComponent {
|
|
16
16
|
constructor(content, callbacks, options) {
|
|
17
|
+
this.labelText = '';
|
|
18
|
+
this.controller = null;
|
|
17
19
|
this.listIndex = 0;
|
|
18
20
|
this.content = [];
|
|
19
21
|
this.moreEntryIndex = -1;
|
|
@@ -41,6 +43,9 @@ class ListComponent {
|
|
|
41
43
|
static nextId() {
|
|
42
44
|
return ListComponent.nextComponentId++;
|
|
43
45
|
}
|
|
46
|
+
setController(controller) {
|
|
47
|
+
this.controller = controller;
|
|
48
|
+
}
|
|
44
49
|
// render the whole screen
|
|
45
50
|
render() {
|
|
46
51
|
if (this.callbacks.render) {
|
|
@@ -64,6 +69,12 @@ class ListComponent {
|
|
|
64
69
|
self.loadMoreContent();
|
|
65
70
|
return;
|
|
66
71
|
}
|
|
72
|
+
// if press 'd'
|
|
73
|
+
if (key.name === 'd' || key.name === 'D') {
|
|
74
|
+
self.selectUpdate(self.listIndex, content, {
|
|
75
|
+
keyName: key.name,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
67
78
|
// move selection down
|
|
68
79
|
if (key.name === 'down' && self.listIndex < self.displayedItems - 1) {
|
|
69
80
|
self.element.select(++self.listIndex);
|
|
@@ -160,9 +171,23 @@ class ListComponent {
|
|
|
160
171
|
setFocusKey(key) {
|
|
161
172
|
this.focusKey = key;
|
|
162
173
|
}
|
|
163
|
-
setLabel(label) {
|
|
164
|
-
|
|
165
|
-
|
|
174
|
+
setLabel(label, option = {}) {
|
|
175
|
+
this.labelText = label;
|
|
176
|
+
let componentLabel = label + chalk_1.default.grey(` (press ${chalk_1.default.inverse(this.focusKey)} to focus)`);
|
|
177
|
+
if (this.controller) {
|
|
178
|
+
const data = this.controller.getComponentDataById(this.id);
|
|
179
|
+
if (data) {
|
|
180
|
+
componentLabel += chalk_1.default.grey(` ${data.items.length} items`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (option.nextTick) {
|
|
184
|
+
process.nextTick(() => {
|
|
185
|
+
this.element.setLabel(componentLabel);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
this.element.setLabel(componentLabel);
|
|
190
|
+
}
|
|
166
191
|
}
|
|
167
192
|
setContent(content) {
|
|
168
193
|
const oldContent = this.content;
|
|
@@ -0,0 +1,11 @@
|
|
|
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 web_perf_infra
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=LocateClosureSourceWorker.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
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 web_perf_infra
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
const fs_1 = __importDefault(require("fs"));
|
|
25
|
+
const worker_threads_1 = require("worker_threads");
|
|
26
|
+
const core_1 = require("@memlab/core");
|
|
27
|
+
const e2e_1 = require("@memlab/e2e");
|
|
28
|
+
if (!worker_threads_1.isMainThread) {
|
|
29
|
+
try {
|
|
30
|
+
displaySourceCode();
|
|
31
|
+
}
|
|
32
|
+
catch (ex) {
|
|
33
|
+
// do nothing
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function displaySourceCode() {
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
const scriptManager = new e2e_1.ScriptManager();
|
|
39
|
+
scriptManager.loadFromFiles();
|
|
40
|
+
const { url, closureVars } = worker_threads_1.workerData;
|
|
41
|
+
const code = scriptManager.loadCodeForUrl(url);
|
|
42
|
+
const scope = scriptManager.getClosureScopeTreeForUrl(url);
|
|
43
|
+
if (!code || !scope) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const file = core_1.fileManager.getDebugSourceFile();
|
|
47
|
+
fs_1.default.writeFileSync(file, code, 'UTF-8');
|
|
48
|
+
iterateClosures(scope, closureScope => {
|
|
49
|
+
const varSet = new Set(closureScope.variablesDefined);
|
|
50
|
+
const found = closureVars.reduce((acc, v) => varSet.has(v) && acc, true);
|
|
51
|
+
if (found && closureScope.loc) {
|
|
52
|
+
const startLine = closureScope.loc.start.line;
|
|
53
|
+
core_1.utils.runShell(`code -g ${file}:${startLine}`, { disconnectStdio: true });
|
|
54
|
+
}
|
|
55
|
+
return found;
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function iterateClosures(scope, callback) {
|
|
60
|
+
if (callback(scope)) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
for (const subScope of scope.nestedClosures) {
|
|
64
|
+
if (iterateClosures(subScope, callback)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
@@ -43,6 +43,7 @@ const HeadfulBrowserOption_1 = __importDefault(require("../../options/e2e/Headfu
|
|
|
43
43
|
const SetUserAgentOption_1 = __importDefault(require("../../options/e2e/SetUserAgentOption"));
|
|
44
44
|
const DisableWebSecurityOption_1 = __importDefault(require("../../options/e2e/DisableWebSecurityOption"));
|
|
45
45
|
const EnableJSRewriteOption_1 = __importDefault(require("../../options/e2e/EnableJSRewriteOption"));
|
|
46
|
+
const EnableJSInterceptOption_1 = __importDefault(require("../../options/e2e/EnableJSInterceptOption"));
|
|
46
47
|
class TakeSnapshotCommand extends BaseCommand_1.default {
|
|
47
48
|
getCommandName() {
|
|
48
49
|
return 'snapshot';
|
|
@@ -83,6 +84,7 @@ class TakeSnapshotCommand extends BaseCommand_1.default {
|
|
|
83
84
|
new DisableXvfbOption_1.default(),
|
|
84
85
|
new DisableWebSecurityOption_1.default(),
|
|
85
86
|
new EnableJSRewriteOption_1.default(),
|
|
87
|
+
new EnableJSInterceptOption_1.default(),
|
|
86
88
|
];
|
|
87
89
|
}
|
|
88
90
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -17,18 +17,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
24
|
const core_1 = require("@memlab/core");
|
|
25
|
+
const OptionConstant_1 = __importDefault(require("./lib/OptionConstant"));
|
|
22
26
|
class DebugOption extends core_1.BaseOption {
|
|
23
27
|
getOptionName() {
|
|
24
|
-
return
|
|
28
|
+
return OptionConstant_1.default.optionNames.DEBUG;
|
|
25
29
|
}
|
|
26
30
|
getDescription() {
|
|
27
31
|
return 'enable manual debugging';
|
|
28
32
|
}
|
|
29
33
|
parse(config, args) {
|
|
30
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
-
if (args[
|
|
35
|
+
if (args[this.getOptionName()]) {
|
|
32
36
|
config.isManualDebug = true;
|
|
33
37
|
}
|
|
34
38
|
});
|
|
@@ -17,14 +17,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
24
|
const core_1 = require("@memlab/core");
|
|
25
|
+
const OptionConstant_1 = __importDefault(require("./lib/OptionConstant"));
|
|
22
26
|
class HelperOption extends core_1.BaseOption {
|
|
23
27
|
getOptionName() {
|
|
24
|
-
return
|
|
28
|
+
return OptionConstant_1.default.optionNames.HELP;
|
|
25
29
|
}
|
|
26
30
|
getOptionShortcut() {
|
|
27
|
-
return
|
|
31
|
+
return OptionConstant_1.default.optionShortcuts.H;
|
|
28
32
|
}
|
|
29
33
|
getDescription() {
|
|
30
34
|
return 'print helper text';
|
|
@@ -17,20 +17,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
24
|
const core_1 = require("@memlab/core");
|
|
22
25
|
const core_2 = require("@memlab/core");
|
|
26
|
+
const OptionConstant_1 = __importDefault(require("./lib/OptionConstant"));
|
|
23
27
|
class MLClusteringLinkageMaxDistanceOption extends core_2.BaseOption {
|
|
24
28
|
getOptionName() {
|
|
25
|
-
return
|
|
29
|
+
return OptionConstant_1.default.optionNames.ML_LINKAGE_MAX_DIST;
|
|
26
30
|
}
|
|
27
31
|
getDescription() {
|
|
28
32
|
return 'set linkage max distance value for clustering. The value should be between [0, 1] inclusive.';
|
|
29
33
|
}
|
|
30
34
|
parse(config, args) {
|
|
31
35
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
const name = this.getOptionName();
|
|
37
|
+
const arg = args[name];
|
|
38
|
+
if (arg) {
|
|
39
|
+
const linkageMaxDist = arg;
|
|
34
40
|
const linkageMaxDistNum = parseFloat(linkageMaxDist);
|
|
35
41
|
if (!isNaN(linkageMaxDistNum) &&
|
|
36
42
|
linkageMaxDistNum >= 0 &&
|
|
@@ -17,20 +17,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
24
|
const core_1 = require("@memlab/core");
|
|
22
25
|
const core_2 = require("@memlab/core");
|
|
26
|
+
const OptionConstant_1 = __importDefault(require("./lib/OptionConstant"));
|
|
23
27
|
class MLClusteringMaxDFOption extends core_2.BaseOption {
|
|
24
28
|
getOptionName() {
|
|
25
|
-
return
|
|
29
|
+
return OptionConstant_1.default.optionNames.ML_CLUSTERING_MAX_DF;
|
|
26
30
|
}
|
|
27
31
|
getDescription() {
|
|
28
32
|
return 'set percentage based max document frequency for limiting the terms that appear too often';
|
|
29
33
|
}
|
|
30
34
|
parse(config, args) {
|
|
31
35
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
const name = this.getOptionName();
|
|
37
|
+
const arg = args[name];
|
|
38
|
+
if (arg) {
|
|
39
|
+
const clusteringMaxDFStr = arg;
|
|
34
40
|
const clusteringMaxDF = parseFloat(clusteringMaxDFStr);
|
|
35
41
|
if (!isNaN(clusteringMaxDF) &&
|
|
36
42
|
clusteringMaxDF >= 0 &&
|
|
@@ -17,18 +17,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
24
|
const core_1 = require("@memlab/core");
|
|
25
|
+
const OptionConstant_1 = __importDefault(require("./lib/OptionConstant"));
|
|
22
26
|
class MLClusteringOption extends core_1.BaseOption {
|
|
23
27
|
getOptionName() {
|
|
24
|
-
return
|
|
28
|
+
return OptionConstant_1.default.optionNames.ML_CLUSTERING;
|
|
25
29
|
}
|
|
26
30
|
getDescription() {
|
|
27
31
|
return 'use machine learning algorithms for clustering leak traces (by default, traces are clustered by heuristics)';
|
|
28
32
|
}
|
|
29
33
|
parse(config, args) {
|
|
30
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
-
|
|
35
|
+
const name = this.getOptionName();
|
|
36
|
+
if (args[name]) {
|
|
32
37
|
config.isMLClustering = true;
|
|
33
38
|
}
|
|
34
39
|
});
|
|
@@ -17,11 +17,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
24
|
const core_1 = require("@memlab/core");
|
|
25
|
+
const OptionConstant_1 = __importDefault(require("./lib/OptionConstant"));
|
|
22
26
|
class NumberOfRunsOption extends core_1.BaseOption {
|
|
23
27
|
getOptionName() {
|
|
24
|
-
return
|
|
28
|
+
return OptionConstant_1.default.optionNames.RUN_NUM;
|
|
25
29
|
}
|
|
26
30
|
getDescription() {
|
|
27
31
|
return 'set number of runs';
|