@memlab/heap-analysis 1.0.0 → 1.0.3

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 (51) hide show
  1. package/README.md +5 -9
  2. package/dist/BaseAnalysis.d.ts +82 -5
  3. package/dist/BaseAnalysis.js +78 -12
  4. package/dist/PluginUtils.d.ts +267 -1
  5. package/dist/PluginUtils.js +269 -3
  6. package/dist/__tests__/package.test.d.ts +2 -0
  7. package/dist/__tests__/package.test.js +85 -0
  8. package/dist/index.d.ts +5 -1
  9. package/dist/index.js +9 -5
  10. package/dist/plugins/CollectionsHoldingStaleAnalysis.d.ts +5 -0
  11. package/dist/plugins/CollectionsHoldingStaleAnalysis.js +11 -0
  12. package/dist/plugins/DetachedDOMElementAnalysis.d.ts +5 -0
  13. package/dist/plugins/DetachedDOMElementAnalysis.js +11 -0
  14. package/dist/plugins/GlobalVariableAnalysis/GlobalVariableAnalysis.d.ts +6 -0
  15. package/dist/plugins/GlobalVariableAnalysis/GlobalVariableAnalysis.js +13 -0
  16. package/dist/plugins/ObjectFanoutAnalysis.d.ts +5 -0
  17. package/dist/plugins/ObjectFanoutAnalysis.js +12 -0
  18. package/dist/plugins/ObjectShallowAnalysis.d.ts +27 -1
  19. package/dist/plugins/ObjectShallowAnalysis.js +25 -0
  20. package/dist/plugins/ObjectShapeAnalysis.d.ts +5 -0
  21. package/dist/plugins/ObjectShapeAnalysis.js +11 -0
  22. package/dist/plugins/ObjectSizeAnalysis.d.ts +5 -0
  23. package/dist/plugins/ObjectSizeAnalysis.js +12 -0
  24. package/dist/plugins/ObjectUnboundGrowthAnalysis.d.ts +5 -0
  25. package/dist/plugins/ObjectUnboundGrowthAnalysis.js +11 -0
  26. package/dist/plugins/ShapeUnboundGrowthAnalysis.d.ts +11 -15
  27. package/dist/plugins/ShapeUnboundGrowthAnalysis.js +16 -1
  28. package/dist/plugins/StringAnalysis.d.ts +34 -2
  29. package/dist/plugins/StringAnalysis.js +32 -3
  30. package/dist/plugins/UnmountedReactFiberNodesAnalysis.d.ts +5 -0
  31. package/dist/plugins/UnmountedReactFiberNodesAnalysis.js +11 -0
  32. package/package.json +9 -5
  33. package/dist/BaseAnalysis.d.ts.map +0 -1
  34. package/dist/HeapAnalysisLoader.d.ts.map +0 -1
  35. package/dist/PluginUtils.d.ts.map +0 -1
  36. package/dist/__tests__/HeapAnalysis.test.d.ts.map +0 -1
  37. package/dist/index.d.ts.map +0 -1
  38. package/dist/options/HeapAnalysisSnapshotDirectoryOption.d.ts.map +0 -1
  39. package/dist/options/HeapAnalysisSnapshotFileOption.d.ts.map +0 -1
  40. package/dist/plugins/CollectionsHoldingStaleAnalysis.d.ts.map +0 -1
  41. package/dist/plugins/DetachedDOMElementAnalysis.d.ts.map +0 -1
  42. package/dist/plugins/GlobalVariableAnalysis/BuiltInGlobalVariables.d.ts.map +0 -1
  43. package/dist/plugins/GlobalVariableAnalysis/GlobalVariableAnalysis.d.ts.map +0 -1
  44. package/dist/plugins/ObjectFanoutAnalysis.d.ts.map +0 -1
  45. package/dist/plugins/ObjectShallowAnalysis.d.ts.map +0 -1
  46. package/dist/plugins/ObjectShapeAnalysis.d.ts.map +0 -1
  47. package/dist/plugins/ObjectSizeAnalysis.d.ts.map +0 -1
  48. package/dist/plugins/ObjectUnboundGrowthAnalysis.d.ts.map +0 -1
  49. package/dist/plugins/ShapeUnboundGrowthAnalysis.d.ts.map +0 -1
  50. package/dist/plugins/StringAnalysis.d.ts.map +0 -1
  51. package/dist/plugins/UnmountedReactFiberNodesAnalysis.d.ts.map +0 -1
@@ -51,9 +51,13 @@ function isNodeWorthInspecting(node) {
51
51
  }
52
52
  return true;
53
53
  }
