Socket
Socket
Sign inDemoInstall

@memlab/core

Package Overview
Dependencies
158
Maintainers
3
Versions
38
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.1.19 to 1.1.20

static/visit-order-single-snapshot.json

13

dist/__tests__/parser/StringNode.test.js

@@ -31,3 +31,3 @@ "use strict";

test('String heap object APIs work', () => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b, _c;
var _a, _b, _c, _d, _e, _f;
class TestObject {

@@ -48,2 +48,4 @@ constructor() {

expect(testObject).not.toBe(null);
// test the number of referrers getter
expect(testObject === null || testObject === void 0 ? void 0 : testObject.numOfReferrers).toBeGreaterThan(0);
// testObject.originalString === 'test'

@@ -63,2 +65,11 @@ const originalString = testObject === null || testObject === void 0 ? void 0 : testObject.getReferenceNode('originalString');

expect((_c = complexConcatString === null || complexConcatString === void 0 ? void 0 : complexConcatString.toStringNode()) === null || _c === void 0 ? void 0 : _c.stringValue).toBe('prefix_value_123_suffix');
// test the toJSONString API
let strRepresentation = (_d = concatString === null || concatString === void 0 ? void 0 : concatString.toJSONString()) !== null && _d !== void 0 ? _d : '{}';
let rep = JSON.parse(strRepresentation);
expect(rep.type).toBe('concatenated string');
expect(rep.stringValue).toBe(undefined);
strRepresentation = (_f = (_e = concatString === null || concatString === void 0 ? void 0 : concatString.toStringNode()) === null || _e === void 0 ? void 0 : _e.toJSONString()) !== null && _f !== void 0 ? _f : '{}';
rep = JSON.parse(strRepresentation);
expect(rep.type).toBe('concatenated string');
expect(rep.stringValue).toBe('prefix_suffix');
}), timeout);

