@naturalcycles/js-lib 15.70.0 → 15.71.0

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.
Files changed (35) hide show
  1. package/dist/asyncManager.d.ts +50 -0
  2. package/dist/asyncManager.js +83 -0
  3. package/dist/browser/adminService.js +0 -1
  4. package/dist/decorators/asyncMemo.decorator.js +0 -1
  5. package/dist/decorators/debounce.decorator.js +0 -2
  6. package/dist/decorators/logMethod.decorator.js +0 -1
  7. package/dist/decorators/memo.decorator.js +0 -1
  8. package/dist/decorators/retry.decorator.js +0 -1
  9. package/dist/decorators/swarmSafe.decorator.js +0 -1
  10. package/dist/decorators/timeout.decorator.js +0 -1
  11. package/dist/error/tryCatch.js +0 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.js +1 -0
  14. package/dist/number/number.util.js +0 -1
  15. package/dist/object/keySortedMap.js +0 -1
  16. package/dist/object/lazyKeySortedMap.js +0 -1
  17. package/dist/string/safeJsonStringify.js +0 -1
  18. package/package.json +2 -2
  19. package/src/asyncManager.ts +96 -0
  20. package/src/browser/adminService.ts +0 -1
  21. package/src/browser/analytics.util.ts +0 -2
  22. package/src/decorators/asyncMemo.decorator.ts +0 -1
  23. package/src/decorators/debounce.decorator.ts +0 -2
  24. package/src/decorators/logMethod.decorator.ts +0 -1
  25. package/src/decorators/memo.decorator.ts +0 -1
  26. package/src/decorators/retry.decorator.ts +0 -1
  27. package/src/decorators/swarmSafe.decorator.ts +0 -1
  28. package/src/decorators/timeout.decorator.ts +0 -1
  29. package/src/error/tryCatch.ts +0 -1
  30. package/src/index.ts +1 -0
  31. package/src/number/number.util.ts +0 -1
  32. package/src/object/keySortedMap.ts +0 -1
  33. package/src/object/lazyKeySortedMap.ts +0 -1
  34. package/src/string/safeJsonStringify.ts +0 -1
  35. package/src/types.ts +0 -2
