graph-by-ivan-tulaev
Version:
Graph library for traversing and processing any directional graphs.
24 lines (23 loc) • 4.46 kB
JavaScript
;var j=Object.defineProperty;var L=(c,e,t)=>e in c?j(c,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):c[e]=t;var p=(c,e,t)=>L(c,typeof e!="symbol"?e+"":e,t);/*!
* MIT License
*
* Copyright (c) 2025 Ivan Tulaev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function E(c,e){return e.nodes.find(t=>!c.has(t))}function N(c){return c.pop()}function T(c){return c.shift()}function w(c,e){for(const t of c)e.push(t)}function _(c,e){for(const t of c)e.unshift(t)}function y(c,e,t){return[...e.getOutgoingEdgesFor(c)].map(n=>n.target).filter(n=>!t.has(n))}function S(c,e,t){return[...e.getIncomingEdgesFor(c)].map(n=>n.source).filter(n=>!t.has(n))}class h{constructor(e=!1){p(this,"notDirected");p(this,"_adjacencyList");this.notDirected=e,this._adjacencyList=new Map}get nodes(){return[...this._adjacencyList.keys()]}addNode(e){this.nodes.includes(e)||this._adjacencyList.set(e,{incoming:new Set,outgoing:new Set})}deleteNode(e){this._adjacencyList.delete(e);for(const[,t]of this._adjacencyList){const{incoming:n,outgoing:i}=t,s=new Set([...n,...i]);for(const r of s)r.source!==e&&r.source!==e||(n.delete(r),i.delete(r))}}get edges(){return new Set([...this._adjacencyList.values()].map(e=>[...e.incoming,...e.outgoing]).flat())}addEdge(e){const{source:t,target:n}=e;if(!this._adjacencyList.has(t)||!this._adjacencyList.has(n))throw new Error(`Cannot add adjacency: has no node ${t} or ${n}`);const i=this._adjacencyList.get(n);i&&i.incoming.add(e);const s=this._adjacencyList.get(t);s&&s.outgoing.add(e)}deleteEdge(e){const{source:t,target:n}=e,i=this._adjacencyList.get(n);i&&i.incoming.delete(e);const s=this._adjacencyList.get(t);s&&s.outgoing.delete(e)}getIncomingEdgesFor(e){var t;return((t=this._adjacencyList.get(e))==null?void 0:t.incoming)||new Set}getOutgoingEdgesFor(e){var t;return((t=this._adjacencyList.get(e))==null?void 0:t.outgoing)||new Set}genericTraversing(e,t,n,i,s){const r=new Set;for(;r.size<this.nodes.length;){const a=e(r,this);if(!a)break;const d=[a];for(;d.length>0;){const o=t(d);if(!o)throw new Error(`Can't get current node from ${d}`);s&&s(o),r.add(o);const g=n(o,this,r);if(!g)break;i(g,d)}}}getSeparatedGraphs(){const e=new Set,t=(s,r)=>{const a=r.getOutgoingEdgesFor(s),d=[...a].map(u=>u.target),o=r.getIncomingEdgesFor(s),g=[...o].map(u=>u.source),f=new Set([...a,...o]),m=new Set([...d,...g]),l=new h(!1);l.addNode(s);for(const u of m)l.addNode(u);for(const u of f)l.addEdge(u);return l},n=(s,r)=>{const a=new Set;for(const d of r.nodes)for(const o of s)if(o.nodes.includes(d)){a.add(o);break}return a},i=(s,r,a)=>{const d=t(s,r),o=n(e,d);if(o.size>0){for(const f of o)e.delete(f);const g=h.mergeGraphs(o.add(d));e.add(g)}else e.add(d);return[...d.nodes].filter(g=>!a.has(g))};return this.genericTraversing(E,N,i,w),[...e]}isNodeTraced(e,t,n=!1){let i=!1;const s=[t].flat(),r=o=>o.has(e)?void 0:e,a=o=>{e===o&&s.includes(o)&&(i=!0)},d=(o,g,f)=>{const m=n?S(o,g,f):y(o,g,f);if(m.some(l=>s.includes(l))){i=!0;return}return m};return this.genericTraversing(r,N,d,w,a),i}static mergeGraphs(e){const t=new h(!1);for(const n of e){for(const i of n.nodes)t.addNode(i);for(const i of n.edges)t.addEdge(i)}return t}}exports.Graph=h;exports.addToEnd=w;exports.addToStart=_;exports.getFirst=T;exports.getFirstUnvisited=E;exports.getLast=N;exports.getNotVisitedIncomingNodes=S;exports.getNotVisitedOutgoingNodes=y;