@memlab/heap-analysis 1.0.3 → 1.0.6

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/README.md CHANGED
@@ -3,5 +3,6 @@
3
3
  This is the memlab heap analysis library. It contains all memlab built-in heap analysis and
4
4
  provides a plugin interface for adding new heap analysis that can be easily added to memlab API and memlab CLI.
5
5
 
6
- ## Full documentation
7
- https://facebookincubator.github.io/memlab
6
+ ## Online Resources
7
+ * [Official Website and Demo](https://facebookincubator.github.io/memlab)
8
+ * [Documentation](https://facebookincubator.github.io/memlab/docs/intro)
@@ -62,7 +62,7 @@ class Analysis {
62
62
  run(options = PluginUtils_1.default.defaultAnalysisArgs) {
63
63
  return __awaiter(this, void 0, void 0, function* () {
64
64
  loadScenarioConfig();
65
- return yield this.process(options);
65
+ yield this.process(options);
66
66
  });
67
67
  }
68
68
  /**
@@ -0,0 +1,21 @@
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
+ * @emails oncall+ws_labs
8
+ * @format
9
+ */
10
+ import type { IHeapSnapshot, Optional, IHeapConfig } from '@memlab/core';
11
+ declare class HeapConfig implements IHeapConfig {
12
+ isCliInteractiveMode: boolean;
13
+ currentHeapFile: Optional<string>;
14
+ currentHeap: Optional<IHeapSnapshot>;
15
+ private constructor();
16
+ private static instance;
17
+ static getInstance(): HeapConfig;
18
+ }
19
+ declare const heapConfig: HeapConfig;
20
+ export default heapConfig;
21
+ //# sourceMappingURL=HeapConfig.d.ts.map
@@ -0,0 +1,29 @@
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
+ * @emails oncall+ws_labs
9
+ * @format
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const core_1 = require("@memlab/core");
13
+ class HeapConfig {
14
+ constructor() {
15
+ this.isCliInteractiveMode = false;
16
+ this.currentHeap = null;
17
+ this.currentHeapFile = null;
18
+ }
19
+ static getInstance() {
20
+ if (!HeapConfig.instance) {
21
+ HeapConfig.instance = new HeapConfig();
22
+ }
23
+ return HeapConfig.instance;
24
+ }
25
+ }
26
+ HeapConfig.instance = null;
27
+ const heapConfig = HeapConfig.getInstance();
28
+ core_1.config.heapConfig = heapConfig;
29
+ exports.default = heapConfig;
@@ -166,14 +166,36 @@ declare function loadHeapSnapshot(options: HeapAnalysisOptions): Promise<IHeapSn
166
166
  * * **Examples**:
167
167
  * ```typescript
168
168
  * import {dumpNodeHeapSnapshot} from '@memlab/core';
169
- * import {getHeapFromFile} from '@memlab/heap-analysis';
169
+ * import {getFullHeapFromFile} from '@memlab/heap-analysis';
170
170
  *
171
171
  * (async function (){
172
172
  * const heapFile = dumpNodeHeapSnapshot();
173
- * const heap = await getHeapFromFile(heapFile);
173
+ * const heap = await getFullHeapFromFile(heapFile);
174
174
  * })();
175
175
  * ```
176
176
  */
177
+ declare function getFullHeapFromFile(file: string): Promise<IHeapSnapshot>;
178
+ /**
179
+ * Take a heap snapshot of the current program state
180
+ * and parse it as {@link IHeapSnapshot}. This
181
+ * API also calculates some heap analysis meta data
182
+ * for heap analysis. But this also means slower heap parsing
183
+ * comparing with {@link takeNodeMinimalHeap}.
184
+ *
185
+ * @returns heap representation with heap analysis meta data.
186
+ *
187
+ * * **Examples:**
188
+ * ```typescript
189
+ * import type {IHeapSnapshot} from '@memlab/core';
190
+ * import type {takeNodeFullHeap} from '@memlab/heap-analysis';
191
+ *
192
+ * (async function () {
193
+ * const heap: IHeapSnapshot = await takeNodeFullHeap();
194
+ * })();
195
+ * ```
196
+ */
197
+ declare function takeNodeFullHeap(): Promise<IHeapSnapshot>;
198
+ /** @deprecated */
177
199
  declare function getHeapFromFile(file: string): Promise<IHeapSnapshot>;
178
200
  /**
179
201
  * When a heap analysis is taking multiple heap snapshots as input for memory
@@ -261,7 +283,7 @@ declare function aggregateDominatorMetrics(ids: Set<number>, snapshot: IHeapSnap
261
283
  * * * **Examples**:
262
284
  * ```typescript
263
285
  * import {dumpNodeHeapSnapshot} from '@memlab/core';
264
- * import {getHeapFromFile, getDominatorNodes} from '@memlab/heap-analysis';
286
+ * import {getFullHeapFromFile, getDominatorNodes} from '@memlab/heap-analysis';
265
287
  *
266
288
  * class TestObject {}
267
289
  *
@@ -271,7 +293,7 @@ declare function aggregateDominatorMetrics(ids: Set<number>, snapshot: IHeapSnap
271
293
  *
272
294
  * // dump the heap of this running JavaScript program
273
295
  * const heapFile = dumpNodeHeapSnapshot();
274
- * const heap = await getHeapFromFile(heapFile);
296
+ * const heap = await getFullHeapFromFile(heapFile);
275
297
  *
276
298
  * // find the heap node for TestObject
277
299
  * let nodes = [];
@@ -306,9 +328,11 @@ declare const _default: {
306
328
  isNodeWorthInspecting: typeof isNodeWorthInspecting;
307
329
  loadHeapSnapshot: typeof loadHeapSnapshot;
308
330
  getHeapFromFile: typeof getHeapFromFile;
331
+ getFullHeapFromFile: typeof getFullHeapFromFile;
309
332
  printNodeListInTerminal: typeof printNodeListInTerminal;
310
333
  printReferencesInTerminal: typeof printReferencesInTerminal;
311
334
  snapshotMapReduce: typeof snapshotMapReduce;
335
+ takeNodeFullHeap: typeof takeNodeFullHeap;
312
336
  };
313
337
  export default _default;
314
338
  //# sourceMappingURL=PluginUtils.d.ts.map
@@ -24,6 +24,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
24
24
  const core_1 = require("@memlab/core");
25
25
  const chalk_1 = __importDefault(require("chalk"));
26
26
  const core_2 = require("@memlab/core");
27
+ const HeapConfig_1 = __importDefault(require("./HeapConfig"));
27
28
  const nodeNameBlockList = new Set([
28
29
  '(Startup object cache)',
29
30
  '(Global handles)',
@@ -231,9 +232,6 @@ function getSnapshotFileForAnalysis(options) {
231
232
  if (args.snapshot) {
232
233
  return args.snapshot;
233
234
  }
234
- if (core_1.config.externalSnapshotFilePaths.length > 0) {
235
- return core_1.config.externalSnapshotFilePaths[core_1.config.externalSnapshotFilePaths.length - 1];
236
- }
237
235
  return core_2.utils.getSingleSnapshotFileForAnalysis();
238
236
  }
239
237
  /**
@@ -330,8 +328,19 @@ function getSnapshotDirForAnalysis(options) {
330
328
  */
331
329
  function loadHeapSnapshot(options) {
332
330
  return __awaiter(this, void 0, void 0, function* () {
333
- const file = getSnapshotFileForAnalysis(options);
334
- return loadProcessedSnapshot({ file });
331
+ if (HeapConfig_1.default.isCliInteractiveMode) {
332
+ if (!HeapConfig_1.default.currentHeap) {
333
+ const file = getSnapshotFileForAnalysis(options);
334
+ const heap = yield loadProcessedSnapshot({ file });
335
+ HeapConfig_1.default.currentHeapFile = file;
336
+ HeapConfig_1.default.currentHeap = heap;
337
+ }
338
+ return HeapConfig_1.default.currentHeap;
339
+ }
340
+ else {
341
+ const file = getSnapshotFileForAnalysis(options);
342
+ return loadProcessedSnapshot({ file });
343
+ }
335
344
  });
336
345
  }
337
346
  /**
@@ -343,14 +352,47 @@ function loadHeapSnapshot(options) {
343
352
  * * **Examples**:
344
353
  * ```typescript
345
354
  * import {dumpNodeHeapSnapshot} from '@memlab/core';
346
- * import {getHeapFromFile} from '@memlab/heap-analysis';
355
+ * import {getFullHeapFromFile} from '@memlab/heap-analysis';
347
356
  *
348
357
  * (async function (){
349
358
  * const heapFile = dumpNodeHeapSnapshot();
350
- * const heap = await getHeapFromFile(heapFile);
359
+ * const heap = await getFullHeapFromFile(heapFile);
351
360
  * })();
352
361
  * ```
353
362
  */
363
+ function getFullHeapFromFile(file) {
364
+ return __awaiter(this, void 0, void 0, function* () {
365
+ return yield loadProcessedSnapshot({ file });
366
+ });
367
+ }
368
+ /**
369
+ * Take a heap snapshot of the current program state
370
+ * and parse it as {@link IHeapSnapshot}. This
371
+ * API also calculates some heap analysis meta data
372
+ * for heap analysis. But this also means slower heap parsing
373
+ * comparing with {@link takeNodeMinimalHeap}.
374
+ *
375
+ * @returns heap representation with heap analysis meta data.
376
+ *
377
+ * * **Examples:**
378
+ * ```typescript
379
+ * import type {IHeapSnapshot} from '@memlab/core';
380
+ * import type {takeNodeFullHeap} from '@memlab/heap-analysis';
381
+ *
382
+ * (async function () {
383
+ * const heap: IHeapSnapshot = await takeNodeFullHeap();
384
+ * })();
385
+ * ```
386
+ */
387
+ function takeNodeFullHeap() {
388
+ return __awaiter(this, void 0, void 0, function* () {
389
+ const heap = yield (0, core_1.takeNodeMinimalHeap)();
390
+ core_2.analysis.preparePathFinder(heap);
391
+ core_2.info.flush();
392
+ return heap;
393
+ });
394
+ }
395
+ /** @deprecated */
354
396
  function getHeapFromFile(file) {
355
397
  return __awaiter(this, void 0, void 0, function* () {
356
398
  return yield loadProcessedSnapshot({ file });
@@ -480,7 +522,7 @@ function aggregateDominatorMetrics(ids, snapshot, checkNodeCb, nodeMetricsCb) {
480
522
  * * * **Examples**:
481
523
  * ```typescript
482
524
  * import {dumpNodeHeapSnapshot} from '@memlab/core';
483
- * import {getHeapFromFile, getDominatorNodes} from '@memlab/heap-analysis';
525
+ * import {getFullHeapFromFile, getDominatorNodes} from '@memlab/heap-analysis';
484
526
  *
485
527
  * class TestObject {}
486
528
  *
@@ -490,7 +532,7 @@ function aggregateDominatorMetrics(ids, snapshot, checkNodeCb, nodeMetricsCb) {
490
532
  *
491
533
  * // dump the heap of this running JavaScript program
492
534
  * const heapFile = dumpNodeHeapSnapshot();
493
- * const heap = await getHeapFromFile(heapFile);
535
+ * const heap = await getFullHeapFromFile(heapFile);
494
536
  *
495
537
  * // find the heap node for TestObject
496
538
  * let nodes = [];
@@ -543,7 +585,9 @@ exports.default = {
543
585
  isNodeWorthInspecting,
544
586
  loadHeapSnapshot,
545
587
  getHeapFromFile,
588
+ getFullHeapFromFile,
546
589
  printNodeListInTerminal,
547
590
  printReferencesInTerminal,
548
591
  snapshotMapReduce,
592
+ takeNodeFullHeap,
549
593
  };
@@ -22,6 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
24
  const core_1 = require("@memlab/core");
25
+ const __1 = require("..");
25
26
  const HeapAnalysisLoader_1 = __importDefault(require("../HeapAnalysisLoader"));
26
27
  beforeEach(() => {
27
28
  core_1.config.isTest = true;
@@ -30,3 +31,19 @@ test('Heap analysis modules can be loaded', () => __awaiter(void 0, void 0, void
30
31
  const heapAnalysisMap = HeapAnalysisLoader_1.default.loadAllAnalysis();
31
32
  expect(heapAnalysisMap.size).toBeGreaterThan(0);
32
33
  }));
34
+ test('takeNodeFullHeap works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
35
+ var _a;
36
+ class TestClass {
37
+ constructor() {
38
+ this.name = 'test';
39
+ this.age = 183;
40
+ }
41
+ }
42
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
43
+ const _v = new TestClass();
44
+ const heap = yield (0, __1.takeNodeFullHeap)();
45
+ const node = heap.getAnyObjectWithClassName('TestClass');
46
+ expect((node === null || node === void 0 ? void 0 : node.dominatorNode) != null).toBe(true);
47
+ const size = (_a = node === null || node === void 0 ? void 0 : node.retainedSize) !== null && _a !== void 0 ? _a : 0;
48
+ expect(size > 0).toBe(true);
49
+ }));
@@ -57,9 +57,9 @@ test('analyzeSnapshotFromFile works as expected', () => __awaiter(void 0, void 0
57
57
  yield analysis.analyzeSnapshotFromFile(heapFile);
58
58
  expect(called).toBe(true);
59
59
  }));
60
- test('getHeapFromFile works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
60
+ test('getFullHeapFromFile works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
61
61
  const heapFile = (0, core_1.dumpNodeHeapSnapshot)();
62
- const heap = yield (0, index_1.getHeapFromFile)(heapFile);
62
+ const heap = yield (0, index_1.getFullHeapFromFile)(heapFile);
63
63
  expect(heap.nodes.length > 0).toBe(true);
64
64
  }));
65
65
  test('getDominatorNodes works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -71,7 +71,7 @@ test('getDominatorNodes works as expected', () => __awaiter(void 0, void 0, void
71
71
  const t2 = new TestObject();
72
72
  // dump the heap of this running JavaScript program
73
73
  const heapFile = (0, core_1.dumpNodeHeapSnapshot)();
74
- const heap = yield (0, index_1.getHeapFromFile)(heapFile);
74
+ const heap = yield (0, index_1.getFullHeapFromFile)(heapFile);
75
75
  // find the heap node for TestObject
76
76
  const nodes = [];
77
77
  heap.nodes.forEach(node => {
package/dist/index.d.ts CHANGED
@@ -7,7 +7,11 @@
7
7
  * @emails oncall+ws_labs
8
8
  * @format
9
9
  */
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>;
10
+ /** @internal */
11
+ export declare function registerPackage(): Promise<void>;
12
+ export declare const getDominatorNodes: (ids: Set<number>, snapshot: import("@memlab/core").IHeapSnapshot) => Set<number>,
13
+ /** @deprecated */
14
+ getHeapFromFile: (file: string) => Promise<import("@memlab/core").IHeapSnapshot>, getFullHeapFromFile: (file: string) => Promise<import("@memlab/core").IHeapSnapshot>, getSnapshotDirForAnalysis: (options: import("./PluginUtils").HeapAnalysisOptions) => import("@memlab/core").Nullable<string>, getSnapshotFileForAnalysis: (options: import("./PluginUtils").HeapAnalysisOptions) => string, loadHeapSnapshot: (options: import("./PluginUtils").HeapAnalysisOptions) => Promise<import("@memlab/core").IHeapSnapshot>, snapshotMapReduce: <T1, T2>(mapCallback: (snapshot: import("@memlab/core").IHeapSnapshot, i: number, file: string) => T1, reduceCallback: (results: T1[]) => T2, options: import("./PluginUtils").HeapAnalysisOptions) => Promise<T2>, takeNodeFullHeap: () => Promise<import("@memlab/core").IHeapSnapshot>;
11
15
  export type { HeapAnalysisOptions } from './PluginUtils';
12
16
  export { default as BaseAnalysis } from './BaseAnalysis';
13
17
  export { default as DetachedDOMElementAnalysis } from './plugins/DetachedDOMElementAnalysis';
@@ -24,4 +28,6 @@ export { default as StringAnalysis } from './plugins/StringAnalysis';
24
28
  export { default as PluginUtils } from './PluginUtils';
25
29
  /** @internal */
26
30
  export { default as heapAnalysisLoader } from './HeapAnalysisLoader';
31
+ /** @internal */
32
+ export { default as heapConfig } from './HeapConfig';
27
33
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -8,13 +8,33 @@
8
8
  * @emails oncall+ws_labs
9
9
  * @format
10
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
+ };
11
20
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
21
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
22
  };
14
23
  Object.defineProperty(exports, "__esModule", { value: true });
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;
24
+ exports.heapConfig = 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.takeNodeFullHeap = exports.snapshotMapReduce = exports.loadHeapSnapshot = exports.getSnapshotFileForAnalysis = exports.getSnapshotDirForAnalysis = exports.getFullHeapFromFile = exports.getHeapFromFile = exports.getDominatorNodes = exports.registerPackage = void 0;
25
+ const path_1 = __importDefault(require("path"));
26
+ const core_1 = require("@memlab/core");
27
+ /** @internal */
28
+ function registerPackage() {
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ return core_1.PackageInfoLoader.registerPackage(path_1.default.join(__dirname, '..'));
31
+ });
32
+ }
33
+ exports.registerPackage = registerPackage;
16
34
  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;
35
+ exports.getDominatorNodes = PluginUtils_1.default.getDominatorNodes,
36
+ /** @deprecated */
37
+ exports.getHeapFromFile = PluginUtils_1.default.getHeapFromFile, exports.getFullHeapFromFile = PluginUtils_1.default.getFullHeapFromFile, exports.getSnapshotDirForAnalysis = PluginUtils_1.default.getSnapshotDirForAnalysis, exports.getSnapshotFileForAnalysis = PluginUtils_1.default.getSnapshotFileForAnalysis, exports.loadHeapSnapshot = PluginUtils_1.default.loadHeapSnapshot, exports.snapshotMapReduce = PluginUtils_1.default.snapshotMapReduce, exports.takeNodeFullHeap = PluginUtils_1.default.takeNodeFullHeap;
18
38
  var BaseAnalysis_1 = require("./BaseAnalysis");
19
39
  Object.defineProperty(exports, "BaseAnalysis", { enumerable: true, get: function () { return __importDefault(BaseAnalysis_1).default; } });
20
40
  var DetachedDOMElementAnalysis_1 = require("./plugins/DetachedDOMElementAnalysis");
@@ -43,3 +63,6 @@ Object.defineProperty(exports, "PluginUtils", { enumerable: true, get: function
43
63
  /** @internal */
44
64
  var HeapAnalysisLoader_1 = require("./HeapAnalysisLoader");
45
65
  Object.defineProperty(exports, "heapAnalysisLoader", { enumerable: true, get: function () { return __importDefault(HeapAnalysisLoader_1).default; } });
66
+ /** @internal */
67
+ var HeapConfig_1 = require("./HeapConfig");
68
+ Object.defineProperty(exports, "heapConfig", { enumerable: true, get: function () { return __importDefault(HeapConfig_1).default; } });
@@ -60,7 +60,7 @@ class StringAnalysis extends BaseAnalysis_1.default {
60
60
  * @internal
61
61
  */
62
62
  getDescription() {
63
- return 'Analyze string in heap';
63
+ return 'Find duplicated string instances in heap';
64
64
  }
65
65
  /** @internal */
66
66
  getOptions() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memlab/heap-analysis",
3
- "version": "1.0.3",
3
+ "version": "1.0.6",
4
4
  "license": "MIT",
5
5
  "description": "heap analysis plugins for memlab",
6
6
  "author": "Liang Gong <lgong@fb.com>",
@@ -19,8 +19,8 @@
19
19
  "dist"
20
20
  ],
21
21
  "dependencies": {
22
- "@memlab/core": "^1.0.0",
23
- "@memlab/e2e": "^1.0.0",
22
+ "@memlab/core": "^1.1.6",
23
+ "@memlab/e2e": "^1.0.7",
24
24
  "ansi": "^0.3.1",
25
25
  "babar": "^0.2.0",
26
26
  "chalk": "^4.0.0",