1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.generateRequestId = generateRequestId;
|
7 | exports.RequestRunner = exports.default = exports.RequestGraph = void 0;
|
8 |
|
9 | var _assert = _interopRequireDefault(require("assert"));
|
10 |
|
11 | var _nullthrows = _interopRequireDefault(require("nullthrows"));
|
12 |
|
13 | var _utils = require("@parcel/utils");
|
14 |
|
15 | var _Graph = _interopRequireDefault(require("./Graph"));
|
16 |
|
17 | var _utils2 = require("./utils");
|
18 |
|
19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
20 |
|
21 | function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
22 |
|
23 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
24 |
|
25 | 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; }
|
26 |
|
27 | const nodeFromFilePath = filePath => ({
|
28 | id: filePath,
|
29 | type: 'file',
|
30 | value: {
|
31 | filePath
|
32 | }
|
33 | });
|
34 |
|
35 | const nodeFromGlob = glob => ({
|
36 | id: glob,
|
37 | type: 'glob',
|
38 | value: glob
|
39 | });
|
40 |
|
41 | const nodeFromRequest = request => ({
|
42 | id: request.id,
|
43 | type: 'request',
|
44 | value: request
|
45 | });
|
46 |
|
47 | class RequestGraph extends _Graph.default {
|
48 | constructor(...args) {
|
49 | super(...args);
|
50 |
|
51 | _defineProperty(this, "invalidNodeIds", new Set());
|
52 |
|
53 | _defineProperty(this, "incompleteNodeIds", new Set());
|
54 |
|
55 | _defineProperty(this, "globNodeIds", new Set());
|
56 |
|
57 | _defineProperty(this, "unpredicatableNodeIds", new Set());
|
58 | }
|
59 |
|
60 |
|
61 | static deserialize(opts) {
|
62 | let deserialized = new RequestGraph(opts);
|
63 | deserialized.invalidNodeIds = opts.invalidNodeIds;
|
64 | deserialized.incompleteNodeIds = opts.incompleteNodeIds;
|
65 | deserialized.globNodeIds = opts.globNodeIds;
|
66 | deserialized.unpredicatableNodeIds = opts.unpredicatableNodeIds;
|
67 |
|
68 | return deserialized;
|
69 | }
|
70 |
|
71 |
|
72 | serialize() {
|
73 | return _objectSpread({}, super.serialize(), {
|
74 | invalidNodeIds: this.invalidNodeIds,
|
75 | incompleteNodeIds: this.incompleteNodeIds,
|
76 | globNodeIds: this.globNodeIds,
|
77 | unpredicatableNodeIds: this.unpredicatableNodeIds
|
78 | });
|
79 | }
|
80 |
|
81 | addNode(node) {
|
82 | if (!this.hasNode(node.id)) {
|
83 | if (node.type === 'glob') {
|
84 | this.globNodeIds.add(node.id);
|
85 | }
|
86 | }
|
87 |
|
88 | return super.addNode(node);
|
89 | }
|
90 |
|
91 | removeNode(node) {
|
92 | this.invalidNodeIds.delete(node.id);
|
93 | this.incompleteNodeIds.delete(node.id);
|
94 |
|
95 | if (node.type === 'glob') {
|
96 | this.globNodeIds.delete(node.id);
|
97 | }
|
98 |
|
99 | return super.removeNode(node);
|
100 | }
|
101 |
|
102 |
|
103 | addRequest(request) {
|
104 | let requestNode = nodeFromRequest(request);
|
105 |
|
106 | if (!this.hasNode(requestNode.id)) {
|
107 | this.addNode(requestNode);
|
108 | } else {
|
109 | requestNode = this.getNode(requestNode.id);
|
110 | }
|
111 |
|
112 | return requestNode;
|
113 | }
|
114 |
|
115 | getRequestNode(id) {
|
116 | let node = (0, _nullthrows.default)(this.getNode(id));
|
117 | (0, _assert.default)(node.type === 'request');
|
118 | return node;
|
119 | }
|
120 |
|
121 | completeRequest(request) {
|
122 | this.invalidNodeIds.delete(request.id);
|
123 | this.incompleteNodeIds.delete(request.id);
|
124 | }
|
125 |
|
126 | replaceSubrequests(requestId, subrequestNodes) {
|
127 | let requestNode = this.getRequestNode(requestId);
|
128 |
|
129 | if (!this.hasNode(requestId)) {
|
130 | this.addNode(requestNode);
|
131 | }
|
132 |
|
133 | for (let subrequestNode of subrequestNodes) {
|
134 | this.invalidNodeIds.delete(subrequestNode.id);
|
135 | }
|
136 |
|
137 | this.replaceNodesConnectedTo(requestNode, subrequestNodes, null, 'subrequest');
|
138 | }
|
139 |
|
140 | invalidateNode(node) {
|
141 | (0, _assert.default)(node.type === 'request');
|
142 |
|
143 | if (this.hasNode(node.id)) {
|
144 | this.invalidNodeIds.add(node.id);
|
145 | this.clearInvalidations(node);
|
146 | let parentNodes = this.getNodesConnectedTo(node, 'subrequest');
|
147 |
|
148 | for (let parentNode of parentNodes) {
|
149 | this.invalidateNode(parentNode);
|
150 | }
|
151 | }
|
152 | }
|
153 |
|
154 | invalidateUnpredictableNodes() {
|
155 | for (let nodeId of this.unpredicatableNodeIds) {
|
156 | let node = (0, _nullthrows.default)(this.getNode(nodeId));
|
157 | (0, _assert.default)(node.type !== 'file' && node.type !== 'glob');
|
158 | this.invalidateNode(node);
|
159 | }
|
160 | }
|
161 |
|
162 | invalidateOnFileUpdate(requestId, filePath) {
|
163 | let requestNode = this.getRequestNode(requestId);
|
164 | let fileNode = nodeFromFilePath(filePath);
|
165 |
|
166 | if (!this.hasNode(fileNode.id)) {
|
167 | this.addNode(fileNode);
|
168 | }
|
169 |
|
170 | if (!this.hasEdge(requestNode.id, fileNode.id, 'invalidated_by_update')) {
|
171 | this.addEdge(requestNode.id, fileNode.id, 'invalidated_by_update');
|
172 | }
|
173 | }
|
174 |
|
175 | invalidateOnFileDelete(requestId, filePath) {
|
176 | let requestNode = this.getRequestNode(requestId);
|
177 | let fileNode = nodeFromFilePath(filePath);
|
178 |
|
179 | if (!this.hasNode(fileNode.id)) {
|
180 | this.addNode(fileNode);
|
181 | }
|
182 |
|
183 | if (!this.hasEdge(requestNode.id, fileNode.id, 'invalidated_by_delete')) {
|
184 | this.addEdge(requestNode.id, fileNode.id, 'invalidated_by_delete');
|
185 | }
|
186 | }
|
187 |
|
188 | invalidateOnFileCreate(requestId, glob) {
|
189 | let requestNode = this.getRequestNode(requestId);
|
190 | let globNode = nodeFromGlob(glob);
|
191 |
|
192 | if (!this.hasNode(globNode.id)) {
|
193 | this.addNode(globNode);
|
194 | }
|
195 |
|
196 | if (!this.hasEdge(requestNode.id, globNode.id, 'invalidated_by_create')) {
|
197 | this.addEdge(requestNode.id, globNode.id, 'invalidated_by_create');
|
198 | }
|
199 | }
|
200 |
|
201 | invalidateOnStartup(requestId) {
|
202 | let requestNode = this.getRequestNode(requestId);
|
203 | this.unpredicatableNodeIds.add(requestNode.id);
|
204 | }
|
205 |
|
206 | clearInvalidations(node) {
|
207 | this.unpredicatableNodeIds.delete(node.id);
|
208 | this.replaceNodesConnectedTo(node, [], null, 'invalidated_by_update');
|
209 | this.replaceNodesConnectedTo(node, [], null, 'invalidated_by_delete');
|
210 | this.replaceNodesConnectedTo(node, [], null, 'invalidated_by_create');
|
211 | }
|
212 |
|
213 | respondToFSEvents(events) {
|
214 | let isInvalid = false;
|
215 |
|
216 | for (let {
|
217 | path,
|
218 | type
|
219 | } of events) {
|
220 | let node = this.getNode(path);
|
221 |
|
222 |
|
223 |
|
224 | if (node && (type === 'create' || type === 'update')) {
|
225 | for (let connectedNode of this.getNodesConnectedTo(node, 'invalidated_by_update')) {
|
226 | this.invalidateNode(connectedNode);
|
227 | isInvalid = true;
|
228 | }
|
229 | } else if (type === 'create') {
|
230 | for (let id of this.globNodeIds) {
|
231 | let globNode = this.getNode(id);
|
232 | (0, _assert.default)(globNode && globNode.type === 'glob');
|
233 |
|
234 | if ((0, _utils.isGlobMatch)(path, globNode.value)) {
|
235 | let connectedNodes = this.getNodesConnectedTo(globNode, 'invalidated_by_create');
|
236 |
|
237 | for (let connectedNode of connectedNodes) {
|
238 | this.invalidateNode(connectedNode);
|
239 | isInvalid = true;
|
240 | }
|
241 | }
|
242 | }
|
243 | } else if (node && type === 'delete') {
|
244 | for (let connectedNode of this.getNodesConnectedTo(node, 'invalidated_by_delete')) {
|
245 | this.invalidateNode(connectedNode);
|
246 | isInvalid = true;
|
247 | }
|
248 | }
|
249 | }
|
250 |
|
251 | return isInvalid;
|
252 | }
|
253 |
|
254 | }
|
255 |
|
256 | exports.RequestGraph = RequestGraph;
|
257 |
|
258 | class RequestTracker {
|
259 | constructor({
|
260 | graph
|
261 | }) {
|
262 | _defineProperty(this, "graph", void 0);
|
263 |
|
264 | this.graph = graph || new RequestGraph();
|
265 | }
|
266 |
|
267 | isTracked(id) {
|
268 | return this.graph.hasNode(id);
|
269 | }
|
270 |
|
271 | getRequest(id) {
|
272 | return (0, _nullthrows.default)(this.graph.getNode(id));
|
273 | }
|
274 |
|
275 | trackRequest(request) {
|
276 | if (this.isTracked(request.id)) {
|
277 | return;
|
278 | }
|
279 |
|
280 | this.graph.incompleteNodeIds.add(request.id);
|
281 | let node = nodeFromRequest(request);
|
282 | this.graph.addNode(node);
|
283 | }
|
284 |
|
285 | untrackRequest(id) {
|
286 | this.graph.removeById(id);
|
287 | }
|
288 |
|
289 | hasValidResult(id) {
|
290 | return !this.graph.invalidNodeIds.has(id) && !this.graph.incompleteNodeIds.has(id);
|
291 | }
|
292 |
|
293 | getRequestResult(id) {
|
294 | let node = (0, _nullthrows.default)(this.graph.getNode(id));
|
295 | (0, _assert.default)(node.type === 'request');
|
296 | return node.value.result;
|
297 | }
|
298 |
|
299 | completeRequest(id) {
|
300 | this.graph.invalidNodeIds.delete(id);
|
301 | this.graph.incompleteNodeIds.delete(id);
|
302 | }
|
303 |
|
304 | respondToFSEvents(events) {
|
305 | return this.graph.respondToFSEvents(events);
|
306 | }
|
307 |
|
308 | hasInvalidRequests() {
|
309 | return this.graph.invalidNodeIds.size > 0;
|
310 | }
|
311 |
|
312 | getInvalidRequests() {
|
313 | let invalidRequests = [];
|
314 |
|
315 | for (let id of this.graph.invalidNodeIds) {
|
316 | let node = (0, _nullthrows.default)(this.graph.getNode(id));
|
317 | (0, _assert.default)(node.type === 'request');
|
318 | invalidRequests.push(node.value);
|
319 | }
|
320 |
|
321 | return invalidRequests;
|
322 | }
|
323 |
|
324 | replaceSubrequests(requestId, subrequestNodes) {
|
325 | this.graph.replaceSubrequests(requestId, subrequestNodes);
|
326 | }
|
327 |
|
328 | }
|
329 |
|
330 | exports.default = RequestTracker;
|
331 |
|
332 | function generateRequestId(type, request) {
|
333 | return (0, _utils.md5FromObject)({
|
334 | type,
|
335 | request
|
336 | });
|
337 | }
|
338 |
|
339 | class RequestRunner {
|
340 | constructor({
|
341 | tracker
|
342 | }) {
|
343 | _defineProperty(this, "type", void 0);
|
344 |
|
345 | _defineProperty(this, "tracker", void 0);
|
346 |
|
347 | this.tracker = tracker;
|
348 | }
|
349 |
|
350 | async runRequest(requestDesc, {
|
351 | signal
|
352 | } = {}) {
|
353 | let id = this.generateRequestId(requestDesc);
|
354 | let request = {
|
355 | id,
|
356 | type: this.type,
|
357 | request: requestDesc
|
358 | };
|
359 | let api = this.createAPI(id);
|
360 | this.tracker.trackRequest(request);
|
361 | let result = this.tracker.hasValidResult(id) ?
|
362 | this.tracker.getRequestResult(id) : await this.run(requestDesc, api);
|
363 | (0, _utils2.assertSignalNotAborted)(signal);
|
364 |
|
365 | if (!this.tracker.isTracked(id)) {
|
366 | return;
|
367 | }
|
368 |
|
369 | await this.onComplete(requestDesc, result, api);
|
370 | this.tracker.completeRequest(id);
|
371 | return result;
|
372 | }
|
373 |
|
374 |
|
375 |
|
376 | run(request, api) {
|
377 | throw new Error(`RequestRunner for type ${this.type} did not implement run()`);
|
378 | }
|
379 |
|
380 |
|
381 |
|
382 | onComplete(request, result, api) {
|
383 | throw new Error(`RequestRunner for type ${this.type} did not implement onComplete()`);
|
384 | }
|
385 |
|
386 | generateRequestId(request) {
|
387 | return (0, _utils.md5FromObject)({
|
388 | type: this.type,
|
389 | request
|
390 | });
|
391 | }
|
392 |
|
393 | createAPI(requestId) {
|
394 | return {
|
395 | invalidateOnFileCreate: glob => this.tracker.graph.invalidateOnFileCreate(requestId, glob),
|
396 | invalidateOnFileDelete: filePath => this.tracker.graph.invalidateOnFileDelete(requestId, filePath),
|
397 | invalidateOnFileUpdate: filePath => this.tracker.graph.invalidateOnFileUpdate(requestId, filePath),
|
398 | invalidateOnStartup: () => this.tracker.graph.invalidateOnStartup(requestId),
|
399 | replaceSubrequests: subrequestNodes => this.tracker.graph.replaceSubrequests(requestId, subrequestNodes)
|
400 | };
|
401 | }
|
402 |
|
403 | }
|
404 |
|
405 | exports.RequestRunner = RequestRunner; |
\ | No newline at end of file |