@@ -0,0 +1,50 @@
1
+ import type { CommonLogger } from './log/commonLogger.js';
2
+ import type { NumberOfMilliseconds } from './types.js';
3
+ declare class AsyncManagerImpl {
4
+ logger: CommonLogger;
5
+ pendingOps: Set<Promise<unknown>>;
6
+ private onErrorHooks;
7
+ runInBackground(promise: Promise<unknown>): void;
8
+ onError(fn: OnErrorHook): void;
9
+ /**
10
+ * Resolves when all pending operations settle.
11
+ * They may resolve or reject, allDone will never throw.
12
+ * Errors (rejections) are reported to onErrorHooks (instead).
13
+ *
14
+ * If timeout is specified - it resolves if timeout has reached.
15
+ */
16
+ allDone(timeout?: NumberOfMilliseconds): Promise<void>;
17
+ reset(): void;
18
+ private fireOnErrorHooks;
19
+ }
20
+ /**
21
+ * Singleton which keeps track of async operations - "voided promise-returning functions"
22
+ * that should run in parallel to the main request.
23
+ *
24
+ * It is an alternative to do `void doSomeAnalytics()`, which should run in parallel
25
+ * and not block the request (not slow down nor fail the request on analytics api failure).
26
+ *
27
+ * At the same time, `void doSomeAnalytics()` gets completely detached and untracked,
28
+ * nothing awaits it, its rejection becomes unhandledRejection (and may kill Node.js process).
29
+ *
30
+ * With AsyncManager, you instead register all those "voided" calls like this:
31
+ *
32
+ * AsyncManager.runInBackground(doSomeAnalytics())
33
+ *
34
+ * Then, in a few places you may be interested to ensure that all async operations have been finished.
35
+ * The places can be:
36
+ * - Graceful shutdown of a backend service
37
+ * - Before the end of runScript
38
+ * - At the end of each unit test, to make sure async ops don't leak
39
+ *
40
+ * You ensure no pending async operations like this:
41
+ *
42
+ * await AsyncManager.allDone()
43
+ *
44
+ * which never throws, but instead awaits all operations to be settled.
45
+ *
46
+ * @experimental
47
+ */
48
+ export declare const AsyncManager: AsyncManagerImpl;
49
+ export type OnErrorHook = (err: Error) => any;
50
+ export {};
@@ -0,0 +1,83 @@
1
+ class AsyncManagerImpl {
2
+ logger = console;
3
+ pendingOps = new Set();
4
+ onErrorHooks = [];
5
+ runInBackground(promise) {
6
+ const wrappedPromise = promise
7
+ .catch(err => this.fireOnErrorHooks(err))
8
+ .finally(() => this.pendingOps.delete(wrappedPromise));
9
+ this.pendingOps.add(wrappedPromise);
10
+ }
11
+ onError(fn) {
12
+ this.onErrorHooks.push(fn);
13
+ }
14
+ /**
15
+ * Resolves when all pending operations settle.
16
+ * They may resolve or reject, allDone will never throw.
17
+ * Errors (rejections) are reported to onErrorHooks (instead).
18
+ *
19
+ * If timeout is specified - it resolves if timeout has reached.
20
+ */
21
+ async allDone(timeout) {
22
+ const { size } = this.pendingOps;
23
+ if (!size)
24
+ return;
25
+ const { logger } = this;
26
+ const started = Date.now();
27
+ if (timeout) {
28
+ const result = await Promise.race([
29
+ Promise.allSettled(this.pendingOps),
30
+ new Promise(resolve => setTimeout(resolve, timeout, 'timeout')),
31
+ ]);
32
+ if (result === 'timeout') {
33
+ logger.warn(`AsyncManager.allDone timed out after ${timeout} ms with ${this.pendingOps.size} pending op(s)`);
34
+ return;
35
+ }
36
+ }
37
+ else {
38
+ await Promise.allSettled(this.pendingOps);
39
+ }
40
+ logger.log(`AsyncManager.allDone for ${size} op(s) in ${Date.now() - started} ms`);
41
+ }
42
+ reset() {
43
+ this.pendingOps.clear();
44
+ this.onErrorHooks = [];
45
+ }
46
+ fireOnErrorHooks(err) {
47
+ if (this.onErrorHooks.length) {
48
+ this.onErrorHooks.forEach(hook => hook(err));
49
+ }
50
+ else {
51
+ this.logger.error('AsyncManager unhandled rejection:', err);
52
+ }
53
+ }
54
+ }
55
+ /**
56
+ * Singleton which keeps track of async operations - "voided promise-returning functions"
57
+ * that should run in parallel to the main request.
58
+ *
59
+ * It is an alternative to do `void doSomeAnalytics()`, which should run in parallel
60
+ * and not block the request (not slow down nor fail the request on analytics api failure).
61
+ *
62
+ * At the same time, `void doSomeAnalytics()` gets completely detached and untracked,
63
+ * nothing awaits it, its rejection becomes unhandledRejection (and may kill Node.js process).
64
+ *
65
+ * With AsyncManager, you instead register all those "voided" calls like this:
66
+ *
67
+ * AsyncManager.runInBackground(doSomeAnalytics())
68
+ *
69
+ * Then, in a few places you may be interested to ensure that all async operations have been finished.
70
+ * The places can be:
71
+ * - Graceful shutdown of a backend service
72
+ * - Before the end of runScript
73
+ * - At the end of each unit test, to make sure async ops don't leak
74
+ *
75
+ * You ensure no pending async operations like this:
76
+ *
77
+ * await AsyncManager.allDone()
78
+ *
79
+ * which never throws, but instead awaits all operations to be settled.
80
+ *
81
+ * @experimental
82
+ */
83
+ export const AsyncManager = new AsyncManagerImpl();
@@ -43,7 +43,6 @@ export class AdminService {
43
43
  stopListening() {
44
44
  if (isServerSide())
45
45
  return;
46
- // oxlint-disable-next-line typescript/unbound-method
47
46
  document.removeEventListener('keydown', this.keydownListener);
48
47
  this.listening = false;
49
48
  }
@@ -10,7 +10,6 @@ import { jsonMemoSerializer } from './memo.util.js';
10
10
  *
11
11
  * @experimental consider normal `@_Memo` for most of the cases, it's stable and predictable
12
12
  */
13
- // eslint-disable-next-line @typescript-eslint/naming-convention
14
13
  export const _AsyncMemo = (opt) => (target, key, descriptor) => {
15
14
  _assertTypeOf(descriptor.value, 'function', 'Memoization can be applied only to methods');
16
15
  const originalFn = descriptor.value;
@@ -1,5 +1,4 @@
1
1
  import { _debounce, _throttle } from './debounce.js';
2
- // eslint-disable-next-line @typescript-eslint/naming-convention
3
2
  export function _Debounce(wait, opt = {}) {
4
3
  return (_target, _key, descriptor) => {
5
4
  const originalFn = descriptor.value;
@@ -7,7 +6,6 @@ export function _Debounce(wait, opt = {}) {
7
6
  return descriptor;
8
7
  };
9
8
  }
10
- // eslint-disable-next-line @typescript-eslint/naming-convention
11
9
  export function _Throttle(wait, opt = {}) {
12
10
  return (_target, _key, descriptor) => {
13
11
  const originalFn = descriptor.value;
@@ -16,7 +16,6 @@ import { _getArgsSignature, _getMethodSignature } from './decorator.util.js';
16
16
  * >> asyncMethod()
17
17
  * << asyncMethodThrow() took 10 ms ERROR: MyError
18
18
  */
19
- // eslint-disable-next-line @typescript-eslint/naming-convention
20
19
  export function _LogMethod(opt = {}) {
21
20
  return (_target, key, descriptor) => {
22
21
  _assert(typeof descriptor.value === 'function', '@_LogMethod can be applied only to methods');
@@ -22,7 +22,6 @@ import { jsonMemoSerializer, MapMemoCache } from './memo.util.js';
22
22
  * http://inlehmansterms.net/2015/03/01/javascript-memoization/
23
23
  * https://community.risingstack.com/the-worlds-fastest-javascript-memoization-library/
24
24
  */
25
- // eslint-disable-next-line @typescript-eslint/naming-convention
26
25
  export const _Memo = (opt = {}) => (target, key, descriptor) => {
27
26
  _assertTypeOf(descriptor.value, 'function', 'Memoization can be applied only to methods');
28
27
  const originalFn = descriptor.value;
@@ -1,5 +1,4 @@
1
1
  import { pRetryFn } from '../promise/pRetry.js';
2
- // eslint-disable-next-line @typescript-eslint/naming-convention
3
2
  export function _Retry(opt = {}) {
4
3
  return (_target, _key, descriptor) => {
5
4
  const originalFn = descriptor.value;
@@ -7,7 +7,6 @@ import { _getTargetMethodSignature } from './decorator.util.js';
7
7
  * Does not support `cacheKey`.
8
8
  * So, the same Promise is returned, regardless of the arguments.
9
9
  */
10
- // eslint-disable-next-line @typescript-eslint/naming-convention
11
10
  export const _SwarmSafe = () => (target, key, descriptor) => {
12
11
  if (typeof descriptor.value !== 'function') {
13
12
  throw new TypeError('@_SwarmSafe can be applied only to methods');
@@ -1,7 +1,6 @@
1
1
  import { _assert } from '../error/assert.js';
2
2
  import { pTimeout } from '../promise/pTimeout.js';
3
3
  import { _getMethodSignature } from './decorator.util.js';
4
- // eslint-disable-next-line @typescript-eslint/naming-convention
5
4
  export function _Timeout(opt) {
6
5
  return (_target, key, descriptor) => {
7
6
  _assert(typeof descriptor.value === 'function', '@_Timeout can be applied only to methods');
@@ -34,7 +34,6 @@ export function _tryCatch(fn, opt = {}) {
34
34
  }
35
35
  };
36
36
  }
37
- // eslint-disable-next-line @typescript-eslint/naming-convention
38
37
  export const _TryCatch = (opt = {}) => (_target, _key, descriptor) => {
39
38
  const originalFn = descriptor.value;
40
39
  descriptor.value = _tryCatch(originalFn, opt);
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './abort.js';
2
+ export * from './asyncManager.js';
2
3
  export * from './bot.model.js';
3
4
  export * from './define.js';
4
5
  export * from './enum.util.js';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './abort.js';
2
+ export * from './asyncManager.js';
2
3
  export * from './bot.model.js';
3
4
  export * from './define.js';
4
5
  export * from './enum.util.js';
@@ -40,7 +40,6 @@ export function _isBetween(x, min, max, incl) {
40
40
  return true;
41
41
  }
42
42
  export function _clamp(x, minIncl, maxIncl) {
43
- // oxlint-disable-next-line unicorn/prefer-math-min-max
44
43
  return x <= minIncl ? minIncl : x >= maxIncl ? maxIncl : x;
45
44
  }
46
45
  /**
@@ -1,5 +1,4 @@
1
1
  import { _assert } from '../error/index.js';
2
- // oxlint-disable-next-line no-unsafe-declaration-merging -- Map<K,V> workaround for oxlint TS2420 false positive
3
2
  export class KeySortedMap {
4
3
  map;
5
4
  #sortedKeys;
@@ -1,5 +1,4 @@
1
1
  import { _assert } from '../error/index.js';
2
- // oxlint-disable-next-line no-unsafe-declaration-merging -- Map<K,V> workaround for oxlint TS2420 false positive
3
2
  export class LazyKeySortedMap {
4
3
  map;
5
4
  maybeSortedKeys;
@@ -13,7 +13,6 @@ export function _safeJsonStringify(obj, replacer, spaces, cycleReplacer) {
13
13
  return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces);
14
14
  }
15
15
  }
16
- // oxlint-disable no-unused-expressions
17
16
  function serializer(replacer, cycleReplacer) {
18
17
  const stack = [];
19
18
  const keys = [];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
3
  "type": "module",
4
- "version": "15.70.0",
4
+ "version": "15.71.0",
5
5
  "dependencies": {
6
6
  "tslib": "^2"
7
7
  },
@@ -17,7 +17,7 @@
17
17
  "@types/crypto-js": "^4",
18
18
  "@types/node": "^25",
19
19
  "@types/semver": "^7",
20
- "@typescript/native-preview": "7.0.0-dev.20260201.1",
20
+ "@typescript/native-preview": "7.0.0-dev.20260301.1",
21
21
  "crypto-js": "^4",
22
22
  "dayjs": "^1",
23
23
  "@naturalcycles/dev-lib": "18.4.2"
@@ -0,0 +1,96 @@
1
+ import type { CommonLogger } from './log/commonLogger.js'
2
+ import type { NumberOfMilliseconds } from './types.js'
3
+
4
+ class AsyncManagerImpl {
5
+ logger: CommonLogger = console
6
+
7
+ pendingOps = new Set<Promise<unknown>>()
8
+
9
+ private onErrorHooks: OnErrorHook[] = []
10
+
11
+ runInBackground(promise: Promise<unknown>): void {
12
+ const wrappedPromise = promise
13
+ .catch(err => this.fireOnErrorHooks(err))
14
+ .finally(() => this.pendingOps.delete(wrappedPromise))
15
+ this.pendingOps.add(wrappedPromise)
16
+ }
17
+
18
+ onError(fn: OnErrorHook): void {
19
+ this.onErrorHooks.push(fn)
20
+ }
21
+
22
+ /**
23
+ * Resolves when all pending operations settle.
24
+ * They may resolve or reject, allDone will never throw.
25
+ * Errors (rejections) are reported to onErrorHooks (instead).
26
+ *
27
+ * If timeout is specified - it resolves if timeout has reached.
28
+ */
29
+ async allDone(timeout?: NumberOfMilliseconds): Promise<void> {
30
+ const { size } = this.pendingOps
31
+ if (!size) return
32
+ const { logger } = this
33
+
34
+ const started = Date.now()
35
+ if (timeout) {
36
+ const result = await Promise.race([
37
+ Promise.allSettled(this.pendingOps),
38
+ new Promise<'timeout'>(resolve => setTimeout(resolve, timeout, 'timeout')),
39
+ ])
40
+ if (result === 'timeout') {
41
+ logger.warn(
42
+ `AsyncManager.allDone timed out after ${timeout} ms with ${this.pendingOps.size} pending op(s)`,
43
+ )
44
+ return
45
+ }
46
+ } else {
47
+ await Promise.allSettled(this.pendingOps)
48
+ }
49
+ logger.log(`AsyncManager.allDone for ${size} op(s) in ${Date.now() - started} ms`)
50
+ }
51
+
52
+ reset(): void {
53
+ this.pendingOps.clear()
54
+ this.onErrorHooks = []
55
+ }
56
+
57
+ private fireOnErrorHooks(err: any): void {
58
+ if (this.onErrorHooks.length) {
59
+ this.onErrorHooks.forEach(hook => hook(err))
60
+ } else {
61
+ this.logger.error('AsyncManager unhandled rejection:', err)
62
+ }
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Singleton which keeps track of async operations - "voided promise-returning functions"
68
+ * that should run in parallel to the main request.
69
+ *
70
+ * It is an alternative to do `void doSomeAnalytics()`, which should run in parallel
71
+ * and not block the request (not slow down nor fail the request on analytics api failure).
72
+ *
73
+ * At the same time, `void doSomeAnalytics()` gets completely detached and untracked,
74
+ * nothing awaits it, its rejection becomes unhandledRejection (and may kill Node.js process).
75
+ *
76
+ * With AsyncManager, you instead register all those "voided" calls like this:
77
+ *
78
+ * AsyncManager.runInBackground(doSomeAnalytics())
79
+ *
80
+ * Then, in a few places you may be interested to ensure that all async operations have been finished.
81
+ * The places can be:
82
+ * - Graceful shutdown of a backend service
83
+ * - Before the end of runScript
84
+ * - At the end of each unit test, to make sure async ops don't leak
85
+ *
86
+ * You ensure no pending async operations like this:
87
+ *
88
+ * await AsyncManager.allDone()
89
+ *
90
+ * which never throws, but instead awaits all operations to be settled.
91
+ *
92
+ * @experimental
93
+ */
94
+ export const AsyncManager = new AsyncManagerImpl()
95
+
96
+ export type OnErrorHook = (err: Error) => any
@@ -103,7 +103,6 @@ export class AdminService {
103
103
 
104
104
  stopListening(): void {
105
105
  if (isServerSide()) return
106
- // oxlint-disable-next-line typescript/unbound-method
107
106
  document.removeEventListener('keydown', this.keydownListener)
108
107
  this.listening = false
109
108
  }
@@ -1,8 +1,6 @@
1
1
  import { isServerSide } from '../env.js'
2
2
  import { loadScript } from './script.util.js'
3
3
 
4
- // oxlint-disable no-var
5
-
6
4
  declare global {
7
5
  var dataLayer: any[]
8
6
  var gtag: (...args: any[]) => void
@@ -43,7 +43,6 @@ export interface AsyncMemoInstance {
43
43
  *
44
44
  * @experimental consider normal `@_Memo` for most of the cases, it's stable and predictable
45
45
  */
46
- // eslint-disable-next-line @typescript-eslint/naming-convention
47
46
  export const _AsyncMemo =
48
47
  <FN>(opt: AsyncMemoOptions<FN>): MethodDecorator<FN> =>
49
48
  (target, key, descriptor) => {
@@ -1,7 +1,6 @@
1
1
  import type { DebounceOptions, ThrottleOptions } from './debounce.js'
2
2
  import { _debounce, _throttle } from './debounce.js'
3
3
 
4
- // eslint-disable-next-line @typescript-eslint/naming-convention
5
4
  export function _Debounce(wait: number, opt: DebounceOptions = {}): MethodDecorator {
6
5
  return (_target, _key, descriptor) => {
7
6
  const originalFn = descriptor.value
@@ -10,7 +9,6 @@ export function _Debounce(wait: number, opt: DebounceOptions = {}): MethodDecora
10
9
  }
11
10
  }
12
11
 
13
- // eslint-disable-next-line @typescript-eslint/naming-convention
14
12
  export function _Throttle(wait: number, opt: ThrottleOptions = {}): MethodDecorator {
15
13
  return (_target, _key, descriptor) => {
16
14
  const originalFn = descriptor.value
@@ -71,7 +71,6 @@ export interface LogMethodOptions {
71
71
  * >> asyncMethod()
72
72
  * << asyncMethodThrow() took 10 ms ERROR: MyError
73
73
  */
74
- // eslint-disable-next-line @typescript-eslint/naming-convention
75
74
  export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
76
75
  return (_target, key, descriptor) => {
77
76
  _assert(typeof descriptor.value === 'function', '@_LogMethod can be applied only to methods')
@@ -56,7 +56,6 @@ export interface MemoInstance {
56
56
  * http://inlehmansterms.net/2015/03/01/javascript-memoization/
57
57
  * https://community.risingstack.com/the-worlds-fastest-javascript-memoization-library/
58
58
  */
59
- // eslint-disable-next-line @typescript-eslint/naming-convention
60
59
  export const _Memo =
61
60
  <FN>(opt: MemoOptions<FN> = {}): MethodDecorator<FN> =>
62
61
  (target, key, descriptor) => {
@@ -1,7 +1,6 @@
1
1
  import type { PRetryOptions } from '../promise/pRetry.js'
2
2
  import { pRetryFn } from '../promise/pRetry.js'
3
3
 
4
- // eslint-disable-next-line @typescript-eslint/naming-convention
5
4
  export function _Retry(opt: PRetryOptions = {}): MethodDecorator {
6
5
  return (_target, _key, descriptor) => {
7
6
  const originalFn = descriptor.value
@@ -9,7 +9,6 @@ import { _getTargetMethodSignature } from './decorator.util.js'
9
9
  * Does not support `cacheKey`.
10
10
  * So, the same Promise is returned, regardless of the arguments.
11
11
  */
12
- // eslint-disable-next-line @typescript-eslint/naming-convention
13
12
  export const _SwarmSafe = (): MethodDecorator => (target, key, descriptor) => {
14
13
  if (typeof descriptor.value !== 'function') {
15
14
  throw new TypeError('@_SwarmSafe can be applied only to methods')
@@ -3,7 +3,6 @@ import type { PTimeoutOptions } from '../promise/pTimeout.js'
3
3
  import { pTimeout } from '../promise/pTimeout.js'
4
4
  import { _getMethodSignature } from './decorator.util.js'
5
5
 
6
- // eslint-disable-next-line @typescript-eslint/naming-convention
7
6
  export function _Timeout(opt: PTimeoutOptions): MethodDecorator {
8
7
  return (_target, key, descriptor) => {
9
8
  _assert(typeof descriptor.value === 'function', '@_Timeout can be applied only to methods')
@@ -65,7 +65,6 @@ export function _tryCatch<T extends AnyFunction>(fn: T, opt: TryCatchOptions = {
65
65
  } as any
66
66
  }
67
67
 
68
- // eslint-disable-next-line @typescript-eslint/naming-convention
69
68
  export const _TryCatch =
70
69
  (opt: TryCatchOptions = {}): MethodDecorator =>
71
70
  (_target, _key, descriptor) => {
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './abort.js'
2
+ export * from './asyncManager.js'
2
3
  export * from './bot.model.js'
3
4
  export * from './define.js'
4
5
  export * from './enum.util.js'
@@ -50,7 +50,6 @@ export function _isBetween<T extends number | string>(
50
50
  }
51
51
 
52
52
  export function _clamp(x: number, minIncl: number, maxIncl: number): number {
53
- // oxlint-disable-next-line unicorn/prefer-math-min-max
54
53
  return x <= minIncl ? minIncl : x >= maxIncl ? maxIncl : x
55
54
  }
56
55
 
@@ -25,7 +25,6 @@ export interface KeySortedMapOptions<K> {
25
25
  // oxlint-disable-next-line no-unsafe-declaration-merging -- Map<K,V> workaround for oxlint TS2420 false positive
26
26
  export interface KeySortedMap<K, V> extends Map<K, V> {}
27
27
 
28
- // oxlint-disable-next-line no-unsafe-declaration-merging -- Map<K,V> workaround for oxlint TS2420 false positive
29
28
  export class KeySortedMap<K, V> {
30
29
  private readonly map: Map<K, V>
31
30
  readonly #sortedKeys: K[]
@@ -20,7 +20,6 @@ export interface LazyKeySortedMapOptions<K> {
20
20
  // oxlint-disable-next-line no-unsafe-declaration-merging -- Map<K,V> workaround for oxlint TS2420 false positive
21
21
  export interface LazyKeySortedMap<K, V> extends Map<K, V> {}
22
22
 
23
- // oxlint-disable-next-line no-unsafe-declaration-merging -- Map<K,V> workaround for oxlint TS2420 false positive
24
23
  export class LazyKeySortedMap<K, V> {
25
24
  private readonly map: Map<K, V>
26
25
  private readonly maybeSortedKeys: K[]
@@ -20,7 +20,6 @@ export function _safeJsonStringify(
20
20
  }
21
21
  }
22
22
 
23
- // oxlint-disable no-unused-expressions
24
23
  function serializer(replacer?: Reviver, cycleReplacer?: Reviver): Reviver {
25
24
  const stack: any[] = []
26
25
  const keys: string[] = []
package/src/types.ts CHANGED
@@ -521,8 +521,6 @@ type ReadonlyObjectDeep<ObjectType extends object> = {
521
521
  readonly [KeyType in keyof ObjectType]: ReadonlyDeep<ObjectType[KeyType]>
522
522
  }
523
523
 
524
- // oxlint-enable
525
-
526
524
  /**
527
525
  Makes one property of T required instead of optional.
528
526
  @example