@hpcc-js/wasm-graphviz 1.24.0 → 1.25.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/README.md +107 -43
- package/dist/index.js +2 -2
- package/dist/index.js.map +3 -3
- package/package.json +4 -4
- package/src/graphviz.ts +387 -52
- package/src/types.ts +6 -0
- package/types/graphviz.d.ts +136 -27
- package/types/graphvizlib.d.ts +52 -0
- package/types/types.d.ts +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hpcc-js/wasm-graphviz",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "hpcc-js - WASM Graphviz",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
20
|
"clean": "rimraf coverage dist dist-test types .nyc_output",
|
|
21
|
-
"gen-types": "
|
|
21
|
+
"gen-types": "tsc --project tsconfig.json --emitDeclarationOnly",
|
|
22
22
|
"gen-types-watch": "npm run gen-types -- --watch",
|
|
23
23
|
"bundle": "node esbuild.js",
|
|
24
24
|
"bundle-dev": "npm run bundle -- --development",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@hpcc-js/esbuild-plugins": "1.9.
|
|
40
|
+
"@hpcc-js/esbuild-plugins": "1.9.4",
|
|
41
41
|
"@hpcc-js/wasm-util": "1.0.0"
|
|
42
42
|
},
|
|
43
43
|
"keywords": [
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
},
|
|
57
57
|
"homepage": "https://hpcc-systems.github.io/hpcc-js-wasm/",
|
|
58
58
|
"license": "Apache-2.0",
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "e9302b649306927c2844eda31d3ee58b17b8eb8a"
|
|
60
60
|
}
|
package/src/graphviz.ts
CHANGED
|
@@ -8,8 +8,24 @@ import type {
|
|
|
8
8
|
GraphDotAttr, GraphAttrs as GraphAttrs
|
|
9
9
|
} from "./types.ts";
|
|
10
10
|
|
|
11
|
+
type AttrValues<T> = Partial<{ [K in keyof T]: NonNullable<T[K]> }>;
|
|
12
|
+
|
|
13
|
+
function applyAttrs<T extends object>(
|
|
14
|
+
attrs: AttrValues<T> | undefined,
|
|
15
|
+
apply: (attr: string, value: string | number | boolean) => void
|
|
16
|
+
): void {
|
|
17
|
+
if (!attrs) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
for (const [attr, value] of Object.entries(attrs)) {
|
|
21
|
+
if (value !== undefined) {
|
|
22
|
+
apply(attr, value as string | number | boolean);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
11
27
|
/**
|
|
12
|
-
* Various graphic and data formats for end user, web, documents and other applications. See [Output Formats](https://graphviz.
|
|
28
|
+
* Various graphic and data formats for end user, web, documents and other applications. See [Output Formats](https://graphviz.org/docs/outputs/) for more information.
|
|
13
29
|
*/
|
|
14
30
|
export type Format = "svg" | "svg_inline" | "dot" | "json" | "dot_json" | "xdot_json" | "plain" | "plain-ext" | "canon";
|
|
15
31
|
|
|
@@ -43,7 +59,7 @@ function parseEdges(json: string): EdgeInfo[] {
|
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
/**
|
|
46
|
-
* Various algorithms for projecting abstract graphs into a space for visualization. See [Layout Engines](https://graphviz.
|
|
62
|
+
* Various algorithms for projecting abstract graphs into a space for visualization. See [Layout Engines](https://graphviz.org/docs/layouts/) for more details.
|
|
47
63
|
*/
|
|
48
64
|
export type Engine = "circo" | "dot" | "fdp" | "sfdp" | "neato" | "osage" | "patchwork" | "twopi" | "nop" | "nop2";
|
|
49
65
|
|
|
@@ -117,6 +133,35 @@ let g_graphviz: Promise<Graphviz> | undefined;
|
|
|
117
133
|
*/
|
|
118
134
|
export type GraphType = "directed" | "undirected" | "strict directed" | "strict undirected";
|
|
119
135
|
|
|
136
|
+
export interface GraphInit {
|
|
137
|
+
name?: string;
|
|
138
|
+
type?: GraphType;
|
|
139
|
+
attrs?: AttrValues<GraphAttrs>;
|
|
140
|
+
htmlAttrs?: AttrValues<GraphAttrs>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface NodeInit {
|
|
144
|
+
name: string;
|
|
145
|
+
attrs?: AttrValues<NodeAttrs>;
|
|
146
|
+
htmlAttrs?: AttrValues<NodeAttrs>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface EdgeInit {
|
|
150
|
+
tail: string;
|
|
151
|
+
head: string;
|
|
152
|
+
key?: string;
|
|
153
|
+
attrs?: AttrValues<EdgeAttrs>;
|
|
154
|
+
htmlAttrs?: AttrValues<EdgeAttrs>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface SubgraphInit {
|
|
158
|
+
name: string;
|
|
159
|
+
attrs?: AttrValues<ClusterAttrs>;
|
|
160
|
+
htmlAttrs?: AttrValues<ClusterAttrs>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export type ClusterInit = SubgraphInit;
|
|
164
|
+
|
|
120
165
|
/**
|
|
121
166
|
* A subgraph (or cluster) inside a {@link Graph}.
|
|
122
167
|
*
|
|
@@ -148,8 +193,15 @@ export class Subgraph {
|
|
|
148
193
|
/**
|
|
149
194
|
* Create (or find) a node and add it to this subgraph.
|
|
150
195
|
*/
|
|
151
|
-
addNode(name: string): this
|
|
196
|
+
addNode(name: string): this;
|
|
197
|
+
addNode(init: NodeInit): this;
|
|
198
|
+
addNode(nameOrInit: string | NodeInit): this {
|
|
199
|
+
const init = typeof nameOrInit === "string" ? { name: nameOrInit } : nameOrInit;
|
|
200
|
+
const { name, attrs, htmlAttrs } = init;
|
|
201
|
+
|
|
152
202
|
this._sg.addNode(name);
|
|
203
|
+
applyAttrs<NodeAttrs>(attrs, (attr, value) => this.setNodeAttr(name, attr, value));
|
|
204
|
+
applyAttrs<NodeAttrs>(htmlAttrs, (attr, value) => this.setNodeHtmlAttr(name, attr, value));
|
|
153
205
|
return this;
|
|
154
206
|
}
|
|
155
207
|
|
|
@@ -157,8 +209,23 @@ export class Subgraph {
|
|
|
157
209
|
* Create an edge inside this subgraph. Both endpoints are created
|
|
158
210
|
* automatically if they do not already exist.
|
|
159
211
|
*/
|
|
160
|
-
addEdge(tail: string, head: string, key
|
|
161
|
-
|
|
212
|
+
addEdge(tail: string, head: string, key?: string): this;
|
|
213
|
+
addEdge(init: EdgeInit): this;
|
|
214
|
+
addEdge(tailOrInit: string | EdgeInit, head?: string, key: string = ""): this {
|
|
215
|
+
const init = typeof tailOrInit === "string"
|
|
216
|
+
? { tail: tailOrInit, head: head!, key }
|
|
217
|
+
: tailOrInit;
|
|
218
|
+
const { tail, head: resolvedHead, key: resolvedKey = "", attrs, htmlAttrs } = init;
|
|
219
|
+
|
|
220
|
+
this._sg.addEdge(tail, resolvedHead, resolvedKey);
|
|
221
|
+
applyAttrs<EdgeAttrs>(attrs, (attr, value) => this.setEdgeAttr(tail, resolvedHead, resolvedKey, attr, value));
|
|
222
|
+
applyAttrs<EdgeAttrs>(htmlAttrs, (attr, value) => this.setEdgeHtmlAttr(tail, resolvedHead, resolvedKey, attr, value));
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
applyInit(init: SubgraphInit): this {
|
|
227
|
+
applyAttrs<ClusterAttrs>(init.attrs, (attr, value) => this.setAttr(attr, value));
|
|
228
|
+
applyAttrs<ClusterAttrs>(init.htmlAttrs, (attr, value) => this.setHtmlAttr(attr, value));
|
|
162
229
|
return this;
|
|
163
230
|
}
|
|
164
231
|
|
|
@@ -183,16 +250,50 @@ export class Subgraph {
|
|
|
183
250
|
|
|
184
251
|
/**
|
|
185
252
|
* Set an attribute on the subgraph itself (e.g. `"label"`, `"style"`,
|
|
186
|
-
* `"color"`, `"bgcolor"`).
|
|
253
|
+
* `"color"`, `"bgcolor"`). See the official Graphviz
|
|
254
|
+
* [attribute reference](https://graphviz.org/docs/attrs/) for supported
|
|
255
|
+
* attributes and values.
|
|
187
256
|
*
|
|
188
257
|
* When `attr` is a known cluster attribute the value type is inferred
|
|
189
258
|
* automatically. A generic `string | number | boolean` fallback is
|
|
190
|
-
* provided for custom or less-common attributes.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
259
|
+
* provided for custom or less-common attributes. Omit `value` to reset
|
|
260
|
+
* the attribute to Graphviz's default empty value. `defaultValue` is
|
|
261
|
+
* passed to Graphviz as the default for this attribute if it has not
|
|
262
|
+
* already been declared.
|
|
263
|
+
*/
|
|
264
|
+
setAttr<K extends ClusterDotAttr>(attr: K, value?: NonNullable<ClusterAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
265
|
+
setAttr(attr: string, value?: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
266
|
+
setAttr(attr: string, value: unknown = "", defaultValue?: unknown): this {
|
|
267
|
+
if (defaultValue === undefined) {
|
|
268
|
+
this._sg.setAttr(attr, String(value));
|
|
269
|
+
} else {
|
|
270
|
+
this._sg.setAttr(attr, String(value), String(defaultValue));
|
|
271
|
+
}
|
|
272
|
+
return this;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
setHtmlAttr<K extends ClusterDotAttr>(attr: K, value: NonNullable<ClusterAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
276
|
+
setHtmlAttr(attr: string, value: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
277
|
+
setHtmlAttr(attr: string, value: unknown, defaultValue?: unknown): this {
|
|
278
|
+
if (defaultValue === undefined) {
|
|
279
|
+
this._sg.setHtmlAttr(attr, String(value));
|
|
280
|
+
} else {
|
|
281
|
+
this._sg.setHtmlAttr(attr, String(value), String(defaultValue));
|
|
282
|
+
}
|
|
283
|
+
return this;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
setDefaultAttr<K extends ClusterDotAttr>(attr: K, value: NonNullable<ClusterAttrs[K]>): this;
|
|
287
|
+
setDefaultAttr(attr: string, value: string | number | boolean): this;
|
|
288
|
+
setDefaultAttr(attr: string, value: unknown): this {
|
|
289
|
+
this._sg.setDefaultAttr(attr, String(value));
|
|
290
|
+
return this;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
setDefaultHtmlAttr<K extends ClusterDotAttr>(attr: K, value: NonNullable<ClusterAttrs[K]>): this;
|
|
294
|
+
setDefaultHtmlAttr(attr: string, value: string | number | boolean): this;
|
|
295
|
+
setDefaultHtmlAttr(attr: string, value: unknown): this {
|
|
296
|
+
this._sg.setDefaultHtmlAttr(attr, String(value));
|
|
196
297
|
return this;
|
|
197
298
|
}
|
|
198
299
|
|
|
@@ -209,12 +310,43 @@ export class Subgraph {
|
|
|
209
310
|
*
|
|
210
311
|
* When `attr` is a known node attribute the value type is inferred
|
|
211
312
|
* automatically. A generic `string | number | boolean` fallback is
|
|
212
|
-
* provided for custom attributes.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
setNodeAttr(node: string, attr:
|
|
217
|
-
|
|
313
|
+
* provided for custom attributes. Omit `value` to reset the attribute to
|
|
314
|
+
* Graphviz's default empty value. `defaultValue` is passed to Graphviz as
|
|
315
|
+
* the default for this attribute if it has not already been declared.
|
|
316
|
+
*/
|
|
317
|
+
setNodeAttr<K extends NodeDotAttr>(node: string, attr: K, value?: NonNullable<NodeAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
318
|
+
setNodeAttr(node: string, attr: string, value?: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
319
|
+
setNodeAttr(node: string, attr: string, value: unknown = "", defaultValue?: unknown): this {
|
|
320
|
+
if (defaultValue === undefined) {
|
|
321
|
+
this._sg.setNodeAttr(node, attr, String(value));
|
|
322
|
+
} else {
|
|
323
|
+
this._sg.setNodeAttr(node, attr, String(value), String(defaultValue));
|
|
324
|
+
}
|
|
325
|
+
return this;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
setNodeHtmlAttr<K extends NodeDotAttr>(node: string, attr: K, value: NonNullable<NodeAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
329
|
+
setNodeHtmlAttr(node: string, attr: string, value: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
330
|
+
setNodeHtmlAttr(node: string, attr: string, value: unknown, defaultValue?: unknown): this {
|
|
331
|
+
if (defaultValue === undefined) {
|
|
332
|
+
this._sg.setNodeHtmlAttr(node, attr, String(value));
|
|
333
|
+
} else {
|
|
334
|
+
this._sg.setNodeHtmlAttr(node, attr, String(value), String(defaultValue));
|
|
335
|
+
}
|
|
336
|
+
return this;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
setDefaultNodeAttr<K extends NodeDotAttr>(attr: K, value: NonNullable<NodeAttrs[K]>): this;
|
|
340
|
+
setDefaultNodeAttr(attr: string, value: string | number | boolean): this;
|
|
341
|
+
setDefaultNodeAttr(attr: string, value: unknown): this {
|
|
342
|
+
this._sg.setDefaultNodeAttr(attr, String(value));
|
|
343
|
+
return this;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
setDefaultNodeHtmlAttr<K extends NodeDotAttr>(attr: K, value: NonNullable<NodeAttrs[K]>): this;
|
|
347
|
+
setDefaultNodeHtmlAttr(attr: string, value: string | number | boolean): this;
|
|
348
|
+
setDefaultNodeHtmlAttr(attr: string, value: unknown): this {
|
|
349
|
+
this._sg.setDefaultNodeHtmlAttr(attr, String(value));
|
|
218
350
|
return this;
|
|
219
351
|
}
|
|
220
352
|
|
|
@@ -232,12 +364,43 @@ export class Subgraph {
|
|
|
232
364
|
*
|
|
233
365
|
* When `attr` is a known edge attribute the value type is inferred
|
|
234
366
|
* automatically. A generic `string | number | boolean` fallback is
|
|
235
|
-
* provided for custom attributes.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
setEdgeAttr(tail: string, head: string, key: string, attr:
|
|
240
|
-
|
|
367
|
+
* provided for custom attributes. Omit `value` to reset the attribute to
|
|
368
|
+
* Graphviz's default empty value. `defaultValue` is passed to Graphviz as
|
|
369
|
+
* the default for this attribute if it has not already been declared.
|
|
370
|
+
*/
|
|
371
|
+
setEdgeAttr<K extends EdgeDotAttr>(tail: string, head: string, key: string, attr: K, value?: NonNullable<EdgeAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
372
|
+
setEdgeAttr(tail: string, head: string, key: string, attr: string, value?: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
373
|
+
setEdgeAttr(tail: string, head: string, key: string, attr: string, value: unknown = "", defaultValue?: unknown): this {
|
|
374
|
+
if (defaultValue === undefined) {
|
|
375
|
+
this._sg.setEdgeAttr(tail, head, key, attr, String(value));
|
|
376
|
+
} else {
|
|
377
|
+
this._sg.setEdgeAttr(tail, head, key, attr, String(value), String(defaultValue));
|
|
378
|
+
}
|
|
379
|
+
return this;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
setEdgeHtmlAttr<K extends EdgeDotAttr>(tail: string, head: string, key: string, attr: K, value: NonNullable<EdgeAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
383
|
+
setEdgeHtmlAttr(tail: string, head: string, key: string, attr: string, value: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
384
|
+
setEdgeHtmlAttr(tail: string, head: string, key: string, attr: string, value: unknown, defaultValue?: unknown): this {
|
|
385
|
+
if (defaultValue === undefined) {
|
|
386
|
+
this._sg.setEdgeHtmlAttr(tail, head, key, attr, String(value));
|
|
387
|
+
} else {
|
|
388
|
+
this._sg.setEdgeHtmlAttr(tail, head, key, attr, String(value), String(defaultValue));
|
|
389
|
+
}
|
|
390
|
+
return this;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
setDefaultEdgeAttr<K extends EdgeDotAttr>(attr: K, value: NonNullable<EdgeAttrs[K]>): this;
|
|
394
|
+
setDefaultEdgeAttr(attr: string, value: string | number | boolean): this;
|
|
395
|
+
setDefaultEdgeAttr(attr: string, value: unknown): this {
|
|
396
|
+
this._sg.setDefaultEdgeAttr(attr, String(value));
|
|
397
|
+
return this;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
setDefaultEdgeHtmlAttr<K extends EdgeDotAttr>(attr: K, value: NonNullable<EdgeAttrs[K]>): this;
|
|
401
|
+
setDefaultEdgeHtmlAttr(attr: string, value: string | number | boolean): this;
|
|
402
|
+
setDefaultEdgeHtmlAttr(attr: string, value: unknown): this {
|
|
403
|
+
this._sg.setDefaultEdgeHtmlAttr(attr, String(value));
|
|
241
404
|
return this;
|
|
242
405
|
}
|
|
243
406
|
|
|
@@ -275,6 +438,11 @@ export class Subgraph {
|
|
|
275
438
|
/** Returns the number of edges in this subgraph. */
|
|
276
439
|
edgeCount(): number { return this._sg.edgeCount(); }
|
|
277
440
|
|
|
441
|
+
/** Returns the degree of a named node in this subgraph. */
|
|
442
|
+
nodeDegree(node: string, inDegree: number = 1, outDegree: number = 1): number {
|
|
443
|
+
return this._sg.nodeDegree(node, inDegree, outDegree);
|
|
444
|
+
}
|
|
445
|
+
|
|
278
446
|
// ---- Attribute reading ----------------------------------------------
|
|
279
447
|
|
|
280
448
|
/**
|
|
@@ -396,8 +564,15 @@ export class Graph {
|
|
|
396
564
|
* Create a node. If a node with this name already exists it is returned
|
|
397
565
|
* unchanged.
|
|
398
566
|
*/
|
|
399
|
-
addNode(name: string): this
|
|
567
|
+
addNode(name: string): this;
|
|
568
|
+
addNode(init: NodeInit): this;
|
|
569
|
+
addNode(nameOrInit: string | NodeInit): this {
|
|
570
|
+
const init = typeof nameOrInit === "string" ? { name: nameOrInit } : nameOrInit;
|
|
571
|
+
const { name, attrs, htmlAttrs } = init;
|
|
572
|
+
|
|
400
573
|
this._graph.addNode(name);
|
|
574
|
+
applyAttrs<NodeAttrs>(attrs, (attr, value) => this.setNodeAttr(name, attr, value));
|
|
575
|
+
applyAttrs<NodeAttrs>(htmlAttrs, (attr, value) => this.setNodeHtmlAttr(name, attr, value));
|
|
401
576
|
return this;
|
|
402
577
|
}
|
|
403
578
|
|
|
@@ -407,22 +582,82 @@ export class Graph {
|
|
|
407
582
|
* parallel edges between the same pair of nodes; omit (or pass `""`) for
|
|
408
583
|
* an anonymous edge.
|
|
409
584
|
*/
|
|
410
|
-
addEdge(tail: string, head: string, key
|
|
411
|
-
|
|
585
|
+
addEdge(tail: string, head: string, key?: string): this;
|
|
586
|
+
addEdge(init: EdgeInit): this;
|
|
587
|
+
addEdge(tailOrInit: string | EdgeInit, head?: string, key: string = ""): this {
|
|
588
|
+
const init = typeof tailOrInit === "string"
|
|
589
|
+
? { tail: tailOrInit, head: head!, key }
|
|
590
|
+
: tailOrInit;
|
|
591
|
+
const { tail, head: resolvedHead, key: resolvedKey = "", attrs, htmlAttrs } = init;
|
|
592
|
+
|
|
593
|
+
this._graph.addEdge(tail, resolvedHead, resolvedKey);
|
|
594
|
+
applyAttrs<EdgeAttrs>(attrs, (attr, value) => this.setEdgeAttr(tail, resolvedHead, resolvedKey, attr, value));
|
|
595
|
+
applyAttrs<EdgeAttrs>(htmlAttrs, (attr, value) => this.setEdgeHtmlAttr(tail, resolvedHead, resolvedKey, attr, value));
|
|
596
|
+
return this;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
applyInit(init: GraphInit): this {
|
|
600
|
+
applyAttrs<GraphAttrs>(init.attrs, (attr, value) => this.setGraphAttr(attr, value));
|
|
601
|
+
applyAttrs<GraphAttrs>(init.htmlAttrs, (attr, value) => this.setGraphHtmlAttr(attr, value));
|
|
602
|
+
return this;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Replace this graph with one parsed from DOT source using Graphviz cgraph
|
|
607
|
+
* reading support.
|
|
608
|
+
*/
|
|
609
|
+
read(dotSource: string): this {
|
|
610
|
+
if (!this._graph.read(dotSource)) {
|
|
611
|
+
throw new Error("Invalid DOT source");
|
|
612
|
+
}
|
|
412
613
|
return this;
|
|
413
614
|
}
|
|
414
615
|
|
|
415
616
|
/**
|
|
416
617
|
* Set a graph-level attribute (e.g. `"rankdir"`, `"label"`, `"bgcolor"`).
|
|
618
|
+
* See the official Graphviz [attribute reference](https://graphviz.org/docs/attrs/)
|
|
619
|
+
* for supported attributes and values.
|
|
417
620
|
*
|
|
418
621
|
* When `attr` is a known graph attribute the value type is inferred
|
|
419
622
|
* automatically. A generic `string | number | boolean` fallback is
|
|
420
|
-
* provided for custom or less-common attributes.
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
623
|
+
* provided for custom or less-common attributes. Omit `value` to reset
|
|
624
|
+
* the attribute to Graphviz's default empty value. `defaultValue` is
|
|
625
|
+
* passed to Graphviz as the default for this attribute if it has not
|
|
626
|
+
* already been declared.
|
|
627
|
+
*/
|
|
628
|
+
setGraphAttr<K extends GraphDotAttr>(attr: K, value?: NonNullable<GraphAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
629
|
+
setGraphAttr(attr: string, value?: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
630
|
+
setGraphAttr(attr: string, value: unknown = "", defaultValue?: unknown): this {
|
|
631
|
+
if (defaultValue === undefined) {
|
|
632
|
+
this._graph.setGraphAttr(attr, String(value));
|
|
633
|
+
} else {
|
|
634
|
+
this._graph.setGraphAttr(attr, String(value), String(defaultValue));
|
|
635
|
+
}
|
|
636
|
+
return this;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
setGraphHtmlAttr<K extends GraphDotAttr>(attr: K, value: NonNullable<GraphAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
640
|
+
setGraphHtmlAttr(attr: string, value: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
641
|
+
setGraphHtmlAttr(attr: string, value: unknown, defaultValue?: unknown): this {
|
|
642
|
+
if (defaultValue === undefined) {
|
|
643
|
+
this._graph.setGraphHtmlAttr(attr, String(value));
|
|
644
|
+
} else {
|
|
645
|
+
this._graph.setGraphHtmlAttr(attr, String(value), String(defaultValue));
|
|
646
|
+
}
|
|
647
|
+
return this;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
setDefaultGraphAttr<K extends GraphDotAttr>(attr: K, value: NonNullable<GraphAttrs[K]>): this;
|
|
651
|
+
setDefaultGraphAttr(attr: string, value: string | number | boolean): this;
|
|
652
|
+
setDefaultGraphAttr(attr: string, value: unknown): this {
|
|
653
|
+
this._graph.setDefaultGraphAttr(attr, String(value));
|
|
654
|
+
return this;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
setDefaultGraphHtmlAttr<K extends GraphDotAttr>(attr: K, value: NonNullable<GraphAttrs[K]>): this;
|
|
658
|
+
setDefaultGraphHtmlAttr(attr: string, value: string | number | boolean): this;
|
|
659
|
+
setDefaultGraphHtmlAttr(attr: string, value: unknown): this {
|
|
660
|
+
this._graph.setDefaultGraphHtmlAttr(attr, String(value));
|
|
426
661
|
return this;
|
|
427
662
|
}
|
|
428
663
|
|
|
@@ -432,12 +667,43 @@ export class Graph {
|
|
|
432
667
|
*
|
|
433
668
|
* When `attr` is a known node attribute the value type is inferred
|
|
434
669
|
* automatically. A generic `string | number | boolean` fallback is
|
|
435
|
-
* provided for custom attributes.
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
setNodeAttr(node: string, attr:
|
|
440
|
-
|
|
670
|
+
* provided for custom attributes. Omit `value` to reset the attribute to
|
|
671
|
+
* Graphviz's default empty value. `defaultValue` is passed to Graphviz as
|
|
672
|
+
* the default for this attribute if it has not already been declared.
|
|
673
|
+
*/
|
|
674
|
+
setNodeAttr<K extends NodeDotAttr>(node: string, attr: K, value?: NonNullable<NodeAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
675
|
+
setNodeAttr(node: string, attr: string, value?: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
676
|
+
setNodeAttr(node: string, attr: string, value: unknown = "", defaultValue?: unknown): this {
|
|
677
|
+
if (defaultValue === undefined) {
|
|
678
|
+
this._graph.setNodeAttr(node, attr, String(value));
|
|
679
|
+
} else {
|
|
680
|
+
this._graph.setNodeAttr(node, attr, String(value), String(defaultValue));
|
|
681
|
+
}
|
|
682
|
+
return this;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
setNodeHtmlAttr<K extends NodeDotAttr>(node: string, attr: K, value: NonNullable<NodeAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
686
|
+
setNodeHtmlAttr(node: string, attr: string, value: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
687
|
+
setNodeHtmlAttr(node: string, attr: string, value: unknown, defaultValue?: unknown): this {
|
|
688
|
+
if (defaultValue === undefined) {
|
|
689
|
+
this._graph.setNodeHtmlAttr(node, attr, String(value));
|
|
690
|
+
} else {
|
|
691
|
+
this._graph.setNodeHtmlAttr(node, attr, String(value), String(defaultValue));
|
|
692
|
+
}
|
|
693
|
+
return this;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
setDefaultNodeAttr<K extends NodeDotAttr>(attr: K, value: NonNullable<NodeAttrs[K]>): this;
|
|
697
|
+
setDefaultNodeAttr(attr: string, value: string | number | boolean): this;
|
|
698
|
+
setDefaultNodeAttr(attr: string, value: unknown): this {
|
|
699
|
+
this._graph.setDefaultNodeAttr(attr, String(value));
|
|
700
|
+
return this;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
setDefaultNodeHtmlAttr<K extends NodeDotAttr>(attr: K, value: NonNullable<NodeAttrs[K]>): this;
|
|
704
|
+
setDefaultNodeHtmlAttr(attr: string, value: string | number | boolean): this;
|
|
705
|
+
setDefaultNodeHtmlAttr(attr: string, value: unknown): this {
|
|
706
|
+
this._graph.setDefaultNodeHtmlAttr(attr, String(value));
|
|
441
707
|
return this;
|
|
442
708
|
}
|
|
443
709
|
|
|
@@ -448,12 +714,43 @@ export class Graph {
|
|
|
448
714
|
*
|
|
449
715
|
* When `attr` is a known edge attribute the value type is inferred
|
|
450
716
|
* automatically. A generic `string | number | boolean` fallback is
|
|
451
|
-
* provided for custom attributes.
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
setEdgeAttr(tail: string, head: string, key: string, attr:
|
|
456
|
-
|
|
717
|
+
* provided for custom attributes. Omit `value` to reset the attribute to
|
|
718
|
+
* Graphviz's default empty value. `defaultValue` is passed to Graphviz as
|
|
719
|
+
* the default for this attribute if it has not already been declared.
|
|
720
|
+
*/
|
|
721
|
+
setEdgeAttr<K extends EdgeDotAttr>(tail: string, head: string, key: string, attr: K, value?: NonNullable<EdgeAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
722
|
+
setEdgeAttr(tail: string, head: string, key: string, attr: string, value?: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
723
|
+
setEdgeAttr(tail: string, head: string, key: string, attr: string, value: unknown = "", defaultValue?: unknown): this {
|
|
724
|
+
if (defaultValue === undefined) {
|
|
725
|
+
this._graph.setEdgeAttr(tail, head, key, attr, String(value));
|
|
726
|
+
} else {
|
|
727
|
+
this._graph.setEdgeAttr(tail, head, key, attr, String(value), String(defaultValue));
|
|
728
|
+
}
|
|
729
|
+
return this;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
setEdgeHtmlAttr<K extends EdgeDotAttr>(tail: string, head: string, key: string, attr: K, value: NonNullable<EdgeAttrs[K]>, defaultValue?: string | number | boolean): this;
|
|
733
|
+
setEdgeHtmlAttr(tail: string, head: string, key: string, attr: string, value: string | number | boolean, defaultValue?: string | number | boolean): this;
|
|
734
|
+
setEdgeHtmlAttr(tail: string, head: string, key: string, attr: string, value: unknown, defaultValue?: unknown): this {
|
|
735
|
+
if (defaultValue === undefined) {
|
|
736
|
+
this._graph.setEdgeHtmlAttr(tail, head, key, attr, String(value));
|
|
737
|
+
} else {
|
|
738
|
+
this._graph.setEdgeHtmlAttr(tail, head, key, attr, String(value), String(defaultValue));
|
|
739
|
+
}
|
|
740
|
+
return this;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
setDefaultEdgeAttr<K extends EdgeDotAttr>(attr: K, value: NonNullable<EdgeAttrs[K]>): this;
|
|
744
|
+
setDefaultEdgeAttr(attr: string, value: string | number | boolean): this;
|
|
745
|
+
setDefaultEdgeAttr(attr: string, value: unknown): this {
|
|
746
|
+
this._graph.setDefaultEdgeAttr(attr, String(value));
|
|
747
|
+
return this;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
setDefaultEdgeHtmlAttr<K extends EdgeDotAttr>(attr: K, value: NonNullable<EdgeAttrs[K]>): this;
|
|
751
|
+
setDefaultEdgeHtmlAttr(attr: string, value: string | number | boolean): this;
|
|
752
|
+
setDefaultEdgeHtmlAttr(attr: string, value: unknown): this {
|
|
753
|
+
this._graph.setDefaultEdgeHtmlAttr(attr, String(value));
|
|
457
754
|
return this;
|
|
458
755
|
}
|
|
459
756
|
|
|
@@ -547,6 +844,11 @@ export class Graph {
|
|
|
547
844
|
/** Returns the number of direct subgraphs of this graph. */
|
|
548
845
|
subgraphCount(): number { return this._graph.subgraphCount(); }
|
|
549
846
|
|
|
847
|
+
/** Returns the degree of a named node in the graph. */
|
|
848
|
+
nodeDegree(node: string, inDegree: number = 1, outDegree: number = 1): number {
|
|
849
|
+
return this._graph.nodeDegree(node, inDegree, outDegree);
|
|
850
|
+
}
|
|
851
|
+
|
|
550
852
|
// ---- Attribute reading ----------------------------------------------
|
|
551
853
|
|
|
552
854
|
/**
|
|
@@ -636,10 +938,13 @@ export class Graph {
|
|
|
636
938
|
* cluster.setAttr("label", "My Cluster").addEdge("a", "b");
|
|
637
939
|
* ```
|
|
638
940
|
*/
|
|
639
|
-
addSubgraph(name: string): Subgraph
|
|
941
|
+
addSubgraph(name: string): Subgraph;
|
|
942
|
+
addSubgraph(init: SubgraphInit): Subgraph;
|
|
943
|
+
addSubgraph(nameOrInit: string | SubgraphInit): Subgraph {
|
|
944
|
+
const init = typeof nameOrInit === "string" ? { name: nameOrInit } : nameOrInit;
|
|
640
945
|
// addSubgraph only returns null when the internal graph pointer is null,
|
|
641
946
|
// which cannot happen while this Graph instance is alive.
|
|
642
|
-
return new Subgraph(this._graph.addSubgraph(name)!);
|
|
947
|
+
return new Subgraph(this._graph.addSubgraph(init.name)!).applyInit(init);
|
|
643
948
|
}
|
|
644
949
|
|
|
645
950
|
/**
|
|
@@ -697,11 +1002,18 @@ export class Graph {
|
|
|
697
1002
|
return retVal;
|
|
698
1003
|
}
|
|
699
1004
|
|
|
1005
|
+
/**
|
|
1006
|
+
* Serialise the graph to a DOT-language string.
|
|
1007
|
+
*/
|
|
1008
|
+
write(): string {
|
|
1009
|
+
return this._graph.write();
|
|
1010
|
+
}
|
|
1011
|
+
|
|
700
1012
|
/**
|
|
701
1013
|
* Serialise the graph to a DOT-language string.
|
|
702
1014
|
*/
|
|
703
1015
|
toDot(): string {
|
|
704
|
-
return this.
|
|
1016
|
+
return this.write();
|
|
705
1017
|
}
|
|
706
1018
|
|
|
707
1019
|
/**
|
|
@@ -1067,9 +1379,32 @@ export class Graphviz {
|
|
|
1067
1379
|
* const svg = graphviz.dot(graph.toDot());
|
|
1068
1380
|
* ```
|
|
1069
1381
|
*/
|
|
1070
|
-
createGraph(name
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1382
|
+
createGraph(name?: string, type?: GraphType): Graph;
|
|
1383
|
+
createGraph(init: GraphInit): Graph;
|
|
1384
|
+
createGraph(nameOrInit: string | GraphInit = "G", type: GraphType = "directed"): Graph {
|
|
1385
|
+
const init = typeof nameOrInit === "string"
|
|
1386
|
+
? { name: nameOrInit, type }
|
|
1387
|
+
: nameOrInit;
|
|
1388
|
+
const resolvedName = init.name ?? "G";
|
|
1389
|
+
const resolvedType = init.type ?? "directed";
|
|
1390
|
+
const directed = !resolvedType.includes("undirected") ? 1 : 0;
|
|
1391
|
+
const strict = resolvedType.startsWith("strict") ? 1 : 0;
|
|
1392
|
+
return new Graph(new this._module.CGraph(resolvedName, directed, strict), this._module).applyInit(init);
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* Parse DOT source into a mutable {@link Graph}. The returned graph can
|
|
1397
|
+
* be queried, modified, rendered directly, or serialised back to DOT with
|
|
1398
|
+
* {@link Graph.toDot}.
|
|
1399
|
+
*/
|
|
1400
|
+
read(dotSource: string): Graph {
|
|
1401
|
+
const graph = this.createGraph();
|
|
1402
|
+
try {
|
|
1403
|
+
graph.read(dotSource);
|
|
1404
|
+
return graph;
|
|
1405
|
+
} catch (e) {
|
|
1406
|
+
graph.delete();
|
|
1407
|
+
throw e;
|
|
1408
|
+
}
|
|
1074
1409
|
}
|
|
1075
1410
|
}
|
package/src/types.ts
CHANGED
|
@@ -81,6 +81,7 @@ export interface NodeAttrs {
|
|
|
81
81
|
group?: string;
|
|
82
82
|
height?: number;
|
|
83
83
|
href?: string;
|
|
84
|
+
id?: string;
|
|
84
85
|
image?: string;
|
|
85
86
|
imagepos?: string;
|
|
86
87
|
imagescale?: boolean | string;
|
|
@@ -146,6 +147,7 @@ export interface EdgeAttrs {
|
|
|
146
147
|
headtooltip?: string;
|
|
147
148
|
headURL?: string;
|
|
148
149
|
href?: string;
|
|
150
|
+
id?: string;
|
|
149
151
|
label?: string;
|
|
150
152
|
labelangle?: number;
|
|
151
153
|
labeldistance?: number;
|
|
@@ -204,6 +206,7 @@ export interface ClusterAttrs {
|
|
|
204
206
|
fontsize?: number;
|
|
205
207
|
gradientangle?: number;
|
|
206
208
|
href?: string;
|
|
209
|
+
id?: string;
|
|
207
210
|
K?: number;
|
|
208
211
|
label?: string;
|
|
209
212
|
labeljust?: string;
|
|
@@ -374,6 +377,7 @@ export const NODE_DOT_ATTRS: readonly NodeDotAttr[] = attrsOf<NodeDotAttr>({
|
|
|
374
377
|
group: true,
|
|
375
378
|
height: true,
|
|
376
379
|
href: true,
|
|
380
|
+
id: true,
|
|
377
381
|
image: true,
|
|
378
382
|
imagepos: true,
|
|
379
383
|
imagescale: true,
|
|
@@ -434,6 +438,7 @@ export const EDGE_DOT_ATTRS: readonly EdgeDotAttr[] = attrsOf<EdgeDotAttr>({
|
|
|
434
438
|
headtooltip: true,
|
|
435
439
|
headURL: true,
|
|
436
440
|
href: true,
|
|
441
|
+
id: true,
|
|
437
442
|
label: true,
|
|
438
443
|
labelangle: true,
|
|
439
444
|
labeldistance: true,
|
|
@@ -486,6 +491,7 @@ export const CLUSTER_DOT_ATTRS: readonly ClusterDotAttr[] = attrsOf<ClusterDotAt
|
|
|
486
491
|
fontsize: true,
|
|
487
492
|
gradientangle: true,
|
|
488
493
|
href: true,
|
|
494
|
+
id: true,
|
|
489
495
|
K: true,
|
|
490
496
|
label: true,
|
|
491
497
|
labeljust: true,
|