54
- // filter out dominators that have a similar size
55
- // for example if input is [A, B] and A is the dominator of B
56
- // then this function throw away A if the size of A is close to the size of B
54
+ /**
55
+ * filter out dominators that have a similar size, for example if
56
+ * input is [A, B] and A is the dominator of B, then this function
57
+ * throw away A if the size of A is close to the size of B
58
+ * @param nodeList an array of heap nodes
59
+ * @returns an array of heap nodes with dominators that have similar size removed
60
+ */
57
61
  function filterOutDominators(nodeList) {
58
62
  const candidateIdSet = new Set(nodeList.map(node => node.id));
59
63
  const childrenSizeInList = new Map();
@@ -182,6 +186,46 @@ function getObjectOutgoingEdgeCount(node) {
182
186
  }
183
187
  return node.edge_count;
184
188
  }
189
+ /**
190
+ * Get the heap snapshot file's absolute path passed to the hosting heap
191
+ * analysis via `HeapAnalysisOptions`.
192
+ *
193
+ * This API is supposed to be used within the overridden `process` method
194
+ * of an `BaseAnalysis` instance.
195
+ *
196
+ * @param options this is the auto-generated input passed to all the `BaseAnalysis` instances
197
+ * @returns the absolute path of the heap snapshot file
198
+ * * **Examples:**
199
+ * ```typescript
200
+ * import type {IHeapSnapshot} from '@memlab/core';
201
+ * import type {HeapAnalysisOptions} from '@memlab/heap-analysis';
202
+ * import {getSnapshotFileForAnalysis, BaseAnalysis} from '@memlab/heap-analysis';
203
+ *
204
+ * class ExampleAnalysis extends BaseAnalysis {
205
+ * public getCommandName(): string {
206
+ * return 'example-analysis';
207
+ * }
208
+ *
209
+ * public getDescription(): string {
210
+ * return 'an example analysis for demo';
211
+ * }
212
+ *
213
+ * async process(options: HeapAnalysisOptions): Promise<void> {
214
+ * const file = getSnapshotFileForAnalysis(options);
215
+ * }
216
+ * }
217
+ * ```
218
+ *
219
+ * Use the following code to invoke the heap analysis:
220
+ * ```typescript
221
+ * const analysis = new ExampleAnalysis();
222
+ * // any .heapsnapshot file recorded by memlab or saved manually from Chrome
223
+ * await analysis.analyzeSnapshotFromFile(snapshotFile);
224
+ * ```
225
+ * The new heap analysis can also be used with {@link analyze}, in that case
226
+ * `getSnapshotFileForAnalysis` will use the last heap snapshot in alphanumerically
227
+ * ascending order from {@link BrowserInteractionResultReader}.
228
+ */
185
229
  function getSnapshotFileForAnalysis(options) {
186
230
  const args = options.args;
187
231
  if (args.snapshot) {
@@ -192,6 +236,47 @@ function getSnapshotFileForAnalysis(options) {
192
236
  }
193
237
  return core_2.utils.getSingleSnapshotFileForAnalysis();
194
238
  }
239
+ /**
240
+ * Get the absolute path of the directory holding all the heap snapshot files
241
+ * passed to the hosting heap analysis via `HeapAnalysisOptions`.
242
+ *
243
+ * This API is supposed to be used within the overridden `process` method
244
+ * of an `BaseAnalysis` instance.
245
+ *
246
+ * @param options this is the auto-generated input passed
247
+ * to all the `BaseAnalysis` instances
248
+ * @returns the absolute path of the directory
249
+ * * **Examples:**
250
+ * ```typescript
251
+ * import type {IHeapSnapshot} from '@memlab/core';
252
+ * import type {HeapAnalysisOptions} from '@memlab/heap-analysis';
253
+ * import {getSnapshotFileForAnalysis, BaseAnalysis} from '@memlab/heap-analysis';
254
+ *
255
+ * class ExampleAnalysis extends BaseAnalysis {
256
+ * public getCommandName(): string {
257
+ * return 'example-analysis';
258
+ * }
259
+ *
260
+ * public getDescription(): string {
261
+ * return 'an example analysis for demo';
262
+ * }
263
+ *
264
+ * async process(options: HeapAnalysisOptions): Promise<void> {
265
+ * const directory = getSnapshotDirForAnalysis(options);
266
+ * }
267
+ * }
268
+ * ```
269
+ *
270
+ * Use the following code to invoke the heap analysis:
271
+ * ```typescript
272
+ * const analysis = new ExampleAnalysis();
273
+ * // any .heapsnapshot file recorded by memlab or saved manually from Chrome
274
+ * await analysis.analyzeSnapshotFromFile(snapshotFile);
275
+ * ```
276
+ * The new heap analysis can also be used with {@link analyze}, in that case
277
+ * `getSnapshotDirForAnalysis` use the snapshot directory from
278
+ * {@link BrowserInteractionResultReader}.
279
+ */
195
280
  function getSnapshotDirForAnalysis(options) {
196
281
  const args = options.args;
197
282
  if (args['snapshot-dir']) {
@@ -202,21 +287,147 @@ function getSnapshotDirForAnalysis(options) {
202
287
  }
203
288
  return null;
204
289
  }
290
+ /**
291
+ * Load the heap graph based on the single JavaScript heap snapshot
292
+ * passed to the hosting heap analysis via `HeapAnalysisOptions`.
293
+ *
294
+ * This API is supposed to be used within the `process` implementation
295
+ * of an `BaseAnalysis` instance.
296
+ *
297
+ * @param options this is the auto-generated input passed to all the `BaseAnalysis` instances
298
+ * @returns the graph representation of the heap
299
+ * * **Examples:**
300
+ * ```typescript
301
+ * import type {IHeapSnapshot} from '@memlab/core';
302
+ * import type {HeapAnalysisOptions} from '@memlab/heap-analysis';
303
+ * import {loadHeapSnapshot, BaseAnalysis} from '@memlab/heap-analysis';
304
+ *
305
+ * class ExampleAnalysis extends BaseAnalysis {
306
+ * public getCommandName(): string {
307
+ * return 'example-analysis';
308
+ * }
309
+ *
310
+ * public getDescription(): string {
311
+ * return 'an example analysis for demo';
312
+ * }
313
+ *
314
+ * async process(options: HeapAnalysisOptions): Promise<void> {
315
+ * const heap = await loadHeapSnapshot(options);
316
+ * // doing heap analysis
317
+ * }
318
+ * }
319
+ * ```
320
+ *
321
+ * Use the following code to invoke the heap analysis:
322
+ * ```typescript
323
+ * const analysis = new ExampleAnalysis();
324
+ * // any .heapsnapshot file recorded by memlab or saved manually from Chrome
325
+ * await analysis.analyzeSnapshotFromFile(snapshotFile);
326
+ * ```
327
+ * The new heap analysis can also be used with {@link analyze}, in that case
328
+ * `loadHeapSnapshot` will use the last heap snapshot in alphanumerically
329
+ * ascending order from {@link BrowserInteractionResultReader}.
330
+ */
205
331
  function loadHeapSnapshot(options) {
206
332
  return __awaiter(this, void 0, void 0, function* () {
207
333
  const file = getSnapshotFileForAnalysis(options);
208
334
  return loadProcessedSnapshot({ file });
209
335
  });
210
336
  }
337
+ /**
338
+ * Load and parse a `.heapsnapshot` file and calculate meta data like
339
+ * dominator nodes and retained sizes.
340
+ * @param file the absolute path of the `.heapsnapshot` file
341
+ * @returns the heap graph representation instance that supports querying
342
+ * the heap
343
+ * * **Examples**:
344
+ * ```typescript
345
+ * import {dumpNodeHeapSnapshot} from '@memlab/core';
346
+ * import {getHeapFromFile} from '@memlab/heap-analysis';
347
+ *
348
+ * (async function (){
349
+ * const heapFile = dumpNodeHeapSnapshot();
350
+ * const heap = await getHeapFromFile(heapFile);
351
+ * })();
352
+ * ```
353
+ */
354
+ function getHeapFromFile(file) {
355
+ return __awaiter(this, void 0, void 0, function* () {
356
+ return yield loadProcessedSnapshot({ file });
357
+ });
358
+ }
211
359
  function loadProcessedSnapshot(options = {}) {
212
360
  return __awaiter(this, void 0, void 0, function* () {
213
361
  const opt = { buildNodeIdIndex: true, verbose: true };
214
362
  const file = options.file || core_2.utils.getSnapshotFilePathWithTabType(/.*/);
215
363
  const snapshot = yield core_2.utils.getSnapshotFromFile(file, opt);
216
364
  core_2.analysis.preparePathFinder(snapshot);
365
+ core_2.info.flush();
217
366
  return snapshot;
218
367
  });
219
368
  }
369
+ /**
370
+ * When a heap analysis is taking multiple heap snapshots as input for memory
371
+ * analysis (e.g., finding which object keeps growing in size in a series of
372
+ * heap snapshots), this API could be used to do
373
+ * [MapRedue](https://en.wikipedia.org/wiki/MapReduce) on all heap snapshots.
374
+ *
375
+ * This API is supposed to be used within the `process` implementation
376
+ * of an `BaseAnalysis` instance that is designed to analyze multiple heap
377
+ * snapshots (as an example, finding which object keeps growing overtime)
378
+ *
379
+ * @param mapCallback the map function in MapReduce, the function will be applied
380
+ * to each heap snapshot
381
+ * @param reduceCallback the reduce function in MapReduce, the function will take
382
+ * as input all intermediate results from all map function calls
383
+ * @typeParam T1 - the type of the intermediate result from each map function call
384
+ * @typeParam T2 - the type of the final result of the reduce function call
385
+ * @param options this is the auto-generated input passed to all the `BaseAnalysis` instances
386
+ * @returns the return value of your reduce function
387
+ * * **Examples:**
388
+ * ```typescript
389
+ * import type {IHeapSnapshot} from '@memlab/core';
390
+ * import type {HeapAnalysisOptions} from '@memlab/heap-analysis';
391
+ * import {snapshotMapReduce, BaseAnalysis} from '@memlab/heap-analysis';
392
+ *
393
+ * class ExampleAnalysis extends BaseAnalysis {
394
+ * public getCommandName(): string {
395
+ * return 'example-analysis';
396
+ * }
397
+ *
398
+ * public getDescription(): string {
399
+ * return 'an example analysis for demo';
400
+ * }
401
+ *
402
+ * async process(options: HeapAnalysisOptions): Promise<void> {
403
+ * // check if the number of heap objects keeps growing overtime
404
+ * const isMonotonicIncreasing = await snapshotMapReduce(
405
+ * (heap) => heap.nodes.length,
406
+ * (nodeCounts) =>
407
+ * nodeCounts[0] < nodeCounts[nodeCounts.length - 1] &&
408
+ * nodeCounts.every((count, i) => i === 0 || count >= nodeCounts[i - 1]),
409
+ * options,
410
+ * );
411
+ * }
412
+ * }
413
+ * ```
414
+ *
415
+ * Use the following code to invoke the heap analysis:
416
+ * ```typescript
417
+ * const analysis = new ExampleAnalysis();
418
+ * // snapshotDir includes a series of .heapsnapshot files recorded by
419
+ * // memlab or saved manually from Chrome, those files will be loaded
420
+ * // in alphanumerically asceneding order
421
+ * await analysis.analyzeSnapshotsInDirectory(snapshotDir);
422
+ * ```
423
+ * The new heap analysis can also be used with {@link analyze}, in that case
424
+ * `snapshotMapReduce` will use all the heap snapshot in alphanumerically
425
+ * ascending order from {@link BrowserInteractionResultReader}.
426
+ *
427
+ * **Why not passing in all heap snapshots as an array of {@link IHeapSnapshot}s?**
428
+ * Each heap snapshot could be non-trivial in size, loading them all at once
429
+ * may not be possible.
430
+ */
220
431
  function snapshotMapReduce(mapCallback, reduceCallback, options) {
221
432
  return __awaiter(this, void 0, void 0, function* () {
222
433
  const snapshotDir = getSnapshotDirForAnalysis(options);
@@ -239,6 +450,18 @@ function snapshotMapReduce(mapCallback, reduceCallback, options) {
239
450
  return reduceCallback(intermediateResults);
240
451
  });
241
452
  }
453
+ /**
454
+ * This API aggregates metrics from the
455
+ * [dominator nodes](https://firefox-source-docs.mozilla.org/devtools-user/memory/dominators/index.html)
456
+ * of the set of input heap objects.
457
+ *
458
+ * @param ids Set of ids of heap objects (or nodes)
459
+ * @param snapshot heap graph loaded from a heap snapshot
460
+ * @param checkNodeCb filter callback to exclude some heap object/nodes
461
+ * before calculating the dominator nodes
462
+ * @param nodeMetricsCb callback to calculate metrics from each dominator node
463
+ * @returns the aggregated metrics
464
+ */
242
465
  function aggregateDominatorMetrics(ids, snapshot, checkNodeCb, nodeMetricsCb) {
243
466
  let ret = 0;
244
467
  const dominators = core_2.utils.getConditionalDominatorIds(ids, snapshot, checkNodeCb);
@@ -247,6 +470,47 @@ function aggregateDominatorMetrics(ids, snapshot, checkNodeCb, nodeMetricsCb) {
247
470
  });
248
471
  return ret;
249
472
  }
473
+ /**
474
+ * This API calculate the set of
475
+ * [dominator nodes](https://firefox-source-docs.mozilla.org/devtools-user/memory/dominators/index.html)
476
+ * of the set of input heap objects.
477
+ * @param ids Set of ids of heap objects (or nodes)
478
+ * @param snapshot heap loaded from a heap snapshot
479
+ * @returns the set of dominator nodes/objects
480
+ * * * **Examples**:
481
+ * ```typescript
482
+ * import {dumpNodeHeapSnapshot} from '@memlab/core';
483
+ * import {getHeapFromFile, getDominatorNodes} from '@memlab/heap-analysis';
484
+ *
485
+ * class TestObject {}
486
+ *
487
+ * (async function () {
488
+ * const t1 = new TestObject();
489
+ * const t2 = new TestObject();
490
+ *
491
+ * // dump the heap of this running JavaScript program
492
+ * const heapFile = dumpNodeHeapSnapshot();
493
+ * const heap = await getHeapFromFile(heapFile);
494
+ *
495
+ * // find the heap node for TestObject
496
+ * let nodes = [];
497
+ * heap.nodes.forEach(node => {
498
+ * if (node.name === 'TestObject' && node.type === 'object') {
499
+ * nodes.push(node);
500
+ * }
501
+ * });
502
+ *
503
+ * // get the dominator nodes
504
+ * const dominatorIds = getDominatorNodes(
505
+ * new Set(nodes.map(node => node.id)),
506
+ * heap,
507
+ * );
508
+ * })();
509
+ * ```
510
+ */
511
+ function getDominatorNodes(ids, snapshot) {
512
+ return core_2.utils.getConditionalDominatorIds(ids, snapshot, () => true);
513
+ }
250
514
  function filterOutLargestObjects(snapshot, objectFilter, listSize = 50) {
251
515
  let largeObjects = [];
252
516
  snapshot.nodes.forEach(node => {
@@ -272,11 +536,13 @@ exports.default = {
272
536
  aggregateDominatorMetrics,
273
537
  defaultAnalysisArgs,
274
538
  filterOutLargestObjects,
539
+ getDominatorNodes,
275
540
  getObjectOutgoingEdgeCount,
276
541
  getSnapshotDirForAnalysis,
277
542
  getSnapshotFileForAnalysis,
278
543
  isNodeWorthInspecting,
279
544
  loadHeapSnapshot,
545
+ getHeapFromFile,
280
546
  printNodeListInTerminal,
281
547
  printReferencesInTerminal,
282
548
  snapshotMapReduce,
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=package.test.d.ts.map
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const core_1 = require("@memlab/core");
13
+ const index_1 = require("../index");
14
+ beforeEach(() => {
15
+ core_1.config.isTest = true;
16
+ });
17
+ test('loadHeapSnapshot works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
18
+ let called = false;
19
+ class ExampleAnalysis extends index_1.BaseAnalysis {
20
+ getCommandName() {
21
+ return 'example-analysis';
22
+ }
23
+ getDescription() {
24
+ return 'an example analysis for demo';
25
+ }
26
+ process(options) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ const heap = yield (0, index_1.loadHeapSnapshot)(options);
29
+ called = true;
30
+ expect(heap.nodes.length > 0).toBe(true);
31
+ });
32
+ }
33
+ }
34
+ const analysis = new ExampleAnalysis();
35
+ yield analysis.analyzeSnapshotFromFile((0, core_1.dumpNodeHeapSnapshot)());
36
+ expect(called).toBe(true);
37
+ }));
38
+ test('analyzeSnapshotFromFile works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
39
+ let called = false;
40
+ const heapFile = (0, core_1.dumpNodeHeapSnapshot)();
41
+ class ExampleAnalysis extends index_1.BaseAnalysis {
42
+ getCommandName() {
43
+ return 'example-analysis';
44
+ }
45
+ getDescription() {
46
+ return 'an example analysis for demo';
47
+ }
48
+ process(options) {
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ const file = (0, index_1.getSnapshotFileForAnalysis)(options);
51
+ called = true;
52
+ expect(file).toBe(heapFile);
53
+ });
54
+ }
55
+ }
56
+ const analysis = new ExampleAnalysis();
57
+ yield analysis.analyzeSnapshotFromFile(heapFile);
58
+ expect(called).toBe(true);
59
+ }));
60
+ test('getHeapFromFile works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
61
+ const heapFile = (0, core_1.dumpNodeHeapSnapshot)();
62
+ const heap = yield (0, index_1.getHeapFromFile)(heapFile);
63
+ expect(heap.nodes.length > 0).toBe(true);
64
+ }));
65
+ test('getDominatorNodes works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
66
+ class TestObject {
67
+ }
68
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
69
+ const t1 = new TestObject();
70
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
71
+ const t2 = new TestObject();
72
+ // dump the heap of this running JavaScript program
73
+ const heapFile = (0, core_1.dumpNodeHeapSnapshot)();
74
+ const heap = yield (0, index_1.getHeapFromFile)(heapFile);
75
+ // find the heap node for TestObject
76
+ const nodes = [];
77
+ heap.nodes.forEach(node => {
78
+ if (node.name === 'TestObject' && node.type === 'object') {
79
+ nodes.push(node);
80
+ }
81
+ });
82
+ // get the dominator nodes
83
+ const dominatorIds = (0, index_1.getDominatorNodes)(new Set(nodes.map(node => node.id)), heap);
84
+ expect(dominatorIds.size).toBeGreaterThan(0);
85
+ }));
package/dist/index.d.ts CHANGED
@@ -7,7 +7,8 @@
7
7
  * @emails oncall+ws_labs
