@ohos-ports/graphviz 0.0.9-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/LICENCE.txt +19 -0
- package/README.md +98 -0
- package/bin/openharmony-arm64/dot +0 -0
- package/bin/openharmony-arm64/gvpr +0 -0
- package/lib/deps/attributs.js +254 -0
- package/lib/deps/core_ext/fs-ext.js +11 -0
- package/lib/deps/core_ext/hash.js +53 -0
- package/lib/deps/edge.js +58 -0
- package/lib/deps/graph.js +402 -0
- package/lib/deps/node.js +58 -0
- package/lib/ext/gvpr/dot2js.g +157 -0
- package/lib/graphviz.js +109 -0
- package/package.json +45 -0
- package/scripts/install-binaries.js +79 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module dependencies
|
|
3
|
+
*/
|
|
4
|
+
var Hash = require( './core_ext/hash' ).Hash,
|
|
5
|
+
Node = require( './node' ).Node,
|
|
6
|
+
Edge = require( './edge' ).Edge,
|
|
7
|
+
gvattrs = require( './attributs' ),
|
|
8
|
+
Attributs = gvattrs.Attributs,
|
|
9
|
+
util = require('util'),
|
|
10
|
+
path = require('path'),
|
|
11
|
+
spawn = require('child_process').spawn;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a new graph
|
|
15
|
+
* @constructor
|
|
16
|
+
* @param {Graph} graph Parent Graph
|
|
17
|
+
* @param {String} id The graphID
|
|
18
|
+
* @return {Graph}
|
|
19
|
+
* @api public
|
|
20
|
+
*/
|
|
21
|
+
var Graph = exports.Graph = function(graph, id) {
|
|
22
|
+
this.relativeGraph = graph;
|
|
23
|
+
this.id = id;
|
|
24
|
+
this.type = 'graph';
|
|
25
|
+
this.gvPath = '';
|
|
26
|
+
this.nodes = new Hash();
|
|
27
|
+
this.edges = new Array();
|
|
28
|
+
this.clusters = new Hash();
|
|
29
|
+
if( this.relativeGraph == null ) {
|
|
30
|
+
this.graphAttributs = new Attributs("G");
|
|
31
|
+
} else {
|
|
32
|
+
this.graphAttributs = new Attributs("C");
|
|
33
|
+
}
|
|
34
|
+
this.nodesAttributs = new Attributs("N");
|
|
35
|
+
this.edgesAttributs = new Attributs("E");
|
|
36
|
+
this.use = 'dot';
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create a new node
|
|
41
|
+
*
|
|
42
|
+
* @param {String} id The node ID
|
|
43
|
+
* @param {Object} attrs Node attributs
|
|
44
|
+
* @return {Node}
|
|
45
|
+
* @api public
|
|
46
|
+
*/
|
|
47
|
+
Graph.prototype.addNode = function(id, attrs) {
|
|
48
|
+
this.nodes.setItem(id, new Node(this, id));
|
|
49
|
+
if( attrs ) {
|
|
50
|
+
for( k in attrs ) {
|
|
51
|
+
this.nodes.items[id].set( k, attrs[k] );
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return this.nodes.items[id];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Return a node for a given ID
|
|
60
|
+
*
|
|
61
|
+
* @param {String} id The node ID
|
|
62
|
+
* @return {Node}
|
|
63
|
+
* @api public
|
|
64
|
+
*/
|
|
65
|
+
Graph.prototype.getNode = function(id) {
|
|
66
|
+
return this.nodes.items[id];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Graph.prototype.from = function(id) {
|
|
70
|
+
if( this.nodes.items[id] == undefined ) {
|
|
71
|
+
this.addNode(id);
|
|
72
|
+
}
|
|
73
|
+
return this.nodes.items[id];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Return the number of nodes in the current graph
|
|
78
|
+
*
|
|
79
|
+
* @return {Integer}
|
|
80
|
+
* @api public
|
|
81
|
+
*/
|
|
82
|
+
Graph.prototype.nodeCount = function() {
|
|
83
|
+
return this.nodes.length;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Create a new edge
|
|
88
|
+
*
|
|
89
|
+
* @param {String|Node} nodeOne
|
|
90
|
+
* @param {String|Node} nodeTwo
|
|
91
|
+
* @param {Object} attrs Node attributs
|
|
92
|
+
* @return {Edge}
|
|
93
|
+
* @api public
|
|
94
|
+
*/
|
|
95
|
+
Graph.prototype.addEdge = function(nodeOne, nodeTwo, attrs) {
|
|
96
|
+
var _nodeOne = nodeOne;
|
|
97
|
+
var _nodeTwo = nodeTwo;
|
|
98
|
+
if( typeof(nodeOne) == 'string' ) {
|
|
99
|
+
_nodeOne = this.nodes.items[nodeOne];
|
|
100
|
+
if( _nodeOne == null ) {
|
|
101
|
+
_nodeOne = this.addNode( nodeOne );
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if( typeof(nodeTwo) == 'string' ) {
|
|
105
|
+
_nodeTwo = this.nodes.items[nodeTwo];
|
|
106
|
+
if( _nodeTwo == null ) {
|
|
107
|
+
_nodeTwo = this.addNode( nodeTwo );
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
var edge = new Edge(this, _nodeOne, _nodeTwo);
|
|
112
|
+
if( attrs ) {
|
|
113
|
+
for( k in attrs ) {
|
|
114
|
+
edge.set( k, attrs[k] );
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
this.edges.push( edge );
|
|
118
|
+
|
|
119
|
+
return edge;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Return the number of edges in the current graph
|
|
124
|
+
*
|
|
125
|
+
* @return {Integer}
|
|
126
|
+
* @api public
|
|
127
|
+
*/
|
|
128
|
+
Graph.prototype.edgeCount = function() {
|
|
129
|
+
return this.edges.length;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Create a new subgraph
|
|
134
|
+
*
|
|
135
|
+
* @param {String} id The subgraph ID
|
|
136
|
+
* @return {Graph}
|
|
137
|
+
* @api public
|
|
138
|
+
*/
|
|
139
|
+
Graph.prototype.addCluster = function(id) {
|
|
140
|
+
var cluster = new Graph(this, id);
|
|
141
|
+
cluster.type = this.type;
|
|
142
|
+
this.clusters.setItem(id, cluster);
|
|
143
|
+
return cluster;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Return a subgraph for a given ID
|
|
148
|
+
*
|
|
149
|
+
* @param {String} id The subgraph ID
|
|
150
|
+
* @return {Graph}
|
|
151
|
+
* @api public
|
|
152
|
+
*/
|
|
153
|
+
Graph.prototype.getCluster = function(id) {
|
|
154
|
+
return this.clusters.items[id];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Return the number of subgraphs in the current graph
|
|
159
|
+
*
|
|
160
|
+
* @return {Integer}
|
|
161
|
+
* @api public
|
|
162
|
+
*/
|
|
163
|
+
Graph.prototype.clusterCount = function() {
|
|
164
|
+
return this.clusters.length;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Set a graph attribut
|
|
169
|
+
*
|
|
170
|
+
* @param {String} name The attribut name
|
|
171
|
+
* @param {Void} value The attribut value
|
|
172
|
+
* @api public
|
|
173
|
+
*/
|
|
174
|
+
Graph.prototype.set = function(name, value) {
|
|
175
|
+
this.graphAttributs.set(name, value);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get a graph attribut
|
|
180
|
+
*
|
|
181
|
+
* @param {String} name The attribut name
|
|
182
|
+
* @return {Void}
|
|
183
|
+
* @api public
|
|
184
|
+
*/
|
|
185
|
+
Graph.prototype.get = function(name) {
|
|
186
|
+
return this.graphAttributs.get(name);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Set a global node attribut
|
|
191
|
+
*
|
|
192
|
+
* @param {String} name The attribut name
|
|
193
|
+
* @param {Void} value The attribut value
|
|
194
|
+
* @api public
|
|
195
|
+
*/
|
|
196
|
+
Graph.prototype.setNodeAttribut = function(name, value) {
|
|
197
|
+
this.nodesAttributs.set(name, value);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get a global node attribut
|
|
202
|
+
*
|
|
203
|
+
* @param {String} name The attribut name
|
|
204
|
+
* @return {Void}
|
|
205
|
+
* @api public
|
|
206
|
+
*/
|
|
207
|
+
Graph.prototype.getNodeAttribut = function(name) {
|
|
208
|
+
return this.nodesAttributs.get(name);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Set a global edge attribut
|
|
213
|
+
*
|
|
214
|
+
* @param {String} name The attribut name
|
|
215
|
+
* @param {Void} value The attribut value
|
|
216
|
+
* @api public
|
|
217
|
+
*/
|
|
218
|
+
Graph.prototype.setEdgeAttribut = function(name, value) {
|
|
219
|
+
this.edgesAttributs.set(name, value);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Get a global edge attribut
|
|
224
|
+
*
|
|
225
|
+
* @param {String} name The attribut name
|
|
226
|
+
* @return {Void}
|
|
227
|
+
* @api public
|
|
228
|
+
*/
|
|
229
|
+
Graph.prototype.getEdgeAttribut = function(name) {
|
|
230
|
+
return this.edgesAttributs.get(name);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Generate the GraphViz script
|
|
235
|
+
*
|
|
236
|
+
* @return {String}
|
|
237
|
+
* @api public
|
|
238
|
+
*/
|
|
239
|
+
Graph.prototype.to_dot = function() {
|
|
240
|
+
var dotScript = '';
|
|
241
|
+
if( this.relativeGraph == null ) {
|
|
242
|
+
dotScript = this.type + ' ' + this.id + ' {\n'
|
|
243
|
+
} else {
|
|
244
|
+
dotScript = 'subgraph ' + this.id + ' {\n'
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Graph attributs
|
|
248
|
+
if( this.graphAttributs.length() > 0 ) {
|
|
249
|
+
dotScript = dotScript + " graph" + this.graphAttributs.to_dot() + ";\n";
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Nodes attributs
|
|
253
|
+
if( this.nodesAttributs.length() > 0 ) {
|
|
254
|
+
dotScript = dotScript + " node" + this.nodesAttributs.to_dot() + ";\n";
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Edges attributs
|
|
258
|
+
if( this.edgesAttributs.length() > 0 ) {
|
|
259
|
+
dotScript = dotScript + " edge" + this.edgesAttributs.to_dot() + ";\n";
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Each clusters
|
|
263
|
+
for( var id in this.clusters.items ) {
|
|
264
|
+
if (this.clusters.items.hasOwnProperty(id)) {
|
|
265
|
+
dotScript = dotScript + this.clusters.items[id].to_dot() + '\n';
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Each nodes
|
|
270
|
+
for( var id in this.nodes.items ) {
|
|
271
|
+
if (this.nodes.items.hasOwnProperty(id)) {
|
|
272
|
+
dotScript = dotScript + ' ' + this.nodes.items[id].to_dot() + ';\n'
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Each edges
|
|
277
|
+
for( var i in this.edges ) {
|
|
278
|
+
if (this.edges.hasOwnProperty(i)) {
|
|
279
|
+
dotScript = dotScript + ' ' + this.edges[i].to_dot() + ';\n'
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
dotScript = dotScript + '}\n'
|
|
284
|
+
|
|
285
|
+
return dotScript;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Generate an output in file or memory
|
|
290
|
+
*
|
|
291
|
+
* @param {String|Object} type The output file type (png, jpeg, ps, ...) or options
|
|
292
|
+
* @param {String|Function} name_or_callback The output file name or callback
|
|
293
|
+
* @param {Function} errback Error callback
|
|
294
|
+
* @api public
|
|
295
|
+
*
|
|
296
|
+
* Options :
|
|
297
|
+
* - type : output file type (png, jpeg, ps, ...)
|
|
298
|
+
* - use : Graphviz command to use (dot, neato, ...)
|
|
299
|
+
* - path : GraphViz path
|
|
300
|
+
* - G :
|
|
301
|
+
* - N :
|
|
302
|
+
* - E :
|
|
303
|
+
*/
|
|
304
|
+
Graph.prototype.render = function(type_or_options, name_or_callback, errback) {
|
|
305
|
+
var parameters = [];
|
|
306
|
+
|
|
307
|
+
// Get output type
|
|
308
|
+
var type = type_or_options;
|
|
309
|
+
if( typeof(type_or_options) == 'object' ) {
|
|
310
|
+
type = type_or_options.type;
|
|
311
|
+
|
|
312
|
+
// Get use
|
|
313
|
+
if( type_or_options.use != undefined ) { this.use = type_or_options.use; }
|
|
314
|
+
|
|
315
|
+
// Get path
|
|
316
|
+
if( type_or_options.path != undefined ) { this.gvPath = type_or_options.path; }
|
|
317
|
+
|
|
318
|
+
// Get extra Graph Options
|
|
319
|
+
if( type_or_options.G != undefined ) {
|
|
320
|
+
for( attr in type_or_options.G ) {
|
|
321
|
+
if( gvattrs.isValid( attr, "G" ) == false ) {
|
|
322
|
+
util.debug( "Warning : Invalid attribut `"+attr+"' for a graph" );
|
|
323
|
+
}
|
|
324
|
+
parameters.push( "-G"+attr+"="+type_or_options.G[attr] )
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
// Get extra Node Options
|
|
328
|
+
if( type_or_options.N != undefined ) {
|
|
329
|
+
for( attr in type_or_options.N ) {
|
|
330
|
+
if( gvattrs.isValid( attr, "N" ) == false ) {
|
|
331
|
+
util.debug( "Warning : Invalid attribut `"+attr+"' for a node" );
|
|
332
|
+
}
|
|
333
|
+
parameters.push( "-N"+attr+"="+type_or_options.N[attr] )
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// Get extra Edge Options
|
|
337
|
+
if( type_or_options.E != undefined ) {
|
|
338
|
+
for( attr in type_or_options.E ) {
|
|
339
|
+
if( gvattrs.isValid( attr, "E" ) == false ) {
|
|
340
|
+
util.debug( "Warning : Invalid attribut `"+attr+"' for an edge" );
|
|
341
|
+
}
|
|
342
|
+
parameters.push( "-E"+attr+"="+type_or_options.E[attr] )
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
parameters.push( '-T' + type );
|
|
347
|
+
|
|
348
|
+
var dotScript = this.to_dot();
|
|
349
|
+
|
|
350
|
+
var cmd = this.use;
|
|
351
|
+
if( this.gvPath != '' ) {
|
|
352
|
+
cmd = path.join( this.gvPath, this.use )
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
var rendered = null;
|
|
356
|
+
var out = ''
|
|
357
|
+
var err = ''
|
|
358
|
+
var outcallback = function(data) {
|
|
359
|
+
if( rendered == null ) {
|
|
360
|
+
rendered = data;
|
|
361
|
+
} else {
|
|
362
|
+
__b = new Buffer( rendered.length + data.length )
|
|
363
|
+
rendered.copy(__b, 0, 0)
|
|
364
|
+
data.copy(__b, rendered.length, 0)
|
|
365
|
+
rendered = __b
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
if( typeof(name_or_callback) == 'string' ) {
|
|
370
|
+
parameters.push( '-o' + name_or_callback )
|
|
371
|
+
outcallback = function(data) { out += data; }
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
graphviz = spawn(cmd, parameters);
|
|
375
|
+
graphviz.stdout.on('data', outcallback);
|
|
376
|
+
graphviz.stderr.on('data', function(data) {
|
|
377
|
+
err += data;
|
|
378
|
+
});
|
|
379
|
+
graphviz.on('exit', function(code) {
|
|
380
|
+
if(code !== 0) {
|
|
381
|
+
if(errback) { errback(code, out, err) }
|
|
382
|
+
} else {
|
|
383
|
+
if( typeof(name_or_callback) == 'function' ) name_or_callback(rendered);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
graphviz.stdin.write(this.to_dot());
|
|
387
|
+
graphviz.stdin.end();
|
|
388
|
+
}
|
|
389
|
+
// Compatibility
|
|
390
|
+
Graph.prototype.output = function(type, name_or_callback, errback) {
|
|
391
|
+
this.render(type, name_or_callback, errback);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Set the GraphViz path
|
|
396
|
+
*
|
|
397
|
+
* @param {String} path The GraphViz path
|
|
398
|
+
* @api public
|
|
399
|
+
*/
|
|
400
|
+
Graph.prototype.setGraphVizPath = function(path) {
|
|
401
|
+
this.gvPath = path;
|
|
402
|
+
}
|
package/lib/deps/node.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module dependencies
|
|
3
|
+
*/
|
|
4
|
+
var Hash = require('./core_ext/hash').Hash,
|
|
5
|
+
Attributs = require('./attributs').Attributs;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create a new node
|
|
9
|
+
* @constructor
|
|
10
|
+
* @param {Graph} graph Parent Graph
|
|
11
|
+
* @param {String} id The node ID
|
|
12
|
+
* @return {Node}
|
|
13
|
+
* @api public
|
|
14
|
+
*/
|
|
15
|
+
var Node = exports.Node = function(graph, id) {
|
|
16
|
+
this.relativeGraph = graph;
|
|
17
|
+
this.id = id;
|
|
18
|
+
this.attributs = new Attributs("N");
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
Node.prototype.to = function(id, attrs) {
|
|
25
|
+
this.relativeGraph.addEdge(this, id, attrs);
|
|
26
|
+
return this.relativeGraph.from(id);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Set a node attribut
|
|
31
|
+
*
|
|
32
|
+
* @param {String} name The attribut name
|
|
33
|
+
* @param {Void} value The attribut value
|
|
34
|
+
* @api public
|
|
35
|
+
*/
|
|
36
|
+
Node.prototype.set = function(name, value) {
|
|
37
|
+
this.attributs.set(name, value);
|
|
38
|
+
return this;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get a node attribut
|
|
43
|
+
*
|
|
44
|
+
* @param {String} name The attribut name
|
|
45
|
+
* @return {Void}
|
|
46
|
+
* @api public
|
|
47
|
+
*/
|
|
48
|
+
Node.prototype.get = function(name) {
|
|
49
|
+
return this.attributs.get(name);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @api private
|
|
54
|
+
*/
|
|
55
|
+
Node.prototype.to_dot = function() {
|
|
56
|
+
var nodeOutput = '"' + this.id + '"' + this.attributs.to_dot();
|
|
57
|
+
return nodeOutput;
|
|
58
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Copyright (c) 2010 Gregoire Lejeune <gregoire.lejeune@free.fr>
|
|
2
|
+
//
|
|
3
|
+
// This program is free software; you can redistribute it and/or modify
|
|
4
|
+
// it under the terms of the GNU General Public License as published by
|
|
5
|
+
// the Free Software Foundation; either version 2 of the License, or
|
|
6
|
+
// (at your option) any later version.
|
|
7
|
+
//
|
|
8
|
+
// This program is distributed in the hope that it will be useful,
|
|
9
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
// GNU General Public License for more details.
|
|
12
|
+
//
|
|
13
|
+
// You should have received a copy of the GNU General Public License
|
|
14
|
+
// along with this program; if not, write to the Free Software
|
|
15
|
+
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
16
|
+
//
|
|
17
|
+
// Usage :
|
|
18
|
+
// gvpr -f dot2js.g [-a <output type>] <dot script>
|
|
19
|
+
|
|
20
|
+
BEGIN {
|
|
21
|
+
int g_strict; int g_direct;
|
|
22
|
+
graph_t cluster;
|
|
23
|
+
node_t cnode;
|
|
24
|
+
edge_t cedge;
|
|
25
|
+
string attr; string attrv;
|
|
26
|
+
graph_t subgraph; graph_t pgraph;
|
|
27
|
+
graph_t ofgraph;
|
|
28
|
+
|
|
29
|
+
string xOut;
|
|
30
|
+
if( ARGC == 0 ) {
|
|
31
|
+
xOut = "_";
|
|
32
|
+
} else {
|
|
33
|
+
xOut = tolower(ARGV[0]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
printf( "// This code was generated by dot2js.g\n\n" );
|
|
37
|
+
|
|
38
|
+
string rubyfy( string s ) {
|
|
39
|
+
string out;
|
|
40
|
+
out = tolower( s );
|
|
41
|
+
out = gsub( out, " ", "__" );
|
|
42
|
+
out = gsub( out, "'", "" );
|
|
43
|
+
out = gsub( out, "-", "_" );
|
|
44
|
+
out = gsub( out, ".", "" );
|
|
45
|
+
out = gsub( out, "%", "u" );
|
|
46
|
+
out = gsub( out, "+", "" );
|
|
47
|
+
out = gsub( out, "/", "_" );
|
|
48
|
+
return( out );
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
BEG_G {
|
|
53
|
+
printf( "var util = require('util'),\n graphviz = require('graphviz');\n\n");
|
|
54
|
+
// Directed
|
|
55
|
+
g_direct = isDirect($);
|
|
56
|
+
if( g_direct == 0 ) {
|
|
57
|
+
printf( "var graph_%s = graphviz.graph( \"%s\" );\n", rubyfy($.name), rubyfy($.name) );
|
|
58
|
+
} else {
|
|
59
|
+
printf( "var graph_%s = graphviz.digraph( \"%s\" );\n", rubyfy($.name), rubyfy($.name) );
|
|
60
|
+
}
|
|
61
|
+
// Strict
|
|
62
|
+
g_strict = isStrict($);
|
|
63
|
+
if( g_strict != 0 ) {
|
|
64
|
+
// printf( ", :strict => true" ); ///////////////////////// TODO
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Attributs of G
|
|
68
|
+
attr = fstAttr($, "G");
|
|
69
|
+
while( attr != "" ) {
|
|
70
|
+
attrv = aget( $, attr );
|
|
71
|
+
if( attrv != "" ) {
|
|
72
|
+
printf( "graph_%s.set( \"%s\", \"%s\" );\n", rubyfy($.name), attr, attrv );
|
|
73
|
+
}
|
|
74
|
+
attr = nxtAttr( $, "G", attr );
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Subgraph
|
|
78
|
+
subgraph = fstsubg( $ );
|
|
79
|
+
while( subgraph != NULL ) {
|
|
80
|
+
pgraph = subgraph.parent;
|
|
81
|
+
printf ( "var graph_%s = graph_%s.addCluster( \"%s\" )\n", rubyfy(subgraph.name), rubyfy(pgraph.name), rubyfy(subgraph.name) );
|
|
82
|
+
|
|
83
|
+
// ATTRS
|
|
84
|
+
attr = fstAttr(subgraph, "G");
|
|
85
|
+
while( attr != "" ) {
|
|
86
|
+
attrv = aget( subgraph, attr );
|
|
87
|
+
if( attrv != "" ) {
|
|
88
|
+
printf( "graph_%s.set( \"%s\", \"%s\" );\n", rubyfy(subgraph.name), attr, attrv );
|
|
89
|
+
}
|
|
90
|
+
attr = nxtAttr( subgraph, "G", attr );
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
subgraph = nxtsubg( subgraph );
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
N {
|
|
98
|
+
pgraph = $.root;
|
|
99
|
+
ofgraph = pgraph;
|
|
100
|
+
|
|
101
|
+
subgraph = fstsubg( pgraph );
|
|
102
|
+
while( subgraph != NULL ) {
|
|
103
|
+
if( isSubnode( subgraph, $ ) != 0 ) {
|
|
104
|
+
ofgraph = subgraph;
|
|
105
|
+
}
|
|
106
|
+
subgraph = nxtsubg( subgraph );
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
printf( "var node_%s = graph_%s.addNode( \"%s\", {", rubyfy($.name), rubyfy(ofgraph.name), $.name );
|
|
110
|
+
|
|
111
|
+
// Attributs of N
|
|
112
|
+
attr = fstAttr($G, "N");
|
|
113
|
+
while( attr != "" ) {
|
|
114
|
+
attrv = aget( $, attr );
|
|
115
|
+
if( attrv != "" ) {
|
|
116
|
+
printf( "\"%s\" : \"%s\", ", attr, gsub( attrv, "'", "\\'" ) );
|
|
117
|
+
// } else {
|
|
118
|
+
// printf( "\"%s\" : \"\", ", attr );
|
|
119
|
+
}
|
|
120
|
+
attr = nxtAttr( $G, "N", attr );
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
printf( "} );\n" );
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
E {
|
|
127
|
+
pgraph = $.root;
|
|
128
|
+
ofgraph = pgraph;
|
|
129
|
+
|
|
130
|
+
subgraph = fstsubg( pgraph );
|
|
131
|
+
while( subgraph != NULL ) {
|
|
132
|
+
if( isSubedge( subgraph, $ ) != 0 ) {
|
|
133
|
+
ofgraph = subgraph;
|
|
134
|
+
}
|
|
135
|
+
subgraph = nxtsubg( subgraph );
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
printf( "graph_%s.addEdge( \"%s\", \"%s\", {", rubyfy(ofgraph.name), $.tail.name, $.head.name );
|
|
139
|
+
|
|
140
|
+
// Attributs of E
|
|
141
|
+
attr = fstAttr($G, "E");
|
|
142
|
+
while( attr != "" ) {
|
|
143
|
+
attrv = aget( $, attr );
|
|
144
|
+
if( attrv != "" ) {
|
|
145
|
+
printf( "\"%s\" : \"%s\", ", attr, gsub( attrv, "'", "\\'" ) );
|
|
146
|
+
// } else {
|
|
147
|
+
// printf( "\"%s\" : \"\", ", attr );
|
|
148
|
+
}
|
|
149
|
+
attr = nxtAttr( $G, "E", attr );
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
printf( "} );\n" );
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
END_G {
|
|
156
|
+
printf( "__graph_eval = graph_%s;\n", rubyfy($.name) );
|
|
157
|
+
}
|
package/lib/graphviz.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module dependencies.
|
|
3
|
+
*/
|
|
4
|
+
var path = require('path'),
|
|
5
|
+
spawn = require('child_process').spawn,
|
|
6
|
+
temp = require('temp'),
|
|
7
|
+
fs = require('fs'),
|
|
8
|
+
fsExt = require('./deps/core_ext/fs-ext'),
|
|
9
|
+
Graph = require('./deps/graph').Graph;
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* OpenHarmony/HarmonyOS port: make the bundled openharmony-arm64
|
|
13
|
+
* GraphViz binaries (dot, gvpr) available even when postinstall
|
|
14
|
+
* scripts are disabled (npm allowScripts policy). Prepend the
|
|
15
|
+
* bundled bin dir to PATH at require time if the binaries exist.
|
|
16
|
+
*/
|
|
17
|
+
(function bundledBinPath() {
|
|
18
|
+
var binDir = path.join(__dirname, '..', 'bin', 'openharmony-arm64');
|
|
19
|
+
if (!fs.existsSync(path.join(binDir, 'dot'))) return;
|
|
20
|
+
if (!fs.existsSync(path.join(binDir, 'gvpr'))) return;
|
|
21
|
+
var entries = (process.env.PATH || '').split(path.delimiter);
|
|
22
|
+
if (entries.indexOf(binDir) === -1) {
|
|
23
|
+
process.env.PATH = binDir + path.delimiter + (process.env.PATH || '');
|
|
24
|
+
}
|
|
25
|
+
})();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a new undirected graph
|
|
29
|
+
* @constructor
|
|
30
|
+
* @param {String} id The graphID
|
|
31
|
+
* @return {Graph}
|
|
32
|
+
* @api public
|
|
33
|
+
*/
|
|
34
|
+
exports.graph = function(id) {
|
|
35
|
+
var graph = new Graph(null, id);
|
|
36
|
+
graph.type = 'graph';
|
|
37
|
+
return graph;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create a new directed graph
|
|
42
|
+
* @constructor
|
|
43
|
+
* @param {String} id The graphID
|
|
44
|
+
* @return {Graph}
|
|
45
|
+
* @api public
|
|
46
|
+
*/
|
|
47
|
+
exports.digraph = function(id) {
|
|
48
|
+
var graph = new Graph(null, id);
|
|
49
|
+
graph.type = 'digraph';
|
|
50
|
+
return graph;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
function _parse(file, callback, errback) {
|
|
54
|
+
var gvprScript = path.join(__dirname, "ext", "gvpr", "dot2js.g"),
|
|
55
|
+
parameters = ["-f" + gvprScript, file],
|
|
56
|
+
cmd = "gvpr",
|
|
57
|
+
__graph_eval,
|
|
58
|
+
err = '',
|
|
59
|
+
out = '',
|
|
60
|
+
graphviz = spawn(cmd, parameters);
|
|
61
|
+
|
|
62
|
+
graphviz.stdout.on('data', function(data) {
|
|
63
|
+
out += data;
|
|
64
|
+
eval(data.toString());
|
|
65
|
+
});
|
|
66
|
+
graphviz.stderr.on('data', function(data) {
|
|
67
|
+
err += data;
|
|
68
|
+
});
|
|
69
|
+
graphviz.stdin.end();
|
|
70
|
+
graphviz.on('exit', function(code) {
|
|
71
|
+
if(code !== 0 || __graph_eval === undefined) {
|
|
72
|
+
if(errback) {
|
|
73
|
+
errback(code, out, err);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
callback(__graph_eval);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Create a new graph from a dot script
|
|
82
|
+
* @constructor
|
|
83
|
+
* @param {String} file_or_script The DOT script or file
|
|
84
|
+
* @param {Function} callback
|
|
85
|
+
* @param {Function} errback
|
|
86
|
+
* @api public
|
|
87
|
+
*/
|
|
88
|
+
exports.parse = function(file_or_script, callback, errback) {
|
|
89
|
+
if(fsExt.exist(file_or_script)) {
|
|
90
|
+
_parse(file_or_script, callback, errback);
|
|
91
|
+
} else {
|
|
92
|
+
temp.open('node-graphviz', function(err, info) {
|
|
93
|
+
if(err) {
|
|
94
|
+
return errback(err);
|
|
95
|
+
}
|
|
96
|
+
fs.write(info.fd, file_or_script, function(err) {
|
|
97
|
+
if(err) {
|
|
98
|
+
return errback(err);
|
|
99
|
+
}
|
|
100
|
+
fs.close(info.fd, function(err) {
|
|
101
|
+
if(err) {
|
|
102
|
+
return errback(err);
|
|
103
|
+
}
|
|
104
|
+
_parse(info.path, callback, errback);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
};
|