Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/common/decorators.ts
3292 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
return (this as any)[memoizeKey];
58
};
59
}
60
61
export interface IDebounceReducer<T> {
62
(previousValue: T, ...args: any[]): T;
63
}
64
65
export function debounce<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T) {
66
return createDecorator((fn, key) => {
67
const timerKey = `$debounce$${key}`;
68
const resultKey = `$debounce$result$${key}`;
69
70
return function (this: any, ...args: any[]) {
71
if (!this[resultKey]) {
72
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
73
}
74
75
clearTimeout(this[timerKey]);
76
77
if (reducer) {
78
this[resultKey] = reducer(this[resultKey], ...args);
79
args = [this[resultKey]];
80
}
81
82
this[timerKey] = setTimeout(() => {
83
fn.apply(this, args);
84
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
85
}, delay);
86
};
87
});
88
}
89
90
export function throttle<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T) {
91
return createDecorator((fn, key) => {
92
const timerKey = `$throttle$timer$${key}`;
93
const resultKey = `$throttle$result$${key}`;
94
const lastRunKey = `$throttle$lastRun$${key}`;
95
const pendingKey = `$throttle$pending$${key}`;
96
97
return function (this: any, ...args: any[]) {
98
if (!this[resultKey]) {
99
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
100
}
101
if (this[lastRunKey] === null || this[lastRunKey] === undefined) {
102
this[lastRunKey] = -Number.MAX_VALUE;
103
}
104
105
if (reducer) {
106
this[resultKey] = reducer(this[resultKey], ...args);
107
}
108
109
if (this[pendingKey]) {
110
return;
111
}
112
113
const nextTime = this[lastRunKey] + delay;
114
if (nextTime <= Date.now()) {
115
this[lastRunKey] = Date.now();
116
fn.apply(this, [this[resultKey]]);
117
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
118
} else {
119
this[pendingKey] = true;
120
this[timerKey] = setTimeout(() => {
121
this[pendingKey] = false;
122
this[lastRunKey] = Date.now();
123
fn.apply(this, [this[resultKey]]);
124
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
125
}, nextTime - Date.now());
126
}
127
};
128
});
129
}
130
131
export { cancelPreviousCalls } from './decorators/cancelPreviousCalls.js';
132
133