1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.removeAssetGroups = removeAssetGroups;
|
7 | exports.default = void 0;
|
8 |
|
9 | var _assert = _interopRequireDefault(require("assert"));
|
10 |
|
11 | var _crypto = _interopRequireDefault(require("crypto"));
|
12 |
|
13 | var _nullthrows = _interopRequireDefault(require("nullthrows"));
|
14 |
|
15 | var _utils = require("@parcel/utils");
|
16 |
|
17 | var _utils2 = require("./utils");
|
18 |
|
19 | var _Graph = _interopRequireWildcard(require("./Graph"));
|
20 |
|
21 | function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
22 |
|
23 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
24 |
|
25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
26 |
|
27 | 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; }
|
28 |
|
29 | class BundleGraph {
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | constructor({
|
35 | graph,
|
36 | bundleContentHashes
|
37 | }) {
|
38 | _defineProperty(this, "_bundleContentHashes", void 0);
|
39 |
|
40 | _defineProperty(this, "_graph", void 0);
|
41 |
|
42 | this._graph = graph;
|
43 | this._bundleContentHashes = bundleContentHashes || new Map();
|
44 | }
|
45 |
|
46 | static deserialize(opts) {
|
47 | return new BundleGraph({
|
48 | graph: opts._graph,
|
49 | bundleContentHashes: opts._bundleContentHashes
|
50 | });
|
51 | }
|
52 |
|
53 | addAssetGraphToBundle(asset, bundle) {
|
54 |
|
55 |
|
56 | this._graph.addEdge(bundle.id, asset.id);
|
57 |
|
58 | this._graph.traverse((node, _, actions) => {
|
59 | if (node.type === 'bundle_group') {
|
60 | actions.skipChildren();
|
61 | return;
|
62 | }
|
63 |
|
64 | if (node.type === 'asset' && !this.bundleHasAsset(bundle, node.value)) {
|
65 | bundle.stats.size += node.value.stats.size;
|
66 | }
|
67 |
|
68 | if (node.type === 'asset' || node.type === 'dependency') {
|
69 | this._graph.addEdge(bundle.id, node.id, 'contains');
|
70 | }
|
71 |
|
72 | if (node.type === 'dependency') {
|
73 | for (let bundleGroupNode of this._graph.getNodesConnectedFrom(node).filter(node => node.type === 'bundle_group')) {
|
74 | this._graph.addEdge(bundle.id, bundleGroupNode.id, 'bundle');
|
75 | }
|
76 | }
|
77 | }, (0, _nullthrows.default)(this._graph.getNode(asset.id)));
|
78 |
|
79 | this._bundleContentHashes.delete(bundle.id);
|
80 | }
|
81 |
|
82 | removeAssetGraphFromBundle(asset, bundle) {
|
83 |
|
84 |
|
85 | this._graph.traverse((node, context, actions) => {
|
86 | if (node.type === 'bundle_group') {
|
87 | actions.skipChildren();
|
88 | return;
|
89 | }
|
90 |
|
91 | if (node.type === 'asset' || node.type === 'dependency') {
|
92 | if (this._graph.hasEdge(bundle.id, node.id, 'contains')) {
|
93 | this._graph.removeEdge(bundle.id, node.id, 'contains',
|
94 |
|
95 |
|
96 |
|
97 | false
|
98 |
|
99 | );
|
100 |
|
101 | if (node.type === 'asset') {
|
102 | bundle.stats.size -= asset.stats.size;
|
103 | }
|
104 | } else {
|
105 | actions.skipChildren();
|
106 | }
|
107 | }
|
108 |
|
109 | if (node.type === 'dependency') {
|
110 | for (let bundleGroupNode of this._graph.getNodesConnectedFrom(node).filter(node => node.type === 'bundle_group')) {
|
111 | let inboundDependencies = this._graph.getNodesConnectedTo(bundleGroupNode).filter(node => node.type === 'dependency');
|
112 |
|
113 |
|
114 |
|
115 | if (inboundDependencies.every(depNode => !this._graph.hasEdge(bundle.id, depNode.id, 'contains'))) {
|
116 | this._graph.removeEdge(bundle.id, bundleGroupNode.id, 'bundle');
|
117 | }
|
118 | }
|
119 | }
|
120 | }, (0, _nullthrows.default)(this._graph.getNode(asset.id)));
|
121 |
|
122 |
|
123 | if (this._graph.hasEdge(bundle.id, asset.id)) {
|
124 | this._graph.removeEdge(bundle.id, asset.id);
|
125 | }
|
126 |
|
127 | this._bundleContentHashes.delete(bundle.id);
|
128 | }
|
129 |
|
130 | createAssetReference(dependency, asset) {
|
131 | this._graph.addEdge(dependency.id, asset.id, 'references');
|
132 |
|
133 | if (this._graph.hasEdge(dependency.id, asset.id)) {
|
134 | this._graph.removeEdge(dependency.id, asset.id);
|
135 | }
|
136 | }
|
137 |
|
138 | findBundlesWithAsset(asset) {
|
139 | return this._graph.getNodesConnectedTo((0, _nullthrows.default)(this._graph.getNode(asset.id)), 'contains').filter(node => node.type === 'bundle').map(node => {
|
140 | (0, _assert.default)(node.type === 'bundle');
|
141 | return node.value;
|
142 | });
|
143 | }
|
144 |
|
145 | getDependencyAssets(dependency) {
|
146 | let dependencyNode = (0, _nullthrows.default)(this._graph.getNode(dependency.id));
|
147 | return this._graph.getNodesConnectedFrom(dependencyNode).filter(node => node.type === 'asset').map(node => {
|
148 | (0, _assert.default)(node.type === 'asset');
|
149 | return node.value;
|
150 | });
|
151 | }
|
152 |
|
153 | getDependencyResolution(dep) {
|
154 | let depNode = this._graph.getNode(dep.id);
|
155 |
|
156 | if (!depNode) {
|
157 | return null;
|
158 | }
|
159 |
|
160 | let res = null;
|
161 |
|
162 | function findFirstAsset(node, _, traversal) {
|
163 | if (node.type === 'asset') {
|
164 | res = node.value;
|
165 | traversal.stop();
|
166 | } else if (node.id !== dep.id) {
|
167 | traversal.skipChildren();
|
168 | }
|
169 | }
|
170 |
|
171 |
|
172 | this._graph.traverse(findFirstAsset, depNode);
|
173 |
|
174 | if (!res) {
|
175 |
|
176 |
|
177 | this._graph.traverse(findFirstAsset, depNode, 'references');
|
178 | }
|
179 |
|
180 | return res;
|
181 | }
|
182 |
|
183 | getDependencies(asset) {
|
184 | let node = this._graph.getNode(asset.id);
|
185 |
|
186 | if (!node) {
|
187 | throw new Error('Asset not found');
|
188 | }
|
189 |
|
190 | return this._graph.getNodesConnectedFrom(node).map(node => {
|
191 | (0, _assert.default)(node.type === 'dependency');
|
192 | return node.value;
|
193 | });
|
194 | }
|
195 |
|
196 | traverseAssets(bundle, visit) {
|
197 | return this.traverseBundle(bundle, (0, _Graph.mapVisitor)(node => node.type === 'asset' ? node.value : null, visit));
|
198 | }
|
199 |
|
200 | isAssetReferenced(asset) {
|
201 | return this._graph.getNodesConnectedTo((0, _nullthrows.default)(this._graph.getNode(asset.id)), 'references').length > 0;
|
202 | }
|
203 |
|
204 | isAssetReferencedByAssetType(asset, type) {
|
205 | let referringBundles = new Set(this._graph.getNodesConnectedTo((0, _nullthrows.default)(this._graph.getNode(asset.id)), 'contains'));
|
206 |
|
207 | return (0, _utils.flatMap)(this._graph.getNodesConnectedTo((0, _nullthrows.default)(this._graph.getNode(asset.id))).filter(node => {
|
208 |
|
209 |
|
210 |
|
211 | return this._graph.getNodesConnectedTo(node, 'contains').filter(node => node.type === 'bundle').some(b => !referringBundles.has(b));
|
212 | }), node => {
|
213 | (0, _assert.default)(node.type === 'dependency');
|
214 | return this._graph.getNodesConnectedTo(node, null);
|
215 | }).filter(node => node.type === 'asset').some(node => {
|
216 | (0, _assert.default)(node.type === 'asset');
|
217 | return node.value.type === type;
|
218 | });
|
219 | }
|
220 |
|
221 | hasParentBundleOfType(bundle, type) {
|
222 | return (0, _utils.flatMap)(this._graph.getNodesConnectedTo((0, _nullthrows.default)(this._graph.getNode(bundle.id)), 'bundle'), node => this._graph.getNodesConnectedTo(node, 'bundle')).every(node => node.type === 'bundle' && node.value.type === type);
|
223 | }
|
224 |
|
225 | isAssetInAncestorBundles(bundle, asset) {
|
226 | let parentBundleNodes = (0, _utils.flatMap)(this._graph.getNodesConnectedTo((0, _nullthrows.default)(this._graph.getNode(bundle.id)), 'bundle'), bundleGroupNode => {
|
227 | (0, _assert.default)(bundleGroupNode.type === 'bundle_group');
|
228 | return this._graph.getNodesConnectedTo(bundleGroupNode, 'bundle');
|
229 | });
|
230 | return parentBundleNodes.every(parentNode => {
|
231 | let inBundle;
|
232 |
|
233 | this._graph.traverseAncestors(parentNode, (node, ctx, actions) => {
|
234 | if (node.type !== 'bundle' || node.id === bundle.id) {
|
235 | return;
|
236 | }
|
237 |
|
238 |
|
239 | if (node.value.env.context !== bundle.env.context) {
|
240 | actions.skipChildren();
|
241 | return;
|
242 | }
|
243 |
|
244 | if (this._graph.hasEdge(node.value.id, asset.id, 'contains')) {
|
245 | inBundle = true;
|
246 | actions.stop();
|
247 | }
|
248 | }, 'bundle');
|
249 |
|
250 | return inBundle;
|
251 | });
|
252 | }
|
253 |
|
254 | traverseBundle(bundle, visit) {
|
255 | return this._graph.filteredTraverse((node, actions) => {
|
256 | if (node.id === bundle.id) {
|
257 | return;
|
258 | }
|
259 |
|
260 | if (node.type === 'dependency' || node.type === 'asset') {
|
261 | if (this._graph.hasEdge(bundle.id, node.id, 'contains')) {
|
262 | return node;
|
263 | }
|
264 | }
|
265 |
|
266 | actions.skipChildren();
|
267 | }, visit, (0, _nullthrows.default)(this._graph.getNode(bundle.id)));
|
268 | }
|
269 |
|
270 | traverseContents(visit) {
|
271 | return this._graph.filteredTraverse(node => node.type === 'asset' || node.type === 'dependency' ? node : null, visit);
|
272 | }
|
273 |
|
274 | getChildBundles(bundle) {
|
275 | let bundles = [];
|
276 | this.traverseBundles((b, _, actions) => {
|
277 | if (bundle.id === b.id) {
|
278 | return;
|
279 | }
|
280 |
|
281 | bundles.push(b);
|
282 | actions.skipChildren();
|
283 | }, bundle);
|
284 | return bundles;
|
285 | }
|
286 |
|
287 | traverseBundles(visit, startBundle) {
|
288 | return this._graph.filteredTraverse(node => node.type === 'bundle' ? node.value : null, visit, startBundle ? (0, _nullthrows.default)(this._graph.getNode(startBundle.id)) : null, 'bundle');
|
289 | }
|
290 |
|
291 | getBundles() {
|
292 | let bundles = [];
|
293 | this.traverseBundles(bundle => {
|
294 | bundles.push(bundle);
|
295 | });
|
296 | return bundles;
|
297 | }
|
298 |
|
299 | getTotalSize(asset) {
|
300 | let size = 0;
|
301 |
|
302 | this._graph.traverse((node, _, actions) => {
|
303 | if (node.type === 'bundle_group') {
|
304 | actions.skipChildren();
|
305 | return;
|
306 | }
|
307 |
|
308 | if (node.type === 'asset') {
|
309 | size += node.value.stats.size;
|
310 | }
|
311 | }, (0, _nullthrows.default)(this._graph.getNode(asset.id)));
|
312 |
|
313 | return size;
|
314 | }
|
315 |
|
316 | getBundleGroupsContainingBundle(bundle) {
|
317 | return this._graph.getNodesConnectedTo((0, _nullthrows.default)(this._graph.getNode(bundle.id)), 'bundle').filter(node => node.type === 'bundle_group').map(node => {
|
318 | (0, _assert.default)(node.type === 'bundle_group');
|
319 | return node.value;
|
320 | });
|
321 | }
|
322 |
|
323 | getBundlesInBundleGroup(bundleGroup) {
|
324 | return this._graph.getNodesConnectedFrom((0, _nullthrows.default)(this._graph.getNode((0, _utils2.getBundleGroupId)(bundleGroup))), 'bundle').filter(node => node.type === 'bundle').map(node => {
|
325 | (0, _assert.default)(node.type === 'bundle');
|
326 | return node.value;
|
327 | });
|
328 | }
|
329 |
|
330 | getSiblingBundles(bundle) {
|
331 | let siblings = [];
|
332 | let bundleGroups = this.getBundleGroupsContainingBundle(bundle);
|
333 |
|
334 | for (let bundleGroup of bundleGroups) {
|
335 | let bundles = this.getBundlesInBundleGroup(bundleGroup);
|
336 |
|
337 | for (let b of bundles) {
|
338 | if (b.id !== bundle.id) {
|
339 | siblings.push(b);
|
340 | }
|
341 | }
|
342 | }
|
343 |
|
344 | return siblings;
|
345 | }
|
346 |
|
347 | getIncomingDependencies(asset) {
|
348 | let node = this._graph.getNode(asset.id);
|
349 |
|
350 | if (!node) {
|
351 | return [];
|
352 | }
|
353 |
|
354 | return this._graph.findAncestors(node, node => node.type === 'dependency').map(node => {
|
355 | (0, _assert.default)(node.type === 'dependency');
|
356 | return node.value;
|
357 | });
|
358 | }
|
359 |
|
360 | bundleHasAsset(bundle, asset) {
|
361 | return this._graph.hasEdge(bundle.id, asset.id, 'contains');
|
362 | }
|
363 |
|
364 | filteredTraverse(bundle, filter, visit) {
|
365 | return this._graph.filteredTraverse(filter, visit, (0, _nullthrows.default)(this._graph.getNode(bundle.id)));
|
366 | }
|
367 |
|
368 | resolveSymbol(asset, symbol) {
|
369 | let identifier = asset.symbols.get(symbol);
|
370 |
|
371 | if (symbol === '*') {
|
372 | return {
|
373 | asset,
|
374 | exportSymbol: '*',
|
375 | symbol: identifier
|
376 | };
|
377 | }
|
378 |
|
379 | let deps = this.getDependencies(asset).reverse();
|
380 |
|
381 | for (let dep of deps) {
|
382 |
|
383 | let symbolLookup = new Map([...dep.symbols].map(([key, val]) => [val, key]));
|
384 | let depSymbol = symbolLookup.get(identifier);
|
385 |
|
386 | if (depSymbol != null) {
|
387 | let resolved = this.getDependencyResolution(dep);
|
388 |
|
389 | if (!resolved) {
|
390 |
|
391 | break;
|
392 | }
|
393 |
|
394 | let {
|
395 | asset: resolvedAsset,
|
396 | symbol: resolvedSymbol,
|
397 | exportSymbol
|
398 | } = this.resolveSymbol(resolved, depSymbol);
|
399 |
|
400 | if (resolvedSymbol == null) {
|
401 | return {
|
402 | asset: resolvedAsset,
|
403 | symbol: resolvedSymbol,
|
404 | exportSymbol
|
405 | };
|
406 | }
|
407 |
|
408 |
|
409 | return {
|
410 | asset: resolvedAsset,
|
411 | symbol: resolvedSymbol,
|
412 | exportSymbol: symbol
|
413 | };
|
414 | }
|
415 |
|
416 |
|
417 |
|
418 | if (dep.symbols.get('*') === '*' && symbol !== 'default') {
|
419 | let resolved = (0, _nullthrows.default)(this.getDependencyResolution(dep));
|
420 | let result = this.resolveSymbol(resolved, symbol);
|
421 |
|
422 | if (result.symbol != null) {
|
423 | return {
|
424 | asset: result.asset,
|
425 | symbol: result.symbol,
|
426 | exportSymbol: symbol
|
427 | };
|
428 | }
|
429 | }
|
430 | }
|
431 |
|
432 | return {
|
433 | asset,
|
434 | exportSymbol: symbol,
|
435 | symbol: identifier
|
436 | };
|
437 | }
|
438 |
|
439 | getExportedSymbols(asset) {
|
440 | let symbols = [];
|
441 |
|
442 | for (let symbol of asset.symbols.keys()) {
|
443 | symbols.push(this.resolveSymbol(asset, symbol));
|
444 | }
|
445 |
|
446 | let deps = this.getDependencies(asset);
|
447 |
|
448 | for (let dep of deps) {
|
449 | if (dep.symbols.get('*') === '*') {
|
450 | let resolved = (0, _nullthrows.default)(this.getDependencyResolution(dep));
|
451 | let exported = this.getExportedSymbols(resolved).filter(s => s.exportSymbol !== 'default');
|
452 | symbols.push(...exported);
|
453 | }
|
454 | }
|
455 |
|
456 | return symbols;
|
457 | }
|
458 |
|
459 | getContentHash(bundle) {
|
460 | let existingHash = this._bundleContentHashes.get(bundle.id);
|
461 |
|
462 | if (existingHash != null) {
|
463 | return existingHash;
|
464 | }
|
465 |
|
466 | let hash = _crypto.default.createHash('md5');
|
467 |
|
468 |
|
469 | this.traverseAssets(bundle, asset => {
|
470 | hash.update([asset.outputHash, asset.filePath].join(':'));
|
471 | });
|
472 | let hashHex = hash.digest('hex');
|
473 |
|
474 | this._bundleContentHashes.set(bundle.id, hashHex);
|
475 |
|
476 | return hashHex;
|
477 | }
|
478 |
|
479 | getHash(bundle) {
|
480 | let hash = _crypto.default.createHash('md5');
|
481 |
|
482 | this.traverseBundles(childBundle => {
|
483 | hash.update(this.getContentHash(childBundle));
|
484 | }, bundle);
|
485 | hash.update(JSON.stringify((0, _utils.objectSortedEntriesDeep)(bundle.env)));
|
486 | return hash.digest('hex');
|
487 | }
|
488 |
|
489 | }
|
490 |
|
491 | exports.default = BundleGraph;
|
492 |
|
493 | function removeAssetGroups(assetGraph) {
|
494 | let graph = new _Graph.default();
|
495 | let rootNode = assetGraph.getRootNode();
|
496 | (0, _assert.default)(rootNode != null && rootNode.type === 'root');
|
497 | graph.setRootNode(rootNode);
|
498 | let assetGroupIds = new Set();
|
499 |
|
500 | for (let [, node] of assetGraph.nodes) {
|
501 | if (node.type === 'asset_group') {
|
502 | assetGroupIds.add(node.id);
|
503 | } else {
|
504 | graph.addNode(node);
|
505 | }
|
506 | }
|
507 |
|
508 | for (let edge of assetGraph.getAllEdges()) {
|
509 | let fromIds;
|
510 |
|
511 | if (assetGroupIds.has(edge.from)) {
|
512 | fromIds = [...assetGraph.inboundEdges.get(edge.from).get(null)];
|
513 | } else {
|
514 | fromIds = [edge.from];
|
515 | }
|
516 |
|
517 | for (let from of fromIds) {
|
518 | if (assetGroupIds.has(edge.to)) {
|
519 | for (let to of assetGraph.outboundEdges.get(edge.to).get(null)) {
|
520 | graph.addEdge(from, to);
|
521 | }
|
522 | } else {
|
523 | graph.addEdge(from, edge.to);
|
524 | }
|
525 | }
|
526 | }
|
527 |
|
528 | return graph;
|
529 | } |
\ | No newline at end of file |