128 lines
2.7 KiB
JavaScript
128 lines
2.7 KiB
JavaScript
var _ = require("./lodash");
|
|
|
|
module.exports = writeOne;
|
|
|
|
var UNESCAPED_ID_PATTERN = /^[a-zA-Z\200-\377_][a-zA-Z\200-\377_0-9]*$/;
|
|
|
|
function writeOne(g) {
|
|
var ec = g.isDirected() ? "->" : "--",
|
|
writer = new Writer();
|
|
|
|
if (!g.isMultigraph()) {
|
|
writer.write("strict ");
|
|
}
|
|
|
|
writer.writeLine((g.isDirected() ? "digraph" : "graph") + " {");
|
|
writer.indent();
|
|
|
|
var graphAttrs = g.graph();
|
|
if (_.isObject(graphAttrs)) {
|
|
_.each(graphAttrs, function(v, k) {
|
|
writer.writeLine(id(k) + "=" + id(v) + ";");
|
|
});
|
|
}
|
|
|
|
writeSubgraph(g, undefined, writer);
|
|
|
|
g.edges().forEach(function(edge) {
|
|
writeEdge(g, edge, ec, writer);
|
|
});
|
|
|
|
writer.unindent();
|
|
writer.writeLine("}");
|
|
|
|
return writer.toString();
|
|
}
|
|
|
|
function writeSubgraph(g, v, writer) {
|
|
var children = g.isCompound() ? g.children(v) : g.nodes();
|
|
_.each(children, function(w) {
|
|
if (!g.isCompound() || !g.children(w).length) {
|
|
writeNode(g, w, writer);
|
|
} else {
|
|
writer.writeLine("subgraph " + id(w) + " {");
|
|
writer.indent();
|
|
|
|
if (_.isObject(g.node(w))) {
|
|
_.map(g.node(w), function(val, key) {
|
|
writer.writeLine(id(key) + "=" + id(val) + ";");
|
|
});
|
|
}
|
|
|
|
writeSubgraph(g, w, writer);
|
|
writer.unindent();
|
|
writer.writeLine("}");
|
|
}
|
|
});
|
|
}
|
|
|
|
function writeNode(g, v, writer) {
|
|
writer.write(id(v));
|
|
writeAttrs(g.node(v), writer);
|
|
writer.writeLine();
|
|
}
|
|
|
|
function writeEdge(g, edge, ec, writer) {
|
|
var v = edge.v,
|
|
w = edge.w,
|
|
attrs = g.edge(edge);
|
|
|
|
writer.write(id(v) + " " + ec + " " + id(w));
|
|
writeAttrs(attrs, writer);
|
|
writer.writeLine();
|
|
}
|
|
|
|
function writeAttrs(attrs, writer) {
|
|
if (_.isObject(attrs)) {
|
|
var attrStrs = _.map(attrs, function(val, key) {
|
|
return id(key) + "=" + id(val);
|
|
});
|
|
if (attrStrs.length) {
|
|
writer.write(" [" + attrStrs.join(",") + "]");
|
|
}
|
|
}
|
|
}
|
|
|
|
function id(obj) {
|
|
if (typeof obj === "number" || obj.toString().match(UNESCAPED_ID_PATTERN)) {
|
|
return obj;
|
|
}
|
|
|
|
return "\"" + obj.toString().replace(/"/g, "\\\"") + "\"";
|
|
}
|
|
|
|
// Helper object for making a pretty printer
|
|
function Writer() {
|
|
this._indent = "";
|
|
this._content = "";
|
|
this._shouldIndent = true;
|
|
}
|
|
|
|
Writer.prototype.INDENT = " ";
|
|
|
|
Writer.prototype.indent = function() {
|
|
this._indent += this.INDENT;
|
|
};
|
|
|
|
Writer.prototype.unindent = function() {
|
|
this._indent = this._indent.slice(this.INDENT.length);
|
|
};
|
|
|
|
Writer.prototype.writeLine = function(line) {
|
|
this.write((line || "") + "\n");
|
|
this._shouldIndent = true;
|
|
};
|
|
|
|
Writer.prototype.write = function(str) {
|
|
if (this._shouldIndent) {
|
|
this._shouldIndent = false;
|
|
this._content += this._indent;
|
|
}
|
|
this._content += str;
|
|
};
|
|
|
|
Writer.prototype.toString = function() {
|
|
return this._content;
|
|
};
|
|
|