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