Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/common/decorators.ts
5240 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
function createDecorator(mapFn: (fn: Function, key: string) => Function): MethodDecorator {
7
return (_target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor<any>) => {
8
let fnKey: 'value' | 'get' | null = null;
9
let fn: Function | null = null;
10
11
if (typeof descriptor.value === 'function') {
12
fnKey = 'value';
13
fn = descriptor.value;
14
} else if (typeof descriptor.get === 'function') {
15
fnKey = 'get';
16
fn = descriptor.get;
17
}
18
19
if (!fn || typeof key === 'symbol') {
20
throw new Error('not supported');
21
}
22
23
descriptor[fnKey!] = mapFn(fn, key);
24
};
25
}
26
27
export function memoize(_target: Object, key: string, descriptor: PropertyDescriptor) {
28
let fnKey: 'value' | 'get' | null = null;
29
let fn: Function | null = null;
30
31
if (typeof descriptor.value === 'function') {
32
fnKey = 'value';
33
fn = descriptor.value;
34
35
if (fn!.length !== 0) {
36
console.warn('Memoize should only be used in functions with zero parameters');
37
}
38
} else if (typeof descriptor.get === 'function') {
39
fnKey = 'get';
40
fn = descriptor.get;
41
}
42
43
if (!fn) {
44
throw new Error('not supported');
45
}
46
47
const memoizeKey = `$memoize$${key}`;
48
descriptor[fnKey!] = function (...args: any[]) {
49
if (!this.hasOwnProperty(memoizeKey)) {
50
Object.defineProperty(this, memoizeKey, {
51
configurable: false,
52
enumerable: false,
53
writable: false,
54
value: fn.apply(this, args)
55
});
56
}
57
// eslint-disable-next-line local/code-no-any-casts
58
return (this as any)[memoizeKey];
59
};
60
}
61
62
export interface IDebounceReducer<T> {
63
(previousValue: T, ...args: any[]): T;
64
}
65
66
export function debounce<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T) {
67
return createDecorator((fn, key) => {
68
const timerKey = `$debounce$${key}`;
69
const resultKey = `$debounce$result$${key}`;
70
71
return function (this: any, ...args: any[]) {
72
if (!this[resultKey]) {
73
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
74
}
75
76
clearTimeout(this[timerKey]);
77
78
if (reducer) {
79
this[resultKey] = reducer(this[resultKey], ...args);
80
args = [this[resultKey]];
81
}
82
83
this[timerKey] = setTimeout(() => {
84
fn.apply(this, args);
85
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
86
}, delay);
87
};
88
});
89
}
90
91
export function throttle<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T) {
92
return createDecorator((fn, key) => {
93
const timerKey = `$throttle$timer$${key}`;
94
const resultKey = `$throttle$result$${key}`;
95
const lastRunKey = `$throttle$lastRun$${key}`;
96
const pendingKey = `$throttle$pending$${key}`;
97
98
return function (this: any, ...args: any[]) {
99
if (!this[resultKey]) {
100
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
101
}
102
if (this[lastRunKey] === null || this[lastRunKey] === undefined) {
103
this[lastRunKey] = -Number.MAX_VALUE;
104
}
105
106
if (reducer) {
107
this[resultKey] = reducer(this[resultKey], ...args);
108
}
109
110
if (this[pendingKey]) {
111
return;
112
}
113
114
const nextTime = this[lastRunKey] + delay;
115
if (nextTime <= Date.now()) {
116
this[lastRunKey] = Date.now();
117
fn.apply(this, [this[resultKey]]);
118
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
119
} else {
120
this[pendingKey] = true;
121
this[timerKey] = setTimeout(() => {
122
this[pendingKey] = false;
123
this[lastRunKey] = Date.now();
124
fn.apply(this, [this[resultKey]]);
125
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
126
}, nextTime - Date.now());
127
}
128
};
129
});
130
}
131
132
export { cancelPreviousCalls } from './decorators/cancelPreviousCalls.js';
133
134