UNPKG

11.6 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.generateRequestId = generateRequestId;
7exports.RequestRunner = exports.default = exports.RequestGraph = void 0;
8
9var _assert = _interopRequireDefault(require("assert"));
10
11var _nullthrows = _interopRequireDefault(require("nullthrows"));
12
13var _utils = require("@parcel/utils");
14
15var _Graph = _interopRequireDefault(require("./Graph"));
16
17var _utils2 = require("./utils");
18
19function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20
21function 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
23function _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
25function _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
27const nodeFromFilePath = filePath => ({
28 id: filePath,
29 type: 'file',
30 value: {
31 filePath
32 }
33});
34
35const nodeFromGlob = glob => ({
36 id: glob,
37 type: 'glob',
38 value: glob
39});
40
41const nodeFromRequest = request => ({
42 id: request.id,
43 type: 'request',
44 value: request
45});
46
47class 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 // $FlowFixMe
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; // $FlowFixMe
67
68 return deserialized;
69 } // $FlowFixMe
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 } // TODO: deprecate
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); // sometimes mac os reports update events as create events
221 // if it was a create event, but the file already exists in the graph,
222 // then we can assume it was actually an update event
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
256exports.RequestGraph = RequestGraph;
257
258class 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
330exports.default = RequestTracker;
331
332function generateRequestId(type, request) {
333 return (0, _utils.md5FromObject)({
334 type,
335 request
336 });
337}
338
339class 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) ? // $FlowFixMe
362 this.tracker.getRequestResult(id) : await this.run(requestDesc, api);
363 (0, _utils2.assertSignalNotAborted)(signal); // Request may have been removed by a parent request
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 } // unused vars are used for types
373 // eslint-disable-next-line no-unused-vars
374
375
376 run(request, api) {
377 throw new Error(`RequestRunner for type ${this.type} did not implement run()`);
378 } // unused vars are used for types
379 // eslint-disable-next-line no-unused-vars
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
405exports.RequestRunner = RequestRunner;
\No newline at end of file