@memlab/core 1.1.20 → 1.1.22

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 (48) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +4 -1
  3. package/dist/lib/Config.d.ts +11 -0
  4. package/dist/lib/Config.js +26 -1
  5. package/dist/lib/Constant.js +1 -0
  6. package/dist/lib/FileManager.d.ts +3 -0
  7. package/dist/lib/FileManager.js +10 -1
  8. package/dist/lib/HeapAnalyzer.d.ts +5 -1
  9. package/dist/lib/HeapAnalyzer.js +56 -34
  10. package/dist/lib/RunInfoUtils.d.ts +39 -0
  11. package/dist/lib/RunInfoUtils.js +86 -0
  12. package/dist/lib/TraceSampler.d.ts +36 -0
  13. package/dist/lib/TraceSampler.js +78 -0
  14. package/dist/lib/Types.d.ts +12 -2
  15. package/dist/lib/Utils.d.ts +31 -19
  16. package/dist/lib/Utils.js +124 -145
  17. package/dist/lib/charts/MemoryBarChart.d.ts +1 -0
  18. package/dist/lib/charts/MemoryBarChart.js +18 -3
  19. package/dist/lib/heap-data/HeapStringNode.js +25 -16
  20. package/dist/lib/leak-filters/rules/FilterOverSizedNodeAsLeak.rule.js +50 -0
  21. package/dist/lib/trace-filters/BaseTraceFilter.rule.d.ts +29 -0
  22. package/dist/lib/trace-filters/BaseTraceFilter.rule.js +22 -0
  23. package/dist/lib/trace-filters/LeakTraceFilter.d.ts +20 -0
  24. package/dist/lib/trace-filters/LeakTraceFilter.js +37 -0
  25. package/dist/lib/trace-filters/TraceFilterRuleList.d.ts +13 -0
  26. package/dist/lib/trace-filters/TraceFilterRuleList.js +35 -0
  27. package/dist/lib/trace-filters/rules/FilterAttachedDOMToDetachedDOMTrace.rule.d.ts +15 -0
  28. package/dist/lib/trace-filters/rules/FilterAttachedDOMToDetachedDOMTrace.rule.js +55 -0
  29. package/dist/lib/trace-filters/rules/FilterCppRootsToDetachedDOMTrace.rule.d.ts +15 -0
  30. package/dist/lib/trace-filters/rules/FilterCppRootsToDetachedDOMTrace.rule.js +44 -0
  31. package/dist/lib/trace-filters/rules/FilterDOMNodeChainTrace.rule.d.ts +15 -0
  32. package/dist/lib/trace-filters/rules/FilterDOMNodeChainTrace.rule.js +41 -0
  33. package/dist/lib/trace-filters/rules/FilterHermesTrace.rule.d.ts +15 -0
  34. package/dist/lib/trace-filters/rules/FilterHermesTrace.rule.js +29 -0
  35. package/dist/lib/trace-filters/rules/FilterInternalNodeTrace.rule.d.ts +15 -0
  36. package/dist/lib/trace-filters/rules/FilterInternalNodeTrace.rule.js +57 -0
  37. package/dist/lib/trace-filters/rules/FilterPendingActivitiesTrace.rule.d.ts +15 -0
  38. package/dist/lib/trace-filters/rules/FilterPendingActivitiesTrace.rule.js +62 -0
  39. package/dist/lib/trace-filters/rules/FilterShadowRootTrace.rule.d.ts +15 -0
  40. package/dist/lib/trace-filters/rules/FilterShadowRootTrace.rule.js +44 -0
  41. package/dist/lib/trace-filters/rules/FilterStyleEngineTrace.rule.d.ts +15 -0
  42. package/dist/lib/trace-filters/rules/FilterStyleEngineTrace.rule.js +49 -0
  43. package/dist/logger/LeakClusterLogger.js +1 -0
  44. package/dist/paths/TraceFinder.js +17 -3
  45. package/dist/trace-cluster/TraceBucket.d.ts +1 -1
  46. package/dist/trace-cluster/TraceBucket.js +20 -14
  47. package/dist/trace-cluster/strategies/TraceSimilarityStrategy.js +1 -0
  48. package/package.json +1 -1
@@ -23,6 +23,8 @@ export declare type Optional<T> = Nullable<T> | undefined;
23
23
  /** @internal */
24
24
  export declare type AnyRecord = Record<string, RecordValue>;
25
25
  /** @internal */
26
+ export declare type StringRecord = Record<string, string>;
27
+ /** @internal */
26
28
  export declare type AnyAyncFunction = (...args: AnyValue[]) => Promise<AnyValue>;
27
29
  /** @internal */
28
30
  export declare type AnyFunction = (...args: AnyValue[]) => AnyValue;
