1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | Object.defineProperty(exports, "__esModule", { value: true });
|
9 | const cancelable_1 = require("@esfx/cancelable");
|
10 | const disposable_1 = require("@esfx/disposable");
|
11 | const list_1 = require("./list");
|
12 | const utils_1 = require("./utils");
|
13 |
|
14 |
|
15 |
|
16 | class CancellationTokenSource {
|
17 | |
18 |
|
19 |
|
20 |
|
21 |
|
22 | constructor(linkedTokens) {
|
23 | this._state = "open";
|
24 | this._token = undefined;
|
25 | this._registrations = undefined;
|
26 | this._linkingRegistrations = undefined;
|
27 | if (!utils_1.isIterable(linkedTokens, true))
|
28 | throw new TypeError("Object not iterable: linkedTokens.");
|
29 | if (linkedTokens) {
|
30 | for (const linkedToken of linkedTokens) {
|
31 | if (!cancelable_1.Cancelable.hasInstance(linkedToken)) {
|
32 | throw new TypeError("CancellationToken expected.");
|
33 | }
|
34 | const token = CancellationToken.from(linkedToken);
|
35 | if (token.cancellationRequested) {
|
36 | this._state = "cancellationRequested";
|
37 | this._unlink();
|
38 | break;
|
39 | }
|
40 | else if (token.canBeCanceled) {
|
41 | if (this._linkingRegistrations === undefined) {
|
42 | this._linkingRegistrations = [];
|
43 | }
|
44 | this._linkingRegistrations.push(token.register(() => this.cancel()));
|
45 | }
|
46 | }
|
47 | }
|
48 | }
|
49 | |
50 |
|
51 |
|
52 | get token() {
|
53 | if (this._token === undefined) {
|
54 | this._token = new CancellationToken(this);
|
55 | }
|
56 | return this._token;
|
57 | }
|
58 | get _currentState() {
|
59 | if (this._state === "open" && this._linkingRegistrations && this._linkingRegistrations.length > 0) {
|
60 | for (const registration of this._linkingRegistrations) {
|
61 | if (registration._cancellationSource &&
|
62 | registration._cancellationSource._currentState === "cancellationRequested") {
|
63 | return "cancellationRequested";
|
64 | }
|
65 | }
|
66 | }
|
67 | return this._state;
|
68 | }
|
69 | |
70 |
|
71 |
|
72 | get _cancellationRequested() {
|
73 | return this._currentState === "cancellationRequested";
|
74 | }
|
75 | |
76 |
|
77 |
|
78 | get _canBeCanceled() {
|
79 | return this._currentState !== "closed";
|
80 | }
|
81 | |
82 |
|
83 |
|
84 |
|
85 | cancel() {
|
86 | if (this._state !== "open") {
|
87 | return;
|
88 | }
|
89 | this._state = "cancellationRequested";
|
90 | this._unlink();
|
91 | const registrations = this._registrations;
|
92 | this._registrations = undefined;
|
93 | if (registrations && registrations.size > 0) {
|
94 | for (const registration of registrations) {
|
95 | if (registration._cancellationTarget) {
|
96 | this._executeCallback(registration._cancellationTarget);
|
97 | }
|
98 | }
|
99 | }
|
100 | }
|
101 | |
102 |
|
103 |
|
104 | close() {
|
105 | if (this._state !== "open") {
|
106 | return;
|
107 | }
|
108 | this._state = "closed";
|
109 | this._unlink();
|
110 | const callbacks = this._registrations;
|
111 | this._registrations = undefined;
|
112 | if (callbacks !== undefined) {
|
113 |
|
114 |
|
115 |
|
116 | callbacks.clear();
|
117 | }
|
118 | }
|
119 | |
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 | _register(callback) {
|
126 | if (!utils_1.isFunction(callback))
|
127 | throw new TypeError("Function expected: callback.");
|
128 | if (this._state === "cancellationRequested") {
|
129 | this._executeCallback(callback);
|
130 | return emptyRegistration;
|
131 | }
|
132 | if (this._state === "closed") {
|
133 | return emptyRegistration;
|
134 | }
|
135 | if (this._registrations === undefined) {
|
136 | this._registrations = new list_1.LinkedList();
|
137 | }
|
138 | function unregister() {
|
139 | if (this._cancellationSource === undefined)
|
140 | return;
|
141 | if (this._cancellationSource._registrations) {
|
142 | this._cancellationSource._registrations.deleteNode(node);
|
143 | }
|
144 | this._cancellationSource = undefined;
|
145 | this._cancellationTarget = undefined;
|
146 | }
|
147 | const node = this._registrations.push({
|
148 | _cancellationSource: this,
|
149 | _cancellationTarget: callback,
|
150 | unregister,
|
151 | [disposable_1.Disposable.dispose]: unregister,
|
152 | });
|
153 | return node.value;
|
154 | }
|
155 | |
156 |
|
157 |
|
158 |
|
159 |
|
160 | _executeCallback(callback) {
|
161 | try {
|
162 | callback();
|
163 | }
|
164 | catch (e) {
|
165 |
|
166 | setTimeout(() => { throw e; }, 0);
|
167 | }
|
168 | }
|
169 | |
170 |
|
171 |
|
172 | _unlink() {
|
173 | const linkingRegistrations = this._linkingRegistrations;
|
174 | this._linkingRegistrations = undefined;
|
175 | if (linkingRegistrations !== undefined) {
|
176 | for (const linkingRegistration of linkingRegistrations) {
|
177 | linkingRegistration.unregister();
|
178 | }
|
179 | }
|
180 | }
|
181 |
|
182 | [cancelable_1.Cancelable.cancelSignal]() { return this.token[cancelable_1.Cancelable.cancelSignal](); }
|
183 |
|
184 |
|
185 | [cancelable_1.CancelableSource.cancel]() { this.cancel(); }
|
186 | }
|
187 | exports.CancellationTokenSource = CancellationTokenSource;
|
188 |
|
189 | const closedSource = new CancellationTokenSource();
|
190 | closedSource.close();
|
191 |
|
192 | const canceledSource = new CancellationTokenSource();
|
193 | canceledSource.cancel();
|
194 | const weakCancelableToToken = typeof WeakMap === "function" ? new WeakMap() : undefined;
|
195 | const weakTokenToCancelable = typeof WeakMap === "function" ? new WeakMap() : undefined;
|
196 |
|
197 |
|
198 |
|
199 | class CancellationToken {
|
200 | constructor(source) {
|
201 | if (utils_1.isMissing(source)) {
|
202 | this._source = closedSource;
|
203 | }
|
204 | else if (utils_1.isBoolean(source)) {
|
205 | this._source = source ? canceledSource : closedSource;
|
206 | }
|
207 | else {
|
208 | if (!utils_1.isInstance(source, CancellationTokenSource))
|
209 | throw new TypeError("CancellationTokenSource expected: source.");
|
210 | this._source = source;
|
211 | }
|
212 | Object.freeze(this);
|
213 | }
|
214 | |
215 |
|
216 |
|
217 | get cancellationRequested() {
|
218 | return this._source._cancellationRequested;
|
219 | }
|
220 | |
221 |
|
222 |
|
223 | get canBeCanceled() {
|
224 | return this._source._canBeCanceled;
|
225 | }
|
226 | |
227 |
|
228 |
|
229 | static from(cancelable) {
|
230 | if (cancelable instanceof CancellationToken) {
|
231 | return cancelable;
|
232 | }
|
233 | if (cancelable_1.Cancelable.hasInstance(cancelable)) {
|
234 | const signal = cancelable[cancelable_1.Cancelable.cancelSignal]();
|
235 | if (signal.signaled)
|
236 | return CancellationToken.canceled;
|
237 | let token = weakCancelableToToken && weakCancelableToToken.get(cancelable);
|
238 | if (!token) {
|
239 | const source = new CancellationTokenSource();
|
240 | signal.subscribe(() => source.cancel());
|
241 | token = source.token;
|
242 | if (weakCancelableToToken)
|
243 | weakCancelableToToken.set(cancelable, token);
|
244 | }
|
245 | return token;
|
246 | }
|
247 | if (isVSCodeCancellationTokenLike(cancelable)) {
|
248 | if (cancelable.isCancellationRequested)
|
249 | return CancellationToken.canceled;
|
250 | const source = new CancellationTokenSource();
|
251 | cancelable.onCancellationRequested(() => source.cancel());
|
252 | return source.token;
|
253 | }
|
254 | if (isAbortSignalLike(cancelable)) {
|
255 | if (cancelable.aborted)
|
256 | return CancellationToken.canceled;
|
257 | const source = new CancellationTokenSource();
|
258 | cancelable.addEventListener("abort", () => source.cancel());
|
259 | return source.token;
|
260 | }
|
261 | throw new TypeError("Invalid token.");
|
262 | }
|
263 | |
264 |
|
265 |
|
266 |
|
267 | static race(tokens) {
|
268 | if (!utils_1.isIterable(tokens))
|
269 | throw new TypeError("Object not iterable: iterable.");
|
270 | const tokensArray = Array.isArray(tokens) ? tokens : [...tokens];
|
271 | return tokensArray.length > 0 ? new CancellationTokenSource(tokensArray).token : CancellationToken.none;
|
272 | }
|
273 | |
274 |
|
275 |
|
276 |
|
277 | static all(tokens) {
|
278 | if (!utils_1.isIterable(tokens))
|
279 | throw new TypeError("Object not iterable: iterable.");
|
280 | const tokensArray = Array.isArray(tokens) ? tokens : [...tokens];
|
281 | return tokensArray.length > 0 ? new CancellationTokenCountdown(tokensArray).token : CancellationToken.none;
|
282 | }
|
283 | |
284 |
|
285 |
|
286 | throwIfCancellationRequested() {
|
287 | if (this.cancellationRequested) {
|
288 | throw new CancelError();
|
289 | }
|
290 | }
|
291 | |
292 |
|
293 |
|
294 |
|
295 |
|
296 | register(callback) {
|
297 | return this._source._register(callback);
|
298 | }
|
299 |
|
300 | [cancelable_1.Cancelable.cancelSignal]() {
|
301 | let signal = weakTokenToCancelable === null || weakTokenToCancelable === void 0 ? void 0 : weakTokenToCancelable.get(this);
|
302 | if (!signal) {
|
303 | const token = this;
|
304 | signal = {
|
305 | get signaled() { return token.cancellationRequested; },
|
306 | subscribe(onCancellationRequested) {
|
307 | const registration = token.register(onCancellationRequested);
|
308 | return {
|
309 | unsubscribe() { registration.unregister(); },
|
310 | [disposable_1.Disposable.dispose]() { this.unsubscribe(); }
|
311 | };
|
312 | },
|
313 | [cancelable_1.Cancelable.cancelSignal]() {
|
314 | return this;
|
315 | }
|
316 | };
|
317 | weakTokenToCancelable === null || weakTokenToCancelable === void 0 ? void 0 : weakTokenToCancelable.set(this, signal);
|
318 | }
|
319 | return signal;
|
320 | }
|
321 | }
|
322 | exports.CancellationToken = CancellationToken;
|
323 |
|
324 |
|
325 |
|
326 | CancellationToken.none = new CancellationToken( false);
|
327 |
|
328 |
|
329 |
|
330 | CancellationToken.canceled = new CancellationToken( true);
|
331 |
|
332 |
|
333 |
|
334 | class CancelError extends Error {
|
335 | constructor(message) {
|
336 | super(message || "Operation was canceled");
|
337 | }
|
338 | }
|
339 | exports.CancelError = CancelError;
|
340 | CancelError.prototype.name = "CancelError";
|
341 | const emptyRegistration = Object.create({ unregister() { } });
|
342 | function isVSCodeCancellationTokenLike(token) {
|
343 | return typeof token === "object"
|
344 | && token !== null
|
345 | && utils_1.isBoolean(token.isCancellationRequested)
|
346 | && utils_1.isFunction(token.onCancellationRequested);
|
347 | }
|
348 | function isAbortSignalLike(token) {
|
349 | return typeof token === "object"
|
350 | && token !== null
|
351 | && utils_1.isBoolean(token.aborted)
|
352 | && utils_1.isFunction(token.addEventListener);
|
353 | }
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 | class CancellationTokenCountdown {
|
360 | constructor(iterable) {
|
361 | this._addedCount = 0;
|
362 | this._signaledCount = 0;
|
363 | this._canBeSignaled = false;
|
364 | this._source = new CancellationTokenSource();
|
365 | this._registrations = [];
|
366 | if (!utils_1.isIterable(iterable, true))
|
367 | throw new TypeError("Object not iterable: iterable.");
|
368 | if (iterable) {
|
369 | for (const token of iterable) {
|
370 | this.add(token);
|
371 | }
|
372 | }
|
373 | this._canBeSignaled = true;
|
374 | this._checkSignalState();
|
375 | }
|
376 | |
377 |
|
378 |
|
379 | get addedCount() { return this._addedCount; }
|
380 | |
381 |
|
382 |
|
383 | get remainingCount() { return this._addedCount - this._signaledCount; }
|
384 | |
385 |
|
386 |
|
387 | get token() { return this._source.token; }
|
388 | |
389 |
|
390 |
|
391 | add(token) {
|
392 | if (!cancelable_1.Cancelable.hasInstance(token))
|
393 | throw new TypeError("CancellationToken or Cancelable expected.");
|
394 | const ct = CancellationToken.from(token);
|
395 | if (this._source._currentState !== "open")
|
396 | return this;
|
397 | if (ct.cancellationRequested) {
|
398 | this._addedCount++;
|
399 | this._signaledCount++;
|
400 | this._checkSignalState();
|
401 | }
|
402 | else if (ct.canBeCanceled) {
|
403 | this._addedCount++;
|
404 | this._registrations.push(ct.register(() => {
|
405 | this._signaledCount++;
|
406 | this._checkSignalState();
|
407 | }));
|
408 | }
|
409 | return this;
|
410 | }
|
411 | _checkSignalState() {
|
412 | if (!this._canBeSignaled || this._signaledCount < this._addedCount)
|
413 | return;
|
414 | this._canBeSignaled = false;
|
415 | if (this._addedCount > 0) {
|
416 | try {
|
417 | for (const registration of this._registrations) {
|
418 | registration.unregister();
|
419 | }
|
420 | }
|
421 | finally {
|
422 | this._registrations.length = 0;
|
423 | this._source.cancel();
|
424 | }
|
425 | }
|
426 | }
|
427 | }
|
428 | exports.CancellationTokenCountdown = CancellationTokenCountdown;
|