8
8
  * @format
9
9
  */
10
- export { default as heapAnalysisLoader } from './HeapAnalysisLoader';
10
+ export declare const getDominatorNodes: (ids: Set<number>, snapshot: import("../../core/src").IHeapSnapshot) => Set<number>, getHeapFromFile: (file: string) => Promise<import("../../core/src").IHeapSnapshot>, getSnapshotDirForAnalysis: (options: import("./PluginUtils").HeapAnalysisOptions) => import("../../core/src").Nullable<string>, getSnapshotFileForAnalysis: (options: import("./PluginUtils").HeapAnalysisOptions) => string, loadHeapSnapshot: (options: import("./PluginUtils").HeapAnalysisOptions) => Promise<import("../../core/src").IHeapSnapshot>, snapshotMapReduce: <T1, T2>(mapCallback: (snapshot: import("../../core/src").IHeapSnapshot, i: number, file: string) => T1, reduceCallback: (results: T1[]) => T2, options: import("./PluginUtils").HeapAnalysisOptions) => Promise<T2>;
11
+ export type { HeapAnalysisOptions } from './PluginUtils';
11
12
  export { default as BaseAnalysis } from './BaseAnalysis';
12
13
  export { default as DetachedDOMElementAnalysis } from './plugins/DetachedDOMElementAnalysis';
