UNPKG

aws-cdk-lib

Version:

Version 2 of the AWS Cloud Development Kit library

5 lines (4 loc) 8.87 kB
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.GraphNodeCollection=exports.Graph=exports.DependencyBuilders=exports.DependencyBuilder=exports.GraphNode=void 0,exports.isGraph=isGraph;var toposort_1=()=>{var tmp=require("./toposort");return toposort_1=()=>tmp,tmp},core_1=()=>{var tmp=require("../../../core");return core_1=()=>tmp,tmp},javascript_1=()=>{var tmp=require("../private/javascript");return javascript_1=()=>tmp,tmp};class GraphNode{static of(id,data){return new GraphNode(id,{data})}constructor(id,props={}){this.id=id,this.dependencies=[],this.data=props.data}get uniqueId(){return this.ancestorPath(this.root).map(x=>x.id).join("-")}get allDeps(){const fromParent=this.parentGraph?.allDeps??[];return Array.from(new Set([...this.dependencies,...fromParent]))}dependOn(...dependencies){if(dependencies.includes(this))throw new(core_1()).UnscopedValidationError(`Cannot add dependency on self: ${this}`);this.dependencies.push(...dependencies.filter(javascript_1().isDefined))}ancestorPath(upTo){let x=this;const ret=[x];for(;x.parentGraph&&x.parentGraph!==upTo;)x=x.parentGraph,ret.unshift(x);return ret}rootPath(){let x=this;const ret=[x];for(;x.parentGraph;)x=x.parentGraph,ret.unshift(x);return ret}get root(){let x=this;for(;x.parentGraph;)x=x.parentGraph;return x}get rootGraph(){const root=this.root;if(!(root instanceof Graph))throw new(core_1()).UnscopedValidationError(`Expecting a graph as root, got: ${root}`);return root}get parentGraph(){return this._parentGraph}_setParentGraph(parentGraph){if(this._parentGraph)throw new(core_1()).UnscopedValidationError("Node already has a parent");this._parentGraph=parentGraph}toString(){return`${this.constructor.name}(${this.id})`}}exports.GraphNode=GraphNode;class DependencyBuilder{constructor(){this._producers=[],this._consumers=[]}dependOn(...targets){for(const target of targets){for(const source of this._consumers)source.dependOn(target);this._producers.push(target)}return this}dependBy(...sources){for(const source of sources){for(const target of this._producers)source.dependOn(target);this._consumers.push(source)}return this}get hasUnsatisfiedConsumers(){return this._consumers.length>0&&this._producers.length===0}get consumers(){return this._consumers}consumersAsString(){return this.consumers.map(c=>`${c}`).join(",")}}exports.DependencyBuilder=DependencyBuilder;class DependencyBuilders{constructor(){this.builders=new Map}for(key){const b=this.builders.get(key);if(b)return b;const ret=new DependencyBuilder;return this.builders.set(key,ret),ret}get(key){return this.for(key)}unsatisfiedBuilders(){const ret=new Array;for(const[k,builder]of this.builders.entries())builder.hasUnsatisfiedConsumers&&ret.push([k,builder]);return ret}}exports.DependencyBuilders=DependencyBuilders;class Graph extends GraphNode{static of(id,data,nodes){return new Graph(id,{data,nodes})}constructor(name,props={}){super(name,props),this.children=new Map,props.nodes&&this.add(...props.nodes)}get nodes(){return new Set(this.children.values())}tryGetChild(name){return this.children.get(name)}containsId(id){return this.tryGetChild(id)!==void 0}contains(node){return this.nodes.has(node)}add(...nodes){for(const node of nodes){if(node._setParentGraph(this),this.children.has(node.id))throw new(core_1()).UnscopedValidationError(`Node with duplicate id: ${node.id}`);this.children.set(node.id,node)}}absorb(other){this.add(...other.nodes)}sortedChildren(fail=!0){const nodes=this.nodes,projectedDependencies=projectDependencies(this.deepDependencies(),node=>{for(;!nodes.has(node)&&node.parentGraph;)node=node.parentGraph;return nodes.has(node)?[node]:[]});return(0,toposort_1().topoSort)(nodes,projectedDependencies,fail)}sortedLeaves(){const descendantsMap=new Map;findDescendants(this);function findDescendants(node){const ret=[];if(node instanceof Graph)for(const child of node.nodes)ret.push(...findDescendants(child));else ret.push(node);return descendantsMap.set(node,ret),ret}const projectedDependencies=projectDependencies(this.deepDependencies(),node=>descendantsMap.get(node)??[]);return(0,toposort_1().topoSort)(new Set(projectedDependencies.keys()),projectedDependencies)}render(){const lines=new Array;return recurse(this,"",!0),lines.join(` `);function recurse(x,indent,last){const bullet=last?"\u2514\u2500":"\u251C\u2500",follow=last?" ":"\u2502 ";if(lines.push(`${indent} ${bullet} ${x}${depString(x)}`),x instanceof Graph){let i=0;const sortedNodes=Array.prototype.concat.call([],...x.sortedChildren(!1));for(const child of sortedNodes)recurse(child,`${indent} ${follow} `,i++==x.nodes.size-1)}}function depString(node){return node.dependencies.length>0?` -> ${Array.from(node.dependencies).join(", ")}`:""}}renderDot(){const lines=new Array;lines.push("digraph G {"),lines.push(' # Arrows represent an "unlocks" relationship (opposite of dependency). So chosen'),lines.push(" # because the layout looks more natural that way."),lines.push(" # To represent subgraph dependencies, subgraphs are represented by BEGIN/END nodes."),lines.push(" # To render: `dot -Tsvg input.dot > graph.svg`, open in a browser."),lines.push(' node [shape="box"];');for(const child of this.nodes)recurse(child);return lines.push("}"),lines.join(` `);function recurse(node){let dependencySource;node instanceof Graph?(lines.push(`${graphBegin(node)} [shape="cds", style="filled", fillcolor="#b7deff"];`),lines.push(`${graphEnd(node)} [shape="cds", style="filled", fillcolor="#b7deff"];`),dependencySource=graphBegin(node)):(dependencySource=nodeLabel(node),lines.push(`${nodeLabel(node)};`));for(const dep of node.dependencies){const dst=dep instanceof Graph?graphEnd(dep):nodeLabel(dep);lines.push(`${dst} -> ${dependencySource};`)}if(node instanceof Graph&&node.nodes.size>0){for(const child of node.nodes)recurse(child);const sortedChildren=node.sortedChildren(!1);for(const first of sortedChildren[0]){const src=first instanceof Graph?graphBegin(first):nodeLabel(first);lines.push(`${graphBegin(node)} -> ${src};`)}for(const last of sortedChildren[sortedChildren.length-1]){const dst=last instanceof Graph?graphEnd(last):nodeLabel(last);lines.push(`${dst} -> ${graphEnd(node)};`)}}}function id(node){return node.rootPath().slice(1).map(n=>n.id).join(".")}function nodeLabel(node){return`"${id(node)}"`}function graphBegin(node){return`"BEGIN ${id(node)}"`}function graphEnd(node){return`"END ${id(node)}"`}}consoleLog(_indent=0){process.stdout.write(this.render()+` `)}deepDependencies(){const ret=new Map;for(const node of this.nodes)recurse(node);return ret;function recurse(node){let deps=ret.get(node);deps||ret.set(node,deps=new Set);for(let dep of node.dependencies)deps.add(dep);if(node instanceof Graph)for(const child of node.nodes)recurse(child)}}allLeaves(){const ret=[];return recurse(this),new GraphNodeCollection(ret);function recurse(node){if(node instanceof Graph)for(const child of node.nodes)recurse(child);else ret.push(node)}}}exports.Graph=Graph;class GraphNodeCollection{constructor(nodes){this.nodes=Array.from(nodes)}dependOn(...dependencies){for(const node of this.nodes)node.dependOn(...dependencies.filter(javascript_1().isDefined))}first(){const nodes=new Set(this.nodes),sorted=this.nodes[0].rootGraph.sortedLeaves();for(const tranche of sorted)for(const node of tranche)if(nodes.has(node))return node;throw new(core_1()).UnscopedValidationError(`Could not calculate first node between ${this}`)}commonAncestor(){const paths=new Array;for(const x of this.nodes)paths.push(x.rootPath());if(paths.length===0)throw new(core_1()).UnscopedValidationError("Cannot find common ancestor between an empty set of nodes");if(paths.length===1){const path=paths[0];if(path.length<2)throw new(core_1()).UnscopedValidationError(`Cannot find ancestor of node without ancestor: ${path[0]}`);return path[path.length-2]}const originalPaths=[...paths];for(;paths.every(path=>paths[0].length>=2&&path.length>=2&&path[1]===paths[0][1]);)for(const path of paths)path.shift();if(paths.some(path=>path.length<2))throw new(core_1()).UnscopedValidationError(`Could not determine a shared parent between nodes: ${originalPaths.map(nodes=>nodes.map(n=>n.id).join("/"))}`);return paths[0][0]}toString(){return this.nodes.map(n=>`${n}`).join(", ")}}exports.GraphNodeCollection=GraphNodeCollection;function projectDependencies(dependencies,project){for(const node of dependencies.keys()){const projectedNodes=project(node);if(projectedNodes.length===1&&projectedNodes[0]===node)continue;const deps=(0,javascript_1().extract)(dependencies,node);for(const projectedNode of projectedNodes)(0,javascript_1().addAll)(dependencies.get(projectedNode),deps)}for(const[node,deps]of dependencies.entries()){const depset=new Set((0,javascript_1().flatMap)(deps,project));depset.delete(node),dependencies.set(node,depset)}return dependencies}function isGraph(x){return x instanceof Graph}