Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/ipynb/src/helper.ts
3291 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
import { CancellationError } from 'vscode';
7
8
export function deepClone<T>(obj: T): T {
9
if (!obj || typeof obj !== 'object') {
10
return obj;
11
}
12
if (obj instanceof RegExp) {
13
// See https://github.com/microsoft/TypeScript/issues/10990
14
return obj as any;
15
}
16
const result: any = Array.isArray(obj) ? [] : {};
17
Object.keys(<any>obj).forEach((key: string) => {
18
if ((<any>obj)[key] && typeof (<any>obj)[key] === 'object') {
19
result[key] = deepClone((<any>obj)[key]);
20
} else {
21
result[key] = (<any>obj)[key];
22
}
23
});
24
return result;
25
}
26
27
// from https://github.com/microsoft/vscode/blob/43ae27a30e7b5e8711bf6b218ee39872ed2b8ef6/src/vs/base/common/objects.ts#L117
28
export function objectEquals(one: any, other: any) {
29
if (one === other) {
30
return true;
31
}
32
if (one === null || one === undefined || other === null || other === undefined) {
33
return false;
34
}
35
if (typeof one !== typeof other) {
36
return false;
37
}
38
if (typeof one !== 'object') {
39
return false;
40
}
41
if ((Array.isArray(one)) !== (Array.isArray(other))) {
42
return false;
43
}
44
45
let i: number;
46
let key: string;
47
48
if (Array.isArray(one)) {
49
if (one.length !== other.length) {
50
return false;
51
}
52
for (i = 0; i < one.length; i++) {
53
if (!objectEquals(one[i], other[i])) {
54
return false;
55
}
56
}
57
} else {
58
const oneKeys: string[] = [];
59
60
for (key in one) {
61
oneKeys.push(key);
62
}
63
oneKeys.sort();
64
const otherKeys: string[] = [];
65
for (key in other) {
66
otherKeys.push(key);
67
}
68
otherKeys.sort();
69
if (!objectEquals(oneKeys, otherKeys)) {
70
return false;
71
}
72
for (i = 0; i < oneKeys.length; i++) {
73
if (!objectEquals(one[oneKeys[i]], other[oneKeys[i]])) {
74
return false;
75
}
76
}
77
}
78
79
return true;
80
}
81
82
/**
83
* A helper to delay/debounce execution of a task, includes cancellation/disposal support.
84
* Pulled from https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/extensions/markdown-language-features/src/util/async.ts
85
*/
86
export class Delayer<T> {
87
88
public defaultDelay: number;
89
private _timeout: any; // Timer
90
private _cancelTimeout: Promise<T | null> | null;
91
private _onSuccess: ((value: T | PromiseLike<T> | undefined) => void) | null;
92
private _task: ITask<T> | null;
93
94
constructor(defaultDelay: number) {
95
this.defaultDelay = defaultDelay;
96
this._timeout = null;
97
this._cancelTimeout = null;
98
this._onSuccess = null;
99
this._task = null;
100
}
101
102
dispose() {
103
this._doCancelTimeout();
104
}
105
106
public trigger(task: ITask<T>, delay: number = this.defaultDelay): Promise<T | null> {
107
this._task = task;
108
if (delay >= 0) {
109
this._doCancelTimeout();
110
}
111
112
if (!this._cancelTimeout) {
113
this._cancelTimeout = new Promise<T | undefined>((resolve) => {
114
this._onSuccess = resolve;
115
}).then(() => {
116
this._cancelTimeout = null;
117
this._onSuccess = null;
118
const result = this._task && this._task?.();
119
this._task = null;
120
return result;
121
});
122
}
123
124
if (delay >= 0 || this._timeout === null) {
125
this._timeout = setTimeout(() => {
126
this._timeout = null;
127
this._onSuccess?.(undefined);
128
}, delay >= 0 ? delay : this.defaultDelay);
129
}
130
131
return this._cancelTimeout;
132
}
133
134
private _doCancelTimeout(): void {
135
if (this._timeout !== null) {
136
clearTimeout(this._timeout);
137
this._timeout = null;
138
}
139
}
140
}
141
142
export interface ITask<T> {
143
(): T;
144
}
145
146
147
/**
148
* Copied from src/vs/base/common/uuid.ts
149
*/
150
export function generateUuid(): string {
151
// use `randomUUID` if possible
152
if (typeof crypto.randomUUID === 'function') {
153
// see https://developer.mozilla.org/en-US/docs/Web/API/Window/crypto
154
// > Although crypto is available on all windows, the returned Crypto object only has one
155
// > usable feature in insecure contexts: the getRandomValues() method.
156
// > In general, you should use this API only in secure contexts.
157
158
return crypto.randomUUID.bind(crypto)();
159
}
160
161
// prep-work
162
const _data = new Uint8Array(16);
163
const _hex: string[] = [];
164
for (let i = 0; i < 256; i++) {
165
_hex.push(i.toString(16).padStart(2, '0'));
166
}
167
168
// get data
169
crypto.getRandomValues(_data);
170
171
// set version bits
172
_data[6] = (_data[6] & 0x0f) | 0x40;
173
_data[8] = (_data[8] & 0x3f) | 0x80;
174
175
// print as string
176
let i = 0;
177
let result = '';
178
result += _hex[_data[i++]];
179
result += _hex[_data[i++]];
180
result += _hex[_data[i++]];
181
result += _hex[_data[i++]];
182
result += '-';
183
result += _hex[_data[i++]];
184
result += _hex[_data[i++]];
185
result += '-';
186
result += _hex[_data[i++]];
187
result += _hex[_data[i++]];
188
result += '-';
189
result += _hex[_data[i++]];
190
result += _hex[_data[i++]];
191
result += '-';
192
result += _hex[_data[i++]];
193
result += _hex[_data[i++]];
194
result += _hex[_data[i++]];
195
result += _hex[_data[i++]];
196
result += _hex[_data[i++]];
197
result += _hex[_data[i++]];
198
return result;
199
}
200
201
export type ValueCallback<T = unknown> = (value: T | Promise<T>) => void;
202
203
const enum DeferredOutcome {
204
Resolved,
205
Rejected
206
}
207
208
209
/**
210
* Creates a promise whose resolution or rejection can be controlled imperatively.
211
*/
212
export class DeferredPromise<T> {
213
214
private completeCallback!: ValueCallback<T>;
215
private errorCallback!: (err: unknown) => void;
216
private outcome?: { outcome: DeferredOutcome.Rejected; value: any } | { outcome: DeferredOutcome.Resolved; value: T };
217
218
public get isRejected() {
219
return this.outcome?.outcome === DeferredOutcome.Rejected;
220
}
221
222
public get isResolved() {
223
return this.outcome?.outcome === DeferredOutcome.Resolved;
224
}
225
226
public get isSettled() {
227
return !!this.outcome;
228
}
229
230
public get value() {
231
return this.outcome?.outcome === DeferredOutcome.Resolved ? this.outcome?.value : undefined;
232
}
233
234
public readonly p: Promise<T>;
235
236
constructor() {
237
this.p = new Promise<T>((c, e) => {
238
this.completeCallback = c;
239
this.errorCallback = e;
240
});
241
}
242
243
public complete(value: T) {
244
return new Promise<void>(resolve => {
245
this.completeCallback(value);
246
this.outcome = { outcome: DeferredOutcome.Resolved, value };
247
resolve();
248
});
249
}
250
251
public error(err: unknown) {
252
return new Promise<void>(resolve => {
253
this.errorCallback(err);
254
this.outcome = { outcome: DeferredOutcome.Rejected, value: err };
255
resolve();
256
});
257
}
258
259
public cancel() {
260
return this.error(new CancellationError());
261
}
262
}
263
264