@@ -33,2 +33,8 @@ /**

}
if (plotData.length === 0) {
if (Config_1.default.verbose) {
Console_1.default.warning('no memory usage data to plot');
}
return;
}
// normalize plot data

@@ -35,0 +41,0 @@ const minY = 1;

@@ -199,2 +199,4 @@ /**

interceptScript: boolean;
isAnalyzingMainThread: boolean;
targetWorkerTitle: Nullable<string>;
constructor(options?: ConfigOption);

@@ -201,0 +203,0 @@ private initInternalConfigs;

@@ -214,2 +214,6 @@ "use strict";

this.warmupRepeat = 2;
// by default, analyzing heap in main thread
this.isAnalyzingMainThread = true;
// target worker's title
this.targetWorkerTitle = null;
// default waiting time when there is no page load checker callback

@@ -216,0 +220,0 @@ this.delayWhenNoPageLoadCheck = 2000;

@@ -54,3 +54,5 @@ /**

getRunMetaFile(options?: FileOption): string;
getRunMetaExternalTemplateFile(): string;
getSnapshotSequenceMetaFile(options?: FileOption): string;
getSnapshotSequenceExternalTemplateFile(): string;
getInputDataDir(): string;

@@ -76,2 +78,3 @@ getAllFilesInSubDirs(dir: string): string[];

isWithinInternalDirectory(filePath: string): boolean;
createDefaultVisitOrderMetaFile(options?: FileOption): void;
initDirs(config: MemLabConfig, options?: FileOption): void;

@@ -78,0 +81,0 @@ }

@@ -182,5 +182,11 @@ "use strict";

}
getRunMetaExternalTemplateFile() {
return path_1.default.join(this.getCodeDataDir(), 'run-meta.json');
}
getSnapshotSequenceMetaFile(options = FileManager.defaultFileOption) {
return path_1.default.join(this.getCurDataDir(options), 'snap-seq.json');
}
getSnapshotSequenceExternalTemplateFile() {
return path_1.default.join(this.getCodeDataDir(), 'visit-order.json');
}
getInputDataDir() {

@@ -335,2 +341,33 @@ return path_1.default.join(this.getDefaultWorkDir(), 'input');

}
createDefaultVisitOrderMetaFile(options = FileManager.defaultFileOption) {
// if memlab/data/cur doesn't exist, return
const curDataDir = this.getCurDataDir(options);
if (!fs_extra_1.default.existsSync(curDataDir)) {
return;
}
// if the snap-seq.json file exists, return
const snapshotSeqMetaFile = this.getSnapshotSequenceMetaFile(options);
if (fs_extra_1.default.existsSync(snapshotSeqMetaFile)) {
return;
}
// if there is no .heapsnapshot file, return
const files = fs_extra_1.default.readdirSync(curDataDir);
const snapshotFile = files.find(file => file.endsWith('.heapsnapshot'));
if (snapshotFile == null) {
return;
}
// If there is at least one snapshot, create a snap-seq.json file.
// First, get the meta file for leak detection in a single heap snapshot
const codeDataDir = this.getCodeDataDir();
const singleSnapshotMetaFile = path_1.default.join(codeDataDir, 'visit-order-single-snapshot.json');
const visitOrder = JSON.parse(fs_extra_1.default.readFileSync(singleSnapshotMetaFile, 'UTF-8'));
// fill in snapshot file name for each entry with snapshot: true
visitOrder.forEach(step => {
if (step.snapshot === true) {
step.snapshotFile = snapshotFile;
}
});
// save the snapshot meta file
fs_extra_1.default.writeFileSync(snapshotSeqMetaFile, JSON.stringify(visitOrder, null, 2), 'UTF-8');
}
initDirs(config, options = FileManager.defaultFileOption) {

@@ -344,2 +381,7 @@ // cache the last processed memlab config instance

const workDir = this.getWorkDir(options);
// if errorWhenAbsent is set to true, make it
// an error when the working directory does not exist
if (options.errorWhenAbsent && !fs_extra_1.default.existsSync(workDir)) {
throw Utils_1.default.haltOrThrow(`work dir does not exist: ${workDir}`);
}
// remember the current working directory

@@ -382,5 +424,5 @@ // especially if this is a transcient working directory

config.reportScreenshotFile = path_1.default.join(outDir, 'report.png');
const codeDataDir = this.getCodeDataDir();
config.externalRunMetaFile = path_1.default.join(codeDataDir, 'run-meta.json');
config.externalSnapshotVisitOrderFile = path_1.default.join(codeDataDir, 'visit-order.json');
config.externalRunMetaFile = this.getRunMetaExternalTemplateFile();
config.externalSnapshotVisitOrderFile =
this.getSnapshotSequenceExternalTemplateFile();
joinAndProcessDir(options, this.getUniqueTraceClusterDir(options));

@@ -392,2 +434,3 @@ config.newUniqueClusterDir = joinAndProcessDir(options, this.getNewUniqueTraceClusterDir(options));

config.allClusterSummaryFile = this.getAllClusterSummaryFile(options);
this.createDefaultVisitOrderMetaFile(options);
}

@@ -394,0 +437,0 @@ }

4

dist/lib/heap-data/HeapEdge.d.ts

@@ -11,3 +11,3 @@ /**

*/
import type { IHeapEdge } from '../Types';
import type { AnyRecord, AnyValue, IHeapEdge } from '../Types';
import type HeapSnapshot from './HeapSnapshot';

@@ -27,3 +27,5 @@ import HeapNode from './HeapNode';

get fromNode(): HeapNode;
getJSONifyableObject(): AnyRecord;
toJSONString(...args: Array<AnyValue>): string;
}
//# sourceMappingURL=HeapEdge.d.ts.map

