Skip to content

Commit 51fa619

Browse files
authoredJun 30, 2022
feat(jest-leak-detector): use FinalizationRegistry when it exists to get rid of external dependency (#12973)
1 parent 43368be commit 51fa619

File tree

2 files changed

+29
-12
lines changed

2 files changed

+29
-12
lines changed
 

‎CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
### Features
44

5+
- `[jest-leak-detector]` Use native `FinalizationRegistry` when it exists to get rid of external C dependency ([#12973](https://github.com/facebook/jest/pull/12973))
6+
57
### Fixes
68

79
- `[jest-changed-files]` Fix a lock-up after repeated invocations ([#12757](https://github.com/facebook/jest/issues/12757))

‎packages/jest-leak-detector/src/index.ts

+27-12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*/
7+
/// <reference lib="es2021.WeakRef" />
78

89
import {promisify} from 'util';
910
import {setFlagsFromString} from 'v8';
@@ -15,6 +16,7 @@ const tick = promisify(setImmediate);
1516

1617
export default class LeakDetector {
1718
private _isReferenceBeingHeld: boolean;
19+
private _finalizationRegistry?: FinalizationRegistry<undefined>;
1820

1921
constructor(value: unknown) {
2022
if (isPrimitive(value)) {
@@ -26,23 +28,36 @@ export default class LeakDetector {
2628
);
2729
}
2830

29-
let weak: typeof import('weak-napi');
31+
// TODO: Remove the `if` and `weak-napi` when we drop node 12, as v14 supports FinalizationRegistry
32+
if (globalThis.FinalizationRegistry) {
33+
// When `_finalizationRegistry` is GCed the callback we set will no longer be called,
34+
// so we need to assign it to `this` to keep it referenced
35+
this._finalizationRegistry = new FinalizationRegistry(() => {
36+
this._isReferenceBeingHeld = false;
37+
});
3038

31-
try {
32-
// eslint-disable-next-line import/no-extraneous-dependencies
33-
weak = require('weak-napi');
34-
} catch (err: any) {
35-
if (!err || err.code !== 'MODULE_NOT_FOUND') {
36-
throw err;
39+
this._finalizationRegistry.register(value as object, undefined);
40+
} else {
41+
let weak: typeof import('weak-napi');
42+
43+
try {
44+
// eslint-disable-next-line import/no-extraneous-dependencies
45+
weak = require('weak-napi');
46+
} catch (err: any) {
47+
if (!err || err.code !== 'MODULE_NOT_FOUND') {
48+
throw err;
49+
}
50+
51+
throw new Error(
52+
'The leaking detection mechanism requires newer version of node that supports ' +
53+
'FinalizationRegistry, update your node or install the "weak-napi" package' +
54+
'which support current node version as a dependency on your main project.',
55+
);
3756
}
3857

39-
throw new Error(
40-
'The leaking detection mechanism requires the "weak-napi" package to be installed and work. ' +
41-
'Please install it as a dependency on your main project',
42-
);
58+
weak(value as object, () => (this._isReferenceBeingHeld = false));
4359
}
4460

45-
weak(value as object, () => (this._isReferenceBeingHeld = false));
4661
this._isReferenceBeingHeld = true;
4762

4863
// Ensure value is not leaked by the closure created by the "weak" callback.

0 commit comments

Comments
 (0)
Please sign in to comment.