From 76bc83b7248ff626a2d7882572865a5cbae7fe6e Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Mon, 17 Oct 2022 10:41:14 +1100 Subject: [PATCH 01/12] Support multiple edge types in Graph.hasEdge --- packages/core/graph/src/AdjacencyList.js | 43 ++++++++++++++++--- packages/core/graph/src/Graph.js | 6 ++- .../core/graph/test/AdjacencyList.test.js | 31 +++++++++++++ 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/packages/core/graph/src/AdjacencyList.js b/packages/core/graph/src/AdjacencyList.js index d68b2463f6a..a99692d06f0 100644 --- a/packages/core/graph/src/AdjacencyList.js +++ b/packages/core/graph/src/AdjacencyList.js @@ -18,6 +18,7 @@ opaque type EdgeAddress = number; export type SerializedAdjacencyList = {| nodes: Uint32Array, edges: Uint32Array, + edgeTypes: Uint8Array, |}; // eslint-disable-next-line no-unused-vars @@ -40,6 +41,7 @@ const SHRINK_FACTOR = 0.5; export default class AdjacencyList { #nodes /*: NodeTypeMap */; #edges /*: EdgeTypeMap */; + #edgeTypes /* Uint8Array */; constructor( opts?: @@ -48,11 +50,13 @@ export default class AdjacencyList { ) { let nodes; let edges; + let edgeTypes; if (opts?.nodes) { - ({nodes, edges} = opts); + ({nodes, edges, edgeTypes} = opts); this.#nodes = new NodeTypeMap(nodes); this.#edges = new EdgeTypeMap(edges); + this.#edgeTypes = edgeTypes; } else { let { nodeCapacity = NodeTypeMap.MIN_CAPACITY, @@ -68,6 +72,7 @@ export default class AdjacencyList { ); this.#nodes = new NodeTypeMap(nodeCapacity); this.#edges = new EdgeTypeMap(edgeCapacity); + this.#edgeTypes = new Uint8Array(0); } } @@ -87,6 +92,7 @@ export default class AdjacencyList { return { nodes: this.#nodes.data, edges: this.#edges.data, + edgeTypes: this.#edgeTypes, }; } @@ -254,6 +260,10 @@ export default class AdjacencyList { // The edge is already in the graph; do nothing. if (edge !== null) return false; + if (!this.#edgeTypes.includes(type)) { + this.#edgeTypes = new Uint8Array([...this.#edgeTypes, type]); + } + let capacity = this.#edges.capacity; // We add 1 to account for the edge we are adding. let count = this.#edges.count + 1; @@ -329,10 +339,33 @@ export default class AdjacencyList { hasEdge( from: NodeId, to: NodeId, - type: TEdgeType | NullEdgeType = 1, + type: + | AllEdgeTypes + | TEdgeType + | NullEdgeType + | Array = 1, ): boolean { - let hash = this.#edges.hash(from, to, type); - return this.#edges.addressOf(hash, from, to, type) !== null; + let hasEdge = (type: TEdgeType | NullEdgeType) => { + let hash = this.#edges.hash(from, to, type); + return this.#edges.addressOf(hash, from, to, type) !== null; + }; + + if (type === ALL_EDGE_TYPES || Array.isArray(type)) { + let types: Iterable = + // $FlowFixMe[incompatible-type-arg] edgeTypes will only contain valid edge types + Array.isArray(type) ? type : this.#edgeTypes; + + for (let currType of types) { + if (hasEdge(currType)) { + return true; + } + } + + return false; + } + + // $FlowFixMe[incompatible-call] ALL_EDGE_TYPES has already been handled + return hasEdge(type); } /** @@ -1076,7 +1109,7 @@ export class EdgeTypeMap extends SharedTypeMap< hash: EdgeHash, from: NodeId, to: NodeId, - type: TEdgeType, + type: TEdgeType | NullEdgeType, ): EdgeAddress | null { let address = this.head(hash); while (address !== null) { diff --git a/packages/core/graph/src/Graph.js b/packages/core/graph/src/Graph.js index 31faaf3b7a1..6aa41fee135 100644 --- a/packages/core/graph/src/Graph.js +++ b/packages/core/graph/src/Graph.js @@ -104,7 +104,11 @@ export default class Graph { hasEdge( from: NodeId, to: NodeId, - type?: TEdgeType | NullEdgeType = 1, + type?: + | TEdgeType + | NullEdgeType + | Array + | AllEdgeTypes = 1, ): boolean { return this.adjacencyList.hasEdge(from, to, type); } diff --git a/packages/core/graph/test/AdjacencyList.test.js b/packages/core/graph/test/AdjacencyList.test.js index 32108771f98..a6ef16bedeb 100644 --- a/packages/core/graph/test/AdjacencyList.test.js +++ b/packages/core/graph/test/AdjacencyList.test.js @@ -5,6 +5,7 @@ import path from 'path'; import {Worker} from 'worker_threads'; import AdjacencyList, {NodeTypeMap, EdgeTypeMap} from '../src/AdjacencyList'; +import {ALL_EDGE_TYPES} from '../src/Graph'; import {toNodeId} from '../src/types'; describe('AdjacencyList', () => { @@ -243,6 +244,36 @@ describe('AdjacencyList', () => { AdjacencyList.prototype.hash = originalHash; }); + it('hasEdge should accept "ALL_EDGE_TYPES"', () => { + let graph = new AdjacencyList(); + let a = graph.addNode(); + let b = graph.addNode(); + let c = graph.addNode(); + + graph.addEdge(a, b, 1); + graph.addEdge(b, c, 2); + + assert.ok(!graph.hasEdge(a, b, 2)); + assert.ok(graph.hasEdge(a, b, ALL_EDGE_TYPES)); + assert.ok(!graph.hasEdge(b, c, 1)); + assert.ok(graph.hasEdge(b, c, ALL_EDGE_TYPES)); + }); + + it('hasEdge should accept an array of edge types', () => { + let graph = new AdjacencyList(); + let a = graph.addNode(); + let b = graph.addNode(); + let c = graph.addNode(); + + graph.addEdge(a, b, 1); + graph.addEdge(b, c, 2); + + assert.ok(!graph.hasEdge(a, b, [2, 3])); + assert.ok(graph.hasEdge(a, b, [1, 2])); + assert.ok(!graph.hasEdge(b, c, [1, 3])); + assert.ok(graph.hasEdge(b, c, [2, 3])); + }); + describe('deserialize', function () { this.timeout(10000); From c917e81b01329c669529542842cb61df1ecd79b4 Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Mon, 17 Oct 2022 10:43:50 +1100 Subject: [PATCH 02/12] Update comment --- packages/core/graph/src/AdjacencyList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/graph/src/AdjacencyList.js b/packages/core/graph/src/AdjacencyList.js index a99692d06f0..2b6155803d8 100644 --- a/packages/core/graph/src/AdjacencyList.js +++ b/packages/core/graph/src/AdjacencyList.js @@ -352,7 +352,7 @@ export default class AdjacencyList { if (type === ALL_EDGE_TYPES || Array.isArray(type)) { let types: Iterable = - // $FlowFixMe[incompatible-type-arg] edgeTypes will only contain valid edge types + // $FlowFixMe[incompatible-type-arg] this.edgeTypes will only contain valid edge types Array.isArray(type) ? type : this.#edgeTypes; for (let currType of types) { From 380123835fe86aef1bf5c86ca75a42b786985e8c Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Tue, 18 Oct 2022 12:04:02 +1100 Subject: [PATCH 03/12] Pass known edge types into Graphs --- .../experimental/src/ExperimentalBundler.js | 4 +- packages/core/core/src/AssetGraph.js | 6 ++- packages/core/core/src/BundleGraph.js | 6 ++- packages/core/core/src/RequestTracker.js | 39 +++++++++++++------ packages/core/graph/src/AdjacencyList.js | 11 +++--- packages/core/graph/src/ContentGraph.js | 24 ++++++++---- packages/core/graph/src/Graph.js | 20 ++++++++-- .../core/graph/test/AdjacencyList.test.js | 2 +- 8 files changed, 78 insertions(+), 34 deletions(-) diff --git a/packages/bundlers/experimental/src/ExperimentalBundler.js b/packages/bundlers/experimental/src/ExperimentalBundler.js index b5c10a830f8..3f0acf05c46 100644 --- a/packages/bundlers/experimental/src/ExperimentalBundler.js +++ b/packages/bundlers/experimental/src/ExperimentalBundler.js @@ -329,7 +329,9 @@ function createIdealGraph( let bundleRootGraph: ContentGraph< BundleRoot | 'root', $Values, - > = new ContentGraph(); + > = new ContentGraph({ + edgeTypes: dependencyPriorityEdges, + }); let bundleGroupBundleIds: Set = new Set(); diff --git a/packages/core/core/src/AssetGraph.js b/packages/core/core/src/AssetGraph.js index 534d7f0b263..7f56c59d1b6 100644 --- a/packages/core/core/src/AssetGraph.js +++ b/packages/core/core/src/AssetGraph.js @@ -136,8 +136,10 @@ export default class AssetGraph extends ContentGraph { } // $FlowFixMe[prop-missing] - static deserialize(opts: AssetGraphOpts): AssetGraph { - return new AssetGraph(opts); + static deserialize(opts: SerializedAssetGraph): AssetGraph { + return new AssetGraph({ + ...opts, + }); } // $FlowFixMe[prop-missing] diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index 04dfabbd4bc..e1539e2cbb5 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -146,7 +146,9 @@ export default class BundleGraph { publicIdByAssetId: Map = new Map(), assetPublicIds: Set = new Set(), ): BundleGraph { - let graph = new ContentGraph(); + let graph = new ContentGraph({ + edgeTypes: bundleGraphEdgeTypes, + }); let assetGroupIds = new Map(); let dependencies = new Map(); let assetGraphNodeIdToBundleGraphNodeId = new Map(); @@ -362,7 +364,7 @@ export default class BundleGraph { }; } - static deserialize(serialized: BundleGraphOpts): BundleGraph { + static deserialize(serialized: SerializedBundleGraph): BundleGraph { return new BundleGraph({ graph: ContentGraph.deserialize(serialized.graph), assetPublicIds: serialized.assetPublicIds, diff --git a/packages/core/core/src/RequestTracker.js b/packages/core/core/src/RequestTracker.js index 08e5c73b453..1c73ce2ed99 100644 --- a/packages/core/core/src/RequestTracker.js +++ b/packages/core/core/src/RequestTracker.js @@ -221,18 +221,35 @@ export class RequestGraph extends ContentGraph< unpredicatableNodeIds: Set = new Set(); invalidateOnBuildNodeIds: Set = new Set(); + constructor(opts?: SerializedRequestGraph) { + if (opts) { + let { + invalidNodeIds, + incompleteNodeIds, + globNodeIds, + envNodeIds, + optionNodeIds, + unpredicatableNodeIds, + invalidateOnBuildNodeIds, + ...rest + } = opts; + super({edgeTypes: requestGraphEdgeTypes, ...rest}); + + this.invalidNodeIds = invalidNodeIds; + this.incompleteNodeIds = incompleteNodeIds; + this.globNodeIds = globNodeIds; + this.envNodeIds = envNodeIds; + this.optionNodeIds = optionNodeIds; + this.unpredicatableNodeIds = unpredicatableNodeIds; + this.invalidateOnBuildNodeIds = invalidateOnBuildNodeIds; + } else { + super({edgeTypes: requestGraphEdgeTypes}); + } + } + // $FlowFixMe[prop-missing] - static deserialize(opts: RequestGraphOpts): RequestGraph { - // $FlowFixMe[prop-missing] - let deserialized = new RequestGraph(opts); - deserialized.invalidNodeIds = opts.invalidNodeIds; - deserialized.incompleteNodeIds = opts.incompleteNodeIds; - deserialized.globNodeIds = opts.globNodeIds; - deserialized.envNodeIds = opts.envNodeIds; - deserialized.optionNodeIds = opts.optionNodeIds; - deserialized.unpredicatableNodeIds = opts.unpredicatableNodeIds; - deserialized.invalidateOnBuildNodeIds = opts.invalidateOnBuildNodeIds; - return deserialized; + static deserialize(opts: SerializedRequestGraph): RequestGraph { + return new RequestGraph(opts); } // $FlowFixMe[prop-missing] diff --git a/packages/core/graph/src/AdjacencyList.js b/packages/core/graph/src/AdjacencyList.js index 2b6155803d8..a06ff77b095 100644 --- a/packages/core/graph/src/AdjacencyList.js +++ b/packages/core/graph/src/AdjacencyList.js @@ -25,6 +25,7 @@ export type SerializedAdjacencyList = {| export type AdjacencyListOptions = {| edgeCapacity?: number, nodeCapacity?: number, + edgeTypes: Uint8Array, |}; /** The upper bound above which capacity should be increased. */ @@ -41,7 +42,7 @@ const SHRINK_FACTOR = 0.5; export default class AdjacencyList { #nodes /*: NodeTypeMap */; #edges /*: EdgeTypeMap */; - #edgeTypes /* Uint8Array */; + #edgeTypes /*: Uint8Array */; constructor( opts?: @@ -61,6 +62,7 @@ export default class AdjacencyList { let { nodeCapacity = NodeTypeMap.MIN_CAPACITY, edgeCapacity = EdgeTypeMap.MIN_CAPACITY, + edgeTypes, } = opts ?? {}; assert( nodeCapacity <= NodeTypeMap.MAX_CAPACITY, @@ -72,7 +74,7 @@ export default class AdjacencyList { ); this.#nodes = new NodeTypeMap(nodeCapacity); this.#edges = new EdgeTypeMap(edgeCapacity); - this.#edgeTypes = new Uint8Array(0); + this.#edgeTypes = edgeTypes; } } @@ -201,6 +203,7 @@ export default class AdjacencyList { let copy = new AdjacencyList({ nodeCapacity: this.#nodes.capacity, edgeCapacity: size, + edgeTypes: this.#edgeTypes, }); // Copy the existing edges into the new array. @@ -260,10 +263,6 @@ export default class AdjacencyList { // The edge is already in the graph; do nothing. if (edge !== null) return false; - if (!this.#edgeTypes.includes(type)) { - this.#edgeTypes = new Uint8Array([...this.#edgeTypes, type]); - } - let capacity = this.#edges.capacity; // We add 1 to account for the edge we are adding. let count = this.#edges.count + 1; diff --git a/packages/core/graph/src/ContentGraph.js b/packages/core/graph/src/ContentGraph.js index f9b3ce33535..c71669f711a 100644 --- a/packages/core/graph/src/ContentGraph.js +++ b/packages/core/graph/src/ContentGraph.js @@ -6,12 +6,13 @@ import nullthrows from 'nullthrows'; export type ContentGraphOpts = {| ...GraphOpts, - _contentKeyToNodeId: Map, - _nodeIdToContentKey: Map, + _contentKeyToNodeId?: Map, + _nodeIdToContentKey?: Map, |}; export type SerializedContentGraph = {| ...SerializedGraph, _contentKeyToNodeId: Map, + _nodeIdToContentKey: Map, |}; export default class ContentGraph extends Graph< @@ -23,12 +24,16 @@ export default class ContentGraph extends Graph< constructor(opts: ?ContentGraphOpts) { if (opts) { - let {_contentKeyToNodeId, _nodeIdToContentKey, ...rest} = opts; + let { + _contentKeyToNodeId = new Map(), + _nodeIdToContentKey = new Map(), + ...rest + } = opts; super(rest); this._contentKeyToNodeId = _contentKeyToNodeId; this._nodeIdToContentKey = _nodeIdToContentKey; } else { - super(); + super(opts); this._contentKeyToNodeId = new Map(); this._nodeIdToContentKey = new Map(); } @@ -36,14 +41,19 @@ export default class ContentGraph extends Graph< // $FlowFixMe[prop-missing] static deserialize( - opts: ContentGraphOpts, + opts: SerializedContentGraph, ): ContentGraph { - return new ContentGraph(opts); + return new ContentGraph({ + nodes: opts.nodes, + adjacencyList: opts.adjacencyList, + rootNodeId: opts.rootNodeId, + _contentKeyToNodeId: opts._contentKeyToNodeId, + _nodeIdToContentKey: opts._nodeIdToContentKey, + }); } // $FlowFixMe[prop-missing] serialize(): SerializedContentGraph { - // $FlowFixMe[prop-missing] return { ...super.serialize(), _contentKeyToNodeId: this._contentKeyToNodeId, diff --git a/packages/core/graph/src/Graph.js b/packages/core/graph/src/Graph.js index 6aa41fee135..e10458a4db7 100644 --- a/packages/core/graph/src/Graph.js +++ b/packages/core/graph/src/Graph.js @@ -13,6 +13,7 @@ export type GraphOpts = {| nodes?: Map, adjacencyList?: SerializedAdjacencyList, rootNodeId?: ?NodeId, + edgeTypes?: {[key: string]: TEdgeType}, |}; export type SerializedGraph = {| @@ -24,6 +25,10 @@ export type SerializedGraph = {| export type AllEdgeTypes = -1; export const ALL_EDGE_TYPES: AllEdgeTypes = -1; +function objectValues(obj: {[Key]: Value}): Array { + return Object.keys(obj).map(key => obj[key]); +} + export default class Graph { nodes: Map; adjacencyList: AdjacencyList; @@ -34,9 +39,16 @@ export default class Graph { this.setRootNodeId(opts?.rootNodeId); let adjacencyList = opts?.adjacencyList; - this.adjacencyList = adjacencyList - ? AdjacencyList.deserialize(adjacencyList) - : new AdjacencyList(); + + if (adjacencyList) { + this.adjacencyList = AdjacencyList.deserialize(adjacencyList); + } else { + // default edgeTypes to array containing just the null edge type + let edgeTypes = new Uint8Array( + opts?.edgeTypes ? objectValues(opts.edgeTypes) : [1], + ); + this.adjacencyList = new AdjacencyList({edgeTypes}); + } } setRootNodeId(id: ?NodeId) { @@ -44,7 +56,7 @@ export default class Graph { } static deserialize( - opts: GraphOpts, + opts: SerializedGraph, ): Graph { return new this({ nodes: opts.nodes, diff --git a/packages/core/graph/test/AdjacencyList.test.js b/packages/core/graph/test/AdjacencyList.test.js index a6ef16bedeb..6d214f9a4a2 100644 --- a/packages/core/graph/test/AdjacencyList.test.js +++ b/packages/core/graph/test/AdjacencyList.test.js @@ -245,7 +245,7 @@ describe('AdjacencyList', () => { }); it('hasEdge should accept "ALL_EDGE_TYPES"', () => { - let graph = new AdjacencyList(); + let graph = new AdjacencyList({edgeTypes: new Uint8Array([1, 2])}); let a = graph.addNode(); let b = graph.addNode(); let c = graph.addNode(); From d1f499b69f433500968800ff24bb609cff47e73c Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Tue, 18 Oct 2022 12:08:06 +1100 Subject: [PATCH 04/12] Remove unused type --- packages/core/core/src/BundleGraph.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index e1539e2cbb5..672b10b3c8e 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -78,14 +78,6 @@ type InternalExportSymbolResolution = {| +exportAs: Symbol | string, |}; -type BundleGraphOpts = {| - graph: ContentGraphOpts, - bundleContentHashes: Map, - assetPublicIds: Set, - publicIdByAssetId: Map, - symbolPropagationRan: boolean, -|}; - type SerializedBundleGraph = {| $$raw: true, graph: SerializedContentGraph, From dbefda4ef13fa1d86d32769497ab3f4ec065b466 Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Tue, 18 Oct 2022 12:08:44 +1100 Subject: [PATCH 05/12] Remove unused type --- packages/core/core/src/RequestTracker.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/core/core/src/RequestTracker.js b/packages/core/core/src/RequestTracker.js index 1c73ce2ed99..b20543aec49 100644 --- a/packages/core/core/src/RequestTracker.js +++ b/packages/core/core/src/RequestTracker.js @@ -62,17 +62,6 @@ export const requestGraphEdgeTypes = { export type RequestGraphEdgeType = $Values; -type RequestGraphOpts = {| - ...ContentGraphOpts, - invalidNodeIds: Set, - incompleteNodeIds: Set, - globNodeIds: Set, - envNodeIds: Set, - optionNodeIds: Set, - unpredicatableNodeIds: Set, - invalidateOnBuildNodeIds: Set, -|}; - type SerializedRequestGraph = {| ...SerializedContentGraph, invalidNodeIds: Set, From 9c7d67d891bba849b5c5173b7300eb1f4b9900f7 Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Tue, 18 Oct 2022 13:40:05 +1100 Subject: [PATCH 06/12] Fix lint --- packages/core/core/src/BundleGraph.js | 7 +------ packages/core/core/src/RequestTracker.js | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index 672b10b3c8e..85010b0b267 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -6,12 +6,7 @@ import type { Symbol, TraversalActions, } from '@parcel/types'; -import type { - ContentKey, - ContentGraphOpts, - NodeId, - SerializedContentGraph, -} from '@parcel/graph'; +import type {ContentKey, NodeId, SerializedContentGraph} from '@parcel/graph'; import type { Asset, diff --git a/packages/core/core/src/RequestTracker.js b/packages/core/core/src/RequestTracker.js index b20543aec49..75780591a3a 100644 --- a/packages/core/core/src/RequestTracker.js +++ b/packages/core/core/src/RequestTracker.js @@ -4,12 +4,7 @@ import type {AbortSignal} from 'abortcontroller-polyfill/dist/cjs-ponyfill'; import type {Async, EnvMap} from '@parcel/types'; import type {EventType, Options as WatcherOptions} from '@parcel/watcher'; import type WorkerFarm from '@parcel/workers'; -import type { - ContentGraphOpts, - ContentKey, - NodeId, - SerializedContentGraph, -} from '@parcel/graph'; +import type {ContentKey, NodeId, SerializedContentGraph} from '@parcel/graph'; import type { ParcelOptions, RequestInvalidation, From b8d2db972772d5d3896070e3854d11343cf9a524 Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Wed, 19 Oct 2022 11:31:51 +1100 Subject: [PATCH 07/12] Rollback ALL_EDGE_TYPE support --- packages/core/core/src/AssetGraph.js | 6 +- packages/core/core/src/BundleGraph.js | 21 +++++-- packages/core/core/src/RequestTracker.js | 57 +++++++++---------- packages/core/graph/src/AdjacencyList.js | 34 ++--------- packages/core/graph/src/ContentGraph.js | 24 +++----- packages/core/graph/src/Graph.js | 26 ++------- .../core/graph/test/AdjacencyList.test.js | 31 ---------- 7 files changed, 63 insertions(+), 136 deletions(-) diff --git a/packages/core/core/src/AssetGraph.js b/packages/core/core/src/AssetGraph.js index 7f56c59d1b6..534d7f0b263 100644 --- a/packages/core/core/src/AssetGraph.js +++ b/packages/core/core/src/AssetGraph.js @@ -136,10 +136,8 @@ export default class AssetGraph extends ContentGraph { } // $FlowFixMe[prop-missing] - static deserialize(opts: SerializedAssetGraph): AssetGraph { - return new AssetGraph({ - ...opts, - }); + static deserialize(opts: AssetGraphOpts): AssetGraph { + return new AssetGraph(opts); } // $FlowFixMe[prop-missing] diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index 85010b0b267..04dfabbd4bc 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -6,7 +6,12 @@ import type { Symbol, TraversalActions, } from '@parcel/types'; -import type {ContentKey, NodeId, SerializedContentGraph} from '@parcel/graph'; +import type { + ContentKey, + ContentGraphOpts, + NodeId, + SerializedContentGraph, +} from '@parcel/graph'; import type { Asset, @@ -73,6 +78,14 @@ type InternalExportSymbolResolution = {| +exportAs: Symbol | string, |}; +type BundleGraphOpts = {| + graph: ContentGraphOpts, + bundleContentHashes: Map, + assetPublicIds: Set, + publicIdByAssetId: Map, + symbolPropagationRan: boolean, +|}; + type SerializedBundleGraph = {| $$raw: true, graph: SerializedContentGraph, @@ -133,9 +146,7 @@ export default class BundleGraph { publicIdByAssetId: Map = new Map(), assetPublicIds: Set = new Set(), ): BundleGraph { - let graph = new ContentGraph({ - edgeTypes: bundleGraphEdgeTypes, - }); + let graph = new ContentGraph(); let assetGroupIds = new Map(); let dependencies = new Map(); let assetGraphNodeIdToBundleGraphNodeId = new Map(); @@ -351,7 +362,7 @@ export default class BundleGraph { }; } - static deserialize(serialized: SerializedBundleGraph): BundleGraph { + static deserialize(serialized: BundleGraphOpts): BundleGraph { return new BundleGraph({ graph: ContentGraph.deserialize(serialized.graph), assetPublicIds: serialized.assetPublicIds, diff --git a/packages/core/core/src/RequestTracker.js b/packages/core/core/src/RequestTracker.js index 75780591a3a..08e5c73b453 100644 --- a/packages/core/core/src/RequestTracker.js +++ b/packages/core/core/src/RequestTracker.js @@ -4,7 +4,12 @@ import type {AbortSignal} from 'abortcontroller-polyfill/dist/cjs-ponyfill'; import type {Async, EnvMap} from '@parcel/types'; import type {EventType, Options as WatcherOptions} from '@parcel/watcher'; import type WorkerFarm from '@parcel/workers'; -import type {ContentKey, NodeId, SerializedContentGraph} from '@parcel/graph'; +import type { + ContentGraphOpts, + ContentKey, + NodeId, + SerializedContentGraph, +} from '@parcel/graph'; import type { ParcelOptions, RequestInvalidation, @@ -57,6 +62,17 @@ export const requestGraphEdgeTypes = { export type RequestGraphEdgeType = $Values; +type RequestGraphOpts = {| + ...ContentGraphOpts, + invalidNodeIds: Set, + incompleteNodeIds: Set, + globNodeIds: Set, + envNodeIds: Set, + optionNodeIds: Set, + unpredicatableNodeIds: Set, + invalidateOnBuildNodeIds: Set, +|}; + type SerializedRequestGraph = {| ...SerializedContentGraph, invalidNodeIds: Set, @@ -205,35 +221,18 @@ export class RequestGraph extends ContentGraph< unpredicatableNodeIds: Set = new Set(); invalidateOnBuildNodeIds: Set = new Set(); - constructor(opts?: SerializedRequestGraph) { - if (opts) { - let { - invalidNodeIds, - incompleteNodeIds, - globNodeIds, - envNodeIds, - optionNodeIds, - unpredicatableNodeIds, - invalidateOnBuildNodeIds, - ...rest - } = opts; - super({edgeTypes: requestGraphEdgeTypes, ...rest}); - - this.invalidNodeIds = invalidNodeIds; - this.incompleteNodeIds = incompleteNodeIds; - this.globNodeIds = globNodeIds; - this.envNodeIds = envNodeIds; - this.optionNodeIds = optionNodeIds; - this.unpredicatableNodeIds = unpredicatableNodeIds; - this.invalidateOnBuildNodeIds = invalidateOnBuildNodeIds; - } else { - super({edgeTypes: requestGraphEdgeTypes}); - } - } - // $FlowFixMe[prop-missing] - static deserialize(opts: SerializedRequestGraph): RequestGraph { - return new RequestGraph(opts); + static deserialize(opts: RequestGraphOpts): RequestGraph { + // $FlowFixMe[prop-missing] + let deserialized = new RequestGraph(opts); + deserialized.invalidNodeIds = opts.invalidNodeIds; + deserialized.incompleteNodeIds = opts.incompleteNodeIds; + deserialized.globNodeIds = opts.globNodeIds; + deserialized.envNodeIds = opts.envNodeIds; + deserialized.optionNodeIds = opts.optionNodeIds; + deserialized.unpredicatableNodeIds = opts.unpredicatableNodeIds; + deserialized.invalidateOnBuildNodeIds = opts.invalidateOnBuildNodeIds; + return deserialized; } // $FlowFixMe[prop-missing] diff --git a/packages/core/graph/src/AdjacencyList.js b/packages/core/graph/src/AdjacencyList.js index a06ff77b095..803655099ab 100644 --- a/packages/core/graph/src/AdjacencyList.js +++ b/packages/core/graph/src/AdjacencyList.js @@ -18,14 +18,12 @@ opaque type EdgeAddress = number; export type SerializedAdjacencyList = {| nodes: Uint32Array, edges: Uint32Array, - edgeTypes: Uint8Array, |}; // eslint-disable-next-line no-unused-vars export type AdjacencyListOptions = {| edgeCapacity?: number, nodeCapacity?: number, - edgeTypes: Uint8Array, |}; /** The upper bound above which capacity should be increased. */ @@ -42,7 +40,6 @@ const SHRINK_FACTOR = 0.5; export default class AdjacencyList { #nodes /*: NodeTypeMap */; #edges /*: EdgeTypeMap */; - #edgeTypes /*: Uint8Array */; constructor( opts?: @@ -51,18 +48,15 @@ export default class AdjacencyList { ) { let nodes; let edges; - let edgeTypes; if (opts?.nodes) { - ({nodes, edges, edgeTypes} = opts); + ({nodes, edges} = opts); this.#nodes = new NodeTypeMap(nodes); this.#edges = new EdgeTypeMap(edges); - this.#edgeTypes = edgeTypes; } else { let { nodeCapacity = NodeTypeMap.MIN_CAPACITY, edgeCapacity = EdgeTypeMap.MIN_CAPACITY, - edgeTypes, } = opts ?? {}; assert( nodeCapacity <= NodeTypeMap.MAX_CAPACITY, @@ -74,7 +68,6 @@ export default class AdjacencyList { ); this.#nodes = new NodeTypeMap(nodeCapacity); this.#edges = new EdgeTypeMap(edgeCapacity); - this.#edgeTypes = edgeTypes; } } @@ -94,7 +87,6 @@ export default class AdjacencyList { return { nodes: this.#nodes.data, edges: this.#edges.data, - edgeTypes: this.#edgeTypes, }; } @@ -203,7 +195,6 @@ export default class AdjacencyList { let copy = new AdjacencyList({ nodeCapacity: this.#nodes.capacity, edgeCapacity: size, - edgeTypes: this.#edgeTypes, }); // Copy the existing edges into the new array. @@ -338,32 +329,17 @@ export default class AdjacencyList { hasEdge( from: NodeId, to: NodeId, - type: - | AllEdgeTypes - | TEdgeType - | NullEdgeType - | Array = 1, + type: TEdgeType | NullEdgeType | Array = 1, ): boolean { let hasEdge = (type: TEdgeType | NullEdgeType) => { let hash = this.#edges.hash(from, to, type); return this.#edges.addressOf(hash, from, to, type) !== null; }; - if (type === ALL_EDGE_TYPES || Array.isArray(type)) { - let types: Iterable = - // $FlowFixMe[incompatible-type-arg] this.edgeTypes will only contain valid edge types - Array.isArray(type) ? type : this.#edgeTypes; - - for (let currType of types) { - if (hasEdge(currType)) { - return true; - } - } - - return false; + if (Array.isArray(type)) { + return type.some(hasEdge); } - // $FlowFixMe[incompatible-call] ALL_EDGE_TYPES has already been handled return hasEdge(type); } @@ -1108,7 +1084,7 @@ export class EdgeTypeMap extends SharedTypeMap< hash: EdgeHash, from: NodeId, to: NodeId, - type: TEdgeType | NullEdgeType, + type: TEdgeType, ): EdgeAddress | null { let address = this.head(hash); while (address !== null) { diff --git a/packages/core/graph/src/ContentGraph.js b/packages/core/graph/src/ContentGraph.js index c71669f711a..f9b3ce33535 100644 --- a/packages/core/graph/src/ContentGraph.js +++ b/packages/core/graph/src/ContentGraph.js @@ -6,13 +6,12 @@ import nullthrows from 'nullthrows'; export type ContentGraphOpts = {| ...GraphOpts, - _contentKeyToNodeId?: Map, - _nodeIdToContentKey?: Map, + _contentKeyToNodeId: Map, + _nodeIdToContentKey: Map, |}; export type SerializedContentGraph = {| ...SerializedGraph, _contentKeyToNodeId: Map, - _nodeIdToContentKey: Map, |}; export default class ContentGraph extends Graph< @@ -24,16 +23,12 @@ export default class ContentGraph extends Graph< constructor(opts: ?ContentGraphOpts) { if (opts) { - let { - _contentKeyToNodeId = new Map(), - _nodeIdToContentKey = new Map(), - ...rest - } = opts; + let {_contentKeyToNodeId, _nodeIdToContentKey, ...rest} = opts; super(rest); this._contentKeyToNodeId = _contentKeyToNodeId; this._nodeIdToContentKey = _nodeIdToContentKey; } else { - super(opts); + super(); this._contentKeyToNodeId = new Map(); this._nodeIdToContentKey = new Map(); } @@ -41,19 +36,14 @@ export default class ContentGraph extends Graph< // $FlowFixMe[prop-missing] static deserialize( - opts: SerializedContentGraph, + opts: ContentGraphOpts, ): ContentGraph { - return new ContentGraph({ - nodes: opts.nodes, - adjacencyList: opts.adjacencyList, - rootNodeId: opts.rootNodeId, - _contentKeyToNodeId: opts._contentKeyToNodeId, - _nodeIdToContentKey: opts._nodeIdToContentKey, - }); + return new ContentGraph(opts); } // $FlowFixMe[prop-missing] serialize(): SerializedContentGraph { + // $FlowFixMe[prop-missing] return { ...super.serialize(), _contentKeyToNodeId: this._contentKeyToNodeId, diff --git a/packages/core/graph/src/Graph.js b/packages/core/graph/src/Graph.js index e10458a4db7..31faaf3b7a1 100644 --- a/packages/core/graph/src/Graph.js +++ b/packages/core/graph/src/Graph.js @@ -13,7 +13,6 @@ export type GraphOpts = {| nodes?: Map, adjacencyList?: SerializedAdjacencyList, rootNodeId?: ?NodeId, - edgeTypes?: {[key: string]: TEdgeType}, |}; export type SerializedGraph = {| @@ -25,10 +24,6 @@ export type SerializedGraph = {| export type AllEdgeTypes = -1; export const ALL_EDGE_TYPES: AllEdgeTypes = -1; -function objectValues(obj: {[Key]: Value}): Array { - return Object.keys(obj).map(key => obj[key]); -} - export default class Graph { nodes: Map; adjacencyList: AdjacencyList; @@ -39,16 +34,9 @@ export default class Graph { this.setRootNodeId(opts?.rootNodeId); let adjacencyList = opts?.adjacencyList; - - if (adjacencyList) { - this.adjacencyList = AdjacencyList.deserialize(adjacencyList); - } else { - // default edgeTypes to array containing just the null edge type - let edgeTypes = new Uint8Array( - opts?.edgeTypes ? objectValues(opts.edgeTypes) : [1], - ); - this.adjacencyList = new AdjacencyList({edgeTypes}); - } + this.adjacencyList = adjacencyList + ? AdjacencyList.deserialize(adjacencyList) + : new AdjacencyList(); } setRootNodeId(id: ?NodeId) { @@ -56,7 +44,7 @@ export default class Graph { } static deserialize( - opts: SerializedGraph, + opts: GraphOpts, ): Graph { return new this({ nodes: opts.nodes, @@ -116,11 +104,7 @@ export default class Graph { hasEdge( from: NodeId, to: NodeId, - type?: - | TEdgeType - | NullEdgeType - | Array - | AllEdgeTypes = 1, + type?: TEdgeType | NullEdgeType = 1, ): boolean { return this.adjacencyList.hasEdge(from, to, type); } diff --git a/packages/core/graph/test/AdjacencyList.test.js b/packages/core/graph/test/AdjacencyList.test.js index 6d214f9a4a2..32108771f98 100644 --- a/packages/core/graph/test/AdjacencyList.test.js +++ b/packages/core/graph/test/AdjacencyList.test.js @@ -5,7 +5,6 @@ import path from 'path'; import {Worker} from 'worker_threads'; import AdjacencyList, {NodeTypeMap, EdgeTypeMap} from '../src/AdjacencyList'; -import {ALL_EDGE_TYPES} from '../src/Graph'; import {toNodeId} from '../src/types'; describe('AdjacencyList', () => { @@ -244,36 +243,6 @@ describe('AdjacencyList', () => { AdjacencyList.prototype.hash = originalHash; }); - it('hasEdge should accept "ALL_EDGE_TYPES"', () => { - let graph = new AdjacencyList({edgeTypes: new Uint8Array([1, 2])}); - let a = graph.addNode(); - let b = graph.addNode(); - let c = graph.addNode(); - - graph.addEdge(a, b, 1); - graph.addEdge(b, c, 2); - - assert.ok(!graph.hasEdge(a, b, 2)); - assert.ok(graph.hasEdge(a, b, ALL_EDGE_TYPES)); - assert.ok(!graph.hasEdge(b, c, 1)); - assert.ok(graph.hasEdge(b, c, ALL_EDGE_TYPES)); - }); - - it('hasEdge should accept an array of edge types', () => { - let graph = new AdjacencyList(); - let a = graph.addNode(); - let b = graph.addNode(); - let c = graph.addNode(); - - graph.addEdge(a, b, 1); - graph.addEdge(b, c, 2); - - assert.ok(!graph.hasEdge(a, b, [2, 3])); - assert.ok(graph.hasEdge(a, b, [1, 2])); - assert.ok(!graph.hasEdge(b, c, [1, 3])); - assert.ok(graph.hasEdge(b, c, [2, 3])); - }); - describe('deserialize', function () { this.timeout(10000); From 2edc192cda4cd74491e64844ff3d63acc29a1d8a Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Wed, 19 Oct 2022 11:34:35 +1100 Subject: [PATCH 08/12] Rollback experimental bundler --- packages/bundlers/experimental/src/ExperimentalBundler.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/bundlers/experimental/src/ExperimentalBundler.js b/packages/bundlers/experimental/src/ExperimentalBundler.js index 3f0acf05c46..b5c10a830f8 100644 --- a/packages/bundlers/experimental/src/ExperimentalBundler.js +++ b/packages/bundlers/experimental/src/ExperimentalBundler.js @@ -329,9 +329,7 @@ function createIdealGraph( let bundleRootGraph: ContentGraph< BundleRoot | 'root', $Values, - > = new ContentGraph({ - edgeTypes: dependencyPriorityEdges, - }); + > = new ContentGraph(); let bundleGroupBundleIds: Set = new Set(); From d4a1bb142986b41be899bd4550c98f330b009de7 Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Wed, 19 Oct 2022 11:35:52 +1100 Subject: [PATCH 09/12] Fix Graph hasEdge type def --- packages/core/graph/src/Graph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/graph/src/Graph.js b/packages/core/graph/src/Graph.js index 31faaf3b7a1..ecdd48dc55a 100644 --- a/packages/core/graph/src/Graph.js +++ b/packages/core/graph/src/Graph.js @@ -104,7 +104,7 @@ export default class Graph { hasEdge( from: NodeId, to: NodeId, - type?: TEdgeType | NullEdgeType = 1, + type?: TEdgeType | NullEdgeType | Array = 1, ): boolean { return this.adjacencyList.hasEdge(from, to, type); } From 4376de0b783a0e862224fa95a927932657cb85f3 Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Wed, 19 Oct 2022 11:37:58 +1100 Subject: [PATCH 10/12] Add test back in --- packages/core/graph/test/ContentGraph.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/core/graph/test/ContentGraph.test.js b/packages/core/graph/test/ContentGraph.test.js index 3cb0e66d95d..1dc8fcfc0e7 100644 --- a/packages/core/graph/test/ContentGraph.test.js +++ b/packages/core/graph/test/ContentGraph.test.js @@ -3,6 +3,8 @@ import assert from 'assert'; import ContentGraph from '../src/ContentGraph'; +let edgeTypes; + describe('ContentGraph', () => { it('should addNodeByContentKey if no node exists with the content key', () => { let graph = new ContentGraph(); From f19fe92530bdb8c25432217e1791afb255940625 Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Wed, 19 Oct 2022 11:38:07 +1100 Subject: [PATCH 11/12] Add test back in --- packages/core/graph/test/AdjacencyList.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/core/graph/test/AdjacencyList.test.js b/packages/core/graph/test/AdjacencyList.test.js index 32108771f98..37f096b6fa3 100644 --- a/packages/core/graph/test/AdjacencyList.test.js +++ b/packages/core/graph/test/AdjacencyList.test.js @@ -243,6 +243,21 @@ describe('AdjacencyList', () => { AdjacencyList.prototype.hash = originalHash; }); + it('hasEdge should accept an array of edge types', () => { + let graph = new AdjacencyList(); + let a = graph.addNode(); + let b = graph.addNode(); + let c = graph.addNode(); + + graph.addEdge(a, b, 1); + graph.addEdge(b, c, 2); + + assert.ok(!graph.hasEdge(a, b, [2, 3])); + assert.ok(graph.hasEdge(a, b, [1, 2])); + assert.ok(!graph.hasEdge(b, c, [1, 3])); + assert.ok(graph.hasEdge(b, c, [2, 3])); + }); + describe('deserialize', function () { this.timeout(10000); From 532863f7ceddc5ee56a3e9808ae80f52ca3261e7 Mon Sep 17 00:00:00 2001 From: mattcompiles Date: Wed, 19 Oct 2022 11:39:02 +1100 Subject: [PATCH 12/12] Rolback COntentGraph --- packages/core/graph/test/ContentGraph.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/core/graph/test/ContentGraph.test.js b/packages/core/graph/test/ContentGraph.test.js index 1dc8fcfc0e7..3cb0e66d95d 100644 --- a/packages/core/graph/test/ContentGraph.test.js +++ b/packages/core/graph/test/ContentGraph.test.js @@ -3,8 +3,6 @@ import assert from 'assert'; import ContentGraph from '../src/ContentGraph'; -let edgeTypes; - describe('ContentGraph', () => { it('should addNodeByContentKey if no node exists with the content key', () => { let graph = new ContentGraph();