UNPKG

@tokens-studio/graph-engine

Version:

An execution engine to handle Token Studios generators and resolvers

136 lines 5.34 kB
import { Graph } from '../../graph/graph.js'; import { Node } from '../../programmatic/node.js'; import { annotatedDeleteable, hideFromParentSubgraph } from '../../annotations/index.js'; import { autorun } from 'mobx'; import InputNode from './input.js'; import OutputNode from './output.js'; export default class SubgraphNode extends Node { static title = 'Subgraph'; static type = 'studio.tokens.generic.subgraph'; static description = 'Allows you to run another subgraph internally'; _innerGraph; constructor(props) { super(props); const existing = !!props.innergraph; this._innerGraph = props.innergraph || new Graph(); // Automatically propagate the parent’s loader, if any if (props.graph?.externalLoader) { this._innerGraph.externalLoader = props.graph.externalLoader; } //Pass capabilities down this._innerGraph.capabilities = this.getGraph().capabilities; let input = undefined; let output = undefined; if (!existing) { input = new InputNode({ graph: this._innerGraph }); input.annotations[annotatedDeleteable] = false; output = new OutputNode({ graph: this._innerGraph }); output.annotations[annotatedDeleteable] = false; //Create the initial input and output nodes this._innerGraph.addNode(input); this._innerGraph.addNode(output); } else { Object.values(this._innerGraph.nodes).forEach(node => { if (node.factory.type == InputNode.type) { input = node; } if (node.factory.type == OutputNode.type) { output = node; } }); } if (!input) throw new Error('No input node found'); if (!output) throw new Error('No output node found'); autorun(() => { //Get the existing inputs const existing = this.inputs; //Iterate through the inputs of the input node in the inner graph Object.entries(input.inputs).forEach(([key, value]) => { //If the key doesn't exist in the existing inputs, add it if (!existing[key] && !value.annotations[hideFromParentSubgraph]) { //Always add it as visible this.addInput(key, { type: value.type }); this.inputs[key].setValue(value.value, { noPropagate: true }); } else { //Note its possible that the input key still does not exist due to an annotation ,etc //Update the value this.inputs[key]?.setValue(value.value, { noPropagate: true }); } //TODO handle deletions and mutations }); }); //Update when the outputs change autorun(() => { const existing = this.outputs; const existingPorts = Object.keys(existing); Object.entries(output.inputs).forEach(([key, value]) => { //If the key doesn't exist in the existing inputs, add it if (!existing[key] && !value.annotations[hideFromParentSubgraph]) { //Always add it as visible this.addOutput(key, { type: value.type }); this.outputs[key].set(value.value, value.type); } else { //Note its possible that the input key still does not exist due to an annotation ,etc //Update the value this.outputs[key]?.set(value.value, value.type); } }); //Remove any outputs that are no longer in the inner graph existingPorts.forEach(port => { if (!output.inputs[port]) { this.removeOutput(port); } }); }); } getSubgraphs() { return [this._innerGraph]; } getGraphProperties() { return { _innerGraph: this._innerGraph }; } serialize() { const serialized = super.serialize(); return { ...serialized, innergraph: this._innerGraph.serialize() }; } static async deserialize(opts) { const innergraph = await new Graph().deserialize(opts.serialized.innergraph, opts.lookup); const node = (await super.deserialize({ ...opts, //@ts-expect-error innergraph })); return node; } async execute() { const inputs = Object.keys(this.inputs).reduce((acc, key) => { this.inputs[key]; //Todo improve this for typing acc[key] = this.inputs[key]; return acc; }, {}); const result = await this._innerGraph.execute({ inputs }); Object.entries(result.output || {}).forEach(([key, value]) => { this.outputs[key].set(value.value, value.type); }); } } //# sourceMappingURL=subgraph.js.map