@percy/core 1.0.0-beta.8 → 1.0.1

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,103 +1,152 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
1
+ import { generatePromise, waitFor } from './utils.js';
2
+ export class Queue {
3
+ running = true;
4
+ closed = false;
5
+ #queued = new Map();
6
+ #pending = new Map();
7
+
8
+ constructor(concurrency = 10) {
9
+ this.concurrency = concurrency;
10
+ }
7
11
 
8
- var _idle = _interopRequireDefault(require("./utils/idle"));
12
+ push(id, callback, 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
+ callback,
19
+ priority
20
+ };
21
+ task.promise = new Promise((resolve, reject) => {
22
+ Object.assign(task, {
23
+ resolve,
24
+ reject
25
+ });
26
+ this.#queued.set(id, task);
9
27
 
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
28
+ this._dequeue();
29
+ });
30
+ return task.promise;
31
+ }
11
32
 
12
- function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to set private field on non-instance"); } 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; } return value; }
33
+ cancel(id) {
34
+ var _this$pending$get, _this$pending$get$can;
13
35
 
14
- function _classPrivateFieldGet(receiver, privateMap) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to get private field on non-instance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
36
+ (_this$pending$get = this.#pending.get(id)) === null || _this$pending$get === void 0 ? void 0 : (_this$pending$get$can = _this$pending$get.cancel) === null || _this$pending$get$can === void 0 ? void 0 : _this$pending$get$can.call(_this$pending$get);
37
+ this.#pending.delete(id);
38
+ this.#queued.delete(id);
39
+ }
15
40
 
16
- var _queue = new WeakMap();
41
+ has(id) {
42
+ return this.#queued.has(id) || this.#pending.has(id);
43
+ }
17
44
 
18
- var _pending = new WeakMap();
45
+ clear() {
46
+ this.#queued.clear();
47
+ return this.size;
48
+ }
19
49
 
20
- // Concurrent task-based queue for handling snapshots and asset discovery.
21
- class Queue {
22
- // Defaults to inifinite concurrency
23
- constructor(concurrency = Infinity) {
24
- _queue.set(this, {
25
- writable: true,
26
- value: []
27
- });
50
+ get size() {
51
+ return this.#queued.size + this.#pending.size;
52
+ }
28
53
 
29
- _pending.set(this, {
30
- writable: true,
31
- value: 0
32
- });
54
+ run() {
55
+ this.running = true;
33
56
 
34
- this.concurrency = concurrency;
35
- } // Pushing a new task to the queue will attempt to run it unless the
36
- // concurrency limit has been reached. The returned promise will resolve or
37
- // reject when the task has succeeded or thrown an error.
57
+ while (this.running && this.#queued.size && this.#pending.size < this.concurrency) this._dequeue();
38
58
 
59
+ return this;
60
+ }
39
61
 
40
- push(task) {
41
- return new Promise((resolve, reject) => {
42
- _classPrivateFieldGet(this, _queue).push({
43
- task,
44
- resolve,
45
- reject
46
- });
62
+ stop() {
63
+ this.running = false;
64
+ return this;
65
+ }
47
66
 
48
- this._dequeue();
49
- });
50
- } // Returns the amount of queued and pending tasks.
67
+ open() {
68
+ this.closed = false;
69
+ return this;
70
+ }
51
71
 
72
+ close(abort) {
73
+ if (abort) this.stop().clear();
74
+ this.closed = true;
75
+ return this;
76
+ }
52
77
 
53
- get length() {
54
- return _classPrivateFieldGet(this, _queue).length + _classPrivateFieldGet(this, _pending);
55
- } // Resolves when there are no more queued or pending tasks.
78
+ idle(callback) {
79
+ return waitFor(() => {
80
+ callback === null || callback === void 0 ? void 0 : callback(this.#pending.size);
81
+ return !this.#pending.size;
82
+ }, {
83
+ idle: 10
84
+ });
85
+ }
56
86
 
87
+ empty(callback) {
88
+ return waitFor(() => {
89
+ callback === null || callback === void 0 ? void 0 : callback(this.size);
90
+ return !this.size;
91
+ }, {
92
+ idle: 10
93
+ });
94
+ }
57
95
 
58
- idle() {
59
- return (0, _idle.default)(() => this.length);
60
- } // Clears the active queue. Tasks that were queued will not be executed and
61
- // tasks that are pending (have already executed) will be allowed to finish.
96
+ flush(callback) {
97
+ let stopped = !this.running;
98
+ this.run().push('@@/flush', () => {
99
+ if (stopped) this.stop();
100
+ });
101
+ return this.idle(pend => {
102
+ let left = [...this.#queued.keys()].indexOf('@@/flush');
103
+ if (!~left && !this.#pending.has('@@/flush')) left = 0;
104
+ callback === null || callback === void 0 ? void 0 : callback(pend + left);
105
+ }).canceled(() => {
106
+ if (stopped) this.stop();
107
+ this.cancel('@@/flush');
108
+ });
109
+ }
62
110
 
111
+ next() {
112
+ let next;
63
113
 
64
- clear() {
65
- _classPrivateFieldSet(this, _queue, []);
114
+ for (let [id, task] of this.#queued) {
115
+ if (!next || task.priority != null && next.priority == null || task.priority < next.priority) next = task;
116
+ if (id === '@@/flush') break;
117
+ }
66
118
 
67
- return this.length;
68
- } // Begins processing the queue by running the oldest task first. Pending tasks
69
- // are tracked and no tasks will run unless there are less pending than the
70
- // concurrency limit. More tasks are dequeued when the current task
71
- // finishes. Resolves when the current task finishes although this method
72
- // should never be awaited on so multiple tasks can run concurrently.
119
+ return next;
120
+ }
73
121
 
122
+ _dequeue() {
123
+ if (!this.running) return;
124
+ if (this.#pending.size >= this.concurrency) return;
125
+ let task = this.next();
126
+ if (!task) return;
127
+ this.#queued.delete(task.id);
128
+ this.#pending.set(task.id, task);
74
129
 
75
- async _dequeue() {
76
- var _this$pending;
130
+ let done = callback => arg => {
131
+ var _task$cancel;
77
132
 
78
- if (_classPrivateFieldGet(this, _pending) >= this.concurrency) return;
133
+ if (!((_task$cancel = task.cancel) !== null && _task$cancel !== void 0 && _task$cancel.triggered)) {
134
+ this.#pending.delete(task.id);
135
+ }
79
136
 
80
- let item = _classPrivateFieldGet(this, _queue).shift();
137
+ callback(arg);
81
138
 
82
- if (!item) return;
83
- _classPrivateFieldSet(this, _pending, (_this$pending = +_classPrivateFieldGet(this, _pending)) + 1), _this$pending;
139
+ this._dequeue();
140
+ };
84
141
 
85
142
  try {
86
- var _this$pending2;
87
-
88
- let value = await item.task();
89
- _classPrivateFieldSet(this, _pending, (_this$pending2 = +_classPrivateFieldGet(this, _pending)) - 1), _this$pending2;
90
- item.resolve(value);
91
- } catch (error) {
92
- var _this$pending3;
93
-
94
- _classPrivateFieldSet(this, _pending, (_this$pending3 = +_classPrivateFieldGet(this, _pending)) - 1), _this$pending3;
95
- item.reject(error);
96
- } finally {
97
- this._dequeue();
143
+ let gen = generatePromise(task.callback);
144
+ task.cancel = gen.cancel;
145
+ return gen.then(done(task.resolve), done(task.reject));
146
+ } catch (err) {
147
+ done(task.reject)(err);
98
148
  }
99
149
  }
100
150
 
101
151
  }
102
-
103
- exports.default = Queue;
152
+ export default Queue;