Son CV dans un terminal web en Javascript! https://terminal-cv.gregandev.fr
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1389 lines
50 KiB

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.bundleGraphEdgeTypes = void 0;
function _assert() {
const data = _interopRequireDefault(require("assert"));
_assert = function () {
return data;
};
return data;
}
function _nullthrows() {
const data = _interopRequireDefault(require("nullthrows"));
_nullthrows = function () {
return data;
};
return data;
}
function _graph() {
const data = require("@parcel/graph");
_graph = function () {
return data;
};
return data;
}
function _hash() {
const data = require("@parcel/hash");
_hash = function () {
return data;
};
return data;
}
function _utils() {
const data = require("@parcel/utils");
_utils = function () {
return data;
};
return data;
}
var _types = require("./types");
var _utils2 = require("./utils");
var _Environment = require("./public/Environment");
var _projectPath = require("./projectPath");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const bundleGraphEdgeTypes = {
// A lack of an edge type indicates to follow the edge while traversing
// the bundle's contents, e.g. `bundle.traverse()` during packaging.
null: 1,
// Used for constant-time checks of presence of a dependency or asset in a bundle,
// avoiding bundle traversal in cases like `isAssetInAncestors`
contains: 2,
// Connections between bundles and bundle groups, for quick traversal of the
// bundle hierarchy.
bundle: 3,
// When dependency -> asset: Indicates that the asset a dependency references
// is contained in another bundle.
// When dependency -> bundle: Indicates the bundle is necessary for any bundles
// with the dependency.
// When bundle -> bundle: Indicates the target bundle is necessary for the
// source bundle.
// This type prevents referenced assets from being traversed from dependencies
// along the untyped edge, and enables traversal to referenced bundles that are
// not directly connected to bundle group nodes.
references: 4,
// Signals that the dependency is internally resolvable via the bundle's ancestry,
// and that the bundle connected to the dependency is not necessary for the source bundle.
internal_async: 5
};
exports.bundleGraphEdgeTypes = bundleGraphEdgeTypes;
function makeReadOnlySet(set) {
return new Proxy(set, {
get(target, property) {
if (property === 'delete' || property === 'add' || property === 'clear') {
return undefined;
} else {
// $FlowFixMe[incompatible-type]
let value = target[property];
return typeof value === 'function' ? value.bind(target) : value;
}
}
});
}
class BundleGraph {
// TODO: These hashes are being invalidated in mutative methods, but this._graph is not a private
// property so it is possible to reach in and mutate the graph without invalidating these hashes.
// It needs to be exposed in BundlerRunner for now based on how applying runtimes works and the
// BundlerRunner takes care of invalidating hashes when runtimes are applied, but this is not ideal.
_targetEntryRoots = new Map();
constructor({
graph,
publicIdByAssetId,
assetPublicIds,
bundleContentHashes,
symbolPropagationRan
}) {
this._graph = graph;
this._assetPublicIds = assetPublicIds;
this._publicIdByAssetId = publicIdByAssetId;
this._bundleContentHashes = bundleContentHashes;
this._symbolPropagationRan = symbolPropagationRan;
}
static fromAssetGraph(assetGraph, publicIdByAssetId = new Map(), assetPublicIds = new Set()) {
let graph = new (_graph().ContentGraph)();
let assetGroupIds = new Set();
let assetGraphNodeIdToBundleGraphNodeId = new Map();
let assetGraphRootNode = assetGraph.rootNodeId != null ? assetGraph.getNode(assetGraph.rootNodeId) : null;
(0, _assert().default)(assetGraphRootNode != null && assetGraphRootNode.type === 'root');
for (let [nodeId, node] of assetGraph.nodes) {
if (node.type === 'asset') {
let {
id: assetId
} = node.value; // Generate a new, short public id for this asset to use.
// If one already exists, use it.
let publicId = publicIdByAssetId.get(assetId);
if (publicId == null) {
publicId = (0, _utils2.getPublicId)(assetId, existing => assetPublicIds.has(existing));
publicIdByAssetId.set(assetId, publicId);
assetPublicIds.add(publicId);
}
} // Don't copy over asset groups into the bundle graph.
if (node.type === 'asset_group') {
assetGroupIds.add(nodeId);
} else {
let bundleGraphNodeId = graph.addNodeByContentKey(node.id, node);
if (node.id === (assetGraphRootNode === null || assetGraphRootNode === void 0 ? void 0 : assetGraphRootNode.id)) {
graph.setRootNodeId(bundleGraphNodeId);
}
assetGraphNodeIdToBundleGraphNodeId.set(nodeId, bundleGraphNodeId);
}
}
for (let edge of assetGraph.getAllEdges()) {
let fromIds;
if (assetGroupIds.has(edge.from)) {
fromIds = [...assetGraph.inboundEdges.getEdges(edge.from, bundleGraphEdgeTypes.null)];
} else {
fromIds = [edge.from];
}
for (let from of fromIds) {
if (assetGroupIds.has(edge.to)) {
for (let to of assetGraph.outboundEdges.getEdges(edge.to, bundleGraphEdgeTypes.null)) {
graph.addEdge((0, _nullthrows().default)(assetGraphNodeIdToBundleGraphNodeId.get(from)), (0, _nullthrows().default)(assetGraphNodeIdToBundleGraphNodeId.get(to)));
}
} else {
graph.addEdge((0, _nullthrows().default)(assetGraphNodeIdToBundleGraphNodeId.get(from)), (0, _nullthrows().default)(assetGraphNodeIdToBundleGraphNodeId.get(edge.to)));
}
}
}
return new BundleGraph({
graph,
assetPublicIds,
bundleContentHashes: new Map(),
publicIdByAssetId,
symbolPropagationRan: assetGraph.symbolPropagationRan
});
}
serialize() {
return {
$$raw: true,
graph: this._graph.serialize(),
assetPublicIds: this._assetPublicIds,
bundleContentHashes: this._bundleContentHashes,
publicIdByAssetId: this._publicIdByAssetId,
symbolPropagationRan: this._symbolPropagationRan
};
}
static deserialize(serialized) {
return new BundleGraph({
graph: _graph().ContentGraph.deserialize(serialized.graph),
assetPublicIds: serialized.assetPublicIds,
bundleContentHashes: serialized.bundleContentHashes,
publicIdByAssetId: serialized.publicIdByAssetId,
symbolPropagationRan: serialized.symbolPropagationRan
});
}
addAssetGraphToBundle(asset, bundle, shouldSkipDependency = d => this.isDependencySkipped(d)) {
let assetNodeId = this._graph.getNodeIdByContentKey(asset.id);
let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); // The root asset should be reached directly from the bundle in traversal.
// Its children will be traversed from there.
this._graph.addEdge(bundleNodeId, assetNodeId);
this._graph.traverse((nodeId, _, actions) => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
if (node.type === 'bundle_group') {
actions.skipChildren();
return;
}
if (node.type === 'dependency' && shouldSkipDependency(node.value)) {
actions.skipChildren();
return;
}
if (node.type === 'asset' || node.type === 'dependency') {
this._graph.addEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.contains);
}
if (node.type === 'dependency') {
for (let [bundleGroupNodeId, bundleGroupNode] of this._graph.getNodeIdsConnectedFrom(nodeId).map(id => [id, (0, _nullthrows().default)(this._graph.getNode(id))]).filter(([, node]) => node.type === 'bundle_group')) {
(0, _assert().default)(bundleGroupNode.type === 'bundle_group');
this._graph.addEdge(bundleNodeId, bundleGroupNodeId, bundleGraphEdgeTypes.bundle);
} // If the dependency references a target bundle, add a reference edge from
// the source bundle to the dependency for easy traversal.
if (this._graph.getNodeIdsConnectedFrom(nodeId, bundleGraphEdgeTypes.references).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).some(node => node.type === 'bundle')) {
this._graph.addEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.references);
}
}
}, assetNodeId);
this._bundleContentHashes.delete(bundle.id);
}
addEntryToBundle(asset, bundle, shouldSkipDependency) {
this.addAssetGraphToBundle(asset, bundle, shouldSkipDependency);
if (!bundle.entryAssetIds.includes(asset.id)) {
bundle.entryAssetIds.push(asset.id);
}
}
internalizeAsyncDependency(bundle, dependency) {
if (dependency.priority === _types.Priority.sync) {
throw new Error('Expected an async dependency');
}
this._graph.addEdge(this._graph.getNodeIdByContentKey(bundle.id), this._graph.getNodeIdByContentKey(dependency.id), bundleGraphEdgeTypes.internal_async);
this.removeExternalDependency(bundle, dependency);
}
isDependencySkipped(dependency) {
let node = this._graph.getNodeByContentKey(dependency.id);
(0, _assert().default)(node && node.type === 'dependency');
return !!node.hasDeferred || node.excluded;
}
getParentBundlesOfBundleGroup(bundleGroup) {
return this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup)), bundleGraphEdgeTypes.bundle).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle').map(node => {
(0, _assert().default)(node.type === 'bundle');
return node.value;
});
}
resolveAsyncDependency(dependency, bundle) {
let depNodeId = this._graph.getNodeIdByContentKey(dependency.id);
let bundleNodeId = bundle != null ? this._graph.getNodeIdByContentKey(bundle.id) : null;
if (bundleNodeId != null && this._graph.hasEdge(bundleNodeId, depNodeId, bundleGraphEdgeTypes.internal_async)) {
let referencedAssetNodeIds = this._graph.getNodeIdsConnectedFrom(depNodeId, bundleGraphEdgeTypes.references);
let resolved;
if (referencedAssetNodeIds.length === 0) {
resolved = this.getResolvedAsset(dependency, bundle);
} else if (referencedAssetNodeIds.length === 1) {
let referencedAssetNode = this._graph.getNode(referencedAssetNodeIds[0]); // If a referenced asset already exists, resolve this dependency to it.
(0, _assert().default)((referencedAssetNode === null || referencedAssetNode === void 0 ? void 0 : referencedAssetNode.type) === 'asset');
resolved = referencedAssetNode.value;
} else {
throw new Error('Dependencies can only reference one asset');
}
if (resolved == null) {
return;
} else {
return {
type: 'asset',
value: resolved
};
}
}
let node = this._graph.getNodeIdsConnectedFrom(this._graph.getNodeIdByContentKey(dependency.id)).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).find(node => node.type === 'bundle_group');
if (node == null) {
return;
}
(0, _assert().default)(node.type === 'bundle_group');
return {
type: 'bundle_group',
value: node.value
};
}
getReferencedBundle(dependency, fromBundle) {
let dependencyNodeId = this._graph.getNodeIdByContentKey(dependency.id); // If this dependency is async, there will be a bundle group attached to it.
let node = this._graph.getNodeIdsConnectedFrom(dependencyNodeId).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).find(node => node.type === 'bundle_group');
if (node != null) {
(0, _assert().default)(node.type === 'bundle_group');
return this.getBundlesInBundleGroup(node.value, {
includeInline: true
}).find(b => {
let mainEntryId = b.entryAssetIds[b.entryAssetIds.length - 1];
return mainEntryId != null && node.value.entryAssetId === mainEntryId;
});
} // Otherwise, it may be a reference to another asset in the same bundle group.
// Resolve the dependency to an asset, and look for it in one of the referenced bundles.
let referencedBundles = this.getReferencedBundles(fromBundle, {
includeInline: true
});
let referenced = this._graph.getNodeIdsConnectedFrom(dependencyNodeId, bundleGraphEdgeTypes.references).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).find(node => node.type === 'asset');
if (referenced != null) {
(0, _assert().default)(referenced.type === 'asset');
return referencedBundles.find(b => this.bundleHasAsset(b, referenced.value));
}
}
removeAssetGraphFromBundle(asset, bundle) {
let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
let assetNodeId = this._graph.getNodeIdByContentKey(asset.id); // Remove all contains edges from the bundle to the nodes in the asset's
// subgraph.
this._graph.traverse((nodeId, context, actions) => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
if (node.type === 'bundle_group') {
actions.skipChildren();
return;
}
if (node.type !== 'dependency' && node.type !== 'asset') {
return;
}
if (this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.contains)) {
this._graph.removeEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.contains, // Removing this contains edge should not orphan the connected node. This
// is disabled for performance reasons as these edges are removed as part
// of a traversal, and checking for orphans becomes quite expensive in
// aggregate.
false
/* removeOrphans */
);
} else {
actions.skipChildren();
}
if (node.type === 'asset' && this._graph.hasEdge(bundleNodeId, nodeId)) {
// Remove the untyped edge from the bundle to the node (it's an entry)
this._graph.removeEdge(bundleNodeId, nodeId);
let entryIndex = bundle.entryAssetIds.indexOf(node.value.id);
if (entryIndex >= 0) {
// Shared bundles have untyped edges to their asset graphs but don't
// have entry assets. For those that have entry asset ids, remove them.
bundle.entryAssetIds.splice(entryIndex, 1);
}
}
if (node.type === 'dependency') {
this.removeExternalDependency(bundle, node.value);
if (this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.references)) {
this._graph.addEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.references);
}
if (this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.internal_async)) {
this._graph.removeEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.internal_async);
}
}
}, assetNodeId); // Remove bundle node if it no longer has any entry assets
if (this._graph.getNodeIdsConnectedFrom(bundleNodeId).length === 0) {
this.removeBundle(bundle);
}
this._bundleContentHashes.delete(bundle.id);
}
removeBundle(bundle) {
// Remove bundle node if it no longer has any entry assets
let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
let bundleGroupNodeIds = this._graph.getNodeIdsConnectedTo(bundleNodeId, bundleGraphEdgeTypes.bundle);
this._graph.removeNode(bundleNodeId);
let removedBundleGroups = new Set(); // Remove bundle group node if it no longer has any bundles
for (let bundleGroupNodeId of bundleGroupNodeIds) {
let bundleGroupNode = (0, _nullthrows().default)(this._graph.getNode(bundleGroupNodeId));
(0, _assert().default)(bundleGroupNode.type === 'bundle_group');
let bundleGroup = bundleGroupNode.value;
if ( // If the bundle group's entry asset belongs to this bundle, the group
// was created because of this bundle. Remove the group.
bundle.entryAssetIds.includes(bundleGroup.entryAssetId) || // If the bundle group is now empty, remove it.
this.getBundlesInBundleGroup(bundleGroup, {
includeInline: true
}).length === 0) {
removedBundleGroups.add(bundleGroup);
this.removeBundleGroup(bundleGroup);
}
}
this._bundleContentHashes.delete(bundle.id);
return removedBundleGroups;
}
removeBundleGroup(bundleGroup) {
let bundleGroupNode = (0, _nullthrows().default)(this._graph.getNodeByContentKey((0, _utils2.getBundleGroupId)(bundleGroup)));
(0, _assert().default)(bundleGroupNode.type === 'bundle_group');
let bundlesInGroup = this.getBundlesInBundleGroup(bundleGroupNode.value, {
includeInline: true
});
for (let bundle of bundlesInGroup) {
if (this.getBundleGroupsContainingBundle(bundle).length === 1) {
let removedBundleGroups = this.removeBundle(bundle);
if (removedBundleGroups.has(bundleGroup)) {
// This function can be reentered through removeBundle above. In the case this
// bundle group has already been removed, stop.
return;
}
}
} // This function can be reentered through removeBundle above. In this case,
// the node may already been removed.
if (this._graph.hasContentKey(bundleGroupNode.id)) {
this._graph.removeNode(this._graph.getNodeIdByContentKey(bundleGroupNode.id));
}
(0, _assert().default)(bundlesInGroup.every(bundle => this.getBundleGroupsContainingBundle(bundle).length > 0));
}
removeExternalDependency(bundle, dependency) {
let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
for (let bundleGroupNode of this._graph.getNodeIdsConnectedFrom(this._graph.getNodeIdByContentKey(dependency.id)).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle_group')) {
let bundleGroupNodeId = this._graph.getNodeIdByContentKey(bundleGroupNode.id);
if (!this._graph.hasEdge(bundleNodeId, bundleGroupNodeId, bundleGraphEdgeTypes.bundle)) {
continue;
}
let inboundDependencies = this._graph.getNodeIdsConnectedTo(bundleGroupNodeId).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'dependency').map(node => {
(0, _assert().default)(node.type === 'dependency');
return node.value;
}); // If every inbound dependency to this bundle group does not belong to this bundle,
// or the dependency is internal to the bundle, then the connection between
// this bundle and the group is safe to remove.
if (inboundDependencies.every(dependency => !this.bundleHasDependency(bundle, dependency) || this._graph.hasEdge(bundleNodeId, this._graph.getNodeIdByContentKey(dependency.id), bundleGraphEdgeTypes.internal_async))) {
this._graph.removeEdge(bundleNodeId, bundleGroupNodeId, bundleGraphEdgeTypes.bundle);
}
}
}
createAssetReference(dependency, asset, bundle) {
let dependencyId = this._graph.getNodeIdByContentKey(dependency.id);
let assetId = this._graph.getNodeIdByContentKey(asset.id);
let bundleId = this._graph.getNodeIdByContentKey(bundle.id);
this._graph.addEdge(dependencyId, assetId, bundleGraphEdgeTypes.references);
this._graph.addEdge(dependencyId, bundleId, bundleGraphEdgeTypes.references);
if (this._graph.hasEdge(dependencyId, assetId)) {
this._graph.removeEdge(dependencyId, assetId);
}
}
createBundleReference(from, to) {
this._graph.addEdge(this._graph.getNodeIdByContentKey(from.id), this._graph.getNodeIdByContentKey(to.id), bundleGraphEdgeTypes.references);
}
getBundlesWithAsset(asset) {
return this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey(asset.id), bundleGraphEdgeTypes.contains).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle').map(node => {
(0, _assert().default)(node.type === 'bundle');
return node.value;
});
}
getBundlesWithDependency(dependency) {
return this._graph.getNodeIdsConnectedTo((0, _nullthrows().default)(this._graph.getNodeIdByContentKey(dependency.id)), bundleGraphEdgeTypes.contains).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle').map(node => {
(0, _assert().default)(node.type === 'bundle');
return node.value;
});
}
getDependencyAssets(dependency) {
return this._graph.getNodeIdsConnectedFrom(this._graph.getNodeIdByContentKey(dependency.id)).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'asset').map(node => {
(0, _assert().default)(node.type === 'asset');
return node.value;
});
}
getResolvedAsset(dep, bundle) {
let assets = this.getDependencyAssets(dep);
let firstAsset = assets[0];
let resolved = // If no bundle is specified, use the first concrete asset.
bundle == null ? firstAsset : // Otherwise, find the first asset that belongs to this bundle.
assets.find(asset => this.bundleHasAsset(bundle, asset)) || firstAsset; // If a resolution still hasn't been found, return the first referenced asset.
if (resolved == null) {
this._graph.traverse((nodeId, _, traversal) => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
if (node.type === 'asset') {
resolved = node.value;
traversal.stop();
} else if (node.id !== dep.id) {
traversal.skipChildren();
}
}, this._graph.getNodeIdByContentKey(dep.id), bundleGraphEdgeTypes.references);
}
return resolved;
}
getDependencies(asset) {
let nodeId = this._graph.getNodeIdByContentKey(asset.id);
return this._graph.getNodeIdsConnectedFrom(nodeId).map(id => {
let node = (0, _nullthrows().default)(this._graph.getNode(id));
(0, _assert().default)(node.type === 'dependency');
return node.value;
});
}
traverseAssets(bundle, visit) {
return this.traverseBundle(bundle, (0, _graph().mapVisitor)(node => node.type === 'asset' ? node.value : null, visit));
}
isAssetReferenced(bundle, asset) {
let assetNodeId = (0, _nullthrows().default)(this._graph.getNodeIdByContentKey(asset.id));
if (this._graph.getNodeIdsConnectedTo(assetNodeId, bundleGraphEdgeTypes.references).map(id => this._graph.getNode(id)).some(node => (node === null || node === void 0 ? void 0 : node.type) === 'dependency' && node.value.priority === _types.Priority.lazy && node.value.specifierType !== _types.SpecifierType.url)) {
// If this asset is referenced by any async dependency, it's referenced.
return true;
}
let dependencies = this._graph.getNodeIdsConnectedTo(assetNodeId).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'dependency').map(node => {
(0, _assert().default)(node.type === 'dependency');
return node.value;
});
const bundleHasReference = bundle => {
return !this.bundleHasAsset(bundle, asset) && dependencies.some(dependency => this.bundleHasDependency(bundle, dependency));
};
let visitedBundles = new Set();
let siblingBundles = new Set(this.getBundleGroupsContainingBundle(bundle).flatMap(bundleGroup => this.getBundlesInBundleGroup(bundleGroup, {
includeInline: true
}))); // Check if any of this bundle's descendants, referencers, bundles referenced
// by referencers, or descendants of its referencers use the asset without
// an explicit reference edge. This can happen if e.g. the asset has been
// deduplicated.
return [...siblingBundles].some(referencer => {
let isReferenced = false;
this.traverseBundles((descendant, _, actions) => {
if (descendant.id === bundle.id) {
return;
}
if (visitedBundles.has(descendant)) {
actions.skipChildren();
return;
}
visitedBundles.add(descendant);
if (descendant.type !== bundle.type || descendant.env.context !== bundle.env.context) {
actions.skipChildren();
return;
}
if (bundleHasReference(descendant)) {
isReferenced = true;
actions.stop();
}
}, referencer);
return isReferenced;
});
}
hasParentBundleOfType(bundle, type) {
let parents = this.getParentBundles(bundle);
return parents.length > 0 && parents.every(parent => parent.type === type);
}
getParentBundles(bundle) {
let parentBundles = new Set();
for (let bundleGroup of this.getBundleGroupsContainingBundle(bundle)) {
for (let parentBundle of this.getParentBundlesOfBundleGroup(bundleGroup)) {
parentBundles.add(parentBundle);
}
}
return [...parentBundles];
}
isAssetReachableFromBundle(asset, bundle) {
// If a bundle's environment is isolated, it can't access assets present
// in any ancestor bundles. Don't consider any assets reachable.
if (_Environment.ISOLATED_ENVS.has(bundle.env.context) || !bundle.isSplittable || bundle.bundleBehavior === _types.BundleBehavior.isolated || bundle.bundleBehavior === _types.BundleBehavior.inline) {
return false;
} // For an asset to be reachable from a bundle, it must either exist in a sibling bundle,
// or in an ancestor bundle group reachable from all parent bundles.
let bundleGroups = this.getBundleGroupsContainingBundle(bundle);
return bundleGroups.every(bundleGroup => {
// If the asset is in any sibling bundles of the original bundle, it is reachable.
let bundles = this.getBundlesInBundleGroup(bundleGroup);
if (bundles.some(b => b.id !== bundle.id && b.bundleBehavior !== _types.BundleBehavior.isolated && b.bundleBehavior !== _types.BundleBehavior.inline && this.bundleHasAsset(b, asset))) {
return true;
} // Get a list of parent bundle nodes pointing to the bundle group
let parentBundleNodes = this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup)), bundleGraphEdgeTypes.bundle); // Check that every parent bundle has a bundle group in its ancestry that contains the asset.
return parentBundleNodes.every(bundleNodeId => {
let bundleNode = (0, _nullthrows().default)(this._graph.getNode(bundleNodeId));
if (bundleNode.type !== 'bundle' || bundleNode.value.bundleBehavior === _types.BundleBehavior.isolated || bundleNode.value.bundleBehavior === _types.BundleBehavior.inline) {
return false;
}
let isReachable = true;
this._graph.traverseAncestors(bundleNodeId, (nodeId, ctx, actions) => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId)); // If we've reached the root or a context change without
// finding this asset in the ancestry, it is not reachable.
if (node.type === 'root' || node.type === 'bundle' && (node.value.id === bundle.id || node.value.env.context !== bundle.env.context)) {
isReachable = false;
actions.stop();
return;
}
if (node.type === 'bundle_group') {
let childBundles = this.getBundlesInBundleGroup(node.value);
if (childBundles.some(b => b.id !== bundle.id && b.bundleBehavior !== _types.BundleBehavior.isolated && b.bundleBehavior !== _types.BundleBehavior.inline && this.bundleHasAsset(b, asset))) {
actions.skipChildren();
}
}
}, [bundleGraphEdgeTypes.references, bundleGraphEdgeTypes.bundle]);
return isReachable;
});
});
}
traverseBundle(bundle, visit) {
let entries = true;
let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id); // A modified DFS traversal which traverses entry assets in the same order
// as their ids appear in `bundle.entryAssetIds`.
return this._graph.dfs({
visit: (0, _graph().mapVisitor)((nodeId, actions) => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
if (nodeId === bundleNodeId) {
return;
}
if (node.type === 'dependency' || node.type === 'asset') {
if (this._graph.hasEdge(bundleNodeId, nodeId, bundleGraphEdgeTypes.contains)) {
return node;
}
}
actions.skipChildren();
}, visit),
startNodeId: bundleNodeId,
getChildren: nodeId => {
let children = this._graph.getNodeIdsConnectedFrom(nodeId).map(id => [id, (0, _nullthrows().default)(this._graph.getNode(id))]);
let sorted = entries && bundle.entryAssetIds.length > 0 ? children.sort(([, a], [, b]) => {
let aIndex = bundle.entryAssetIds.indexOf(a.id);
let bIndex = bundle.entryAssetIds.indexOf(b.id);
if (aIndex === bIndex) {
// If both don't exist in the entry asset list, or
// otherwise have the same index.
return 0;
} else if (aIndex === -1) {
return 1;
} else if (bIndex === -1) {
return -1;
}
return aIndex - bIndex;
}) : children;
entries = false;
return sorted.map(([id]) => id);
}
});
}
traverse(visit) {
return this._graph.filteredTraverse(nodeId => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
if (node.type === 'asset' || node.type === 'dependency') {
return node;
}
}, visit, undefined, // start with root
// $FlowFixMe
_graph().ALL_EDGE_TYPES);
}
getChildBundles(bundle) {
let siblings = new Set(this.getReferencedBundles(bundle));
let bundles = [];
this.traverseBundles((b, _, actions) => {
if (bundle.id === b.id) {
return;
}
if (!siblings.has(b)) {
bundles.push(b);
}
actions.skipChildren();
}, bundle);
return bundles;
}
traverseBundles(visit, startBundle) {
return this._graph.filteredTraverse(nodeId => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
return node.type === 'bundle' ? node.value : null;
}, visit, startBundle ? this._graph.getNodeIdByContentKey(startBundle.id) : null, [bundleGraphEdgeTypes.bundle, bundleGraphEdgeTypes.references]);
}
getBundles(opts) {
let bundles = [];
this.traverseBundles(bundle => {
if (opts !== null && opts !== void 0 && opts.includeInline || bundle.bundleBehavior !== _types.BundleBehavior.inline) {
bundles.push(bundle);
}
});
return bundles;
}
getTotalSize(asset) {
let size = 0;
this._graph.traverse((nodeId, _, actions) => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
if (node.type === 'bundle_group') {
actions.skipChildren();
return;
}
if (node.type === 'asset') {
size += node.value.stats.size;
}
}, this._graph.getNodeIdByContentKey(asset.id));
return size;
}
getReferencingBundles(bundle) {
let referencingBundles = new Set();
this._graph.traverseAncestors(this._graph.getNodeIdByContentKey(bundle.id), nodeId => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
if (node.type === 'bundle' && node.value.id !== bundle.id) {
referencingBundles.add(node.value);
}
}, bundleGraphEdgeTypes.references);
return [...referencingBundles];
}
getBundleGroupsContainingBundle(bundle) {
let bundleGroups = new Set();
for (let currentBundle of [bundle, ...this.getReferencingBundles(bundle)]) {
for (let bundleGroup of this.getDirectParentBundleGroups(currentBundle)) {
bundleGroups.add(bundleGroup);
}
}
return [...bundleGroups];
}
getDirectParentBundleGroups(bundle) {
return this._graph.getNodeIdsConnectedTo((0, _nullthrows().default)(this._graph.getNodeIdByContentKey(bundle.id)), bundleGraphEdgeTypes.bundle).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(node => node.type === 'bundle_group').map(node => {
(0, _assert().default)(node.type === 'bundle_group');
return node.value;
});
}
getBundlesInBundleGroup(bundleGroup, opts) {
let bundles = new Set();
for (let bundleNodeId of this._graph.getNodeIdsConnectedFrom(this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup)), bundleGraphEdgeTypes.bundle)) {
let bundleNode = (0, _nullthrows().default)(this._graph.getNode(bundleNodeId));
(0, _assert().default)(bundleNode.type === 'bundle');
let bundle = bundleNode.value;
if (opts !== null && opts !== void 0 && opts.includeInline || bundle.bundleBehavior !== _types.BundleBehavior.inline) {
bundles.add(bundle);
}
for (let referencedBundle of this.getReferencedBundles(bundle, {
includeInline: true
})) {
bundles.add(referencedBundle);
}
}
return [...bundles];
}
getReferencedBundles(bundle, opts) {
var _opts$recursive, _opts$includeInline;
let recursive = (_opts$recursive = opts === null || opts === void 0 ? void 0 : opts.recursive) !== null && _opts$recursive !== void 0 ? _opts$recursive : true;
let includeInline = (_opts$includeInline = opts === null || opts === void 0 ? void 0 : opts.includeInline) !== null && _opts$includeInline !== void 0 ? _opts$includeInline : false;
let referencedBundles = new Set();
this._graph.dfs({
visit: (nodeId, _, actions) => {
let node = (0, _nullthrows().default)(this._graph.getNode(nodeId));
if (node.type !== 'bundle') {
return;
}
if (node.value.id === bundle.id) {
return;
}
if (includeInline || node.value.bundleBehavior !== _types.BundleBehavior.inline) {
referencedBundles.add(node.value);
}
if (!recursive) {
actions.skipChildren();
}
},
startNodeId: this._graph.getNodeIdByContentKey(bundle.id),
getChildren: nodeId => // Shared bundles seem to depend on being used in the opposite order
// they were added.
// TODO: Should this be the case?
this._graph.getNodeIdsConnectedFrom(nodeId, bundleGraphEdgeTypes.references).reverse()
});
return [...referencedBundles];
}
getIncomingDependencies(asset) {
if (!this._graph.hasContentKey(asset.id)) {
return [];
} // Dependencies can be a a parent node via an untyped edge (like in the AssetGraph but without AssetGroups)
// or they can be parent nodes via a 'references' edge
return this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey(asset.id), // $FlowFixMe
_graph().ALL_EDGE_TYPES).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).filter(n => n.type === 'dependency').map(n => {
(0, _assert().default)(n.type === 'dependency');
return n.value;
});
}
getAssetWithDependency(dep) {
if (!this._graph.hasContentKey(dep.id)) {
return null;
}
let res = this._graph.getNodeIdsConnectedTo(this._graph.getNodeIdByContentKey(dep.id));
(0, _assert().default)(res.length <= 1, 'Expected a single asset to be connected to a dependency');
let resNode = this._graph.getNode(res[0]);
if ((resNode === null || resNode === void 0 ? void 0 : resNode.type) === 'asset') {
return resNode.value;
}
}
bundleHasAsset(bundle, asset) {
let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
let assetNodeId = this._graph.getNodeIdByContentKey(asset.id);
return this._graph.hasEdge(bundleNodeId, assetNodeId, bundleGraphEdgeTypes.contains);
}
bundleHasDependency(bundle, dependency) {
let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
let dependencyNodeId = this._graph.getNodeIdByContentKey(dependency.id);
return this._graph.hasEdge(bundleNodeId, dependencyNodeId, bundleGraphEdgeTypes.contains);
}
filteredTraverse(bundleNodeId, filter, visit) {
return this._graph.filteredTraverse(filter, visit, bundleNodeId);
}
getSymbolResolution(asset, symbol, boundary) {
var _asset$symbols, _asset$symbols$get;
let assetOutside = boundary && !this.bundleHasAsset(boundary, asset);
let identifier = (_asset$symbols = asset.symbols) === null || _asset$symbols === void 0 ? void 0 : (_asset$symbols$get = _asset$symbols.get(symbol)) === null || _asset$symbols$get === void 0 ? void 0 : _asset$symbols$get.local;
if (symbol === '*') {
var _asset$symbols2, _asset$symbols2$get;
return {
asset,
exportSymbol: '*',
symbol: identifier !== null && identifier !== void 0 ? identifier : null,
loc: (_asset$symbols2 = asset.symbols) === null || _asset$symbols2 === void 0 ? void 0 : (_asset$symbols2$get = _asset$symbols2.get(symbol)) === null || _asset$symbols2$get === void 0 ? void 0 : _asset$symbols2$get.loc
};
}
let found = false;
let skipped = false;
let deps = this.getDependencies(asset).reverse();
let potentialResults = [];
for (let dep of deps) {
var _depSymbols$get;
let depSymbols = dep.symbols;
if (!depSymbols) {
found = true;
continue;
} // If this is a re-export, find the original module.
let symbolLookup = new Map([...depSymbols].map(([key, val]) => [val.local, key]));
let depSymbol = symbolLookup.get(identifier);
if (depSymbol != null) {
let resolved = this.getResolvedAsset(dep);
if (!resolved || resolved.id === asset.id) {
var _asset$symbols3, _asset$symbols3$get;
// External module or self-reference
return {
asset,
exportSymbol: symbol,
symbol: identifier,
loc: (_asset$symbols3 = asset.symbols) === null || _asset$symbols3 === void 0 ? void 0 : (_asset$symbols3$get = _asset$symbols3.get(symbol)) === null || _asset$symbols3$get === void 0 ? void 0 : _asset$symbols3$get.loc
};
}
if (assetOutside) {
// We found the symbol, but `asset` is outside, return `asset` and the original symbol
found = true;
break;
}
if (this.isDependencySkipped(dep)) {
// We found the symbol and `dep` was skipped
skipped = true;
break;
}
let {
asset: resolvedAsset,
symbol: resolvedSymbol,
exportSymbol,
loc
} = this.getSymbolResolution(resolved, depSymbol, boundary);
if (!loc) {
var _asset$symbols4, _asset$symbols4$get;
// Remember how we got there
loc = (_asset$symbols4 = asset.symbols) === null || _asset$symbols4 === void 0 ? void 0 : (_asset$symbols4$get = _asset$symbols4.get(symbol)) === null || _asset$symbols4$get === void 0 ? void 0 : _asset$symbols4$get.loc;
}
return {
asset: resolvedAsset,
symbol: resolvedSymbol,
exportSymbol,
loc
};
} // If this module exports wildcards, resolve the original module.
// Default exports are excluded from wildcard exports.
// Wildcard reexports are never listed in the reexporting asset's symbols.
if (identifier == null && ((_depSymbols$get = depSymbols.get('*')) === null || _depSymbols$get === void 0 ? void 0 : _depSymbols$get.local) === '*' && symbol !== 'default') {
let resolved = this.getResolvedAsset(dep);
if (!resolved) {
continue;
}
let result = this.getSymbolResolution(resolved, symbol, boundary); // We found the symbol
if (result.symbol != undefined) {
var _resolved$symbols, _resolved$symbols$get;
if (assetOutside) {
// ..., but `asset` is outside, return `asset` and the original symbol
found = true;
break;
}
if (this.isDependencySkipped(dep)) {
// We found the symbol and `dep` was skipped
skipped = true;
break;
}
return {
asset: result.asset,
symbol: result.symbol,
exportSymbol: result.exportSymbol,
loc: (_resolved$symbols = resolved.symbols) === null || _resolved$symbols === void 0 ? void 0 : (_resolved$symbols$get = _resolved$symbols.get(symbol)) === null || _resolved$symbols$get === void 0 ? void 0 : _resolved$symbols$get.loc
};
}
if (result.symbol === null) {
found = true;
if (boundary && !this.bundleHasAsset(boundary, result.asset)) {
// If the returned asset is outside (and it's the first asset that is outside), return it.
if (!assetOutside) {
var _resolved$symbols2, _resolved$symbols2$ge;
return {
asset: result.asset,
symbol: result.symbol,
exportSymbol: result.exportSymbol,
loc: (_resolved$symbols2 = resolved.symbols) === null || _resolved$symbols2 === void 0 ? void 0 : (_resolved$symbols2$ge = _resolved$symbols2.get(symbol)) === null || _resolved$symbols2$ge === void 0 ? void 0 : _resolved$symbols2$ge.loc
};
} else {
// Otherwise the original asset will be returned at the end.
break;
}
} else {
var _resolved$symbols3, _resolved$symbols3$ge;
// We didn't find it in this dependency, but it might still be there: bailout.
// Continue searching though, with the assumption that there are no conficting reexports
// and there might be a another (re)export (where we might statically find the symbol).
potentialResults.push({
asset: result.asset,
symbol: result.symbol,
exportSymbol: result.exportSymbol,
loc: (_resolved$symbols3 = resolved.symbols) === null || _resolved$symbols3 === void 0 ? void 0 : (_resolved$symbols3$ge = _resolved$symbols3.get(symbol)) === null || _resolved$symbols3$ge === void 0 ? void 0 : _resolved$symbols3$ge.loc
});
}
}
}
} // We didn't find the exact symbol...
if (potentialResults.length == 1) {
// ..., but if it does exist, it has to be behind this one reexport.
return potentialResults[0];
} else {
var _asset$symbols5, _asset$symbols6, _asset$symbols6$get;
// ... and there is no single reexport, but `bailout` tells us if it might still be exported.
return {
asset,
exportSymbol: symbol,
symbol: skipped ? false : found ? null : identifier !== null && identifier !== void 0 ? identifier : (_asset$symbols5 = asset.symbols) !== null && _asset$symbols5 !== void 0 && _asset$symbols5.has('*') ? null : undefined,
loc: (_asset$symbols6 = asset.symbols) === null || _asset$symbols6 === void 0 ? void 0 : (_asset$symbols6$get = _asset$symbols6.get(symbol)) === null || _asset$symbols6$get === void 0 ? void 0 : _asset$symbols6$get.loc
};
}
}
getAssetById(contentKey) {
let node = this._graph.getNodeByContentKey(contentKey);
if (node == null) {
throw new Error('Node not found');
} else if (node.type !== 'asset') {
throw new Error('Node was not an asset');
}
return node.value;
}
getAssetPublicId(asset) {
let publicId = this._publicIdByAssetId.get(asset.id);
if (publicId == null) {
throw new Error("Asset or it's public id not found");
}
return publicId;
}
getExportedSymbols(asset, boundary) {
if (!asset.symbols) {
return [];
}
let symbols = [];
for (let symbol of asset.symbols.keys()) {
symbols.push({ ...this.getSymbolResolution(asset, symbol, boundary),
exportAs: symbol
});
}
let deps = this.getDependencies(asset);
for (let dep of deps) {
var _depSymbols$get2;
let depSymbols = dep.symbols;
if (!depSymbols) continue;
if (((_depSymbols$get2 = depSymbols.get('*')) === null || _depSymbols$get2 === void 0 ? void 0 : _depSymbols$get2.local) === '*') {
let resolved = this.getResolvedAsset(dep);
if (!resolved) continue;
let exported = this.getExportedSymbols(resolved, boundary).filter(s => s.exportSymbol !== 'default').map(s => ({ ...s,
exportAs: s.exportSymbol
}));
symbols.push(...exported);
}
}
return symbols;
}
getContentHash(bundle) {
let existingHash = this._bundleContentHashes.get(bundle.id);
if (existingHash != null) {
return existingHash;
}
let hash = new (_hash().Hash)(); // TODO: sort??
this.traverseAssets(bundle, asset => {
{
hash.writeString([this.getAssetPublicId(asset), asset.outputHash, asset.filePath, asset.query, asset.type, asset.uniqueKey].join(':'));
}
});
let hashHex = hash.finish();
this._bundleContentHashes.set(bundle.id, hashHex);
return hashHex;
}
getInlineBundles(bundle) {
let bundles = [];
let seen = new Set();
let addReferencedBundles = bundle => {
if (seen.has(bundle.id)) {
return;
}
seen.add(bundle.id);
let referencedBundles = this.getReferencedBundles(bundle, {
includeInline: true
});
for (let referenced of referencedBundles) {
if (referenced.bundleBehavior === _types.BundleBehavior.inline) {
bundles.push(referenced);
addReferencedBundles(referenced);
}
}
};
addReferencedBundles(bundle);
this.traverseBundles((childBundle, _, traversal) => {
if (childBundle.bundleBehavior === _types.BundleBehavior.inline) {
bundles.push(childBundle);
} else if (childBundle.id !== bundle.id) {
traversal.skipChildren();
}
}, bundle);
return bundles;
}
getHash(bundle) {
let hash = new (_hash().Hash)();
hash.writeString(bundle.id + bundle.target.publicUrl + this.getContentHash(bundle));
let inlineBundles = this.getInlineBundles(bundle);
for (let inlineBundle of inlineBundles) {
hash.writeString(this.getContentHash(inlineBundle));
}
for (let referencedBundle of this.getReferencedBundles(bundle)) {
hash.writeString(referencedBundle.id);
}
hash.writeString(JSON.stringify((0, _utils().objectSortedEntriesDeep)(bundle.env)));
return hash.finish();
}
getBundleGraphHash() {
let hashes = '';
for (let bundle of this.getBundles()) {
hashes += this.getHash(bundle);
}
return (0, _hash().hashString)(hashes);
}
addBundleToBundleGroup(bundle, bundleGroup) {
let bundleGroupNodeId = this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup));
let bundleNodeId = this._graph.getNodeIdByContentKey(bundle.id);
if (this._graph.hasEdge(bundleGroupNodeId, bundleNodeId, bundleGraphEdgeTypes.bundle)) {
// Bundle group already has bundle
return;
}
this._graph.addEdge(bundleGroupNodeId, bundleNodeId);
this._graph.addEdge(bundleGroupNodeId, bundleNodeId, bundleGraphEdgeTypes.bundle);
for (let entryAssetId of bundle.entryAssetIds) {
let entryAssetNodeId = this._graph.getNodeIdByContentKey(entryAssetId);
if (this._graph.hasEdge(bundleGroupNodeId, entryAssetNodeId)) {
this._graph.removeEdge(bundleGroupNodeId, entryAssetNodeId);
}
}
}
getUsedSymbolsAsset(asset) {
let node = this._graph.getNodeByContentKey(asset.id);
(0, _assert().default)(node && node.type === 'asset');
return this._symbolPropagationRan ? makeReadOnlySet(node.usedSymbols) : null;
}
getUsedSymbolsDependency(dep) {
let node = this._graph.getNodeByContentKey(dep.id);
(0, _assert().default)(node && node.type === 'dependency');
return this._symbolPropagationRan ? makeReadOnlySet(node.usedSymbolsUp) : null;
}
merge(other) {
let otherGraphIdToThisNodeId = new Map();
for (let [otherNodeId, otherNode] of other._graph.nodes) {
if (this._graph.hasContentKey(otherNode.id)) {
let existingNodeId = this._graph.getNodeIdByContentKey(otherNode.id);
otherGraphIdToThisNodeId.set(otherNodeId, existingNodeId);
let existingNode = (0, _nullthrows().default)(this._graph.getNode(existingNodeId)); // Merge symbols, recompute dep.exluded based on that
if (existingNode.type === 'asset') {
(0, _assert().default)(otherNode.type === 'asset');
existingNode.usedSymbols = new Set([...existingNode.usedSymbols, ...otherNode.usedSymbols]);
} else if (existingNode.type === 'dependency') {
(0, _assert().default)(otherNode.type === 'dependency');
existingNode.usedSymbolsDown = new Set([...existingNode.usedSymbolsDown, ...otherNode.usedSymbolsDown]);
existingNode.usedSymbolsUp = new Set([...existingNode.usedSymbolsUp, ...otherNode.usedSymbolsUp]);
existingNode.excluded = (existingNode.excluded || Boolean(existingNode.hasDeferred)) && (otherNode.excluded || Boolean(otherNode.hasDeferred));
}
} else {
let updateNodeId = this._graph.addNodeByContentKey(otherNode.id, otherNode);
otherGraphIdToThisNodeId.set(otherNodeId, updateNodeId);
}
}
for (let edge of other._graph.getAllEdges()) {
this._graph.addEdge((0, _nullthrows().default)(otherGraphIdToThisNodeId.get(edge.from)), (0, _nullthrows().default)(otherGraphIdToThisNodeId.get(edge.to)), edge.type);
}
}
isEntryBundleGroup(bundleGroup) {
return this._graph.getNodeIdsConnectedTo((0, _nullthrows().default)(this._graph.getNodeIdByContentKey((0, _utils2.getBundleGroupId)(bundleGroup))), bundleGraphEdgeTypes.bundle).map(id => (0, _nullthrows().default)(this._graph.getNode(id))).some(n => n.type === 'root');
}
getEntryRoot(projectRoot, target) {
let cached = this._targetEntryRoots.get(target.distDir);
if (cached != null) {
return cached;
}
let entryBundleGroupIds = this._graph.getNodeIdsConnectedFrom((0, _nullthrows().default)(this._graph.rootNodeId), bundleGraphEdgeTypes.bundle);
let entries = [];
for (let bundleGroupId of entryBundleGroupIds) {
let bundleGroupNode = this._graph.getNode(bundleGroupId);
(0, _assert().default)((bundleGroupNode === null || bundleGroupNode === void 0 ? void 0 : bundleGroupNode.type) === 'bundle_group');
if (bundleGroupNode.value.target.distDir === target.distDir) {
let entryAssetNode = this._graph.getNodeByContentKey(bundleGroupNode.value.entryAssetId);
(0, _assert().default)((entryAssetNode === null || entryAssetNode === void 0 ? void 0 : entryAssetNode.type) === 'asset');
entries.push((0, _projectPath.fromProjectPath)(projectRoot, entryAssetNode.value.filePath));
}
}
let root = (0, _utils().getRootDir)(entries);
this._targetEntryRoots.set(target.distDir, root);
return root;
}
}
exports.default = BundleGraph;