@percy/core 1.10.4 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/queue.js CHANGED
@@ -1,142 +1,378 @@
1
- import { yieldFor, generatePromise, AbortController } from './utils.js';
2
- export class Queue {
3
- running = true;
4
- closed = false;
5
- #queued = new Map();
6
- #pending = new Map();
1
+ function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
7
2
 
8
- constructor(concurrency = 10) {
9
- this.concurrency = concurrency;
10
- }
3
+ function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
4
+
5
+ function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
6
+
7
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
8
+
9
+ function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
10
+
11
+ function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
12
+
13
+ function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
14
+
15
+ function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
16
+
17
+ function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
18
+
19
+ function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
11
20
 
12
- push(id, generator, priority) {
13
- /* istanbul ignore next: race condition paranoia */
14
- if (this.closed && !id.startsWith('@@/')) return;
15
- this.cancel(id);
16
- let task = {
17
- id,
18
- generator,
19
- priority
20
- };
21
- task.promise = new Promise((resolve, reject) => {
22
- Object.assign(task, {
21
+ import { yieldFor, generatePromise, AbortController } from './utils.js'; // Assigns a deffered promise and resolve & reject functions to an object
22
+
23
+ function deferred(obj) {
24
+ return Object.assign(obj, {
25
+ deferred: new Promise((resolve, reject) => {
26
+ Object.assign(obj, {
23
27
  resolve,
24
28
  reject
25
29
  });
26
- this.#queued.set(id, task);
30
+ })
31
+ });
32
+ } // Returns the position of a needle within a haystack, or undefined if not found
27
33
 
28
- this._dequeue();
29
- });
30
- return task.promise;
34
+
35
+ function positionOf(haystack, needle, i = 1) {
36
+ for (let item of haystack) {
37
+ if (item !== needle) i++;else return i;
31
38
  }
39
+ } // Thrown when attempting to push to a closed queue
32
40
 
33
- cancel(id) {
34
- var _this$pending$get, _this$pending$get$ctr;
35
41
 
36
- (_this$pending$get = this.#pending.get(id)) === null || _this$pending$get === void 0 ? void 0 : (_this$pending$get$ctr = _this$pending$get.ctrl) === null || _this$pending$get$ctr === void 0 ? void 0 : _this$pending$get$ctr.abort();
37
- this.#pending.delete(id);
38
- this.#queued.delete(id);
39
- }
42
+ class QueueClosedError extends Error {
43
+ name = this.constructor.name;
44
+ } // A queue instance keeps a list of arbitrary items to process concurrently,
45
+ // configured and controlled by various methods
40
46
 
41
- has(id) {
42
- return this.#queued.has(id) || this.#pending.has(id);
43
- }
44
47
 
45
- clear() {
46
- this.#queued.clear();
47
- return this.size;
48
+ var _handlers = /*#__PURE__*/new WeakMap();
49
+
50
+ var _queued = /*#__PURE__*/new WeakMap();
51
+
52
+ var _pending = /*#__PURE__*/new WeakMap();
53
+
54
+ var _dequeue = /*#__PURE__*/new WeakSet();
55
+
56
+ var _find = /*#__PURE__*/new WeakSet();
57
+
58
+ var _start = /*#__PURE__*/new WeakMap();
59
+
60
+ var _end = /*#__PURE__*/new WeakMap();
61
+
62
+ var _process = /*#__PURE__*/new WeakSet();
63
+
64
+ var _until = /*#__PURE__*/new WeakSet();
65
+
66
+ export class Queue {
67
+ constructor() {
68
+ _classPrivateMethodInitSpec(this, _until);
69
+
70
+ _classPrivateMethodInitSpec(this, _process);
71
+
72
+ _classPrivateMethodInitSpec(this, _find);
73
+
74
+ _classPrivateMethodInitSpec(this, _dequeue);
75
+
76
+ _defineProperty(this, "concurrency", 10);
77
+
78
+ _classPrivateFieldInitSpec(this, _handlers, {
79
+ writable: true,
80
+ value: {}
81
+ });
82
+
83
+ _classPrivateFieldInitSpec(this, _queued, {
84
+ writable: true,
85
+ value: new Set()
86
+ });
87
+
88
+ _classPrivateFieldInitSpec(this, _pending, {
89
+ writable: true,
90
+ value: new Set()
91
+ });
92
+
93
+ _classPrivateFieldInitSpec(this, _start, {
94
+ writable: true,
95
+ value: null
96
+ });
97
+
98
+ _classPrivateFieldInitSpec(this, _end, {
99
+ writable: true,
100
+ value: null
101
+ });
102
+
103
+ _defineProperty(this, "readyState", 0);
48
104
  }
49
105
 
106
+ // Configure queue properties
107
+ set({
108
+ concurrency
109
+ }) {
110
+ if (concurrency) this.concurrency = concurrency;
111
+ return this;
112
+ } // Configure queue handlers
113
+
114
+
115
+ handle(event, handler) {
116
+ _classPrivateFieldGet(this, _handlers)[event] = handler;
117
+ return this;
118
+ } // internal queues
119
+
120
+
121
+ // Queue size is total queued and pending items
50
122
  get size() {
51
- return this.#queued.size + this.#pending.size;
52
- }
123
+ return _classPrivateFieldGet(this, _queued).size + _classPrivateFieldGet(this, _pending).size;
124
+ } // Pushes an item into the queue, additional args are passed to any configured task handler.
125
+
126
+
127
+ push(item, ...args) {
128
+ let task = deferred({
129
+ item
130
+ }); // attach any configured error handler
131
+
132
+ task.deferred = task.deferred.catch(e => {
133
+ if (!_classPrivateFieldGet(this, _handlers).error) throw e;
134
+ return _classPrivateFieldGet(this, _handlers).error(item, e);
135
+ }); // when closed, reject with a queue closed error
136
+
137
+ if (this.readyState > 2) {
138
+ task.reject(new QueueClosedError());
139
+ return task.deferred;
140
+ } // call or set up other handlers
141
+
142
+
143
+ let exists = this.cancel(item);
144
+ task.item = item = _classPrivateFieldGet(this, _handlers).push ? _classPrivateFieldGet(this, _handlers).push(item, exists) : item;
145
+
146
+ task.handler = () => _classPrivateFieldGet(this, _handlers).task ? _classPrivateFieldGet(this, _handlers).task(item, ...args) : item;
147
+
148
+ task.ctrl = new AbortController(); // queue this task & maybe dequeue the next task
149
+
150
+ _classPrivateFieldGet(this, _queued).add(task);
151
+
152
+ _classPrivateMethodGet(this, _dequeue, _dequeue2).call(this); // return the deferred task promise
153
+
154
+
155
+ return task.deferred;
156
+ } // Maybe processes the next queued item task.
157
+
158
+
159
+ // Cancels and aborts a specific item task.
160
+ cancel(item) {
161
+ let task = _classPrivateMethodGet(this, _find, _find2).call(this, item);
162
+
163
+ task === null || task === void 0 ? void 0 : task.ctrl.abort();
164
+
165
+ let queued = _classPrivateFieldGet(this, _queued).delete(task);
166
+
167
+ let pending = _classPrivateFieldGet(this, _pending).delete(task); // reject queued tasks that are not pending
168
+
169
+
170
+ if (task && queued && !pending) {
171
+ task.reject(task.ctrl.signal.reason);
172
+ } // return the cancelled item
173
+
174
+
175
+ return task === null || task === void 0 ? void 0 : task.item;
176
+ } // Returns an item task matching the provided subject.
177
+
178
+
179
+ // Initialize a starting task or return an existing one.
180
+ start() {
181
+ var _classPrivateFieldGet2;
182
+
183
+ _classPrivateFieldGet(this, _start) ?? _classPrivateFieldSet(this, _start, deferred({
184
+ readyState: 1
185
+ }));
186
+ (_classPrivateFieldGet2 = _classPrivateFieldGet(this, _start)).handler ?? (_classPrivateFieldGet2.handler = _classPrivateFieldGet(this, _end) // wait for any ending task to complete first
187
+ ? () => _classPrivateFieldGet(this, _end).promise.then(_classPrivateFieldGet(this, _handlers).start) : _classPrivateFieldGet(this, _handlers).start);
188
+ return _classPrivateMethodGet(this, _process, _process2).call(this, _classPrivateFieldGet(this, _start)).deferred;
189
+ } // intialize an ending task or return an existing one
190
+
53
191
 
192
+ end() {
193
+ var _classPrivateFieldGet3;
194
+
195
+ _classPrivateFieldGet(this, _end) ?? _classPrivateFieldSet(this, _end, deferred({
196
+ readyState: 0
197
+ }));
198
+ (_classPrivateFieldGet3 = _classPrivateFieldGet(this, _end)).handler ?? (_classPrivateFieldGet3.handler = _classPrivateFieldGet(this, _start) // wait for any starting task to complete first
199
+ ? () => _classPrivateFieldGet(this, _start).promise.then(_classPrivateFieldGet(this, _handlers).end) : _classPrivateFieldGet(this, _handlers).end);
200
+ return _classPrivateMethodGet(this, _process, _process2).call(this, _classPrivateFieldGet(this, _end)).deferred;
201
+ } // represents various queue states such as ready, running, or closed
202
+
203
+
204
+ // run the queue, starting it if necessary, and start dequeuing tasks
54
205
  run() {
55
- this.running = true;
206
+ if (!_classPrivateFieldGet(this, _start)) this.start(); // when starting, state is updated afterwards
56
207
 
57
- while (this.running && this.#queued.size && this.#pending.size < this.concurrency) this._dequeue();
208
+ if (this.readyState === 0) _classPrivateFieldGet(this, _start).readyState = 2;
209
+ if (this.readyState === 1) this.readyState = 2;
210
+
211
+ while (_classPrivateMethodGet(this, _dequeue, _dequeue2).call(this)) _classPrivateMethodGet(this, _dequeue, _dequeue2).call(this);
58
212
 
59
213
  return this;
60
- }
214
+ } // stop a running queue
215
+
61
216
 
62
217
  stop() {
63
- this.running = false;
218
+ if (this.readyState === 2) this.readyState = 1;
64
219
  return this;
65
- }
220
+ } // close a running queue, optionally aborting it
66
221
 
67
- open() {
68
- this.closed = false;
69
- return this;
70
- }
71
222
 
72
223
  close(abort) {
73
- if (abort) this.stop().clear();
74
- this.closed = true;
224
+ var _classPrivateFieldGet4;
225
+
226
+ // when starting, state is updated afterwards
227
+ if ((_classPrivateFieldGet4 = _classPrivateFieldGet(this, _start)) !== null && _classPrivateFieldGet4 !== void 0 && _classPrivateFieldGet4.pending) _classPrivateFieldGet(this, _start).readyState = 3;
228
+ if (this.readyState < 3) this.readyState = 3;
229
+ if (abort) this.clear();
75
230
  return this;
76
- }
231
+ } // clear and abort any queued tasks
232
+
233
+
234
+ clear() {
235
+ let tasks = [..._classPrivateFieldGet(this, _queued)];
236
+
237
+ _classPrivateFieldGet(this, _queued).clear();
238
+
239
+ for (let task of tasks) {
240
+ task.ctrl.abort();
241
+ task.reject(task.ctrl.signal.reason);
242
+ }
243
+ } // process a single item task when started
244
+
77
245
 
246
+ process(item) {
247
+ var _classPrivateFieldGet5;
248
+
249
+ let task = _classPrivateMethodGet(this, _find, _find2).call(this, item);
250
+
251
+ if (task && !_classPrivateFieldGet(this, _start)) this.start();
252
+ (_classPrivateFieldGet5 = _classPrivateFieldGet(this, _start)) === null || _classPrivateFieldGet5 === void 0 ? void 0 : _classPrivateFieldGet5.promise.then(() => _classPrivateMethodGet(this, _process, _process2).call(this, task));
253
+ return task === null || task === void 0 ? void 0 : task.deferred;
254
+ } // processes tasks using a generator promise, allowing task handlers to be cancelable
255
+
256
+
257
+ // returns a generator that yeilds until started and no longer pending, calling the
258
+ // callback every 10ms during checks with the current number of pending tasks
78
259
  idle(callback) {
79
260
  return yieldFor(() => {
80
- callback === null || callback === void 0 ? void 0 : callback(this.#pending.size);
81
- return !this.#pending.size;
82
- }, {
83
- idle: 10
84
- });
85
- }
261
+ var _classPrivateFieldGet6;
86
262
 
87
- empty(callback) {
88
- return yieldFor(() => {
89
- callback === null || callback === void 0 ? void 0 : callback(this.size);
90
- return !this.size;
263
+ callback === null || callback === void 0 ? void 0 : callback(_classPrivateFieldGet(this, _pending).size);
264
+ let starting = ((_classPrivateFieldGet6 = _classPrivateFieldGet(this, _start)) === null || _classPrivateFieldGet6 === void 0 ? void 0 : _classPrivateFieldGet6.pending) === true;
265
+ return !starting && !_classPrivateFieldGet(this, _pending).size;
91
266
  }, {
92
267
  idle: 10
93
268
  });
94
- }
269
+ } // process items up to the latest queued item, starting the queue if necessary;
270
+ // returns a generator that yields until the flushed item has finished processing
95
271
 
96
- async *flush(callback) {
97
- let stopped = !this.running;
98
- this.run().push('@@/flush', () => {
99
- if (stopped) this.stop();
100
- });
101
272
 
102
- try {
103
- yield* this.idle(pend => {
104
- let left = [...this.#queued.keys()].indexOf('@@/flush');
105
- if (!~left && !this.#pending.has('@@/flush')) left = 0;
106
- callback === null || callback === void 0 ? void 0 : callback(pend + left);
107
- });
108
- } catch (error) {
109
- if (stopped) this.stop();
110
- this.cancel('@@/flush');
111
- throw error;
112
- }
113
- }
273
+ flush(callback) {
274
+ let interrupt = // check for existing interrupts
275
+ [..._classPrivateFieldGet(this, _pending)].find(t => t.stop) ?? [..._classPrivateFieldGet(this, _queued)].find(t => t.stop); // get the latest queued or pending task to track
114
276
 
115
- next() {
116
- let next;
277
+ let flush = [..._classPrivateFieldGet(this, _queued)].pop() ?? [..._classPrivateFieldGet(this, _pending)].pop(); // determine if the queue should be stopped after flushing
117
278
 
118
- for (let [id, task] of this.#queued) {
119
- if (!next || task.priority != null && next.priority == null || task.priority < next.priority) next = task;
120
- if (id === '@@/flush') break;
121
- }
279
+ if (flush) flush.stop = (interrupt === null || interrupt === void 0 ? void 0 : interrupt.stop) ?? this.readyState < 2; // remove the old interrupt to avoid stopping early
122
280
 
123
- return next;
124
- }
281
+ if (interrupt) delete interrupt.stop; // start the queue if not started
282
+
283
+ if (!_classPrivateFieldGet(this, _start)) this.start(); // run the queue if stopped
284
+
285
+ if (flush !== null && flush !== void 0 && flush.stop) this.run(); // will yield with the callback until done flushing
125
286
 
126
- _dequeue() {
127
- if (!this.running) return;
128
- if (this.#pending.size >= this.concurrency) return;
129
- let task = this.next();
130
- if (!task) return;
131
- this.#queued.delete(task.id);
132
- this.#pending.set(task.id, task);
133
- let ctrl = task.ctrl = new AbortController();
134
- return generatePromise(task.generator, ctrl.signal, (err, val) => {
135
- if (!ctrl.signal.aborted) this.#pending.delete(task.id);
136
- task[err ? 'reject' : 'resolve'](err ?? val);
137
- return this._dequeue();
287
+ return _classPrivateMethodGet(this, _until, _until2).call(this, flush, callback);
288
+ } // Repeatedly yields, calling the callback with the position of the task within the queue
289
+
290
+
291
+ }
292
+
293
+ function _dequeue2() {
294
+ if (!_classPrivateFieldGet(this, _queued).size || this.readyState < 2) return;
295
+ if (_classPrivateFieldGet(this, _pending).size >= this.concurrency) return;
296
+
297
+ let [task] = _classPrivateFieldGet(this, _queued);
298
+
299
+ return _classPrivateMethodGet(this, _process, _process2).call(this, task);
300
+ }
301
+
302
+ function _find2(subject) {
303
+ let find = _classPrivateFieldGet(this, _handlers).find // use any configured find handler to match items
304
+ ? ({
305
+ item
306
+ }) => _classPrivateFieldGet(this, _handlers).find(subject, item) : ({
307
+ item
308
+ }) => subject === item;
309
+ return (// look at queued then pending items
310
+ [..._classPrivateFieldGet(this, _queued)].find(find) ?? [..._classPrivateFieldGet(this, _pending)].find(find)
311
+ );
312
+ }
313
+
314
+ function _process2(task) {
315
+ var _task$ctrl;
316
+
317
+ if (!task || task.promise) return task;
318
+
319
+ let queued = _classPrivateFieldGet(this, _queued).has(task); // remove queued tasks from the queue
320
+
321
+
322
+ if (queued) _classPrivateFieldGet(this, _queued).delete(task); // clear queued tasks when ending
323
+
324
+ if (task === _classPrivateFieldGet(this, _end)) this.clear(); // add queued tasks to pending queue
325
+
326
+ if (queued) _classPrivateFieldGet(this, _pending).add(task); // stop the queue when necessary
327
+
328
+ if (task.stop) this.stop(); // mark task as pending
329
+
330
+ task.pending = true; // handle the task using a generator promise
331
+
332
+ task.promise = generatePromise(task.handler, (_task$ctrl = task.ctrl) === null || _task$ctrl === void 0 ? void 0 : _task$ctrl.signal, (err, val) => {
333
+ // clean up pending tasks that have not been aborted
334
+ if (queued && !task.ctrl.signal.aborted) _classPrivateFieldGet(this, _pending).delete(task); // update queue state when necessary
335
+
336
+ if (task.readyState != null) this.readyState = task.readyState; // clean up internal tasks after ending
337
+
338
+ if (!this.readyState) _classPrivateFieldSet(this, _start, _classPrivateFieldSet(this, _end, null)); // resolve or reject the deferred task promise
339
+
340
+ task[err ? 'reject' : 'resolve'](err ?? val); // keep dequeuing when running
341
+
342
+ if (this.readyState === 2) this.run(); // mark pending task done
343
+
344
+ task.pending = false;
345
+ });
346
+ return task;
347
+ }
348
+
349
+ async function* _until2(task, callback) {
350
+ try {
351
+ yield* yieldFor(() => {
352
+ var _classPrivateFieldGet7;
353
+
354
+ if ((_classPrivateFieldGet7 = _classPrivateFieldGet(this, _start)) !== null && _classPrivateFieldGet7 !== void 0 && _classPrivateFieldGet7.pending) return false;
355
+
356
+ let queued,
357
+ pending = _classPrivateFieldGet(this, _pending).size; // calculate the position within queued when not pending
358
+
359
+
360
+ if (task && task.pending == null) queued = positionOf(_classPrivateFieldGet(this, _queued), task); // calculate the position within pending when not stopping
361
+
362
+ if (!(task !== null && task !== void 0 && task.stop) && (task === null || task === void 0 ? void 0 : task.pending) != null) pending = positionOf(_classPrivateFieldGet(this, _pending), task); // call the callback and return true when not queued or pending
363
+
364
+ let position = (queued ?? 0) + (pending ?? 0);
365
+ callback === null || callback === void 0 ? void 0 : callback(position);
366
+ return !position;
367
+ }, {
368
+ idle: 10
138
369
  });
370
+ } catch (err) {
371
+ // reset flushed tasks on error
372
+ if (task.stop) this.stop();
373
+ delete task.stop;
374
+ throw err;
139
375
  }
140
-
141
376
  }
377
+
142
378
  export default Queue;
package/dist/session.js CHANGED
@@ -23,7 +23,8 @@ export class Session extends EventEmitter {
23
23
  }
24
24
 
25
25
  async close() {
26
- if (!this.browser) return;
26
+ if (!this.browser || this.closing) return;
27
+ this.closing = true;
27
28
  await this.browser.send('Target.closeTarget', {
28
29
  targetId: this.targetId
29
30
  }).catch(this._handleClosedError);