@@ -74,3 +74,16 @@ /**

}
getJSONifyableObject() {
return {
name_or_index: this.name_or_index,
type: this.type,
edgeIndex: this.edgeIndex,
toNode: this.toNode.getJSONifyableObject(),
fromNode: this.fromNode.getJSONifyableObject(),
};
}
toJSONString(...args) {
const rep = this.getJSONifyableObject();
return JSON.stringify(rep, ...args);
}
}
exports.default = HeapEdge;

@@ -11,3 +11,3 @@ /**

*/
import type { IHeapLocation, IHeapNode, Nullable } from '../Types';
import type { AnyRecord, AnyValue, IHeapLocation, IHeapNode, Nullable } from '../Types';
import type HeapSnapshot from './HeapSnapshot';

@@ -23,3 +23,5 @@ export default class HeapLocation implements IHeapLocation {

get column(): number;
getJSONifyableObject(): AnyRecord;
toJSONString(...args: Array<AnyValue>): string;
}
//# sourceMappingURL=HeapLocation.d.ts.map

@@ -46,3 +46,17 @@ /**

}
getJSONifyableObject() {
const node = this.node;
const jsonNode = node == null ? null : node.getJSONifyableObject();
return {
node: jsonNode,
script_id: this.script_id,
line: this.line,
column: this.column,
};
}
toJSONString(...args) {
const rep = this.getJSONifyableObject();
return JSON.stringify(rep, ...args);
}
}
exports.default = HeapLocation;

@@ -11,3 +11,3 @@ /**

*/
import type { IHeapNode, IHeapEdge, Nullable, EdgeIterationCallback, Predicator, IHeapStringNode } from '../Types';
import type { IHeapNode, IHeapEdge, Nullable, EdgeIterationCallback, Predicator, IHeapStringNode, AnyRecord, AnyValue } from '../Types';
import type HeapSnapshot from './HeapSnapshot';

@@ -37,4 +37,7 @@ import HeapEdge from './HeapEdge';

findAnyReferrer(predicate: Predicator<IHeapEdge>): Nullable<IHeapEdge>;
findAnyReferrerNode(predicate: Predicator<IHeapNode>): Nullable<IHeapNode>;
findReferrers(predicate: Predicator<IHeapEdge>): IHeapEdge[];
findReferrerNodes(predicate: Predicator<IHeapNode>): IHeapNode[];
get referrers(): HeapEdge[];
get numOfReferrers(): number;
forEachReferrer(callback: EdgeIterationCallback): void;

@@ -58,3 +61,5 @@ get hasPathEdge(): boolean;

toStringNode(): Nullable<IHeapStringNode>;
getJSONifyableObject(): AnyRecord;
toJSONString(...args: Array<AnyValue>): string;
}
//# sourceMappingURL=HeapNode.d.ts.map

@@ -154,2 +154,13 @@ /**

}
findAnyReferrerNode(predicate) {
let found = null;
this.forEachReferrer((edge) => {
const node = edge.fromNode;
if (predicate(node)) {
found = node;
return { stop: true };
}
});
return found;
}
findReferrers(predicate) {

@@ -165,2 +176,13 @@ const ret = [];

}
findReferrerNodes(predicate) {
const ret = [];
this.forEachReferrer((edge) => {
const node = edge.fromNode;
if (predicate(node)) {
ret.push(node);
}
return null;
});
return ret;
}
get referrers() {

@@ -179,2 +201,9 @@ const heapSnapshot = this.heapSnapshot;

}
get numOfReferrers() {
const heapSnapshot = this.heapSnapshot;
const firstRetainerIndex = heapSnapshot._firstRetainerIndex;
const beginIdx = firstRetainerIndex[this.idx];
const endIdx = firstRetainerIndex[this.idx + 1];
return endIdx - beginIdx;
}
forEachReferrer(callback) {

@@ -348,2 +377,19 @@ const heapSnapshot = this.heapSnapshot;

}
getJSONifyableObject() {
return {
id: this.id,
name: this.name,
type: this.type,
self_size: this.self_size,
trace_node_id: this.trace_node_id,
nodeIndex: this.nodeIndex,
outGoingEdgeCount: this.edge_count,
incomingEdgeCount: this.numOfReferrers,
contructorName: this.constructor.name,
};
}
toJSONString(...args) {
const rep = this.getJSONifyableObject();
return JSON.stringify(rep, ...args);
}
}

@@ -350,0 +396,0 @@ exports.default = HeapNode;

@@ -11,3 +11,3 @@ /**

*/
import type { IHeapNode, IHeapNodes, IHeapEdges, IHeapSnapshot, HeapNodeTypes, HeapEdgeTypes, HeapSnapshotMeta, RawHeapSnapshot, NumericDictionary, Nullable } from '../Types';
import type { AnyRecord, AnyValue, IHeapNode, IHeapNodes, IHeapEdges, IHeapSnapshot, HeapNodeTypes, HeapEdgeTypes, HeapSnapshotMeta, RawHeapSnapshot, NumericDictionary, Nullable } from '../Types';
import HeapNode from './HeapNode';

