metagraph
Version:
A framework for building higher-order graph data structures
127 lines (122 loc) • 4.75 kB
JavaScript
/*!
* metagraph.js <%= conf.pkg.version %>
* http://gordonwoodhull.github.io/metagraph.js/
* Copyright 2019 AT&T Intellectual Property
*
* Licensed under the MIT License
*
* 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.
*/
import { as_array } from './core.js';
import { topological_sort } from './topological_sort.js';
import { graph_detect } from './graph.js';
import { pattern } from './pattern.js';
/**
* Composes multiple graph patterns into a single unified pattern.
* Resolves dependencies between patterns and creates a combined interface.
*
* @param composition - A graph where nodes are patterns and edges define dependencies
* @returns A composed pattern that combines all input patterns
*
* @example
* ```typescript
* const comp = compose(graph_detect({
* nodes: {
* graph: graph_pattern(),
* subgraph: subgraph_pattern()
* },
* edges: {
* dependency: {source: 'graph', target: 'subgraph', input: 'parent'}
* }
* }));
* ```
*/
const compose = (composition) => {
const sorted = topological_sort(composition);
const built = {};
const flowspecs = {};
const input_edge = (patnode, name) => patnode.ins().find((pe) => pe.value().input === name);
// resolve dependencies and build patterns
sorted.forEach(patnode => {
const flowspec = graph_detect(patnode.value().dataflow);
const fnodes = flowspec.nodes().map(fn => {
const v2 = Object.assign({}, fn.value());
v2.refs = as_array(v2.refs).map((ref) => {
const parts = ref.split('.');
if (parts.length > 1) {
const patedge = input_edge(patnode, parts[0]);
return patedge.source().key() + '.' + parts[1];
}
else
return patnode.key() + '.' + parts[0];
});
return {
key: fn.key(),
value: v2
};
});
const fedges = flowspec.edges().map(e => ({ key: e.key(), value: e.value() }));
flowspecs[patnode.key()] = graph_detect({ nodes: fnodes, edges: fedges });
const interf = patnode.value().interface;
built[patnode.key()] = graph_detect({
nodes: interf.nodes,
edges: interf.edges
});
});
// unite patterns
const nodes = [];
const edges = [];
const mappings = {};
const lookup = (key) => mappings[key] || key;
sorted.forEach(patnode => {
const pattern = built[patnode.key()];
pattern.nodes().forEach(inode => {
const key = patnode.key() + '.' + inode.key();
const ref = as_array(inode.value()).find((spec) => typeof spec === 'string');
if (ref) {
const parts = ref.split('.');
const patedge = input_edge(patnode, parts[0]);
const key2 = lookup(patedge.source().key() + '.' + parts[1]);
mappings[key] = key2;
}
else
nodes.push({
key: key,
value: inode.value()
});
});
pattern.edges().forEach(iedge => {
const val2 = Object.assign({}, iedge.value());
val2.source = lookup(patnode.key() + '.' + iedge.source().key());
val2.target = lookup(patnode.key() + '.' + iedge.target().key());
edges.push({
key: patnode.key() + '.' + iedge.key(),
value: val2
});
});
});
return pattern({
interface: {
nodes,
edges
}
}, flowspecs);
};
export { compose };
//# sourceMappingURL=compose.js.map