metagraph
Version:
A framework for building higher-order graph data structures
140 lines (135 loc) • 5.52 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, as_keyvalue } from './core.js';
import { graph_detect } from './graph.js';
import { dataflow } from './dataflow.js';
/**
* Creates a reusable graph pattern that can generate graph instances from data.
* Patterns define the structure and behavior of graphs through dataflow and interface specifications.
*
* @param spec - Pattern specification containing dataflow computation and interface definition
* @param flowspecs - Optional additional flowspecs for composed patterns
* @returns A pattern graph that can create instances via the 'create' method
*
* @example
* ```typescript
* const graphPattern = pattern(graph_pattern());
* const instance = graphPattern.node('Graph').value().create({
* nodes: [{key: 'a'}, {key: 'b'}],
* edges: [{key: 'e', value: {source: 'a', target: 'b'}}]
* });
* ```
*/
const pattern = (spec, flowspecs) => {
const flowspec = spec.dataflow && graph_detect(spec.dataflow);
const interf = graph_detect(spec.interface);
const defn = { node: {}, edge: {} };
interf.nodes().forEach(inode => {
defn.node[inode.key()] = {
members: {},
class_members: {},
wrap: (flow, val) => {
const wrapper = {};
const members = defn.node[inode.key()].members;
Object.keys(members).forEach(name => {
wrapper[name] = members[name].defn(defn, flow, val);
});
return wrapper;
}
};
});
const resolve = (deps, funfun) => (defn, flow, val) => {
const action = funfun(defn, flow, val);
return (...args) => action.apply(null, deps.map(dep => {
const parts = dep.split('.');
if (parts.length > 1) {
return flow.input(parts[0], parts[1]);
}
else {
return flow.calc(dep);
}
})).apply(null, args);
};
interf.edges().forEach(iedge => {
const ekey = iedge.key();
const evalue = iedge.value();
const fs = flowspec || (flowspecs === null || flowspecs === void 0 ? void 0 : flowspecs[ekey.split('.')[0]]);
const action = evalue.member;
if (action && action.funfun) {
const funfun = action.funfun(fs, iedge, flowspecs);
const deps = as_array(evalue.deps);
const resolvedFunfun = resolve(deps, funfun);
defn.node[iedge.source().key()].members[evalue.name] = { defn: resolvedFunfun };
}
});
interf.nodes().forEach(inode => {
const nkey = inode.key();
inode.value();
const fs = flowspec || (flowspecs === null || flowspecs === void 0 ? void 0 : flowspecs[nkey.split('.')[0]]);
as_array(inode.value()).forEach((spec) => {
as_keyvalue(spec.class_members).forEach((cmemspec) => {
defn.node[nkey].class_members[cmemspec.key] = cmemspec.value(fs, inode);
});
as_keyvalue(spec.members).forEach((memspec) => {
const mem = memspec.value(fs, inode);
defn.node[nkey].members[memspec.key] = {
accessor: mem.accessor,
defn: mem.defn
};
});
});
});
const inodes2 = interf.nodes().map(n => {
const n2 = { key: n.key(), value: {} };
const class_members = defn.node[n.key()].class_members;
Object.keys(class_members).forEach(name => {
n2.value[name] = class_members[name].defn(defn);
});
return n2;
});
const iedges2 = interf.edges().map(e => ({
key: e.key(),
value: {
source: e.source().key(),
target: e.target().key()
}
}));
return graph_detect({ nodes: inodes2, edges: iedges2 });
};
const define_dataflow = (flowspec, defn) => {
const flownodes = flowspec.nodes().map(fsn => ({
key: fsn.key(),
value: {
calc: fsn.value().node.calc(fsn)(defn)
}
}));
return dataflow({
nodes: flownodes,
edges: flowspec.edges().map(e => ({ key: e.key(), value: e.value() }))
});
};
export { define_dataflow, pattern };
//# sourceMappingURL=pattern.js.map