13
14
  export { default as GlobalVariableAnalysis } from './plugins/GlobalVariableAnalysis/GlobalVariableAnalysis';
@@ -19,5 +20,8 @@ export { default as ObjectFanoutAnalysis } from './plugins/ObjectFanoutAnalysis'
19
20
  export { default as ObjectShapeAnalysis } from './plugins/ObjectShapeAnalysis';
20
21
  export { default as ObjectUnboundGrowthAnalysis } from './plugins/ObjectUnboundGrowthAnalysis';
21
22
  export { default as StringAnalysis } from './plugins/StringAnalysis';
23
+ /** @internal */
22
24
  export { default as PluginUtils } from './PluginUtils';
25
+ /** @internal */
26
+ export { default as heapAnalysisLoader } from './HeapAnalysisLoader';
23
27
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -12,9 +12,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.PluginUtils = exports.StringAnalysis = exports.ObjectUnboundGrowthAnalysis = exports.ObjectShapeAnalysis = exports.ObjectFanoutAnalysis = exports.ShapeUnboundGrowthAnalysis = exports.ObjectSizeAnalysis = exports.ObjectShallowAnalysis = exports.CollectionsHoldingStaleAnalysis = exports.GlobalVariableAnalysis = exports.DetachedDOMElementAnalysis = exports.BaseAnalysis = exports.heapAnalysisLoader = void 0;
16
- var HeapAnalysisLoader_1 = require("./HeapAnalysisLoader");
17
- Object.defineProperty(exports, "heapAnalysisLoader", { enumerable: true, get: function () { return __importDefault(HeapAnalysisLoader_1).default; } });
15
+ exports.heapAnalysisLoader = exports.PluginUtils = exports.StringAnalysis = exports.ObjectUnboundGrowthAnalysis = exports.ObjectShapeAnalysis = exports.ObjectFanoutAnalysis = exports.ShapeUnboundGrowthAnalysis = exports.ObjectSizeAnalysis = exports.ObjectShallowAnalysis = exports.CollectionsHoldingStaleAnalysis = exports.GlobalVariableAnalysis = exports.DetachedDOMElementAnalysis = exports.BaseAnalysis = exports.snapshotMapReduce = exports.loadHeapSnapshot = exports.getSnapshotFileForAnalysis = exports.getSnapshotDirForAnalysis = exports.getHeapFromFile = exports.getDominatorNodes = void 0;
16
+ const PluginUtils_1 = __importDefault(require("./PluginUtils"));
17
+ exports.getDominatorNodes = PluginUtils_1.default.getDominatorNodes, exports.getHeapFromFile = PluginUtils_1.default.getHeapFromFile, exports.getSnapshotDirForAnalysis = PluginUtils_1.default.getSnapshotDirForAnalysis, exports.getSnapshotFileForAnalysis = PluginUtils_1.default.getSnapshotFileForAnalysis, exports.loadHeapSnapshot = PluginUtils_1.default.loadHeapSnapshot, exports.snapshotMapReduce = PluginUtils_1.default.snapshotMapReduce;
18
18
  var BaseAnalysis_1 = require("./BaseAnalysis");
