@nodescript/core
Version:
Visual programming language for Browser and Node
152 lines • 4.58 kB
JavaScript
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