UNPKG

@nodescript/core

Version:

Visual programming language for Browser and Node

152 lines 4.58 kB
import { clone } from '../util/clone.js'; import { MultiMap } from '../util/multimap.js'; import { NodeView } from './NodeView.js'; export class GraphView { constructor(loader, graphSpec, parentNode = null) { this.loader = loader; this.graphSpec = graphSpec; this.parentNode = parentNode; } toJSON() { return clone(this.graphSpec); } get scopeId() { return this.parentNode == null ? 'root' : this.parentNode.graph.scopeId + ':' + this.parentNode.localId; } get moduleSpec() { return this.graphSpec.moduleSpec; } get metadata() { return this.graphSpec.metadata; } get rootNodeId() { return this.graphSpec.rootNodeId; } get rootGraph() { return this.parentNode == null ? this : this.parentNode.graph.rootGraph; } isSubgraph() { return this.parentNode != null; } *ancestors() { if (this.parentNode) { yield* this.parentNode.graph.ancestors(); } yield this; } isNodeExists(id) { return this.graphSpec.nodes[id] != null; } getNodeById(id) { const localId = id.includes(':') ? id.split(':').pop() : id; if (!localId) { return null; } const nodeSpec = this.graphSpec.nodes[localId]; return nodeSpec ? new NodeView(this, localId, nodeSpec) : null; } getNodes() { return Object.entries(this.graphSpec.nodes).map(_ => new NodeView(this, _[0], _[1])); } getRootNode() { return this.getNodeById(this.graphSpec.rootNodeId); } getNodesByRef(ref) { const results = []; for (const [localId, nodeSpec] of Object.entries(this.graphSpec.nodes)) { if (nodeSpec.ref === ref) { results.push(new NodeView(this, localId, nodeSpec)); } } return results; } /** * Returns an array of the nodes that have no outbound links. */ rightmostNodes() { const nodes = this.getNodes(); const candidates = new Set(this.getNodes()); for (const node of nodes) { for (const link of node.inboundLinks()) { candidates.delete(link.linkNode); } } return [...candidates]; } getEmittedNodes() { const rootNode = this.getRootNode(); if (rootNode) { return [...rootNode.leftNodes()]; } return []; } /** * Returns `manual` if any of the emitted nodes are manually evaluated, * otherwise returns `auto`. * * @see NodeView.getEvalMode for more info on node evaluation semantics. */ getEvalMode() { for (const node of this.getEmittedNodes()) { if (node.getEvalMode() === 'manual') { return 'manual'; } } return 'auto'; } *allLinks() { for (const node of this.getNodes()) { yield* node.inboundLinks(); } } /** * Returns a map of all outbound links for each node. */ computeLinkMap() { const map = new MultiMap(); for (const node of this.getNodes()) { for (const link of node.inboundLinks()) { map.add(link.linkNode.localId, link); } } return map; } *collectRefs() { for (const node of this.getNodes()) { yield node.ref; const subgraph = node.getSubgraph(); if (subgraph) { yield* subgraph.collectRefs(); } } } uniqueRefs() { return [...new Set(this.collectRefs())]; } *collectSubgraphs() { for (const node of this.getNodes()) { const subgraph = node.getSubgraph(); if (subgraph) { yield subgraph; yield* subgraph.collectSubgraphs(); } } } async loadRefs() { // Note: we need to load own graph refs first before loading subgraphs, // because subgraphs cannot be resolved without their enclosing node's moduleSpec const promises = []; for (const moduleRef of this.uniqueRefs()) { const promise = this.loader.loadModule(moduleRef); promises.push(promise); } await Promise.allSettled(promises); // 2. load all subgraphs for (const subgraph of this.collectSubgraphs()) { await subgraph.loadRefs(); } } } //# sourceMappingURL=GraphView.js.map