@parcel/graph
Advanced tools
Comparing version 2.0.2-nightly.2536 to 2.0.2-nightly.2540
@@ -47,2 +47,3 @@ "use strict"; | ||
serialize() { | ||
// $FlowFixMe[prop-missing] | ||
return { ...super.serialize(), | ||
@@ -49,0 +50,0 @@ _contentKeyToNodeId: this._contentKeyToNodeId, |
253
lib/Graph.js
@@ -11,2 +11,4 @@ "use strict"; | ||
var _AdjacencyList = _interopRequireDefault(require("./AdjacencyList")); | ||
function _assert() { | ||
@@ -34,31 +36,11 @@ const data = _interopRequireDefault(require("assert")); | ||
const ALL_EDGE_TYPES = '@@all_edge_types'; | ||
const ALL_EDGE_TYPES = -1; | ||
exports.ALL_EDGE_TYPES = ALL_EDGE_TYPES; | ||
class Graph { | ||
nextNodeId = 1; | ||
constructor(opts) { | ||
var _opts$nextNodeId; | ||
this.nodes = (opts === null || opts === void 0 ? void 0 : opts.nodes) || new Map(); | ||
this.setRootNodeId(opts === null || opts === void 0 ? void 0 : opts.rootNodeId); | ||
this.nextNodeId = (_opts$nextNodeId = opts === null || opts === void 0 ? void 0 : opts.nextNodeId) !== null && _opts$nextNodeId !== void 0 ? _opts$nextNodeId : 0; | ||
let edges = opts === null || opts === void 0 ? void 0 : opts.edges; | ||
if (edges != null) { | ||
this.inboundEdges = new AdjacencyList(); | ||
this.outboundEdges = new AdjacencyList(edges); | ||
for (let [from, edgeList] of edges) { | ||
for (let [type, toNodes] of edgeList) { | ||
for (let to of toNodes) { | ||
this.inboundEdges.addEdge(to, from, type); | ||
} | ||
} | ||
} | ||
} else { | ||
this.inboundEdges = new AdjacencyList(); | ||
this.outboundEdges = new AdjacencyList(); | ||
} | ||
let adjacencyList = opts === null || opts === void 0 ? void 0 : opts.adjacencyList; | ||
this.adjacencyList = adjacencyList ? _AdjacencyList.default.deserialize(adjacencyList) : new _AdjacencyList.default(); | ||
} | ||
@@ -73,5 +55,4 @@ | ||
nodes: opts.nodes, | ||
edges: opts.edges, | ||
rootNodeId: opts.rootNodeId, | ||
nextNodeId: opts.nextNodeId | ||
adjacencyList: opts.adjacencyList, | ||
rootNodeId: opts.rootNodeId | ||
}); | ||
@@ -83,7 +64,6 @@ } | ||
nodes: this.nodes, | ||
edges: this.outboundEdges.getListMap(), | ||
rootNodeId: this.rootNodeId, | ||
nextNodeId: this.nextNodeId | ||
adjacencyList: this.adjacencyList.serialize(), | ||
rootNodeId: this.rootNodeId | ||
}; | ||
} // Returns a list of all edges in the graph. This can be large, so iterating | ||
} // Returns an iterator of all edges in the graph. This can be large, so iterating | ||
// the complete list can be costly in large graphs. Used when merging graphs. | ||
@@ -93,21 +73,7 @@ | ||
getAllEdges() { | ||
let edges = []; | ||
for (let [from, edgeList] of this.outboundEdges.getListMap()) { | ||
for (let [type, toNodes] of edgeList) { | ||
for (let to of toNodes) { | ||
edges.push({ | ||
from, | ||
to, | ||
type | ||
}); | ||
} | ||
} | ||
} | ||
return edges; | ||
return this.adjacencyList.getAllEdges(); | ||
} | ||
addNode(node) { | ||
let id = (0, _types.toNodeId)(this.nextNodeId++); | ||
let id = this.adjacencyList.addNode(); | ||
this.nodes.set(id, node); | ||
@@ -126,2 +92,6 @@ return id; | ||
addEdge(from, to, type = 1) { | ||
if (Number(type) === 0) { | ||
throw new Error(`Edge type "${type}" not allowed`); | ||
} | ||
if (!this.getNode(from)) { | ||
@@ -135,8 +105,7 @@ throw new Error(`"from" node '${(0, _types.fromNodeId)(from)}' not found`); | ||
this.outboundEdges.addEdge(from, to, type); | ||
this.inboundEdges.addEdge(to, from, type); | ||
return this.adjacencyList.addEdge(from, to, type); | ||
} | ||
hasEdge(from, to, type = 1) { | ||
return this.outboundEdges.hasEdge(from, to, type); | ||
return this.adjacencyList.hasEdge(from, to, type); | ||
} | ||
@@ -147,35 +116,3 @@ | ||
let inboundByType = this.inboundEdges.getEdgesByType(nodeId); | ||
if (inboundByType == null) { | ||
return []; | ||
} | ||
let nodes; | ||
if (type === ALL_EDGE_TYPES) { | ||
nodes = new Set(); | ||
for (let [, typeNodes] of inboundByType) { | ||
for (let node of typeNodes) { | ||
nodes.add(node); | ||
} | ||
} | ||
} else if (Array.isArray(type)) { | ||
nodes = new Set(); | ||
for (let typeName of type) { | ||
for (let node of (_inboundByType$get$va = (_inboundByType$get = inboundByType.get(typeName)) === null || _inboundByType$get === void 0 ? void 0 : _inboundByType$get.values()) !== null && _inboundByType$get$va !== void 0 ? _inboundByType$get$va : []) { | ||
var _inboundByType$get$va, _inboundByType$get; | ||
nodes.add(node); | ||
} | ||
} | ||
} else { | ||
var _inboundByType$get$va2, _inboundByType$get2; | ||
nodes = new Set((_inboundByType$get$va2 = (_inboundByType$get2 = inboundByType.get(type)) === null || _inboundByType$get2 === void 0 ? void 0 : _inboundByType$get2.values()) !== null && _inboundByType$get$va2 !== void 0 ? _inboundByType$get$va2 : []); | ||
} | ||
return [...nodes]; | ||
return this.adjacencyList.getNodeIdsConnectedTo(nodeId, type); | ||
} | ||
@@ -186,35 +123,3 @@ | ||
let outboundByType = this.outboundEdges.getEdgesByType(nodeId); | ||
if (outboundByType == null) { | ||
return []; | ||
} | ||
let nodes; | ||
if (type === ALL_EDGE_TYPES) { | ||
nodes = new Set(); | ||
for (let [, typeNodes] of outboundByType) { | ||
for (let node of typeNodes) { | ||
nodes.add(node); | ||
} | ||
} | ||
} else if (Array.isArray(type)) { | ||
nodes = new Set(); | ||
for (let typeName of type) { | ||
for (let node of (_outboundByType$get$v = (_outboundByType$get = outboundByType.get(typeName)) === null || _outboundByType$get === void 0 ? void 0 : _outboundByType$get.values()) !== null && _outboundByType$get$v !== void 0 ? _outboundByType$get$v : []) { | ||
var _outboundByType$get$v, _outboundByType$get; | ||
nodes.add(node); | ||
} | ||
} | ||
} else { | ||
var _outboundByType$get$v2, _outboundByType$get2; | ||
nodes = new Set((_outboundByType$get$v2 = (_outboundByType$get2 = outboundByType.get(type)) === null || _outboundByType$get2 === void 0 ? void 0 : _outboundByType$get2.values()) !== null && _outboundByType$get$v2 !== void 0 ? _outboundByType$get$v2 : []); | ||
} | ||
return [...nodes]; | ||
return this.adjacencyList.getNodeIdsConnectedFrom(nodeId, type); | ||
} // Removes node and any edges coming from or to that node | ||
@@ -226,16 +131,16 @@ | ||
for (let [type, nodesForType] of this.inboundEdges.getEdgesByType(nodeId)) { | ||
for (let from of nodesForType) { | ||
this.removeEdge(from, nodeId, type, // Do not allow orphans to be removed as this node could be one | ||
// and is already being removed. | ||
false | ||
/* removeOrphans */ | ||
); | ||
} | ||
for (let { | ||
type, | ||
from | ||
} of this.adjacencyList.getInboundEdgesByType(nodeId)) { | ||
this.removeEdge(from, nodeId, type, // Do not allow orphans to be removed as this node could be one | ||
// and is already being removed. | ||
false); | ||
} | ||
for (let [type, toNodes] of this.outboundEdges.getEdgesByType(nodeId)) { | ||
for (let to of toNodes) { | ||
this.removeEdge(nodeId, to, type); | ||
} | ||
for (let { | ||
type, | ||
to | ||
} of this.adjacencyList.getOutboundEdgesByType(nodeId)) { | ||
this.removeEdge(nodeId, to, type); | ||
} | ||
@@ -250,3 +155,3 @@ | ||
for (let to of this.outboundEdges.getEdges(nodeId, type)) { | ||
for (let to of this.getNodeIdsConnectedFrom(nodeId, type)) { | ||
this.removeEdge(nodeId, to, type); | ||
@@ -258,13 +163,8 @@ } | ||
removeEdge(from, to, type = 1, removeOrphans = true) { | ||
if (!this.outboundEdges.hasEdge(from, to, type)) { | ||
throw new Error(`Outbound edge from ${(0, _types.fromNodeId)(from)} to ${(0, _types.fromNodeId)(to)} not found!`); | ||
if (!this.adjacencyList.hasEdge(from, to, type)) { | ||
throw new Error(`Edge from ${(0, _types.fromNodeId)(from)} to ${(0, _types.fromNodeId)(to)} not found!`); | ||
} | ||
if (!this.inboundEdges.hasEdge(to, from, type)) { | ||
throw new Error(`Inbound edge from ${(0, _types.fromNodeId)(to)} to ${(0, _types.fromNodeId)(from)} not found!`); | ||
} | ||
this.adjacencyList.removeEdge(from, to, type); | ||
this.outboundEdges.removeEdge(from, to, type); | ||
this.inboundEdges.removeEdge(to, from, type); | ||
if (removeOrphans && this.isOrphanedNode(to)) { | ||
@@ -281,10 +181,3 @@ this.removeNode(to); | ||
// this node should not be considered orphaned. | ||
// return false; | ||
for (let [, inboundNodeIds] of this.inboundEdges.getEdgesByType(nodeId)) { | ||
if (inboundNodeIds.size > 0) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
return !this.adjacencyList.hasInboundEdges(nodeId); | ||
} // Otherwise, attempt to traverse backwards to the root. If there is a path, | ||
@@ -301,4 +194,3 @@ // then this is not an orphaned node. | ||
} | ||
}, // $FlowFixMe | ||
ALL_EDGE_TYPES); | ||
}, ALL_EDGE_TYPES); | ||
@@ -316,13 +208,2 @@ if (hasPathToRoot) { | ||
this.nodes.set(nodeId, node); | ||
} | ||
replaceNode(fromNodeId, toNodeId, type = 1) { | ||
this._assertHasNodeId(fromNodeId); | ||
for (let parent of this.inboundEdges.getEdges(fromNodeId, type)) { | ||
this.addEdge(parent, toNodeId, type); | ||
this.removeEdge(parent, fromNodeId, type); | ||
} | ||
this.removeNode(fromNodeId); | ||
} // Update a node's downstream nodes making sure to prune any orphaned branches | ||
@@ -334,4 +215,4 @@ | ||
let outboundEdges = this.outboundEdges.getEdges(fromNodeId, type); | ||
let childrenToRemove = new Set(replaceFilter ? [...outboundEdges].filter(toNodeId => replaceFilter(toNodeId)) : outboundEdges); | ||
let outboundEdges = this.getNodeIdsConnectedFrom(fromNodeId, type); | ||
let childrenToRemove = new Set(replaceFilter ? outboundEdges.filter(toNodeId => replaceFilter(toNodeId)) : outboundEdges); | ||
@@ -568,56 +449,2 @@ for (let toNodeId of toNodeIds) { | ||
return mapped; | ||
} | ||
class AdjacencyList { | ||
constructor(listMap) { | ||
this._listMap = listMap !== null && listMap !== void 0 ? listMap : new Map(); | ||
} | ||
getListMap() { | ||
return this._listMap; | ||
} | ||
getEdges(from, type) { | ||
var _this$_listMap$get$ge, _this$_listMap$get; | ||
return (_this$_listMap$get$ge = (_this$_listMap$get = this._listMap.get(from)) === null || _this$_listMap$get === void 0 ? void 0 : _this$_listMap$get.get(type)) !== null && _this$_listMap$get$ge !== void 0 ? _this$_listMap$get$ge : new Set(); | ||
} | ||
getEdgesByType(from) { | ||
var _this$_listMap$get2; | ||
return (_this$_listMap$get2 = this._listMap.get(from)) !== null && _this$_listMap$get2 !== void 0 ? _this$_listMap$get2 : new Map(); | ||
} | ||
hasEdge(from, to, type) { | ||
var _this$_listMap$get3, _this$_listMap$get3$g; | ||
return Boolean((_this$_listMap$get3 = this._listMap.get(from)) === null || _this$_listMap$get3 === void 0 ? void 0 : (_this$_listMap$get3$g = _this$_listMap$get3.get(type)) === null || _this$_listMap$get3$g === void 0 ? void 0 : _this$_listMap$get3$g.has(to)); | ||
} | ||
addEdge(from, to, type) { | ||
let types = this._listMap.get(from); | ||
if (types == null) { | ||
types = new Map(); | ||
this._listMap.set(from, types); | ||
} | ||
let adjacent = types.get(type); | ||
if (adjacent == null) { | ||
adjacent = new Set(); | ||
types.set(type, adjacent); | ||
} | ||
adjacent.add(to); | ||
} | ||
removeEdge(from, to, type) { | ||
var _this$_listMap$get4, _this$_listMap$get4$g; | ||
(_this$_listMap$get4 = this._listMap.get(from)) === null || _this$_listMap$get4 === void 0 ? void 0 : (_this$_listMap$get4$g = _this$_listMap$get4.get(type)) === null || _this$_listMap$get4$g === void 0 ? void 0 : _this$_listMap$get4$g.delete(to); | ||
} | ||
} |
@@ -30,8 +30,2 @@ "use strict"; | ||
}); | ||
Object.defineProperty(exports, "GraphOpts", { | ||
enumerable: true, | ||
get: function () { | ||
return _Graph.GraphOpts; | ||
} | ||
}); | ||
Object.defineProperty(exports, "mapVisitor", { | ||
@@ -49,8 +43,2 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(exports, "SerializedContentGraph", { | ||
enumerable: true, | ||
get: function () { | ||
return _ContentGraph.SerializedContentGraph; | ||
} | ||
}); | ||
@@ -61,6 +49,8 @@ var _types = require("./types"); | ||
var _ContentGraph = _interopRequireWildcard(require("./ContentGraph")); | ||
var _ContentGraph = _interopRequireDefault(require("./ContentGraph")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } | ||
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; } |
{ | ||
"name": "@parcel/graph", | ||
"version": "2.0.2-nightly.2536+145bfb82", | ||
"version": "2.0.2-nightly.2540+3eb0fc79", | ||
"description": "Blazing fast, zero configuration web application bundler", | ||
@@ -25,3 +25,3 @@ "license": "MIT", | ||
}, | ||
"gitHead": "145bfb8243c516765bcf5c59e381d0bc45fc5f9e" | ||
"gitHead": "3eb0fc79fe22d5875e1d2cbf71d03773610818ec" | ||
} |
// @flow strict-local | ||
import type {ContentKey, NodeId} from './types'; | ||
import Graph, {type GraphOpts} from './Graph'; | ||
import Graph, {type SerializedGraph, type GraphOpts} from './Graph'; | ||
import nullthrows from 'nullthrows'; | ||
export type SerializedContentGraph<TNode, TEdgeType: number = 1> = {| | ||
export type ContentGraphOpts<TNode, TEdgeType: number = 1> = {| | ||
...GraphOpts<TNode, TEdgeType>, | ||
@@ -12,2 +12,6 @@ _contentKeyToNodeId: Map<ContentKey, NodeId>, | ||
|}; | ||
export type SerializedContentGraph<TNode, TEdgeType: number = 1> = {| | ||
...SerializedGraph<TNode, TEdgeType>, | ||
_contentKeyToNodeId: Map<ContentKey, NodeId>, | ||
|}; | ||
@@ -21,3 +25,3 @@ export default class ContentGraph<TNode, TEdgeType: number = 1> extends Graph< | ||
constructor(opts: ?SerializedContentGraph<TNode, TEdgeType>) { | ||
constructor(opts: ?ContentGraphOpts<TNode, TEdgeType>) { | ||
if (opts) { | ||
@@ -37,3 +41,3 @@ let {_contentKeyToNodeId, _nodeIdToContentKey, ...rest} = opts; | ||
static deserialize( | ||
opts: SerializedContentGraph<TNode, TEdgeType>, | ||
opts: ContentGraphOpts<TNode, TEdgeType>, | ||
): ContentGraph<TNode, TEdgeType> { | ||
@@ -45,2 +49,3 @@ return new ContentGraph(opts); | ||
serialize(): SerializedContentGraph<TNode, TEdgeType> { | ||
// $FlowFixMe[prop-missing] | ||
return { | ||
@@ -47,0 +52,0 @@ ...super.serialize(), |
272
src/Graph.js
// @flow strict-local | ||
import {toNodeId, fromNodeId} from './types'; | ||
import {fromNodeId} from './types'; | ||
import AdjacencyList, {type SerializedAdjacencyList} from './AdjacencyList'; | ||
import type {Edge, NodeId} from './types'; | ||
@@ -10,18 +11,22 @@ import type {TraversalActions, GraphVisitor} from '@parcel/types'; | ||
type NullEdgeType = 1; | ||
export type NullEdgeType = 1; | ||
export type GraphOpts<TNode, TEdgeType: number = 1> = {| | ||
nodes?: Map<NodeId, TNode>, | ||
edges?: AdjacencyListMap<TEdgeType | NullEdgeType>, | ||
adjacencyList?: SerializedAdjacencyList<TEdgeType>, | ||
rootNodeId?: ?NodeId, | ||
nextNodeId?: ?number, | ||
|}; | ||
export const ALL_EDGE_TYPES = '@@all_edge_types'; | ||
export type SerializedGraph<TNode, TEdgeType: number = 1> = {| | ||
nodes: Map<NodeId, TNode>, | ||
adjacencyList: SerializedAdjacencyList<TEdgeType>, | ||
rootNodeId: ?NodeId, | ||
|}; | ||
export type AllEdgeTypes = -1; | ||
export const ALL_EDGE_TYPES: AllEdgeTypes = -1; | ||
export default class Graph<TNode, TEdgeType: number = 1> { | ||
nodes: Map<NodeId, TNode>; | ||
inboundEdges: AdjacencyList<TEdgeType | NullEdgeType>; | ||
outboundEdges: AdjacencyList<TEdgeType | NullEdgeType>; | ||
adjacencyList: AdjacencyList<TEdgeType>; | ||
rootNodeId: ?NodeId; | ||
nextNodeId: number = 1; | ||
@@ -31,19 +36,7 @@ constructor(opts: ?GraphOpts<TNode, TEdgeType>) { | ||
this.setRootNodeId(opts?.rootNodeId); | ||
this.nextNodeId = opts?.nextNodeId ?? 0; | ||
let edges = opts?.edges; | ||
if (edges != null) { | ||
this.inboundEdges = new AdjacencyList(); | ||
this.outboundEdges = new AdjacencyList(edges); | ||
for (let [from, edgeList] of edges) { | ||
for (let [type, toNodes] of edgeList) { | ||
for (let to of toNodes) { | ||
this.inboundEdges.addEdge(to, from, type); | ||
} | ||
} | ||
} | ||
} else { | ||
this.inboundEdges = new AdjacencyList(); | ||
this.outboundEdges = new AdjacencyList(); | ||
} | ||
let adjacencyList = opts?.adjacencyList; | ||
this.adjacencyList = adjacencyList | ||
? AdjacencyList.deserialize(adjacencyList) | ||
: new AdjacencyList<TEdgeType>(); | ||
} | ||
@@ -60,33 +53,23 @@ | ||
nodes: opts.nodes, | ||
edges: opts.edges, | ||
adjacencyList: opts.adjacencyList, | ||
rootNodeId: opts.rootNodeId, | ||
nextNodeId: opts.nextNodeId, | ||
}); | ||
} | ||
serialize(): GraphOpts<TNode, TEdgeType> { | ||
serialize(): SerializedGraph<TNode, TEdgeType> { | ||
return { | ||
nodes: this.nodes, | ||
edges: this.outboundEdges.getListMap(), | ||
adjacencyList: this.adjacencyList.serialize(), | ||
rootNodeId: this.rootNodeId, | ||
nextNodeId: this.nextNodeId, | ||
}; | ||
} | ||
// Returns a list of all edges in the graph. This can be large, so iterating | ||
// Returns an iterator of all edges in the graph. This can be large, so iterating | ||
// the complete list can be costly in large graphs. Used when merging graphs. | ||
getAllEdges(): Array<Edge<TEdgeType | NullEdgeType>> { | ||
let edges = []; | ||
for (let [from, edgeList] of this.outboundEdges.getListMap()) { | ||
for (let [type, toNodes] of edgeList) { | ||
for (let to of toNodes) { | ||
edges.push({from, to, type}); | ||
} | ||
} | ||
} | ||
return edges; | ||
getAllEdges(): Iterator<Edge<TEdgeType | NullEdgeType>> { | ||
return this.adjacencyList.getAllEdges(); | ||
} | ||
addNode(node: TNode): NodeId { | ||
let id = toNodeId(this.nextNodeId++); | ||
let id = this.adjacencyList.addNode(); | ||
this.nodes.set(id, node); | ||
@@ -104,3 +87,11 @@ return id; | ||
addEdge(from: NodeId, to: NodeId, type: TEdgeType | NullEdgeType = 1): void { | ||
addEdge( | ||
from: NodeId, | ||
to: NodeId, | ||
type: TEdgeType | NullEdgeType = 1, | ||
): boolean { | ||
if (Number(type) === 0) { | ||
throw new Error(`Edge type "${type}" not allowed`); | ||
} | ||
if (!this.getNode(from)) { | ||
@@ -114,4 +105,3 @@ throw new Error(`"from" node '${fromNodeId(from)}' not found`); | ||
this.outboundEdges.addEdge(from, to, type); | ||
this.inboundEdges.addEdge(to, from, type); | ||
return this.adjacencyList.addEdge(from, to, type); | ||
} | ||
@@ -124,3 +114,3 @@ | ||
): boolean { | ||
return this.outboundEdges.hasEdge(from, to, type); | ||
return this.adjacencyList.hasEdge(from, to, type); | ||
} | ||
@@ -130,31 +120,11 @@ | ||
nodeId: NodeId, | ||
type: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1, | ||
type: | ||
| TEdgeType | ||
| NullEdgeType | ||
| Array<TEdgeType | NullEdgeType> | ||
| AllEdgeTypes = 1, | ||
): Array<NodeId> { | ||
this._assertHasNodeId(nodeId); | ||
let inboundByType = this.inboundEdges.getEdgesByType(nodeId); | ||
if (inboundByType == null) { | ||
return []; | ||
} | ||
let nodes; | ||
if (type === ALL_EDGE_TYPES) { | ||
nodes = new Set(); | ||
for (let [, typeNodes] of inboundByType) { | ||
for (let node of typeNodes) { | ||
nodes.add(node); | ||
} | ||
} | ||
} else if (Array.isArray(type)) { | ||
nodes = new Set(); | ||
for (let typeName of type) { | ||
for (let node of inboundByType.get(typeName)?.values() ?? []) { | ||
nodes.add(node); | ||
} | ||
} | ||
} else { | ||
nodes = new Set(inboundByType.get(type)?.values() ?? []); | ||
} | ||
return [...nodes]; | ||
return this.adjacencyList.getNodeIdsConnectedTo(nodeId, type); | ||
} | ||
@@ -164,30 +134,11 @@ | ||
nodeId: NodeId, | ||
type: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1, | ||
type: | ||
| TEdgeType | ||
| NullEdgeType | ||
| Array<TEdgeType | NullEdgeType> | ||
| AllEdgeTypes = 1, | ||
): Array<NodeId> { | ||
this._assertHasNodeId(nodeId); | ||
let outboundByType = this.outboundEdges.getEdgesByType(nodeId); | ||
if (outboundByType == null) { | ||
return []; | ||
} | ||
let nodes; | ||
if (type === ALL_EDGE_TYPES) { | ||
nodes = new Set(); | ||
for (let [, typeNodes] of outboundByType) { | ||
for (let node of typeNodes) { | ||
nodes.add(node); | ||
} | ||
} | ||
} else if (Array.isArray(type)) { | ||
nodes = new Set(); | ||
for (let typeName of type) { | ||
for (let node of outboundByType.get(typeName)?.values() ?? []) { | ||
nodes.add(node); | ||
} | ||
} | ||
} else { | ||
nodes = new Set(outboundByType.get(type)?.values() ?? []); | ||
} | ||
return [...nodes]; | ||
return this.adjacencyList.getNodeIdsConnectedFrom(nodeId, type); | ||
} | ||
@@ -199,19 +150,15 @@ | ||
for (let [type, nodesForType] of this.inboundEdges.getEdgesByType(nodeId)) { | ||
for (let from of nodesForType) { | ||
this.removeEdge( | ||
from, | ||
nodeId, | ||
type, | ||
// Do not allow orphans to be removed as this node could be one | ||
// and is already being removed. | ||
false /* removeOrphans */, | ||
); | ||
} | ||
for (let {type, from} of this.adjacencyList.getInboundEdgesByType(nodeId)) { | ||
this.removeEdge( | ||
from, | ||
nodeId, | ||
type, | ||
// Do not allow orphans to be removed as this node could be one | ||
// and is already being removed. | ||
false, | ||
); | ||
} | ||
for (let [type, toNodes] of this.outboundEdges.getEdgesByType(nodeId)) { | ||
for (let to of toNodes) { | ||
this.removeEdge(nodeId, to, type); | ||
} | ||
for (let {type, to} of this.adjacencyList.getOutboundEdgesByType(nodeId)) { | ||
this.removeEdge(nodeId, to, type); | ||
} | ||
@@ -226,3 +173,3 @@ | ||
for (let to of this.outboundEdges.getEdges(nodeId, type)) { | ||
for (let to of this.getNodeIdsConnectedFrom(nodeId, type)) { | ||
this.removeEdge(nodeId, to, type); | ||
@@ -239,19 +186,9 @@ } | ||
) { | ||
if (!this.outboundEdges.hasEdge(from, to, type)) { | ||
if (!this.adjacencyList.hasEdge(from, to, type)) { | ||
throw new Error( | ||
`Outbound edge from ${fromNodeId(from)} to ${fromNodeId( | ||
to, | ||
)} not found!`, | ||
`Edge from ${fromNodeId(from)} to ${fromNodeId(to)} not found!`, | ||
); | ||
} | ||
if (!this.inboundEdges.hasEdge(to, from, type)) { | ||
throw new Error( | ||
`Inbound edge from ${fromNodeId(to)} to ${fromNodeId(from)} not found!`, | ||
); | ||
} | ||
this.outboundEdges.removeEdge(from, to, type); | ||
this.inboundEdges.removeEdge(to, from, type); | ||
this.adjacencyList.removeEdge(from, to, type); | ||
if (removeOrphans && this.isOrphanedNode(to)) { | ||
@@ -268,10 +205,3 @@ this.removeNode(to); | ||
// this node should not be considered orphaned. | ||
// return false; | ||
for (let [, inboundNodeIds] of this.inboundEdges.getEdgesByType(nodeId)) { | ||
if (inboundNodeIds.size > 0) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
return !this.adjacencyList.hasInboundEdges(nodeId); | ||
} | ||
@@ -291,3 +221,2 @@ | ||
}, | ||
// $FlowFixMe | ||
ALL_EDGE_TYPES, | ||
@@ -308,15 +237,2 @@ ); | ||
replaceNode( | ||
fromNodeId: NodeId, | ||
toNodeId: NodeId, | ||
type: TEdgeType | NullEdgeType = 1, | ||
): void { | ||
this._assertHasNodeId(fromNodeId); | ||
for (let parent of this.inboundEdges.getEdges(fromNodeId, type)) { | ||
this.addEdge(parent, toNodeId, type); | ||
this.removeEdge(parent, fromNodeId, type); | ||
} | ||
this.removeNode(fromNodeId); | ||
} | ||
// Update a node's downstream nodes making sure to prune any orphaned branches | ||
@@ -331,6 +247,6 @@ replaceNodeIdsConnectedTo( | ||
let outboundEdges = this.outboundEdges.getEdges(fromNodeId, type); | ||
let outboundEdges = this.getNodeIdsConnectedFrom(fromNodeId, type); | ||
let childrenToRemove = new Set( | ||
replaceFilter | ||
? [...outboundEdges].filter(toNodeId => replaceFilter(toNodeId)) | ||
? outboundEdges.filter(toNodeId => replaceFilter(toNodeId)) | ||
: outboundEdges, | ||
@@ -354,3 +270,7 @@ ); | ||
startNodeId: ?NodeId, | ||
type: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1, | ||
type: | ||
| TEdgeType | ||
| NullEdgeType | ||
| Array<TEdgeType | NullEdgeType> | ||
| AllEdgeTypes = 1, | ||
): ?TContext { | ||
@@ -368,3 +288,3 @@ return this.dfs({ | ||
startNodeId: ?NodeId, | ||
type?: TEdgeType | Array<TEdgeType | NullEdgeType>, | ||
type?: TEdgeType | Array<TEdgeType | NullEdgeType> | AllEdgeTypes, | ||
): ?TContext { | ||
@@ -377,3 +297,7 @@ return this.traverse(mapVisitor(filter, visit), startNodeId, type); | ||
visit: GraphVisitor<NodeId, TContext>, | ||
type: TEdgeType | NullEdgeType | Array<TEdgeType | NullEdgeType> = 1, | ||
type: | ||
| TEdgeType | ||
| NullEdgeType | ||
| Array<TEdgeType | NullEdgeType> | ||
| AllEdgeTypes = 1, | ||
): ?TContext { | ||
@@ -595,45 +519,1 @@ return this.dfs({ | ||
} | ||
type AdjacencyListMap<TEdgeType> = Map<NodeId, Map<TEdgeType, Set<NodeId>>>; | ||
class AdjacencyList<TEdgeType> { | ||
_listMap: AdjacencyListMap<TEdgeType>; | ||
constructor(listMap?: AdjacencyListMap<TEdgeType>) { | ||
this._listMap = listMap ?? new Map(); | ||
} | ||
getListMap(): AdjacencyListMap<TEdgeType> { | ||
return this._listMap; | ||
} | ||
getEdges(from: NodeId, type: TEdgeType): $ReadOnlySet<NodeId> { | ||
return this._listMap.get(from)?.get(type) ?? new Set(); | ||
} | ||
getEdgesByType(from: NodeId): $ReadOnlyMap<TEdgeType, $ReadOnlySet<NodeId>> { | ||
return this._listMap.get(from) ?? new Map(); | ||
} | ||
hasEdge(from: NodeId, to: NodeId, type: TEdgeType): boolean { | ||
return Boolean(this._listMap.get(from)?.get(type)?.has(to)); | ||
} | ||
addEdge(from: NodeId, to: NodeId, type: TEdgeType): void { | ||
let types = this._listMap.get(from); | ||
if (types == null) { | ||
types = new Map<TEdgeType, Set<NodeId>>(); | ||
this._listMap.set(from, types); | ||
} | ||
let adjacent = types.get(type); | ||
if (adjacent == null) { | ||
adjacent = new Set<NodeId>(); | ||
types.set(type, adjacent); | ||
} | ||
adjacent.add(to); | ||
} | ||
removeEdge(from: NodeId, to: NodeId, type: TEdgeType): void { | ||
this._listMap.get(from)?.get(type)?.delete(to); | ||
} | ||
} |
// @flow strict-local | ||
export type {NodeId, ContentKey, Edge} from './types'; | ||
export type {GraphOpts} from './Graph'; | ||
export type {ContentGraphOpts, SerializedContentGraph} from './ContentGraph'; | ||
export {toNodeId, fromNodeId} from './types'; | ||
export {default as Graph, ALL_EDGE_TYPES, GraphOpts, mapVisitor} from './Graph'; | ||
export {default as ContentGraph, SerializedContentGraph} from './ContentGraph'; | ||
export {default as Graph, ALL_EDGE_TYPES, mapVisitor} from './Graph'; | ||
export {default as ContentGraph} from './ContentGraph'; |
@@ -13,3 +13,3 @@ // @flow strict-local | ||
assert.deepEqual(graph.nodes, new Map()); | ||
assert.deepEqual(graph.getAllEdges(), []); | ||
assert.deepEqual([...graph.getAllEdges()], []); | ||
}); | ||
@@ -118,3 +118,6 @@ | ||
assert(!graph.nodes.has(nodeC)); | ||
assert.deepEqual(graph.getAllEdges(), [{from: nodeA, to: nodeD, type: 1}]); | ||
assert.deepEqual( | ||
[...graph.getAllEdges()], | ||
[{from: nodeA, to: nodeD, type: 1}], | ||
); | ||
}); | ||
@@ -159,3 +162,3 @@ | ||
assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]); | ||
assert.deepEqual(graph.getAllEdges(), [ | ||
assert.deepEqual(Array.from(graph.getAllEdges()), [ | ||
{from: nodeA, to: nodeC, type: 1}, | ||
@@ -205,3 +208,3 @@ {from: nodeC, to: nodeF, type: 1}, | ||
assert.deepEqual([...graph.nodes.keys()], [nodeA, nodeC, nodeF]); | ||
assert.deepEqual(graph.getAllEdges(), [ | ||
assert.deepEqual(Array.from(graph.getAllEdges()), [ | ||
{from: nodeA, to: nodeC, type: 1}, | ||
@@ -241,3 +244,3 @@ {from: nodeC, to: nodeF, type: 1}, | ||
assert.deepEqual(nodesBefore, getNodeIds()); | ||
assert.deepEqual(graph.getAllEdges(), [ | ||
assert.deepEqual(Array.from(graph.getAllEdges()), [ | ||
{from: nodeA, to: nodeB, type: 1}, | ||
@@ -285,3 +288,3 @@ {from: nodeB, to: nodeC, type: 1}, | ||
assert(graph.hasNode(nodeD)); | ||
assert.deepEqual(graph.getAllEdges(), [ | ||
assert.deepEqual(Array.from(graph.getAllEdges()), [ | ||
{from: nodeA, to: nodeB, type: 1}, | ||
@@ -288,0 +291,0 @@ {from: nodeA, to: nodeD, type: 1}, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
127067
16
3574
2