UNPKG

webpack-subresource-integrity

Version:
122 lines 4.65 kB
"use strict"; /** * Copyright (c) 2015-present, Waysact Pty Ltd * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createDAGfromGraph = void 0; const util_1 = require("./util"); class SccVerticesBuilder { constructor({ vertices, edges }) { this.vertexMetadata = new Map(); this.stack = []; this.index = 0; this.stronglyConnectedComponents = new Set(); this.vertices = vertices; this.edges = edges; for (const vertex of this.vertices) { if (!this.vertexMetadata.has(vertex)) { this.strongConnect(vertex); } } } build() { return this.stronglyConnectedComponents; } strongConnectChildren(vertex, vertexData) { var _a; for (const child of (_a = this.edges.get(vertex)) !== null && _a !== void 0 ? _a : []) { this.strongConnectChild(child, vertexData); } } strongConnectChild(child, vertexData) { const childData = this.vertexMetadata.get(child); if ((childData === null || childData === void 0 ? void 0 : childData.onstack) === false) { return; } vertexData.lowlink = Math.min(vertexData.lowlink, childData ? // Child is in stack and hence in the current SCC // If child is not on stack, then (vertex, child) is an edge pointing to an SCC already found and must be ignored // Note: The next line may look odd - but is correct. // It says childData.index not childData.lowlink; that is deliberate and from the original paper childData.index : // Child has not yet been visited; recurse on it this.strongConnect(child).lowlink); } strongConnect(vertex) { // Set the depth index for v to the smallest unused index const vertexData = { index: this.index, lowlink: this.index, onstack: true, }; this.vertexMetadata.set(vertex, vertexData); this.index++; this.stack.push(vertex); this.strongConnectChildren(vertex, vertexData); // If vertex is a root node, pop the stack and generate an SCC if (vertexData.index === vertexData.lowlink) { const newStronglyConnectedComponent = { nodes: new Set() }; let currentNode; do { currentNode = this.stack.pop(); (0, util_1.assert)(currentNode, "Working stack was empty"); const metadata = this.vertexMetadata.get(currentNode); (0, util_1.assert)(metadata, "All nodes on stack should have metadata"); metadata.onstack = false; newStronglyConnectedComponent.nodes.add(currentNode); } while (currentNode !== vertex); this.stronglyConnectedComponents.add(newStronglyConnectedComponent); } return vertexData; } } class SccEdgesBuilder { constructor(vertices, edges) { this.vertexToSCCMap = new Map(); this.vertices = vertices; this.edges = edges; for (const scc of this.vertices) { for (const vertex of scc.nodes) { this.vertexToSCCMap.set(vertex, scc); } } } build() { // Now that all SCCs have been identified, rebuild the graph const sccEdges = new Map(); for (const scc of this.vertices) { sccEdges.set(scc, this.getChildSCCNodes(scc)); } return sccEdges; } getChildSCCNodes(scc) { const childSCCNodes = new Set(); scc.nodes.forEach((vertex) => { const edge = this.edges.get(vertex); if (!edge) { return; } edge.forEach((childVertex) => { const childScc = this.vertexToSCCMap.get(childVertex); if (childScc && childScc !== scc) { childSCCNodes.add(childScc); } }); }); return childSCCNodes; } } /** * Tarjan's strongly connected components algorithm * https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm */ function createDAGfromGraph(graph) { const vertices = new SccVerticesBuilder(graph).build(); const edges = new SccEdgesBuilder(vertices, graph.edges).build(); return { vertices, edges }; } exports.createDAGfromGraph = createDAGfromGraph; //# sourceMappingURL=scc.js.map