@@ -66,6 +68,7 @@ export declare type XvfbType = {
66
68
  export declare type ShellOptions = {
67
69
  dir?: Optional<string>;
68
70
  ignoreError?: Optional<boolean>;
71
+ throwError?: Optional<boolean>;
69
72
  disconnectStdio?: Optional<boolean>;
70
73
  };
71
74
  /** @internal */
@@ -942,6 +945,8 @@ export declare type RunMetaInfo = {
942
945
  * output data from the browser
943
946
  */
944
947
  browserInfo: IBrowserInfo;
948
+ /** @internal */
949
+ extraInfo?: StringRecord;
945
950
  };
946
951
  /**
947
952
  * A heap snapshot is generally a graph where graph nodes are JS heap objects
@@ -1924,12 +1929,12 @@ export interface IOveralLeakInfo extends Partial<IOveralHeapInfo> {
1924
1929
  }
1925
1930
  /** @internal */
1926
1931
  export declare type DiffLeakOptions = {
1927
- controlWorkDir: string;
1932
+ controlWorkDirs: string[];
1928
1933
  treatmentWorkDir: string;
1929
1934
  };
1930
1935
  /** @internal */
1931
1936
  export declare type PlotMemoryOptions = {
1932
- controlWorkDir?: string;
1937
+ controlWorkDirs?: string[];
1933
1938
  treatmentWorkDir?: string;
1934
1939
  workDir?: string;
1935
1940
  } & IMemoryAnalystOptions;
@@ -1966,4 +1971,9 @@ export interface IHeapConfig {
1966
1971
  }
1967
1972
  /** @internal */
1968
1973
  export declare type ErrorWithMessage = Pick<Error, 'message'>;
1974
+ /** @internal */
1975
+ export declare type CommandOptionExample = string | {
1976
+ description?: string;
1977
+ cliOptionExample: string;
1978
+ };
1969
1979
  //# sourceMappingURL=Types.d.ts.map
@@ -7,13 +7,15 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { HaltOrThrowOptions, HeapNodeIdSet, ShellOptions } from './Types';
10
+ import type { HaltOrThrowOptions, HeapNodeIdSet, ShellOptions, StringRecord } from './Types';
11
11
  import type { Browser, Page } from 'puppeteer';
12
- import type { AnyAyncFunction, AnyOptions, E2EStepInfo, IHeapSnapshot, IHeapNode, IHeapEdge, IScenario, ILeakFilter, LeakTracePathItem, RunMetaInfo, RawHeapSnapshot, Nullable, Optional } from './Types';
12
+ import type { AnyAyncFunction, AnyOptions, E2EStepInfo, IHeapSnapshot, IHeapNode, IHeapEdge, IScenario, ILeakFilter, LeakTracePathItem, RawHeapSnapshot, Nullable, Optional } from './Types';
13
13
  declare function isHermesInternalObject(node: IHeapNode): boolean;
14
14
  declare function isStackTraceFrame(node: IHeapNode): boolean;
15
15
  declare function isFiberNode(node: Optional<IHeapNode>): boolean;
16
16
  declare function isDetachedFiberNode(node: IHeapNode): boolean;
17
+ declare function isDOMInternalNode(node: Optional<IHeapNode>): boolean;
18
+ declare function isGlobalHandlesNode(node: Optional<IHeapNode>): boolean;
17
19
  declare function isDetachedDOMNode(node: Optional<IHeapNode>, args?: AnyOptions): boolean;
18
20
  declare function isWeakMapEdge(edge: IHeapEdge): boolean;
19
21
  declare function isWeakMapEdgeToKey(edge: IHeapEdge): boolean;
@@ -23,6 +25,10 @@ declare function isFiberNodeDeletionsEdge(edge: IHeapEdge): boolean;
23
25
  declare function isBlinkRootNode(node: IHeapNode): boolean;
24
26
  declare function isPendingActivityNode(node: IHeapNode): boolean;
25
27
  declare function isDOMNodeIncomplete(node: IHeapNode): boolean;
28
+ declare function isXMLDocumentNode(node: IHeapNode): boolean;
29
+ declare function isHTMLDocumentNode(node: IHeapNode): boolean;
30
+ declare function isDOMTextNode(node: IHeapNode): boolean;
31
+ declare function isCppRootsNode(node: IHeapNode): boolean;
26
32
  declare function isRootNode(node: IHeapNode, opt?: AnyOptions): boolean;
27
33
  declare function isDirectPropEdge(edge: IHeapEdge): boolean;
28
34
  declare function isReturnEdge(edge: IHeapEdge): boolean;
@@ -64,16 +70,14 @@ declare function getBooleanNodeValue(node: IHeapNode): Nullable<boolean>;
64
70
  declare function getToNodeByEdge(node: Nullable<IHeapNode>, propName: string, propType?: string): Nullable<IHeapNode>;
65
71
  declare function extractHTMLElementNodeInfo(node: IHeapNode): string;
66
72
  declare function hasOnlyWeakReferrers(node: IHeapNode): boolean;
67
- declare function getRunMetaFilePath(): string;
68
- declare function loadRunMetaInfo(metaFile?: Optional<string>): RunMetaInfo;
69
- declare function loadTargetInfoFromRunMeta(): void;
70
73
  declare function getSnapshotSequenceFilePath(): string;
71
74
  declare function loadTabsOrder(metaFile?: Optional<string>): E2EStepInfo[];
72
- declare function isInterestingPath(p: LeakTracePathItem): boolean;
73
75
  declare function isObjectNode(node: IHeapNode): boolean;
74
76
  declare function isPlainJSObjectNode(node: IHeapNode): boolean;
75
77
  declare function pathHasDetachedHTMLNode(path: LeakTracePathItem): boolean;
76
78
  declare function pathHasEdgeWithIndex(path: LeakTracePathItem, idx: number): boolean;
79
+ declare function pathHasEdgeWithName(path: LeakTracePathItem, edgeName: string): boolean;
80
+ declare function pathHasNodeOrEdgeWithName(path: LeakTracePathItem, name: Optional<string>): boolean;
77
81
  declare function getLastNodeId(path: LeakTracePathItem): number;
78
82
  declare function getReadablePercent(num: number): string;
79
83
  declare function getReadableBytes(bytes: Optional<number>): string;
@@ -129,14 +133,16 @@ declare function getRetainedSize(node: IHeapNode): number;
129
133
  declare function aggregateDominatorMetrics(ids: HeapNodeIdSet, snapshot: IHeapSnapshot, checkNodeCb: (node: IHeapNode) => boolean, nodeMetricsCb: (node: IHeapNode) => number): number;
130
134
  declare function getLeakTracePathLength(path: LeakTracePathItem): number;
131
135
  declare function getNumberAtPercentile(arr: number[], percentile: number): number;
136
+ declare function mapToObject(map: Map<string, string>): StringRecord;
137
+ declare function objectToMap(object: StringRecord): Map<string, string>;
132
138
  declare const _default: {
133
139
  aggregateDominatorMetrics: typeof aggregateDominatorMetrics;
134
140
  applyToNodes: typeof applyToNodes;
135
141
  callAsync: typeof callAsync;
136
142
  camelCaseToReadableString: typeof camelCaseToReadableString;
143
+ checkIsChildOfParent: typeof checkIsChildOfParent;
137
144
  checkSnapshots: typeof checkSnapshots;
138
145
  checkUninstalledLibrary: typeof checkUninstalledLibrary;
139
- checkIsChildOfParent: typeof checkIsChildOfParent;
140
146
  closePuppeteer: typeof closePuppeteer;
141
147
  dumpSnapshot: typeof dumpSnapshot;
142
148
  equalOrMatch: typeof equalOrMatch;
@@ -145,13 +151,14 @@ declare const _default: {
145
151
  extractHTMLElementNodeInfo: typeof extractHTMLElementNodeInfo;
146
152
  filterNodesInPlace: typeof filterNodesInPlace;
147
153
  getAllDominators: typeof getAllDominators;
154
+ getBooleanNodeValue: typeof getBooleanNodeValue;
148
155
  getClosureSourceUrl: typeof getClosureSourceUrl;
149
156
  getConditionalDominatorIds: typeof getConditionalDominatorIds;
150
- getError: typeof getError;
151
157
  getEdgeByNameAndType: typeof getEdgeByNameAndType;
158
+ getError: typeof getError;
152
159
  getLastNodeId: typeof getLastNodeId;
153
- getLeakedNode: typeof getLeakedNode;
154
160
  getLeakTracePathLength: typeof getLeakTracePathLength;
161
+ getLeakedNode: typeof getLeakedNode;
155
162
  getNodesIdSet: typeof getNodesIdSet;
156
163
  getNumberAtPercentile: typeof getNumberAtPercentile;
157
164
  getNumberNodeValue: typeof getNumberNodeValue;
@@ -159,17 +166,16 @@ declare const _default: {
159
166
  getReadablePercent: typeof getReadablePercent;
160
167
  getReadableTime: typeof getReadableTime;
161
168
  getRetainedSize: typeof getRetainedSize;
162
- getRunMetaFilePath: typeof getRunMetaFilePath;
163
169
  getScenarioName: typeof getScenarioName;
164
170
  getSingleSnapshotFileForAnalysis: typeof getSingleSnapshotFileForAnalysis;
165
171
  getSnapshotDirForAnalysis: typeof getSnapshotDirForAnalysis;
166
- getSnapshotFilesInDir: typeof getSnapshotFilesInDir;
172
+ getSnapshotFilePath: typeof getSnapshotFilePath;
173
+ getSnapshotFilePathWithTabType: typeof getSnapshotFilePathWithTabType;
167
174
  getSnapshotFilesFromTabsOrder: typeof getSnapshotFilesFromTabsOrder;
175
+ getSnapshotFilesInDir: typeof getSnapshotFilesInDir;
168
176
  getSnapshotFromFile: typeof getSnapshotFromFile;
169
177
  getSnapshotNodeIdsFromFile: typeof getSnapshotNodeIdsFromFile;
170
178
  getSnapshotSequenceFilePath: typeof getSnapshotSequenceFilePath;
171
- getSnapshotFilePath: typeof getSnapshotFilePath;
172
- getSnapshotFilePathWithTabType: typeof getSnapshotFilePathWithTabType;
173
179
  getStringNodeValue: typeof getStringNodeValue;
174
180
  getToNodeByEdge: typeof getToNodeByEdge;
175
181
  getUniqueID: typeof getUniqueID;
@@ -180,18 +186,22 @@ declare const _default: {
180
186
  hasReactEdges: typeof hasReactEdges;
181
187
  isAlternateNode: typeof isAlternateNode;
182
188
  isBlinkRootNode: typeof isBlinkRootNode;
189
+ isCppRootsNode: typeof isCppRootsNode;
190
+ isDOMInternalNode: typeof isDOMInternalNode;
191
+ isDOMNodeIncomplete: typeof isDOMNodeIncomplete;
192
+ isDOMTextNode: typeof isDOMTextNode;
183
193
  isDebuggableNode: typeof isDebuggableNode;
184
- isDetachedFiberNode: typeof isDetachedFiberNode;
185
194
  isDetachedDOMNode: typeof isDetachedDOMNode;
195
+ isDetachedFiberNode: typeof isDetachedFiberNode;
186
196
  isDirectPropEdge: typeof isDirectPropEdge;
187
197
  isDocumentDOMTreesRoot: typeof isDocumentDOMTreesRoot;
188
- isDOMNodeIncomplete: typeof isDOMNodeIncomplete;
189
198
  isEssentialEdge: typeof isEssentialEdge;
190
199
  isFiberNode: typeof isFiberNode;
191
200
  isFiberNodeDeletionsEdge: typeof isFiberNodeDeletionsEdge;
201
+ isGlobalHandlesNode: typeof isGlobalHandlesNode;
202
+ isHTMLDocumentNode: typeof isHTMLDocumentNode;
192
203
  isHermesInternalObject: typeof isHermesInternalObject;
193
204
  isHostRoot: typeof isHostRoot;
194
- isInterestingPath: typeof isInterestingPath;
195
205
  isMeaningfulEdge: typeof isMeaningfulEdge;
196
206
  isMeaningfulNode: typeof isMeaningfulNode;
197
207
  isNodeDominatedByDeletionsArray: typeof isNodeDominatedByDeletionsArray;
@@ -210,19 +220,22 @@ declare const _default: {
210
220
  isWeakMapEdge: typeof isWeakMapEdge;
211
221
  isWeakMapEdgeToKey: typeof isWeakMapEdgeToKey;
212
222
  isWeakMapEdgeToValue: typeof isWeakMapEdgeToValue;
223
+ isXMLDocumentNode: typeof isXMLDocumentNode;
213
224
  iterateChildFiberNodes: typeof iterateChildFiberNodes;
214
225
  iterateDescendantFiberNodes: typeof iterateDescendantFiberNodes;
215
- loadRunMetaInfo: typeof loadRunMetaInfo;
216
226
  loadLeakFilter: typeof loadLeakFilter;
217
227
  loadScenario: typeof loadScenario;
218
228
  loadTabsOrder: typeof loadTabsOrder;
219
- loadTargetInfoFromRunMeta: typeof loadTargetInfoFromRunMeta;
229
+ mapToObject: typeof mapToObject;
220
230
  markAllDetachedFiberNode: typeof markAllDetachedFiberNode;
221
231
  markAlternateFiberNode: typeof markAlternateFiberNode;
222
232
  memCache: Record<string, any>;
223
233
  normalizeBaseUrl: typeof normalizeBaseUrl;
234
+ objectToMap: typeof objectToMap;
224
235
  pathHasDetachedHTMLNode: typeof pathHasDetachedHTMLNode;
225
236
  pathHasEdgeWithIndex: typeof pathHasEdgeWithIndex;
237
+ pathHasEdgeWithName: typeof pathHasEdgeWithName;
238
+ pathHasNodeOrEdgeWithName: typeof pathHasNodeOrEdgeWithName;
226
239
  repeat: typeof repeat;
227
240
  resolveFilePath: typeof resolveFilePath;
228
241
  resolveSnapshotFilePath: typeof resolveSnapshotFilePath;
@@ -233,7 +246,6 @@ declare const _default: {
233
246
  shuffleArray: typeof shuffleArray;
234
247
  throwError: typeof throwError;
235
248
  upperCaseFirstCharacter: typeof upperCaseFirstCharacter;
236
- getBooleanNodeValue: typeof getBooleanNodeValue;
237
249
  };
238
250
  export default _default;
239
251
  //# sourceMappingURL=Utils.d.ts.map
package/dist/lib/Utils.js CHANGED
@@ -53,7 +53,6 @@ const Config_1 = __importStar(require("./Config"));
53
53
  const Console_1 = __importDefault(require("./Console"));
54
54
  const Constant_1 = __importDefault(require("./Constant"));
55
55
  const HeapParser_1 = __importDefault(require("./HeapParser"));
56
- const BrowserInfo_1 = __importDefault(require("./BrowserInfo"));
57
56
  const memCache = Object.create(null);
58
57
  const FileManager_1 = __importDefault(require("./FileManager"));
59
58
  const __1 = require("..");
@@ -133,6 +132,21 @@ function isFiberNode(node) {
133
132
  function isDetachedFiberNode(node) {
134
133
  return isFiberNode(node) && isDetached(node);
135
134
  }
135
+ // return true if this node is InternalNode (native)
136
+ function isDOMInternalNode(node) {
137
+ if (node == null) {
138
+ return false;
139
+ }
140
+ return (node.type === 'native' &&
141
+ (node.name === 'InternalNode' || node.name === 'Detached InternalNode'));
142
+ }
143
+ // return true the the nodee is a global handles node
144
+ function isGlobalHandlesNode(node) {
145
+ if (node == null) {
146
+ return false;
147
+ }
148
+ return node.name === '(Global handles)' && node.type === 'synthetic';
149
+ }
136
150
  // this function returns a more general sense of DOM nodes. Specifically,
137
151
  // any detached DOM nodes (e.g., HTMLXXElement, IntersectionObserver etc.)
138
152
  // that are not internal nodes.
@@ -211,18 +225,55 @@ function isPendingActivityNode(node) {
211
225
  if (!node || !node.name) {
212
226
  return false;
213
227
  }
214
- return node.type === 'synthetic' && node.name === 'Pending activities';
228
+ if (node.type !== 'synthetic' && node.type !== 'native') {
229
+ return false;
230
+ }
231
+ return node.name === 'Pending activities';
215
232
  }
233
+ const htmlElementRegex = /^HTML.*Element$/;
234
+ const svgElementRegex = /^SVG.*Element$/;
235
+ const htmlCollectionRegex = /^HTML.*Collection$/;
236
+ const cssElementRegex = /^CSS/;
237
+ const styleSheetRegex = /StyleSheet/;
238
+ // special DOM element names that are not
239
+ // included in the previous regex definitions
240
+ const domElementSpecialNames = new Set([
241
+ 'DOMTokenList',
242
+ 'HTMLDocument',
243
+ 'InternalNode',
244
+ 'Text',
245
+ 'XMLDocument',
246
+ ]);
216
247
  // check the node against a curated list of known HTML Elements
217
248
  // the list may be incomplete
218
249
  function isDOMNodeIncomplete(node) {
250
+ if (node.type !== 'native') {
251
+ return false;
252
+ }
219
253
  let name = node.name;
220
- const pattern = /^HTML.*Element$/;
221
254
  const detachedPrefix = 'Detached ';
222
255
  if (name.startsWith(detachedPrefix)) {
223
256
  name = name.substring(detachedPrefix.length);
224
257
  }
225
- return pattern.test(name);
258
+ return (htmlElementRegex.test(name) ||
259
+ svgElementRegex.test(name) ||
260
+ cssElementRegex.test(name) ||
261
+ styleSheetRegex.test(name) ||
262
+ htmlCollectionRegex.test(name) ||
263
+ domElementSpecialNames.has(name));
264
+ }
265
+ function isXMLDocumentNode(node) {
266
+ return node.type === 'native' && node.name === 'XMLDocument';
267
+ }
268
+ function isHTMLDocumentNode(node) {
269
+ return node.type === 'native' && node.name === 'HTMLDocument';
270
+ }
271
+ function isDOMTextNode(node) {
272
+ return node.type === 'native' && node.name === 'Text';
273
+ }
274
+ // check if this is a [C++ roots] (synthetic) node
275
+ function isCppRootsNode(node) {
276
+ return node.name === 'C++ roots' && node.type === 'synthetic';
226
277
  }
227
278
  function isRootNode(node, opt = {}) {
228
279
  if (!node) {
@@ -452,7 +503,7 @@ function hasHostRoot(node) {
452
503
  return false;
453
504
  }
454
505
  function filterNodesInPlace(idSet, snapshot, cb) {
455
- const ids = Array.from(idSet.keys());
506
+ const ids = Array.from(idSet);
456
507
  for (const id of ids) {
457
508
  const node = snapshot.getNodeById(id);
458
509
  if (node && !cb(node, snapshot)) {
@@ -461,7 +512,7 @@ function filterNodesInPlace(idSet, snapshot, cb) {
461
512
  }
462
513
  }
463
514
  function applyToNodes(idSet, snapshot, cb, options = {}) {
464
- let ids = Array.from(idSet.keys());
515
+ let ids = Array.from(idSet);
465
516
  if (options.shuffle) {
466
517
  ids.sort(() => Math.random() - 0.5);
467
518
  }
@@ -471,7 +522,9 @@ function applyToNodes(idSet, snapshot, cb, options = {}) {
471
522
  for (const id of ids) {
472
523
  const node = snapshot.getNodeById(id);
473
524
  if (!node) {
474
- Console_1.default.warning(`node @${id} is not found`);
525
+ if (Config_1.default.verbose) {
526
+ Console_1.default.warning(`node @${id} is not found`);
527
+ }
475
528
  return;
476
529
  }
477
530
  cb(node, snapshot);
@@ -831,27 +884,6 @@ function hasOnlyWeakReferrers(node) {
831
884
  (edge) => edge.type !== 'weak' && edge.type !== 'shortcut');
832
885
  return referrer == null;
833
886
  }
834
- function getRunMetaFilePath() {
835
- return Config_1.default.useExternalSnapshot
836
- ? Config_1.default.externalRunMetaFile
837
- : Config_1.default.runMetaFile;
838
- }
839
- function loadRunMetaInfo(metaFile = undefined) {
840
- const file = metaFile || getRunMetaFilePath();
841
- try {
842
- const content = fs_1.default.readFileSync(file, 'UTF-8');
843
- return JSON.parse(content);
844
- }
845
- catch (_) {
846
- throw haltOrThrow('Run info missing. Please make sure `memlab run` is complete.');
847
- }
848
- }
849
- function loadTargetInfoFromRunMeta() {
850
- const meta = loadRunMetaInfo();
851
- Config_1.default.targetApp = meta.app;
852
- Config_1.default.targetTab = meta.interaction;
853
- BrowserInfo_1.default.load(meta.browserInfo);
854
- }
855
887
  function getSnapshotSequenceFilePath() {
856
888
  if (!Config_1.default.useExternalSnapshot) {
857
889
  // load the snapshot sequence meta file from the default location
@@ -870,7 +902,9 @@ function getSnapshotSequenceFilePath() {
870
902
  // this should be called only after exploration
871
903
  function loadTabsOrder(metaFile = undefined) {
872
904
  try {
873
- const file = metaFile || getSnapshotSequenceFilePath();
905
+ const file = metaFile != null && fs_1.default.existsSync(metaFile)
906
+ ? metaFile
907
+ : getSnapshotSequenceFilePath();
874
908
  const content = fs_1.default.readFileSync(file, 'UTF-8');
875
909
  return JSON.parse(content);
876
910
  }
@@ -878,31 +912,6 @@ function loadTabsOrder(metaFile = undefined) {
878
912
  throw haltOrThrow('snapshot meta data invalid or missing');
879
913
  }
880
914
  }
881
- // if true the leak trace is will be reported
882
- function isInterestingPath(p) {
883
- // do not filter paths when analyzing Hermes snapshots
884
- if (Config_1.default.jsEngine === 'hermes') {
885
- return true;
886
- }
887
- // if the path has pattern: Window -> [InternalNode]+ -> DetachedElement
888
- if (Config_1.default.hideBrowserLeak && internalNodeRetainsDetachedElement(p)) {
889
- return false;
890
- }
891
- // if the path has pattern: ShadowRoot -> DetachedElement
892
- if (Config_1.default.hideBrowserLeak && shadowRootRetainsDetachedElement(p)) {
893
- return false;
894
- }
895
- // if the path has pattern: StyleEngine -> InternalNode -> DetachedElement
896
- if (Config_1.default.hideBrowserLeak && styleEngineRetainsDetachedElement(p)) {
897
- return false;
898
- }
899
- // if the path has pattern: Pending activitiies -> DetachedElement
900
- if (Config_1.default.hideBrowserLeak &&
901
- pendingActivitiesRetainsDetachedElementChain(p)) {
902
- return false;
903
- }
904
- return true;
905
- }
906
915
  // return true if the heap node represents JS object or closure
907
916
  function isObjectNode(node) {
908
917
  if (isPlainJSObjectNode(node)) {
@@ -920,109 +929,53 @@ function isPlainJSObjectNode(node) {
920
929
  }
921
930
  return node.name === 'Object';
922
931
  }
923
- // check if the path has pattern:
924
- // Window -> [InternalNode | Text]+ -> DetachedElement
925
- function internalNodeRetainsDetachedElement(path) {
926
- var _a, _b;
932
+ function pathHasDetachedHTMLNode(path) {
927
933
  if (!path) {
928
934
  return false;
929
935
  }
930
936
  let p = path;
931
- // GC root is not Window
932
- if (!p.node || !p.node.name.startsWith('Window')) {
933
- return false;
934
- }
935
- p = p.next;
936
- // Window is not poining to InternalNode
937
- if (!p || !p.node || p.node.name !== 'InternalNode') {
938
- return false;
939
- }
940
- // skip the rest InternalNode
941
- while (((_a = p.node) === null || _a === void 0 ? void 0 : _a.name) === 'InternalNode' || ((_b = p.node) === null || _b === void 0 ? void 0 : _b.name) === 'Text') {
942
- p = p.next;
943
- if (!p) {
944
- return false;
937
+ while (p) {
938
+ if (p.node && isDetachedDOMNode(p.node)) {
939
+ return true;
945
940
  }
946
- }
947
- // check if the node is a detached element
948
- return p && isDetachedDOMNode(p.node);
949
- }
950
- // check if the path has pattern: ShadowRoot -> DetachedElement
951
- function shadowRootRetainsDetachedElement(path) {
952
- let p = path;
953
- // find the ShadowRoot
954
- while (p && p.node && p.node.name !== 'ShadowRoot') {
955
941
  p = p.next;
956
- if (!p) {
957
- return false;
958
- }
959
942
  }
960
- p = p.next;
961
- // check if the node is a detached element
962
- return !!p && isDetachedDOMNode(p.node);
943
+ return false;
963
944
  }
964
- // check if the path has pattern: StyleEngine -> InternalNode -> DetachedElement
965
- function styleEngineRetainsDetachedElement(path) {
966
- let p = path;
967
- // find the StyleEngine
968
- while (p && p.node && p.node.name !== 'StyleEngine') {
969
- p = p.next;
970
- if (!p) {
971
- return false;
972
- }
973
- }
974
- p = p.next;
975
- // StyleEngine is not poining to InternalNode
976
- if (!p || !p.node || p.node.name !== 'InternalNode') {
945
+ function pathHasEdgeWithIndex(path, idx) {
946
+ if (!path || typeof idx !== 'number') {
977
947
  return false;
978
948
  }
979
- p = p.next;
980
- // check if the InternalNode is pointing to a detached element
981
- return !!p && isDetachedDOMNode(p.node);
982
- }
983
- function pendingActivitiesRetainsDetachedElementChain(path) {
984
949
  let p = path;
985
- // find the Pending activities
986
- while (p && p.node && !isPendingActivityNode(p.node)) {
987
- p = p.next;
988
- if (!p) {
989
- return false;
990
- }
991
- }
992
- p = p.next;
993
- if (!p || !p.node) {
994
- return false;
995
- }
996
- // all the following reference chain is detached DOM elements
997
- // pointing to other detached DOM elements
998
- while (p && p.node) {
999
- if (!isDetachedDOMNode(p.node)) {
1000
- return false;
950
+ while (p) {
951
+ if (p.edge && p.edge.edgeIndex === idx) {
952
+ return true;
1001
953
  }
1002
954
  p = p.next;
1003
955
  }
1004
- return true;
956
+ return false;
1005
957
  }
1006
- function pathHasDetachedHTMLNode(path) {
1007
- if (!path) {
1008
- return false;
1009
- }
958
+ function pathHasEdgeWithName(path, edgeName) {
1010
959
  let p = path;
1011
960
  while (p) {
1012
- if (p.node && isDetachedDOMNode(p.node)) {
961
+ if (p.edge && p.edge.name_or_index === edgeName) {
1013
962
  return true;
1014
963
  }
1015
964
  p = p.next;
1016
965
  }
1017
966
  return false;
1018
967
  }
1019
- function pathHasEdgeWithIndex(path, idx) {
1020
- if (!path || typeof idx !== 'number') {
1021
- return false;
968
+ function pathHasNodeOrEdgeWithName(path, name) {
969
+ if (name == null) {
970
+ return true;
1022
971
  }
972
+ name = name.toLowerCase();
1023
973
  let p = path;
1024
974
  while (p) {
1025
- if (p.edge && p.edge.edgeIndex === idx) {
975
+ if (p.edge && `${p.edge.name_or_index}`.toLowerCase().includes(name)) {
976
+ return true;
977
+ }
978
+ if (p.node && `${p.node.name}`.toLowerCase().includes(name)) {
1026
979
  return true;
1027
980
  }
1028
981
  p = p.next;
@@ -1772,16 +1725,22 @@ function runShell(command, options = {}) {
1772
1725
  execOptions.shell = '/bin/bash';
1773
1726
  }
1774
1727
  let ret = null;
1728
+ if (Config_1.default.verbose || Config_1.default.isContinuousTest) {
1729
+ Console_1.default.lowLevel(`running shell command: ${command}`);
1730
+ }
1775
1731
  try {
1776
1732
  ret = child_process_1.default.execSync(command, execOptions);
1777
1733
  }
1778
1734
  catch (ex) {
1779
- if (Config_1.default.verbose) {
1735
+ if (Config_1.default.verbose || Config_1.default.isContinuousTest) {
1780
1736
  if (ex instanceof Error) {
1781
1737
  Console_1.default.lowLevel(ex.message);
1782
1738
  Console_1.default.lowLevel((_c = ex.stack) !== null && _c !== void 0 ? _c : '');
1783
1739
  }
1784
1740
  }
1741
+ if (options.throwError) {
1742
+ throw ex;
1743
+ }
1785
1744
  if (options.ignoreError === true) {
1786
1745
  return '';
1787
1746
  }
@@ -1824,14 +1783,28 @@ function getNumberAtPercentile(arr, percentile) {
1824
1783
  }
1825
1784
  return arr[indexInt];
1826
1785
  }
1786
+ function mapToObject(map) {
1787
+ const ret = Object.create(null);
1788
+ map.forEach((v, k) => {
1789
+ ret[k] = v;
1790
+ });
1791
+ return ret;
1792
+ }
1793
+ function objectToMap(object) {
1794
+ const ret = new Map();
1795
+ for (const k of Object.keys(object)) {
1796
+ ret.set(k, object[k]);
1797
+ }
1798
+ return ret;
1799
+ }
1827
1800
  exports.default = {
1828
1801
  aggregateDominatorMetrics,
1829
1802
  applyToNodes,
1830
1803
  callAsync,
1831
1804
  camelCaseToReadableString,
1805
+ checkIsChildOfParent,
1832
1806
  checkSnapshots,
1833
1807
  checkUninstalledLibrary,
1834
- checkIsChildOfParent,
1835
1808
  closePuppeteer,
1836
1809
  dumpSnapshot,
1837
1810
  equalOrMatch,
@@ -1840,13 +1813,14 @@ exports.default = {
1840
1813
  extractHTMLElementNodeInfo,
1841
1814
  filterNodesInPlace,
1842
1815
  getAllDominators,
1816
+ getBooleanNodeValue,
1843
1817
  getClosureSourceUrl,
1844
1818
  getConditionalDominatorIds,
1845
- getError,
1846
1819
  getEdgeByNameAndType,
1820
+ getError,
1847
1821
  getLastNodeId,
1848
- getLeakedNode,
1849
1822
  getLeakTracePathLength,
1823
+ getLeakedNode,
1850
1824
  getNodesIdSet,
1851
1825
  getNumberAtPercentile,
1852
1826
  getNumberNodeValue,
@@ -1854,17 +1828,16 @@ exports.default = {
1854
1828
  getReadablePercent,
1855
1829
  getReadableTime,
1856
1830
  getRetainedSize,
1857
- getRunMetaFilePath,
1858
1831
  getScenarioName,
1859
1832
  getSingleSnapshotFileForAnalysis,
1860
1833
  getSnapshotDirForAnalysis,
1861
- getSnapshotFilesInDir,
1834
+ getSnapshotFilePath,
1835
+ getSnapshotFilePathWithTabType,
1862
1836
  getSnapshotFilesFromTabsOrder,
1837
+ getSnapshotFilesInDir,
1863
1838
  getSnapshotFromFile,
1864
1839
  getSnapshotNodeIdsFromFile,
1865
1840
  getSnapshotSequenceFilePath,
1866
- getSnapshotFilePath,
1867
- getSnapshotFilePathWithTabType,
1868
1841
  getStringNodeValue,
1869
1842
  getToNodeByEdge,
1870
1843
  getUniqueID,
@@ -1875,18 +1848,22 @@ exports.default = {
1875
1848
  hasReactEdges,
1876
1849
  isAlternateNode,
1877
1850
  isBlinkRootNode,
1851
+ isCppRootsNode,
1852
+ isDOMInternalNode,
1853
+ isDOMNodeIncomplete,
1854
+ isDOMTextNode,
1878
1855
  isDebuggableNode,
1879
- isDetachedFiberNode,
1880
1856
  isDetachedDOMNode,
1857
+ isDetachedFiberNode,
1881
1858
  isDirectPropEdge,
1882
1859
  isDocumentDOMTreesRoot,
1883
- isDOMNodeIncomplete,
1884
1860
  isEssentialEdge,
1885
1861
  isFiberNode,
1886
1862
  isFiberNodeDeletionsEdge,
1863
+ isGlobalHandlesNode,
1864
+ isHTMLDocumentNode,
1887
1865
  isHermesInternalObject,
1888
1866
  isHostRoot,
1889
- isInterestingPath,
1890
1867
  isMeaningfulEdge,
1891
1868
  isMeaningfulNode,
1892
1869
  isNodeDominatedByDeletionsArray,
@@ -1905,19 +1882,22 @@ exports.default = {
1905
1882
  isWeakMapEdge,
1906
1883
  isWeakMapEdgeToKey,
1907
1884
  isWeakMapEdgeToValue,
1885
+ isXMLDocumentNode,
1908
1886
  iterateChildFiberNodes,
1909
1887
  iterateDescendantFiberNodes,
1910
- loadRunMetaInfo,
1911
1888
  loadLeakFilter,
1912
1889
  loadScenario,
1913
1890
  loadTabsOrder,
1914
- loadTargetInfoFromRunMeta,
1891
+ mapToObject,
1915
1892
  markAllDetachedFiberNode,
1916
1893
  markAlternateFiberNode,
1917
1894
  memCache,
1918
1895
  normalizeBaseUrl,
1896
+ objectToMap,
1919
1897
  pathHasDetachedHTMLNode,
1920
1898
  pathHasEdgeWithIndex,
1899
+ pathHasEdgeWithName,
1900
+ pathHasNodeOrEdgeWithName,
1921
1901
  repeat,
1922
1902
  resolveFilePath,
1923
1903
  resolveSnapshotFilePath,
@@ -1928,5 +1908,4 @@ exports.default = {
1928
1908
  shuffleArray,
1929
1909
  throwError,
1930
1910
  upperCaseFirstCharacter,
1931
- getBooleanNodeValue,
1932
1911
  };
@@ -10,6 +10,7 @@
10
10
  import type { PlotMemoryOptions } from '../Types';
11
11
  declare class MemoryBarChart {
12
12
  plotMemoryBarChart(options?: PlotMemoryOptions): void;
13
+ private isPlotDataValid;
13
14
  private loadPlotDataFromTabsOrder;
14
15
  private loadPlotDataFromWorkDir;
15
16
  private loadPlotData;