@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.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -1
- package/dist/lib/Config.d.ts +11 -0
- package/dist/lib/Config.js +26 -1
- package/dist/lib/Constant.js +1 -0
- package/dist/lib/FileManager.d.ts +3 -0
- package/dist/lib/FileManager.js +10 -1
- package/dist/lib/HeapAnalyzer.d.ts +5 -1
- package/dist/lib/HeapAnalyzer.js +56 -34
- package/dist/lib/RunInfoUtils.d.ts +39 -0
- package/dist/lib/RunInfoUtils.js +86 -0
- package/dist/lib/TraceSampler.d.ts +36 -0
- package/dist/lib/TraceSampler.js +78 -0
- package/dist/lib/Types.d.ts +12 -2
- package/dist/lib/Utils.d.ts +31 -19
- package/dist/lib/Utils.js +124 -145
- package/dist/lib/charts/MemoryBarChart.d.ts +1 -0
- package/dist/lib/charts/MemoryBarChart.js +18 -3
- package/dist/lib/heap-data/HeapStringNode.js +25 -16
- package/dist/lib/leak-filters/rules/FilterOverSizedNodeAsLeak.rule.js +50 -0
- package/dist/lib/trace-filters/BaseTraceFilter.rule.d.ts +29 -0
- package/dist/lib/trace-filters/BaseTraceFilter.rule.js +22 -0
- package/dist/lib/trace-filters/LeakTraceFilter.d.ts +20 -0
- package/dist/lib/trace-filters/LeakTraceFilter.js +37 -0
- package/dist/lib/trace-filters/TraceFilterRuleList.d.ts +13 -0
- package/dist/lib/trace-filters/TraceFilterRuleList.js +35 -0
- package/dist/lib/trace-filters/rules/FilterAttachedDOMToDetachedDOMTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterAttachedDOMToDetachedDOMTrace.rule.js +55 -0
- package/dist/lib/trace-filters/rules/FilterCppRootsToDetachedDOMTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterCppRootsToDetachedDOMTrace.rule.js +44 -0
- package/dist/lib/trace-filters/rules/FilterDOMNodeChainTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterDOMNodeChainTrace.rule.js +41 -0
- package/dist/lib/trace-filters/rules/FilterHermesTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterHermesTrace.rule.js +29 -0
- package/dist/lib/trace-filters/rules/FilterInternalNodeTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterInternalNodeTrace.rule.js +57 -0
- package/dist/lib/trace-filters/rules/FilterPendingActivitiesTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterPendingActivitiesTrace.rule.js +62 -0
- package/dist/lib/trace-filters/rules/FilterShadowRootTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterShadowRootTrace.rule.js +44 -0
- package/dist/lib/trace-filters/rules/FilterStyleEngineTrace.rule.d.ts +15 -0
- package/dist/lib/trace-filters/rules/FilterStyleEngineTrace.rule.js +49 -0
- package/dist/logger/LeakClusterLogger.js +1 -0
- package/dist/paths/TraceFinder.js +17 -3
- package/dist/trace-cluster/TraceBucket.d.ts +1 -1
- package/dist/trace-cluster/TraceBucket.js +20 -14
- package/dist/trace-cluster/strategies/TraceSimilarityStrategy.js +1 -0
- package/package.json +1 -1
package/dist/lib/Types.d.ts
CHANGED
|
@@ -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
|
-
|
|
1932
|
+
controlWorkDirs: string[];
|
|
1928
1933
|
treatmentWorkDir: string;
|
|
1929
1934
|
};
|
|
1930
1935
|
/** @internal */
|
|
1931
1936
|
export declare type PlotMemoryOptions = {
|
|
1932
|
-
|
|
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
|
package/dist/lib/Utils.d.ts
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
932
|
-
|
|
933
|
-
|
|
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
|
-
|
|
961
|
-
// check if the node is a detached element
|
|
962
|
-
return !!p && isDetachedDOMNode(p.node);
|
|
943
|
+
return false;
|
|
963
944
|
}
|
|
964
|
-
|
|
965
|
-
|
|
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
|
-
|
|
986
|
-
|
|
987
|
-
|
|
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
|
|
956
|
+
return false;
|
|
1005
957
|
}
|
|
1006
|
-
function
|
|
1007
|
-
if (!path) {
|
|
1008
|
-
return false;
|
|
1009
|
-
}
|
|
958
|
+
function pathHasEdgeWithName(path, edgeName) {
|
|
1010
959
|
let p = path;
|
|
1011
960
|
while (p) {
|
|
1012
|
-
if (p.
|
|
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
|
|
1020
|
-
if (
|
|
1021
|
-
return
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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;
|