@memlab/core
Advanced tools
Comparing version 1.1.1 to 1.1.2
@@ -39,3 +39,3 @@ "use strict"; | ||
const injected = new TestObject(); | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
expect(heap.hasObjectWithClassName('TestObject')).toBe(true); | ||
@@ -53,4 +53,4 @@ }), timeout); | ||
injected = null; | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
expect(heap.hasObjectWithClassName('TestObject')).toBe(false); | ||
}), timeout); |
@@ -33,3 +33,3 @@ "use strict"; | ||
const object = { 'memlab-test-heap-property': 'memlab-test-heap-value' }; | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
expect(heap.hasObjectWithPropertyName('memlab-test-heap-property')).toBe(true); | ||
@@ -43,3 +43,3 @@ }), timeout); | ||
object = null; | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
expect(heap.hasObjectWithPropertyName('memlab-test-heap-property')).toBe(false); | ||
@@ -64,3 +64,3 @@ }), timeout); | ||
const object = buildTest(); | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
expect(heap.hasObjectWithClassName('TestClass1')).toBe(true); | ||
@@ -86,3 +86,3 @@ expect(heap.hasObjectWithClassName('TestClass2')).toBe(true); | ||
const object = buildTest(); | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
expect(heap.hasObjectWithClassName('TestClass3')).toBe(true); | ||
@@ -97,5 +97,5 @@ expect(heap.hasObjectWithClassName('TestClass4')).toBe(false); | ||
o2 = null; | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true); | ||
expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false); | ||
}), timeout); |
@@ -44,3 +44,3 @@ "use strict"; | ||
injected.complexConcatString += '_suffix'; | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
const testObject = heap.getAnyObjectWithClassName('TestObject'); | ||
@@ -47,0 +47,0 @@ expect(testObject).not.toBe(null); |
@@ -77,3 +77,3 @@ "use strict"; | ||
}; | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
expect(checker(heap)).toBe(true); | ||
@@ -139,4 +139,4 @@ }), timeout); | ||
}; | ||
const heap = yield (0, NodeHeap_1.getCurrentNodeHeap)(); | ||
const heap = yield (0, NodeHeap_1.getNodeInnocentHeap)(); | ||
expect(checker(heap)).toBe(true); | ||
}), timeout); |
@@ -64,2 +64,3 @@ /** | ||
}): void; | ||
flush(): void; | ||
} | ||
@@ -66,0 +67,0 @@ declare const _default: MemLabConsole; |
@@ -343,3 +343,6 @@ /** | ||
} | ||
flush() { | ||
this.clearPrevOverwriteMsg(); | ||
} | ||
} | ||
exports.default = MemLabConsole.getInstance(); |
@@ -46,2 +46,4 @@ /** | ||
getCoreProjectBaseDir(): string; | ||
getMonoRepoDir(): string; | ||
getDocDir(): string; | ||
getReportOutDir(options?: FileOption): string; | ||
@@ -48,0 +50,0 @@ getPreviewReportDir(options?: FileOption): string; |
@@ -136,2 +136,8 @@ "use strict"; | ||
} | ||
getMonoRepoDir() { | ||
return path_1.default.join(this.getCoreProjectBaseDir(), '..', '..'); | ||
} | ||
getDocDir() { | ||
return path_1.default.join(this.getMonoRepoDir(), 'website', 'docs'); | ||
} | ||
getReportOutDir(options = {}) { | ||
@@ -138,0 +144,0 @@ return path_1.default.join(this.getPersistDataDir(options), 'reports'); |
@@ -10,8 +10,67 @@ /** | ||
*/ | ||
import type { AnyValue, IHeapSnapshot } from './Types'; | ||
declare type AnyObject = Record<AnyValue, AnyValue>; | ||
export declare function tagObject(o: AnyObject, tag: string): AnyObject; | ||
import type { IHeapSnapshot } from './Types'; | ||
/** | ||
* Tags a string marker to an object instance, which can later be checked by | ||
* {@link hasObjectWithTag}. This API does not modify the object instance in | ||
* any way (e.g., no additional or hidden properties added to the tagged | ||
* object). | ||
* | ||
* @param o specify the object instance you want to tag, you cannot tag a | ||
* [primitive](https://developer.mozilla.org/en-US/docs/Glossary/Primitive). | ||
* @param tag marker name to tag on the object instance | ||
* @returns returns the tagged object instance (same reference as | ||
* the input argument `o`) | ||
* * **Examples**: | ||
* ```typescript | ||
* import type {IHeapSnapshot, AnyValue} from '@memlab/core'; | ||
* import {config, getNodeInnocentHeap, tagObject} from '@memlab/core'; | ||
* | ||
* test('memory test', async () => { | ||
* config.muteConsole = true; | ||
* const o1: AnyValue = {}; | ||
* let o2: AnyValue = {}; | ||
* | ||
* // tag o1 with marker: "memlab-mark-1", does not modify o1 in any way | ||
* tagObject(o1, 'memlab-mark-1'); | ||
* // tag o2 with marker: "memlab-mark-2", does not modify o2 in any way | ||
* tagObject(o2, 'memlab-mark-2'); | ||
* | ||
* o2 = null; | ||
* | ||
* const heap: IHeapSnapshot = await getNodeInnocentHeap(); | ||
* | ||
* // expect object with marker "memlab-mark-1" exists | ||
* expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true); | ||
* | ||
* // expect object with marker "memlab-mark-2" can be GCed | ||
* expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false); | ||
* | ||
* }, 30000); | ||
* ``` | ||
*/ | ||
export declare function tagObject<T extends object>(o: T, tag: string): T; | ||
export declare function dumpNodeHeapSnapshot(): string; | ||
export declare function getCurrentNodeHeap(): Promise<IHeapSnapshot>; | ||
export {}; | ||
/** | ||
* Take a heap snapshot of the current program state | ||
* and parse it as {@link IHeapSnapshot}. Notice that | ||
* this API does not calculate some heap analysis meta data | ||
* for heap analysis. But this also means faster heap parsing. | ||
* | ||
* @returns heap representation without heap analysis meta data. | ||
* | ||
* If you need to get the heap snapshot with heap analysis meta data | ||
* use {@link dumpNodeHeapSnapshot} and {@link getHeapFromFile}, | ||
* for example: | ||
* ```typescript | ||
* import type {IHeapSnapshot} from '@memlab/core'; | ||
* import {dumpNodeHeapSnapshot} from '@memlab/core'; | ||
* import {getHeapFromFile} from '@memlab/heap-analysis'; | ||
* | ||
* (async function () { | ||
* const heapFile = dumpNodeHeapSnapshot(); | ||
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile); | ||
* })(); | ||
* ``` | ||
*/ | ||
export declare function getNodeInnocentHeap(): Promise<IHeapSnapshot>; | ||
//# sourceMappingURL=NodeHeap.d.ts.map |
@@ -24,3 +24,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getCurrentNodeHeap = exports.dumpNodeHeapSnapshot = exports.tagObject = void 0; | ||
exports.getNodeInnocentHeap = exports.dumpNodeHeapSnapshot = exports.tagObject = void 0; | ||
const fs_extra_1 = __importDefault(require("fs-extra")); | ||
@@ -37,2 +37,41 @@ const path_1 = __importDefault(require("path")); | ||
const store = new MemLabTaggedStore(); | ||
/** | ||
* Tags a string marker to an object instance, which can later be checked by | ||
* {@link hasObjectWithTag}. This API does not modify the object instance in | ||
* any way (e.g., no additional or hidden properties added to the tagged | ||
* object). | ||
* | ||
* @param o specify the object instance you want to tag, you cannot tag a | ||
* [primitive](https://developer.mozilla.org/en-US/docs/Glossary/Primitive). | ||
* @param tag marker name to tag on the object instance | ||
* @returns returns the tagged object instance (same reference as | ||
* the input argument `o`) | ||
* * **Examples**: | ||
* ```typescript | ||
* import type {IHeapSnapshot, AnyValue} from '@memlab/core'; | ||
* import {config, getNodeInnocentHeap, tagObject} from '@memlab/core'; | ||
* | ||
* test('memory test', async () => { | ||
* config.muteConsole = true; | ||
* const o1: AnyValue = {}; | ||
* let o2: AnyValue = {}; | ||
* | ||
* // tag o1 with marker: "memlab-mark-1", does not modify o1 in any way | ||
* tagObject(o1, 'memlab-mark-1'); | ||
* // tag o2 with marker: "memlab-mark-2", does not modify o2 in any way | ||
* tagObject(o2, 'memlab-mark-2'); | ||
* | ||
* o2 = null; | ||
* | ||
* const heap: IHeapSnapshot = await getNodeInnocentHeap(); | ||
* | ||
* // expect object with marker "memlab-mark-1" exists | ||
* expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true); | ||
* | ||
* // expect object with marker "memlab-mark-2" can be GCed | ||
* expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false); | ||
* | ||
* }, 30000); | ||
* ``` | ||
*/ | ||
function tagObject(o, tag) { | ||
@@ -52,3 +91,25 @@ if (!store.taggedObjects[tag]) { | ||
exports.dumpNodeHeapSnapshot = dumpNodeHeapSnapshot; | ||
function getCurrentNodeHeap() { | ||
/** | ||
* Take a heap snapshot of the current program state | ||
* and parse it as {@link IHeapSnapshot}. Notice that | ||
* this API does not calculate some heap analysis meta data | ||
* for heap analysis. But this also means faster heap parsing. | ||
* | ||
* @returns heap representation without heap analysis meta data. | ||
* | ||
* If you need to get the heap snapshot with heap analysis meta data | ||
* use {@link dumpNodeHeapSnapshot} and {@link getHeapFromFile}, | ||
* for example: | ||
* ```typescript | ||
* import type {IHeapSnapshot} from '@memlab/core'; | ||
* import {dumpNodeHeapSnapshot} from '@memlab/core'; | ||
* import {getHeapFromFile} from '@memlab/heap-analysis'; | ||
* | ||
* (async function () { | ||
* const heapFile = dumpNodeHeapSnapshot(); | ||
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile); | ||
* })(); | ||
* ``` | ||
*/ | ||
function getNodeInnocentHeap() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -65,2 +126,2 @@ const file = dumpNodeHeapSnapshot(); | ||
} | ||
exports.getCurrentNodeHeap = getCurrentNodeHeap; | ||
exports.getNodeInnocentHeap = getNodeInnocentHeap; |
@@ -610,11 +610,207 @@ /** | ||
export interface IHeapSnapshot { | ||
/** @internal */ | ||
snapshot: RawHeapSnapshot; | ||
/** | ||
* A pseudo array containing all heap graph nodes (JS objects in heap). | ||
* A JS heap could contain millions of heap objects, so memlab uses | ||
* a pseudo array as the collection of all the heap objects. The pseudo | ||
* array provides API to query and traverse all heap objects. | ||
* | ||
* * **Examples**: | ||
* ```typescript | ||
* import type {IHeapSnapshot, IHeapNode} from '@memlab/core'; | ||
* import {dumpNodeHeapSnapshot} from '@memlab/core'; | ||
* import {getHeapFromFile} from '@memlab/heap-analysis'; | ||
* | ||
* (async function () { | ||
* const heapFile = dumpNodeHeapSnapshot(); | ||
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile); | ||
* | ||
* // get the total number of heap objects | ||
* heap.nodes.length; | ||
* | ||
* heap.nodes.forEach((node: IHeapNode) => { | ||
* // traverse each heap object | ||
* }); | ||
* })(); | ||
* ``` | ||
*/ | ||
nodes: IHeapNodes; | ||
/** | ||
* A pseudo array containing all heap graph edges (references to heap objects | ||
* in heap). A JS heap could contain millions of references, so memlab uses | ||
* a pseudo array as the collection of all the heap edges. The pseudo | ||
* array provides API to query and traverse all heap references. | ||
* | ||
* * **Examples**: | ||
* ```typescript | ||
* import type {IHeapSnapshot, IHeapEdge} from '@memlab/core'; | ||
* import {dumpNodeHeapSnapshot} from '@memlab/core'; | ||
* import {getHeapFromFile} from '@memlab/heap-analysis'; | ||
* | ||
* (async function () { | ||
* const heapFile = dumpNodeHeapSnapshot(); | ||
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile); | ||
* | ||
* // get the total number of heap references | ||
* heap.edges.length; | ||
* | ||
* heap.edges.forEach((edge: IHeapEdge) => { | ||
* // traverse each reference in the heap | ||
* }); | ||
* })(); | ||
* ``` | ||
*/ | ||
edges: IHeapEdges; | ||
/** | ||
* If you have the id of a heap node (JS object in heap), use this API | ||
* to get an {@link IHeapNode} associated with the id. | ||
* @param id id of the heap node (JS object in heap) you would like to query | ||
* @returns the API returns `null` if no heap object has the specified id. | ||
* | ||
* * **Examples**: | ||
* ```typescript | ||
* import type {IHeapSnapshot} from '@memlab/core'; | ||
* import {dumpNodeHeapSnapshot} from '@memlab/core'; | ||
* import {getHeapFromFile} from '@memlab/heap-analysis'; | ||
* | ||
* (async function () { | ||
* const heapFile = dumpNodeHeapSnapshot(); | ||
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile); | ||
* | ||
* const node = heap.getNodeById(351); | ||
* node?.id; // should be 351 | ||
* })(); | ||
* ``` | ||
*/ | ||
getNodeById(id: number): Nullable<IHeapNode>; | ||
clearShortestPathInfo(): void; | ||
/** | ||
* Search for the heap and check if there is any JS object instance with | ||
* a specified constructor name. | ||
* @param className The contructor name of the object instance | ||
* @returns `true` if there is at least one such object in the heap | ||
* | ||
* * **Examples**: you can write a jest unit test with memory assertions: | ||
* ```typescript | ||
* // save as example.test.ts | ||
* import type {IHeapSnapshot, Nullable} from '@memlab/core'; | ||
* import {config, getNodeInnocentHeap} from '@memlab/core'; | ||
* | ||
* class TestObject { | ||
* public arr1 = [1, 2, 3]; | ||
* public arr2 = ['1', '2', '3']; | ||
* } | ||
* | ||
* test('memory test with heap assertion', async () => { | ||
* config.muteConsole = true; // no console output | ||
* | ||
* let obj: Nullable<TestObject> = new TestObject(); | ||
* // get a heap snapshot of the current program state | ||
* let heap: IHeapSnapshot = await getNodeInnocentHeap(); | ||
* | ||
* // call some function that may add references to obj | ||
* rabbitHole(obj) | ||
* | ||
* expect(heap.hasObjectWithClassName('TestObject')).toBe(true); | ||
* obj = null; | ||
* | ||
* heap = await getNodeInnocentHeap(); | ||
* // if rabbitHole does not have any side effect that | ||
* // adds new references to obj, then obj can be GCed | ||
* expect(heap.hasObjectWithClassName('TestObject')).toBe(false); | ||
* | ||
* }, 30000); | ||
* ``` | ||
*/ | ||
hasObjectWithClassName(className: string): boolean; | ||
/** | ||
* Search for the heap and get one of the JS object instances with | ||
* a specified constructor name (if there is any). | ||
* @param className The contructor name of the object instance | ||
* @returns a handle pointing to any one of the object instances, returns | ||
* `null` if no such object exists in the heap. | ||
* | ||
* * **Examples**: | ||
* ```typescript | ||
* import type {IHeapSnapshot} from '@memlab/core'; | ||
* import {getNodeInnocentHeap} from '@memlab/core'; | ||
* | ||
* class TestObject { | ||
* public arr1 = [1, 2, 3]; | ||
* public arr2 = ['1', '2', '3']; | ||
* } | ||
* | ||
* (async function () { | ||
* const obj = new TestObject(); | ||
* // get a heap snapshot of the current program state | ||
* const heap: IHeapSnapshot = await getNodeInnocentHeap(); | ||
* | ||
* const node = heap.getAnyObjectWithClassName('TestObject'); | ||
* console.log(node?.name); // should be 'TestObject' | ||
* })(); | ||
* ``` | ||
*/ | ||
getAnyObjectWithClassName(className: string): Nullable<IHeapNode>; | ||
/** | ||
* Search for the heap and check if there is any JS object instance with | ||
* a specified property name. | ||
* @param nameOrIndex The property name (string) or element index (number) | ||
* on the object instance | ||
* @returns returns `true` if there is at least one such object in the heap | ||
* | ||
* * **Examples**: | ||
* ```typescript | ||
* import type {IHeapSnapshot} from '@memlab/core'; | ||
* import {dumpNodeHeapSnapshot} from '@memlab/core'; | ||
* import {getHeapFromFile} from '@memlab/heap-analysis'; | ||
* | ||
* (async function () { | ||
* // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
* const object = {'memlab-test-heap-property': 'memlab-test-heap-value'}; | ||
* | ||
* const heapFile = dumpNodeHeapSnapshot(); | ||
* const heap: IHeapSnapshot = await getHeapFromFile(heapFile); | ||
* | ||
* // should be true | ||
* console.log(heap.hasObjectWithPropertyName('memlab-test-heap-property')); | ||
* })(); | ||
* ``` | ||
*/ | ||
hasObjectWithPropertyName(nameOrIndex: string | number): boolean; | ||
/** | ||
* Search for the heap and check if there is any JS object instance with | ||
* a marker tagged by {@link tagObject}. | ||
* @param tag marker name on the object instances tagged by {@link tagObject} | ||
* @returns returns `true` if there is at least one such object in the heap | ||
* | ||
* ```typescript | ||
* import type {IHeapSnapshot, AnyValue} from '@memlab/core'; | ||
* import {config, getNodeInnocentHeap, tagObject} from '@memlab/core'; | ||
* | ||
* test('memory test', async () => { | ||
* config.muteConsole = true; | ||
* const o1: AnyValue = {}; | ||
* let o2: AnyValue = {}; | ||
* | ||
* // tag o1 with marker: "memlab-mark-1", does not modify o1 in any way | ||
* tagObject(o1, 'memlab-mark-1'); | ||
* // tag o2 with marker: "memlab-mark-2", does not modify o2 in any way | ||
* tagObject(o2, 'memlab-mark-2'); | ||
* | ||
* o2 = null; | ||
* | ||
* const heap: IHeapSnapshot = await getNodeInnocentHeap(); | ||
* | ||
* // expect object with marker "memlab-mark-1" exists | ||
* expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true); | ||
* | ||
* // expect object with marker "memlab-mark-2" can be GCed | ||
* expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false); | ||
* | ||
* }, 30000); | ||
* ``` | ||
*/ | ||
hasObjectWithTag(tag: string): boolean; | ||
/** @internal */ | ||
clearShortestPathInfo(): void; | ||
} | ||
@@ -621,0 +817,0 @@ export interface IHeapLocation { |
@@ -545,2 +545,3 @@ "use strict"; | ||
} | ||
Console_1.default.flush(); | ||
return ret; | ||
@@ -547,0 +548,0 @@ }); |
{ | ||
"name": "@memlab/core", | ||
"version": "1.1.1", | ||
"version": "1.1.2", | ||
"license": "MIT", | ||
@@ -61,2 +61,3 @@ "description": "memlab core libraries", | ||
"test-pkg": "jest .", | ||
"publish-patch": "npm version patch --force && npm publish", | ||
"clean-pkg": "rm -rf ./dist && rm -rf ./node_modules && rm -f ./tsconfig.tsbuildinfo" | ||
@@ -63,0 +64,0 @@ }, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
464446
12015