@pkerschbaum/code-oss-file-service
Version:
VS Code ([microsoft/vscode](https://github.com/microsoft/vscode)) includes a rich "`FileService`" and "`DiskFileSystemProvider`" abstraction built on top of Node.js core modules (`fs`, `path`) and Electron's `shell` module. This package allows to use that
131 lines (109 loc) • 3.92 kB
text/typescript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export function createDecorator(mapFn: (fn: Function, key: string) => Function): Function {
return (target: any, key: string, descriptor: any) => {
let fnKey: string | null = null;
let fn: Function | null = null;
if (typeof descriptor.value === 'function') {
fnKey = 'value';
fn = descriptor.value;
} else if (typeof descriptor.get === 'function') {
fnKey = 'get';
fn = descriptor.get;
}
if (!fn) {
throw new Error('not supported');
}
descriptor[fnKey!] = mapFn(fn, key);
};
}
export function memoize(_target: any, key: string, descriptor: any) {
let fnKey: string | null = null;
let fn: Function | null = null;
if (typeof descriptor.value === 'function') {
fnKey = 'value';
fn = descriptor.value;
if (fn!.length !== 0) {
console.warn('Memoize should only be used in functions with zero parameters');
}
} else if (typeof descriptor.get === 'function') {
fnKey = 'get';
fn = descriptor.get;
}
if (!fn) {
throw new Error('not supported');
}
const memoizeKey = `$memoize$${key}`;
descriptor[fnKey!] = function (...args: any[]) {
if (!this.hasOwnProperty(memoizeKey)) {
Object.defineProperty(this, memoizeKey, {
configurable: false,
enumerable: false,
writable: false,
value: fn!.apply(this, args)
});
}
return this[memoizeKey];
};
}
export interface IDebounceReducer<T> {
(previousValue: T, ...args: any[]): T;
}
export function debounce<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T): Function {
return createDecorator((fn, key) => {
const timerKey = `$debounce$${key}`;
const resultKey = `$debounce$result$${key}`;
return function (this: any, ...args: any[]) {
if (!this[resultKey]) {
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
}
clearTimeout(this[timerKey]);
if (reducer) {
this[resultKey] = reducer(this[resultKey], ...args);
args = [this[resultKey]];
}
this[timerKey] = setTimeout(() => {
fn.apply(this, args);
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
}, delay);
};
});
}
export function throttle<T>(delay: number, reducer?: IDebounceReducer<T>, initialValueProvider?: () => T): Function {
return createDecorator((fn, key) => {
const timerKey = `$throttle$timer$${key}`;
const resultKey = `$throttle$result$${key}`;
const lastRunKey = `$throttle$lastRun$${key}`;
const pendingKey = `$throttle$pending$${key}`;
return function (this: any, ...args: any[]) {
if (!this[resultKey]) {
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
}
if (this[lastRunKey] === null || this[lastRunKey] === undefined) {
this[lastRunKey] = -Number.MAX_VALUE;
}
if (reducer) {
this[resultKey] = reducer(this[resultKey], ...args);
}
if (this[pendingKey]) {
return;
}
const nextTime = this[lastRunKey] + delay;
if (nextTime <= Date.now()) {
this[lastRunKey] = Date.now();
fn.apply(this, [this[resultKey]]);
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
} else {
this[pendingKey] = true;
this[timerKey] = setTimeout(() => {
this[pendingKey] = false;
this[lastRunKey] = Date.now();
fn.apply(this, [this[resultKey]]);
this[resultKey] = initialValueProvider ? initialValueProvider() : undefined;
}, nextTime - Date.now());
}
};
});
}