@@ -71,2 +71,4 @@ export default class HeapSnapshot implements IHeapSnapshot {

constructor(snapshot: RawHeapSnapshot, _options?: Record<string, never>);
getJSONifyableObject(): AnyRecord;
toJSONString(...args: Array<AnyValue>): string;
hasObjectWithClassName(className: string): boolean;

@@ -73,0 +75,0 @@ getAnyObjectWithClassName(className: string): Nullable<IHeapNode>;

@@ -132,2 +132,9 @@ /**

}
getJSONifyableObject() {
return Object.assign({}, this.snapshot.snapshot);
}
toJSONString(...args) {
const rep = this.getJSONifyableObject();
return JSON.stringify(rep, ...args);
}
hasObjectWithClassName(className) {

@@ -134,0 +141,0 @@ let detected = false;

@@ -11,3 +11,3 @@ /**

*/
import type { IHeapStringNode } from '../Types';
import type { AnyRecord, IHeapStringNode } from '../Types';
import type HeapSnapshot from './HeapSnapshot';

@@ -18,3 +18,4 @@ import HeapNode from './HeapNode';

get stringValue(): string;
getJSONifyableObject(): AnyRecord;
}
//# sourceMappingURL=HeapStringNode.d.ts.map

@@ -44,3 +44,8 @@ /**

}
getJSONifyableObject() {
const rep = super.getJSONifyableObject();
rep.stringValue = this.stringValue;
return rep;
}
}
exports.default = HeapStringNode;

@@ -128,4 +128,6 @@ /**

export declare function runShell(command: string, options?: ShellOptions): Nullable<string>;
export declare function getRetainedSize(node: IHeapNode): number;
export declare function aggregateDominatorMetrics(ids: HeapNodeIdSet, snapshot: IHeapSnapshot, checkNodeCb: (node: IHeapNode) => boolean, nodeMetricsCb: (node: IHeapNode) => number): number;
declare function getRetainedSize(node: IHeapNode): number;
declare function aggregateDominatorMetrics(ids: HeapNodeIdSet, snapshot: IHeapSnapshot, checkNodeCb: (node: IHeapNode) => boolean, nodeMetricsCb: (node: IHeapNode) => number): number;
declare function getLeakTracePathLength(path: LeakTracePathItem): number;
declare function getNumberAtPercentile(arr: number[], percentile: number): number;
declare const _default: {

@@ -153,3 +155,5 @@ aggregateDominatorMetrics: typeof aggregateDominatorMetrics;

getLeakedNode: typeof getLeakedNode;
getLeakTracePathLength: typeof getLeakTracePathLength;
getNodesIdSet: typeof getNodesIdSet;
getNumberAtPercentile: typeof getNumberAtPercentile;
getNumberNodeValue: typeof getNumberNodeValue;

@@ -156,0 +160,0 @@ getReadableBytes: typeof getReadableBytes;

@@ -47,3 +47,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.aggregateDominatorMetrics = exports.getRetainedSize = exports.runShell = exports.resolveSnapshotFilePath = void 0;
exports.runShell = exports.resolveSnapshotFilePath = void 0;
const fs_1 = __importDefault(require("fs"));

@@ -1276,3 +1276,3 @@ const path_1 = __importDefault(require("path"));

else {
snapshotDir = FileManager_1.default.getCurDataDir({});
snapshotDir = FileManager_1.default.getCurDataDir({ workDir: Config_1.default.workDir });
}

@@ -1352,2 +1352,5 @@ if (options.snapshotDir) {

function getSnapshotFilePath(tab, options = {}) {
if (tab.snapshotFile) {
return path_1.default.join(FileManager_1.default.getCurDataDir(options), tab.snapshotFile);
}
const fileName = `s${tab.idx}.heapsnapshot`;

@@ -1796,3 +1799,2 @@ if (options.workDir) {

}
exports.getRetainedSize = getRetainedSize;
function aggregateDominatorMetrics(ids, snapshot, checkNodeCb, nodeMetricsCb) {

@@ -1806,3 +1808,25 @@ let ret = 0;

}
exports.aggregateDominatorMetrics = aggregateDominatorMetrics;
function getLeakTracePathLength(path) {
let len = 0;
let p = path;
while (p) {
p = p.next;
++len;
}
return len;
}
function getNumberAtPercentile(arr, percentile) {
arr.sort(function (a, b) {
return a - b;
});
const index = (percentile / 100) * arr.length;
const indexInt = Math.floor(index);
if (indexInt === index) {
return arr[Math.floor(index)];
}
if (indexInt + 1 < arr.length) {
return (arr[indexInt] + arr[indexInt + 1]) / 2;
}
return arr[indexInt];
}
exports.default = {

@@ -1830,3 +1854,5 @@ aggregateDominatorMetrics,

getLeakedNode,
getLeakTracePathLength,
getNodesIdSet,
getNumberAtPercentile,
getNumberNodeValue,

@@ -1833,0 +1859,0 @@ getReadableBytes,

@@ -15,2 +15,4 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const Config_1 = __importDefault(require("../../lib/Config"));
const Console_1 = __importDefault(require("../../lib/Console"));
const ClusterUtils_1 = __importDefault(require("../ClusterUtils"));

@@ -45,2 +47,9 @@ // cluster by putting similar traces together

const traceToCheck = newTraces[i];
// use an odd number as the divider. If we choose 10 as the divider,
// when updating the progress indicator, the final digit always ends
// with a zero, which can appear strange and not representative of
// the actual progress.
if (!Config_1.default.isContinuousTest && i % 17 === 0) {
Console_1.default.overwrite(`clustering trace: ${i} / ${newTraces.length}`);
}
for (let j = 0; j < clusters.length; ++j) {

@@ -47,0 +56,0 @@ const repTrace = clusters[j][0];

@@ -27,2 +27,3 @@ /**

static calculateClusterRetainedSize(cluster: TraceCluster, snapshot: IHeapSnapshot, aggregateDominatorMetrics: AggregateNodeCb): number;
static getSamplePathMaxLength(paths: LeakTracePathItem[]): number;
static samplePaths(paths: LeakTracePathItem[]): LeakTracePathItem[];

@@ -29,0 +30,0 @@ private static diffTraces;

@@ -125,4 +125,11 @@ "use strict";

}
static getSamplePathMaxLength(paths) {
const lengthArr = paths.map(p => Utils_1.default.getLeakTracePathLength(p));
return Math.max(30, Utils_1.default.getNumberAtPercentile(lengthArr, 80));
}
static samplePaths(paths) {
const maxCount = 5000;
if (paths.length <= maxCount) {
return [...paths];
}
const sampleRatio = Math.min(1, maxCount / paths.length);

@@ -132,6 +139,13 @@ if (sampleRatio < 1) {

Console_1.default.lowLevel(` Number of Traces: ${paths.length}`);
Console_1.default.lowLevel(` Sampling Ratio: ${Utils_1.default.getReadablePercent(sampleRatio)}`);
Console_1.default.lowLevel(` Sampling Ratio: ${Utils_1.default.getReadablePercent(sampleRatio)}`);
}
const ret = [];
const samplePathMaxLength = NormalizedTrace.getSamplePathMaxLength(paths);
if (Config_1.default.verbose) {
Console_1.default.lowLevel(` Sample Trace's Max Length: ${samplePathMaxLength}`);
}
for (const p of paths) {
if (Utils_1.default.getLeakTracePathLength(p) > samplePathMaxLength) {
continue;
}
if (Math.random() < sampleRatio) {

@@ -138,0 +152,0 @@ ret.push(p);

@@ -10,3 +10,3 @@ /**

*/
import type { EdgeIterationCallback, IHeapEdge, IHeapLocation, IHeapNode, IHeapSnapshot, IHeapStringNode, Nullable } from '../lib/Types';
import type { AnyValue, EdgeIterationCallback, IHeapEdge, IHeapLocation, IHeapNode, IHeapSnapshot, IHeapStringNode, Nullable } from '../lib/Types';
export declare class NodeRecord implements IHeapNode {

@@ -36,2 +36,3 @@ kind: string;

get referrers(): IHeapEdge[];
get numOfReferrers(): number;
toStringNode(): IHeapStringNode;

@@ -41,3 +42,5 @@ forEachReferrer(_callback: EdgeIterationCallback): void;

findAnyReferrer(): Nullable<IHeapEdge>;
findAnyReferrerNode(): Nullable<IHeapNode>;
findReferrers(): IHeapEdge[];
findReferrerNodes(): IHeapNode[];
set hasPathEdge(f: boolean);

@@ -57,2 +60,3 @@ get hasPathEdge(): boolean;

getReferrerNodes(_edgeName: string | number, _edgeType?: string): IHeapNode[];
toJSONString(...args: Array<AnyValue>): string;
constructor(node: IHeapNode);

@@ -69,2 +73,3 @@ private extraceNodeName;

constructor(edge: IHeapEdge);
toJSONString(...args: Array<AnyValue>): string;
set snapshot(s: IHeapSnapshot);

@@ -71,0 +76,0 @@ get snapshot(): IHeapSnapshot;

@@ -65,2 +65,5 @@ "use strict";

}
get numOfReferrers() {
throw new Error('NodeRecord.numOfReferrers cannot be read');
}
toStringNode() {

@@ -80,5 +83,11 @@ throw new Error('NodeRecord.toStringNode is not implemented');

}
findAnyReferrerNode() {
throw new Error('NodeRecord.findAnyReferrerNode is not implemented');
}
findReferrers() {
throw new Error('NodeRecord.findReferrers is not implemented');
}
findReferrerNodes() {
throw new Error('NodeRecord.findReferrerNodes is not implemented');
}
set hasPathEdge(f) {

@@ -150,2 +159,16 @@ throw new Error('NodeRecord.hasPathEdge cannot be assigned');

}
toJSONString(...args) {
const rep = {
id: this.id,
kind: this.kind,
name: this.name,
type: this.type,
self_size: this.self_size,
trace_node_id: this.trace_node_id,
nodeIndex: this.nodeIndex,
incomingEdgeCount: this.numOfReferrers,
contructorName: this.constructor.name,
};
return JSON.stringify(rep, ...args);
}
extraceNodeName(node) {

@@ -169,2 +192,12 @@ // deserialized node may not have snapshot info

}
toJSONString(...args) {
const rep = {
kind: this.kind,
name_or_index: this.name_or_index,
type: this.type,
edgeIndex: this.edgeIndex,
to_node: this.to_node,
};
return JSON.stringify(rep, ...args);
}
set snapshot(s) {

@@ -171,0 +204,0 @@ throw new Error('EdgeRecord.snapshot cannot be assigned.');

{
"name": "@memlab/core",
"version": "1.1.19",
"version": "1.1.20",
"license": "MIT",

@@ -5,0 +5,0 @@ "description": "memlab core libraries",

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc