Skip to content

Commit 0beeb9e

Browse files
committed
Refactor decorators/utilities and adjust package exports
Remove ES module-only flag and add CommonJS-friendly exports; refactor many decorators and utility modules for consistency, robustness, and clearer naming. Key changes: - package.json: removed "type": "module" and added require/default entries under exports to improve CommonJS compatibility. - Debugging decorators: standardized parameter and variable names (e.g. methodName, startTime/endTime), detect thenables instead of using instanceof Promise, normalize errors, and make logging/handlers more resilient. - Network logging: safer global fetch patching with refcounting, clearer naming (createFetchPatch/extractRequestDetails), and robust timing/cleanup. - Memory/performance warnings: renamed helpers (readMemoryUsage → readMemoryUsage, etc.), per-instance state maps renamed for clarity, added safer cleanup and constructor wrapping fixes. - Optimization decorators (AutoRetry, Debounce, Throttle, Memoize, LazyLoad): consistent naming, improved promise handling, safer time handling, better per-instance maps, and clearer error messages. - Utilities: unify quoting/style, improved serialization error messages, clarified time/memory utility behavior and error messages. - Tests: updated to reflect API/behavior/style changes. Improved compatibility (CJS), and maintainability of decorators and utilities while keeping existing behavior where possible.
1 parent 460a5bb commit 0beeb9e

33 files changed

Lines changed: 658 additions & 766 deletions

