GraphStream
This commit is contained in:
@ -1,10 +0,0 @@
|
||||
export enum GraphLayouts {
|
||||
neato = 'neato',
|
||||
dot = 'dot',
|
||||
circo = 'circo',
|
||||
fdp = 'fdp',
|
||||
sfdp = 'sfdp',
|
||||
osage = 'osage',
|
||||
twopi = 'twopi',
|
||||
patchwork = 'patchwork'
|
||||
}
|
10
lib/Helper.ts
Normal file
10
lib/Helper.ts
Normal file
@ -0,0 +1,10 @@
|
||||
function validate_name (name: string): string {
|
||||
const new_name = name
|
||||
.replace (/[^a-z0-9]/giu, '')
|
||||
.replace (/^[0-9]+/iu, '');
|
||||
if (new_name === '')
|
||||
throw new Error (`invalid node name ${name}`);
|
||||
return new_name;
|
||||
}
|
||||
|
||||
export { validate_name };
|
@ -1,33 +0,0 @@
|
||||
enum EdgeStyles {
|
||||
default = '',
|
||||
solid = 'solid',
|
||||
dashed = 'dashed',
|
||||
dotted='dotted',
|
||||
bold='bold'
|
||||
}
|
||||
|
||||
enum NodeStyles {
|
||||
default = '',
|
||||
solid='solid',
|
||||
dashed='dashed',
|
||||
dotted='dotted',
|
||||
bold='bold',
|
||||
rounded='rounded',
|
||||
diagonals='diagonals',
|
||||
filled='filled',
|
||||
striped='striped',
|
||||
wedged='wedged',
|
||||
invisible='invis'
|
||||
}
|
||||
|
||||
enum GraphStyles {
|
||||
solid = 'solid',
|
||||
dashed = 'dashed',
|
||||
dotted = 'dotted',
|
||||
bold = 'bold',
|
||||
rounded = 'rounded',
|
||||
filled = 'filled',
|
||||
striped = 'striped'
|
||||
}
|
||||
|
||||
export { EdgeStyles, NodeStyles, GraphStyles };
|
@ -1,4 +1,4 @@
|
||||
import { EdgeStyles } from './Styles';
|
||||
import { EdgeStyles } from '../enums/Styles';
|
||||
import { Color } from './Color';
|
||||
|
||||
export class Edge {
|
@ -1,3 +1,5 @@
|
||||
import { validate_name } from '../Helper';
|
||||
|
||||
export class Element {
|
||||
private _name = '';
|
||||
protected parent_name: string;
|
||||
@ -13,11 +15,7 @@ export class Element {
|
||||
}
|
||||
|
||||
public set name (val: string) {
|
||||
const new_name = val.replace (/[^a-z0-9]/giu, '')
|
||||
.replace (/^[0-9]+/iu, '');
|
||||
if (new_name === '')
|
||||
throw new Error (`invalid node name ${val}`);
|
||||
this._name = new_name;
|
||||
this._name = validate_name (val);
|
||||
}
|
||||
|
||||
public get parent (): string {
|
@ -1,9 +1,9 @@
|
||||
import { GraphStyles, NodeStyles } from '../enums/Styles';
|
||||
import { GraphLayouts } from '../enums/GraphLayouts';
|
||||
import { Element } from './Element';
|
||||
import { Edge } from './Edge';
|
||||
import { Node } from './Node';
|
||||
import { GraphStyles, NodeStyles } from './Styles';
|
||||
import { Color } from './Color';
|
||||
import { GraphLayouts } from './GraphLayouts';
|
||||
|
||||
interface NodeOptions {
|
||||
name: string;
|
160
lib/classes/GraphStream.ts
Normal file
160
lib/classes/GraphStream.ts
Normal file
@ -0,0 +1,160 @@
|
||||
/* eslint-disable line-comment-position */
|
||||
/* eslint-disable no-inline-comments */
|
||||
import { Transform } from 'stream';
|
||||
import { GraphStreamJSON } from '../interfaces/GraphStreamJSON';
|
||||
import { GraphStreamCommand } from '../enums/GraphStreamCommand';
|
||||
|
||||
interface Stringable {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
export class GraphStream extends Transform {
|
||||
private _path: string[] = [];
|
||||
private _state = '';
|
||||
private _directional = false;
|
||||
|
||||
public get path (): string {
|
||||
return this._path.join ('_');
|
||||
}
|
||||
|
||||
private get level (): string {
|
||||
return ' '.repeat (this._path.length);
|
||||
}
|
||||
|
||||
private expect_state (instr: GraphStreamCommand): void {
|
||||
const states = [];
|
||||
if ([
|
||||
'cug',
|
||||
'cdg'
|
||||
].includes (instr))
|
||||
states.push ('');
|
||||
|
||||
if ([
|
||||
'eg',
|
||||
'cn',
|
||||
'csg',
|
||||
'ce'
|
||||
].includes (instr))
|
||||
states.push ('en', 'at', 'eg', 'cug', 'cdg', 'csg', 'ce');
|
||||
|
||||
switch (instr) {
|
||||
case 'en':
|
||||
states.push ('cn', 'at');
|
||||
break;
|
||||
case 'at':
|
||||
states.push ('cn', 'cug', 'cdg', 'csg');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!states.includes (this._state)) {
|
||||
throw new Error (`invalid state to execute command ${instr}
|
||||
expected: ${states.join (', ')}`);
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention, complexity, max-lines-per-function
|
||||
public _transform (
|
||||
chunk: string,
|
||||
encoding: string,
|
||||
callback: ((error?: Error) => unknown)
|
||||
): void {
|
||||
const instr = JSON.parse (chunk) as GraphStreamJSON;
|
||||
this.expect_state (instr.type);
|
||||
switch (instr.type) {
|
||||
case 'cug': // create unordered graph
|
||||
this._path.push (instr.args[0]);
|
||||
this.push (`graph ${this.path} {\n`);
|
||||
this._directional = false;
|
||||
break;
|
||||
case 'cdg': // create directional graph
|
||||
this._path.push (instr.args[0]);
|
||||
this.push (`digraph ${this.path} {\n`);
|
||||
this._directional = true;
|
||||
break;
|
||||
case 'csg': // create subgraph
|
||||
this.push (
|
||||
`${this.level}subgraph cluster_${this.path}_${instr.args[0]} {\n`
|
||||
);
|
||||
this._path.push (instr.args[0]);
|
||||
break;
|
||||
case 'eg': // end graph
|
||||
this._path.pop ();
|
||||
this.push (`${this.level}}\n\n`);
|
||||
break;
|
||||
case 'cn': // create node
|
||||
this.push (`${this.level}${this.path}_${instr.args[0]}`);
|
||||
break;
|
||||
case 'en': // end node
|
||||
this.push ('\n');
|
||||
break;
|
||||
case 'at': // add attributes
|
||||
if (this._state === 'cn') {
|
||||
this.push (` [${instr.args.join (', ')}]`);
|
||||
}
|
||||
else {
|
||||
this.push (`${this.level}${
|
||||
instr.args.join (`\n${this.level}`)
|
||||
.replace (/"/gu, '')
|
||||
}\n\n`);
|
||||
}
|
||||
break;
|
||||
case 'ce':
|
||||
this.push (`${this.level}${
|
||||
instr.args[0]
|
||||
} -${this._directional ? '>' : '-'} ${instr.args[1]}\n`);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this._state = instr.type;
|
||||
callback ();
|
||||
}
|
||||
|
||||
public write (
|
||||
instr: GraphStreamJSON
|
||||
): boolean {
|
||||
return super.write (JSON.stringify (instr), 'utf-8');
|
||||
}
|
||||
|
||||
public create_node (name: string): boolean {
|
||||
return this.write ({ type: 'cn', args: [ name ] });
|
||||
}
|
||||
|
||||
public end_node (): boolean {
|
||||
return this.write ({ type: 'en', args: [] });
|
||||
}
|
||||
|
||||
public create_graph (name: string, type: 'u'|'d'|'s' = 's'): boolean {
|
||||
const instr_type = `c${type}g` as GraphStreamCommand;
|
||||
return this.write ({ type: instr_type, args: [ name ] });
|
||||
}
|
||||
|
||||
public end_graph (): boolean {
|
||||
return this.write ({ type: 'eg', args: [] });
|
||||
}
|
||||
|
||||
public attributes (attrs: Record<string, Stringable>): boolean {
|
||||
const solved = [];
|
||||
for (const attr of Object.keys (attrs)) {
|
||||
const val = attrs[attr].toString ();
|
||||
if ((/\n/u).test (val))
|
||||
solved.push (`${attr} = <${val}>`);
|
||||
else
|
||||
solved.push (`${attr} = "${val}"`);
|
||||
}
|
||||
return this.write ({ type: 'at', args: solved });
|
||||
}
|
||||
|
||||
public create_edge (origin: string, target: string): boolean {
|
||||
return this.write ({
|
||||
type: 'ce',
|
||||
args: [
|
||||
origin,
|
||||
target
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { NodeStyles } from '../enums/Styles';
|
||||
import { Element } from './Element';
|
||||
import { NodeStyles } from './Styles';
|
||||
import { Color } from './Color';
|
||||
|
||||
export class Node extends Element {
|
9
lib/enums/GraphLayouts.ts
Normal file
9
lib/enums/GraphLayouts.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export type GraphLayouts =
|
||||
'neato'
|
||||
| 'dot'
|
||||
| 'circo'
|
||||
| 'fdp'
|
||||
| 'sfdp'
|
||||
| 'osage'
|
||||
| 'twopi'
|
||||
| 'patchwork'
|
11
lib/enums/GraphStreamCommand.ts
Normal file
11
lib/enums/GraphStreamCommand.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* eslint-disable line-comment-position */
|
||||
/* eslint-disable no-inline-comments */
|
||||
export type GraphStreamCommand =
|
||||
'cn'| // create node
|
||||
'en'| // end node
|
||||
'cug'| // create unordered graph
|
||||
'cdg'| // create directional graph
|
||||
'csg'| // create subgraph
|
||||
'eg'| // end graph
|
||||
'at'| // add attributes
|
||||
'ce' // create edge
|
32
lib/enums/Styles.ts
Normal file
32
lib/enums/Styles.ts
Normal file
@ -0,0 +1,32 @@
|
||||
type EdgeStyles =
|
||||
''
|
||||
|'solid'
|
||||
|'dashed'
|
||||
|'dotted'
|
||||
|'bold'
|
||||
|
||||
|
||||
type NodeStyles =
|
||||
''
|
||||
|'solid'
|
||||
|'dashed'
|
||||
|'dotted'
|
||||
|'bold'
|
||||
|'rounded'
|
||||
|'diagonals'
|
||||
|'filled'
|
||||
|'striped'
|
||||
|'wedged'
|
||||
|'invis'
|
||||
|
||||
|
||||
type GraphStyles =
|
||||
'solid'
|
||||
| 'dashed'
|
||||
| 'dotted'
|
||||
| 'bold'
|
||||
| 'rounded'
|
||||
| 'filled'
|
||||
| 'striped'
|
||||
|
||||
export { EdgeStyles, NodeStyles, GraphStyles };
|
20
lib/index.ts
20
lib/index.ts
@ -1,8 +1,12 @@
|
||||
export { Graph } from './Graph';
|
||||
export { Node } from './Node';
|
||||
export { Element } from './Element';
|
||||
export { Edge } from './Edge';
|
||||
export { Color } from './Color';
|
||||
export { EdgeStyles, NodeStyles, GraphStyles } from './Styles';
|
||||
export { GraphLayouts } from './GraphLayouts';
|
||||
export { Graphable } from './Graphable';
|
||||
import { Graph } from './classes/Graph';
|
||||
|
||||
export * from './classes/Color';
|
||||
export * from './classes/Edge';
|
||||
export * from './classes/Element';
|
||||
export { Graph };
|
||||
export * from './classes/GraphStream';
|
||||
export * from './classes/Node';
|
||||
export * from './enums/GraphLayouts';
|
||||
export * from './enums/Styles';
|
||||
export * from './interfaces/Graphable';
|
||||
export default Graph;
|
||||
|
6
lib/interfaces/GraphStreamJSON.ts
Normal file
6
lib/interfaces/GraphStreamJSON.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { GraphStreamCommand } from '../enums/GraphStreamCommand';
|
||||
|
||||
export interface GraphStreamJSON {
|
||||
type: GraphStreamCommand;
|
||||
args: string[];
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { Graph } from './Graph';
|
||||
import { Graph } from '../classes/Graph';
|
||||
|
||||
export interface Graphable {
|
||||
to_graph(g: Graph, ...args: unknown[]): unknown;
|
Reference in New Issue
Block a user