19
19
  Object.defineProperty(exports, "BaseAnalysis", { enumerable: true, get: function () { return __importDefault(BaseAnalysis_1).default; } });
20
20
  var DetachedDOMElementAnalysis_1 = require("./plugins/DetachedDOMElementAnalysis");
@@ -37,5 +37,9 @@ var ObjectUnboundGrowthAnalysis_1 = require("./plugins/ObjectUnboundGrowthAnalys
37
37
  Object.defineProperty(exports, "ObjectUnboundGrowthAnalysis", { enumerable: true, get: function () { return __importDefault(ObjectUnboundGrowthAnalysis_1).default; } });
38
38
  var StringAnalysis_1 = require("./plugins/StringAnalysis");
39
39
  Object.defineProperty(exports, "StringAnalysis", { enumerable: true, get: function () { return __importDefault(StringAnalysis_1).default; } });
40
- var PluginUtils_1 = require("./PluginUtils");
41
- Object.defineProperty(exports, "PluginUtils", { enumerable: true, get: function () { return __importDefault(PluginUtils_1).default; } });
40
+ /** @internal */
41
+ var PluginUtils_2 = require("./PluginUtils");
42
+ Object.defineProperty(exports, "PluginUtils", { enumerable: true, get: function () { return __importDefault(PluginUtils_2).default; } });
43
+ /** @internal */
44
+ var HeapAnalysisLoader_1 = require("./HeapAnalysisLoader");
45
+ Object.defineProperty(exports, "heapAnalysisLoader", { enumerable: true, get: function () { return __importDefault(HeapAnalysisLoader_1).default; } });
@@ -12,9 +12,14 @@ import { BaseOption } from '@memlab/core';
12
12
  import BaseAnalysis from '../BaseAnalysis';
13
13
  export default class CollectionsHoldingStaleAnalysis extends BaseAnalysis {
14
14
  getCommandName(): string;
15
+ /** @internal */
15
16
  getDescription(): string;
17
+ /** @internal */
16
18
  getOptions(): BaseOption[];
19
+ /** @internal */
20
+ analyzeSnapshotsInDirectory(directory: string): Promise<void>;
17
21
  private staleCollectionMapper;
22
+ /** @internal */
18
23
  process(options: HeapAnalysisOptions): Promise<void>;
19
24
  private getCollectionsWithStaleValues;
20
25
  private print;
@@ -69,12 +69,23 @@ class CollectionsHoldingStaleAnalysis extends BaseAnalysis_1.default {
69
69
  getCommandName() {
70
70
  return 'collections-with-stale';
71
71
  }
72
+ /** @internal */
72
73
  getDescription() {
73
74
  return 'Analyze collections holding stale objects';
74
75
  }
76
+ /** @internal */
75
77
  getOptions() {
76
78
  return [new HeapAnalysisSnapshotFileOption_1.default()];
77
79
  }
80
+ /** @internal */
81
+ analyzeSnapshotsInDirectory(directory) {
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
84
+ const d = directory;
85
+ throw core_1.utils.haltOrThrow(`${this.constructor.name} does not support analyzeSnapshotsInDirectory`);
86
+ });
87
+ }
88
+ /** @internal */
78
89
  process(options) {
79
90
  return __awaiter(this, void 0, void 0, function* () {
80
91
  const snapshot = yield PluginUtils_1.default.loadHeapSnapshot(options);
@@ -13,10 +13,15 @@ import { BaseOption } from '@memlab/core';
13
13
  import BaseAnalysis from '../BaseAnalysis';
14
14
  export default class DetachedDOMElementAnalysis extends BaseAnalysis {
15
15
  getCommandName(): string;
16
+ /** @internal */
16
17
  getDescription(): string;
18
+ /** @internal */
17
19
  getOptions(): BaseOption[];
20
+ /** @internal */
21
+ analyzeSnapshotsInDirectory(directory: string): Promise<void>;
18
22
  private detachedElements;
19
23
  getDetachedElements(): IHeapNode[];
24
+ /** @internal */
20
25
  process(options: HeapAnalysisOptions): Promise<void>;
21
26
  }
22
27
  //# sourceMappingURL=DetachedDOMElementAnalysis.d.ts.map
@@ -33,15 +33,26 @@ class DetachedDOMElementAnalysis extends BaseAnalysis_1.default {
33
33
  getCommandName() {
34
34
  return 'detached-DOM';
35
35
  }
36
+ /** @internal */
36
37
  getDescription() {
37
38
  return 'Get detached DOM elements';
38
39
  }
40
+ /** @internal */
39
41
  getOptions() {
40
42
  return [new HeapAnalysisSnapshotFileOption_1.default()];
41
43
  }
44
+ /** @internal */
45
+ analyzeSnapshotsInDirectory(directory) {
46
+ return __awaiter(this, void 0, void 0, function* () {
47
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
48
+ const d = directory;
49
+ throw core_1.utils.haltOrThrow(`${this.constructor.name} does not support analyzeSnapshotsInDirectory`);
50
+ });
51
+ }
42
52
  getDetachedElements() {
43
53
  return this.detachedElements;
44
54
  }
55
+ /** @internal */
45
56
  process(options) {
46
57
  return __awaiter(this, void 0, void 0, function* () {
47
58
  const snapshot = yield PluginUtils_1.default.loadHeapSnapshot(options);
@@ -12,10 +12,16 @@ import { BaseOption } from '@memlab/core';
12
12
  import BaseAnalysis from '../../BaseAnalysis';
13
13
  declare class GlobalVariableAnalysis extends BaseAnalysis {
14
14
  getCommandName(): string;
15
+ /** @internal */
15
16
  getDescription(): string;
17
+ /** @internal */
16
18
  getOptions(): BaseOption[];
19
+ /** @internal */
17
20
  process(options: HeapAnalysisOptions): Promise<void>;
21
+ /** @internal */
22
+ analyzeSnapshotsInDirectory(directory: string): Promise<void>;
18
23
  private shouldFilterOutEdge;
24
+ /** @internal */
19
25
  private getGlobalVariables;
20
26
  }
21
27
  export default GlobalVariableAnalysis;
@@ -21,6 +21,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
21
21
  return (mod && mod.__esModule) ? mod : { "default": mod };
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
+ const core_1 = require("@memlab/core");
24
25
  const HeapAnalysisSnapshotFileOption_1 = __importDefault(require("../../options/HeapAnalysisSnapshotFileOption"));
25
26
  const BaseAnalysis_1 = __importDefault(require("../../BaseAnalysis"));
26
27
  const PluginUtils_1 = __importDefault(require("../../PluginUtils"));
@@ -29,12 +30,15 @@ class GlobalVariableAnalysis extends BaseAnalysis_1.default {
29
30
  getCommandName() {
30
31
  return 'global-variable';
31
32
  }
33
+ /** @internal */
32
34
  getDescription() {
33
35
  return 'Get global variables in heap';
34
36
  }
37
+ /** @internal */
35
38
  getOptions() {
36
39
  return [new HeapAnalysisSnapshotFileOption_1.default()];
37
40
  }
41
+ /** @internal */
38
42
  process(options) {
39
43
  return __awaiter(this, void 0, void 0, function* () {
40
44
  const snapshot = yield PluginUtils_1.default.loadHeapSnapshot(options);
@@ -42,6 +46,14 @@ class GlobalVariableAnalysis extends BaseAnalysis_1.default {
42
46
  PluginUtils_1.default.printReferencesInTerminal(list);
43
47
  });
44
48
  }
49
+ /** @internal */
50
+ analyzeSnapshotsInDirectory(directory) {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
53
+ const d = directory;
54
+ throw core_1.utils.haltOrThrow(`${this.constructor.name} does not support analyzeSnapshotsInDirectory`);
55
+ });
56
+ }
45
57
  shouldFilterOutEdge(edge) {
46
58
  if (BuiltInGlobalVariables_1.default.has(`${edge.name_or_index}`)) {
47
59
  return true;
@@ -57,6 +69,7 @@ class GlobalVariableAnalysis extends BaseAnalysis_1.default {
57
69
  }
58
70
  return false;
59
71
  }
72
+ /** @internal */
60
73
  getGlobalVariables(snapshot) {
61
74
  // rank heap objects based on fanout
62
75
  const ret = [];
@@ -12,8 +12,13 @@ import { BaseOption } from '@memlab/core';
12
12
  import BaseAnalysis from '../BaseAnalysis';
13
13
  declare class ObjectFanoutAnalysis extends BaseAnalysis {
14
14
  getCommandName(): string;
15
+ /** @internal */
15
16
  getDescription(): string;
17
+ /** @internal */
16
18
  getOptions(): BaseOption[];
19
+ /** @internal */
20
+ analyzeSnapshotsInDirectory(directory: string): Promise<void>;
21
+ /** @internal */
17
22
  process(options: HeapAnalysisOptions): Promise<void>;
18
23
  private getObjectsWithHighFanout;
19
24
  }
@@ -21,6 +21,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
21
21
  return (mod && mod.__esModule) ? mod : { "default": mod };
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
+ const core_1 = require("@memlab/core");
24
25
  const BaseAnalysis_1 = __importDefault(require("../BaseAnalysis"));
25
26
  const PluginUtils_1 = __importDefault(require("../PluginUtils"));
26
27
  const HeapAnalysisSnapshotFileOption_1 = __importDefault(require("../options/HeapAnalysisSnapshotFileOption"));
@@ -28,12 +29,23 @@ class ObjectFanoutAnalysis extends BaseAnalysis_1.default {
28
29
  getCommandName() {
29
30
  return 'object-fanout';
30
31
  }
32
+ /** @internal */
31
33
  getDescription() {
32
34
  return 'Get objects with the most out-going references in heap';
33
35
  }
36
+ /** @internal */
34
37
  getOptions() {
35
38
  return [new HeapAnalysisSnapshotFileOption_1.default()];
36
39
  }
40
+ /** @internal */
41
+ analyzeSnapshotsInDirectory(directory) {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
44
+ const d = directory;
45
+ throw core_1.utils.haltOrThrow(`${this.constructor.name} does not support analyzeSnapshotsInDirectory`);
46
+ });
47
+ }
48
+ /** @internal */
37
49
  process(options) {
38
50
  return __awaiter(this, void 0, void 0, function* () {
39
51
  const snapshot = yield PluginUtils_1.default.loadHeapSnapshot(options);