package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"name": "performance-decorators",
33
"version": "3.0.4",
44
"description": "A set of decorators to help with performance testing",
5-
"type": "module",
65
"main": "dist/index.js",
76
"types": "dist/index.d.ts",
87
"scripts": {
@@ -16,15 +15,18 @@
1615
"exports": {
1716
".": {
1817
"types": "./dist/index.d.ts",
19-
"import": "./dist/index.js"
18+
"require": "./dist/index.js",
19+
"default": "./dist/index.js"
2020
},
2121
"./optimization": {
2222
"types": "./dist/optimization/index.d.ts",
23-
"import": "./dist/optimization/index.js"
23+
"require": "./dist/optimization/index.js",
24+
"default": "./dist/optimization/index.js"
2425
},
2526
"./debugging": {
2627
"types": "./dist/debugging/index.d.ts",
27-
"import": "./dist/debugging/index.js"
28+
"require": "./dist/debugging/index.js",
29+
"default": "./dist/debugging/index.js"
2830
}
2931
},
3032
"repository": {

src/debugging/LogExecutionTime.ts

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
// src/debugging/LogExecutionTime.ts
2-
import { Method, MethodContext } from "../types";
3-
import { isBrowserEnvironment, isNodeEnvironment } from "../utilities";
4-
import { calculateTimeInMilliseconds, getHighResolutionTime } from "../utilities/TimeUtilities";
1+
import { Method, MethodContext } from '../types';
2+
import { calculateTimeInMilliseconds, getHighResolutionTime } from '../utilities/TimeUtilities';
53

64
/**
75
* Logs execution time for a method using high-resolution clocks.
@@ -22,48 +20,43 @@ import { calculateTimeInMilliseconds, getHighResolutionTime } from "../utilities
2220
* }
2321
* }
2422
*/
25-
export function LogExecutionTime(
26-
handler?: (ms: number, methodName: string) => void
27-
) {
28-
return function <This, Args extends unknown[], Return>(
29-
value: Method<This, Args, Return>,
30-
context: MethodContext<This, Args, Return>
31-
): Method<This, Args, Return> {
32-
const name = String(context.name);
23+
export function LogExecutionTime(handler?: (elapsedMilliseconds: number, methodName: string) => void) {
24+
return function <This, Args extends unknown[], Return>(value: Method<This, Args, Return>, context: MethodContext<This, Args, Return>): Method<This, Args, Return> {
25+
const methodName = String(context.name);
3326

3427
return function (this: This, ...args: Args): Return {
35-
let start: number | bigint;
28+
let startTime: number | bigint;
3629
try {
37-
start = getHighResolutionTime();
30+
startTime = getHighResolutionTime();
3831
} catch {
39-
// Fall back: still run original
4032
return value.apply(this, args);
4133
}
4234

4335
try {
44-
const out = value.apply(this, args);
45-
if (out instanceof Promise) {
36+
const result = value.apply(this, args);
37+
const isThenable = result && typeof (result as any).then === 'function';
38+
if (isThenable) {
4639
return (async () => {
4740
try {
48-
const r = await out;
49-
const end = getHighResolutionTime();
50-
handler?.(calculateTimeInMilliseconds(start, end), name);
51-
return r;
52-
} catch (e) {
53-
const end = getHighResolutionTime();
54-
handler?.(calculateTimeInMilliseconds(start, end), name);
55-
throw e;
41+
const resolvedValue = await (result as unknown as Promise<unknown>);
42+
const endTime = getHighResolutionTime();
43+
handler?.(calculateTimeInMilliseconds(startTime, endTime), methodName);
44+
return resolvedValue as Return;
45+
} catch (thrownError) {
46+
const endTime = getHighResolutionTime();
47+
handler?.(calculateTimeInMilliseconds(startTime, endTime), methodName);
48+
throw thrownError;
5649
}
5750
})() as unknown as Return;
5851
} else {
59-
const end = getHighResolutionTime();
60-
handler?.(calculateTimeInMilliseconds(start, end), name);
61-
return out;
52+
const endTime = getHighResolutionTime();
53+
handler?.(calculateTimeInMilliseconds(startTime, endTime), methodName);
54+
return result;
6255
}
63-
} catch (e) {
64-
const end = getHighResolutionTime();
65-
handler?.(calculateTimeInMilliseconds(start, end), name);
66-
throw e;
56+
} catch (thrownError) {
57+
const endTime = getHighResolutionTime();
58+
handler?.(calculateTimeInMilliseconds(startTime, endTime), methodName);
59+
throw thrownError;
6760
}
6861
};
6962
};

src/debugging/LogMemoryUsage.ts

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
// src/debugging/LogMemoryUsage.ts
2-
import { Method, MethodContext } from "../types";
3-
import { getMemoryUsage } from "../utilities/MemoryUtilities";
1+
import { Method, MethodContext } from '../types';
2+
import { getMemoryUsage } from '../utilities/MemoryUtilities';
43

54
/**
65
* Logs memory delta (bytes) before/after a method call.
@@ -17,50 +16,52 @@ import { getMemoryUsage } from "../utilities/MemoryUtilities";
1716
* }
1817
* @endcode
1918
*/
20-
export function LogMemoryUsage(
21-
memoryHandler?: (deltaBytes: number, methodName: string) => void
22-
) {
23-
return function <
24-
This,
25-
Args extends unknown[],
26-
Return
27-
>(
28-
value: Method<This, Args, Return>,
29-
context: MethodContext<This, Args, Return>
30-
): Method<This, Args, Return> {
19+
export function LogMemoryUsage(memoryHandler?: (deltaBytes: number, methodName: string) => void) {
20+
return function <This, Args extends unknown[], Return>(value: Method<This, Args, Return>, context: MethodContext<This, Args, Return>): Method<This, Args, Return> {
3121
const methodName = String(context.name);
3222

33-
const safeGet = (): number | undefined => {
34-
try { return getMemoryUsage(); } catch { return undefined; }
23+
const safeReadMemoryUsage = (): number | undefined => {
24+
try {
25+
return getMemoryUsage();
26+
} catch {
27+
return undefined;
28+
}
3529
};
3630

37-
const finalize = (before?: number) => {
31+
const recordMemoryDelta = (initialMemory?: number) => {
3832
try {
39-
const after = safeGet();
40-
if (before === undefined || after === undefined) return;
41-
const delta = after - before;
42-
// Optional: keep a default console line for quick use
43-
// eslint-disable-next-line no-console
44-
console.log(`🧠 [Memory] ${methodName}: Δ=${delta} bytes`);
45-
memoryHandler?.(delta, methodName);
46-
} catch {/* ignore */}
33+
const finalMemory = safeReadMemoryUsage();
34+
if (initialMemory === undefined || finalMemory === undefined) return;
35+
const memoryDelta = finalMemory - initialMemory;
36+
console.log(`${methodName}: Δ ${memoryDelta} bytes`);
37+
memoryHandler?.(memoryDelta, methodName);
38+
} catch {
39+
// swallow
40+
}
4741
};
4842

4943
return function (this: This, ...args: Args): Return {
50-
const before = safeGet();
44+
const initialMemory = safeReadMemoryUsage();
5145

5246
try {
53-
const out = value.apply(this, args);
54-
if (out instanceof Promise) {
55-
return (out as Promise<unknown>)
56-
.then((r) => { finalize(before); return r as Return; })
57-
.catch((e) => { finalize(before); throw e; }) as Return;
47+
const result = value.apply(this, args);
48+
const isThenable = result && typeof (result as any).then === 'function';
49+
if (isThenable) {
50+
return (result as unknown as Promise<unknown>)
51+
.then((resolvedValue) => {
52+
recordMemoryDelta(initialMemory);
53+
return resolvedValue as Return;
54+
})
55+
.catch((thrownError) => {
56+
recordMemoryDelta(initialMemory);
57+
throw thrownError;
58+
}) as Return;
5859
}
59-
finalize(before);
60-
return out;
61-
} catch (err) {
62-
finalize(before);
63-
throw err;
60+
recordMemoryDelta(initialMemory);
61+
return result;
62+
} catch (thrownError) {
63+
recordMemoryDelta(initialMemory);
64+
throw thrownError;
6465
}
6566
};
6667
};

src/debugging/LogMethodError.ts

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// src/debugging/LogMethodError.ts
2-
import { Method, MethodContext } from "../types";
1+
import { Method, MethodContext } from '../types';
32

43
/**
54
* Logs any error thrown/rejected by a method. Optionally rethrows.
@@ -16,46 +15,35 @@ import { Method, MethodContext } from "../types";
1615
* }
1716
* @endcode
1817
*/
19-
export function LogMethodError(
20-
rethrow: boolean = true,
21-
errorHandler?: (error: Error, methodName: string) => void
22-
) {
23-
const emit = (raw: unknown, name: string): Error => {
24-
const err = raw instanceof Error ? raw : new Error(`Non-Error exception: ${String(raw)}`);
18+
export function LogMethodError(rethrow: boolean = true, errorHandler?: (error: Error, methodName: string) => void) {
19+
const logAndNormalizeError = (thrownValue: unknown, methodName: string): Error => {
20+
const normalizedError = thrownValue instanceof Error ? thrownValue : new Error(`Non-Error exception: ${String(thrownValue)}`);
2521
try {
26-
if (errorHandler) errorHandler(err, name);
27-
else // eslint-disable-next-line no-console
28-
console.error(`🚨 [Error] ${name}:`, err);
29-
} catch {/* ignore handler failures */}
30-
return err;
22+
if (errorHandler) errorHandler(normalizedError, methodName);
23+
else console.error(`${methodName}:`, normalizedError);
24+
} catch {
25+
// ignore handler failures
26+
}
27+
return normalizedError;
3128
};
3229

33-
return function <
34-
This,
35-
Args extends unknown[],
36-
Return
37-
>(
38-
value: Method<This, Args, Return>,
39-
context: MethodContext<This, Args, Return>
40-
): Method<This, Args, Return> {
30+
return function <This, Args extends unknown[], Return>(value: Method<This, Args, Return>, context: MethodContext<This, Args, Return>): Method<This, Args, Return> {
4131
const methodName = String(context.name);
4232

4333
return function (this: This, ...args: Args): Return {
4434
try {
45-
const out = value.apply(this, args);
46-
if (out instanceof Promise) {
47-
return (out as Promise<unknown>)
48-
.catch((e) => {
49-
const err = emit(e, methodName);
50-
if (rethrow) throw err;
51-
// swallow by resolving to undefined
52-
return undefined as unknown as Return;
53-
}) as Return;
35+
const result = value.apply(this, args);
36+
if (result instanceof Promise) {
37+
return (result as Promise<unknown>).catch((thrownError) => {
38+
const normalizedError = logAndNormalizeError(thrownError, methodName);
39+
if (rethrow) throw normalizedError;
40+
return undefined as unknown as Return;
41+
}) as Return;
5442
}
55-
return out;
56-
} catch (e) {
57-
const err = emit(e, methodName);
58-
if (rethrow) throw err;
43+
return result;
44+
} catch (thrownError) {
45+
const normalizedError = logAndNormalizeError(thrownError, methodName);
46+
if (rethrow) throw normalizedError;
5947
return undefined as unknown as Return;
6048
}
6149
};

0 commit comments

Comments
 (0)