Compare commits

..

67 Commits

Author SHA1 Message Date
cef87ba4a5 lint
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-25 14:17:58 +01:00
78556c6c98 node shape
Some checks failed
continuous-integration/drone/push Build is failing
2023-03-25 14:12:10 +01:00
019647b04a formatting, update
Some checks failed
continuous-integration/drone/push Build is failing
2021-05-02 11:30:21 +02:00
fa8e0d25c6 bump version
All checks were successful
continuous-integration/drone/push Build is passing
2020-10-05 20:16:10 +02:00
af7bd4e00e additional test for expected states
Some checks failed
continuous-integration/drone/push Build is failing
2020-10-05 20:15:22 +02:00
9a2c2ce14c remove obsolete enum type 2020-10-05 19:32:29 +02:00
59542eb7b1 use jasmine 2020-10-05 19:16:09 +02:00
cafcc73366 update-scanner: automatic update
Some checks failed
continuous-integration/drone/push Build is failing
eslint: 7.7.0 ==> 7.8.1 minor
2020-09-07 13:36:51 +02:00
e8382f8117 update-scanner: automatic update
Some checks failed
continuous-integration/drone/push Build is failing
ava: 3.11.1 ==> 3.12.1 minor
2020-08-30 15:59:46 +02:00
4be028f4ef upgrade typescript
All checks were successful
continuous-integration/drone/push Build is passing
2020-08-21 13:17:17 +02:00
efdd4ebcd6 update-scanner: automatic update
Some checks failed
continuous-integration/drone/push Build is failing
eslint: 7.6.0 ==> 7.7.0 minor
2020-08-19 08:28:13 +02:00
78ad75fd8e fix drone config
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-07 08:12:45 +02:00
38a5d2f710 update-scanner: automatic update
Some checks failed
continuous-integration/drone/push Build is failing
ava: 3.10.1 ==> 3.11.1 minor
eslint: 7.5.0 ==> 7.6.0 minor
2020-08-04 12:59:51 +02:00
b95f5daa60 update-scanner: automatic update
All checks were successful
continuous-integration/drone/push Build is passing
@sapphirecode/eslint-config-ts: 1.1.21 ==> 1.1.22 minor
2020-07-25 16:54:02 +02:00
aa1343fedf update-scanner: automatic update
All checks were successful
continuous-integration/drone/push Build is passing
@sapphirecode/encoding-helper: 1.0.48 ==> 1.0.49 minor
@sapphirecode/eslint-config-ts: 1.1.20 ==> 1.1.21 minor
2020-07-19 15:10:59 +02:00
f057f2caa6 fix
Some checks failed
continuous-integration/drone/push Build is failing
2020-07-19 14:03:57 +02:00
dfe3224dec update-scanner: automatic update
Some checks failed
continuous-integration/drone/push Build is failing
eslint: 7.4.0 ==> 7.5.0 minor
typescript: 3.9.6 ==> 3.9.7 minor
2020-07-19 12:15:06 +02:00
de5810d368 stream: node count
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-17 13:29:03 +02:00
040e421d9b update-scanner: automatic update
All checks were successful
continuous-integration/drone/push Build is passing
@sapphirecode/eslint-config-ts: 1.1.19 ==> 1.1.20 minor
2020-07-16 10:55:12 +02:00
9c2c95e108 update-scanner: automatic update
All checks were successful
continuous-integration/drone/push Build is passing
@sapphirecode/encoding-helper: 1.0.46 ==> 1.0.48 minor
@sapphirecode/eslint-config-ts: 1.1.17 ==> 1.1.19 minor
ava: 3.9.0 ==> 3.10.1 minor
eslint: 7.3.1 ==> 7.4.0 minor
typescript: 3.9.5 ==> 3.9.6 minor
2020-07-10 12:35:57 +02:00
76b2ff31e6 switch to drone
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-10 08:30:42 +02:00
35e3c69405 update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.45 ==> 1.0.46 minor
@sapphirecode/eslint-config-ts: 1.1.16 ==> 1.1.17 minor
2020-07-01 09:35:11 +02:00
86dd8fefe0 update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.44 ==> 1.0.45 minor
@sapphirecode/eslint-config-ts: 1.1.14 ==> 1.1.16 minor
eslint: 7.3.0 ==> 7.3.1 minor
2020-06-24 12:54:14 +02:00
6af5a144ad update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.43 ==> 1.0.44 minor
@sapphirecode/eslint-config-ts: 1.1.13 ==> 1.1.14 minor
eslint: 7.2.0 ==> 7.3.0 minor
2020-06-22 08:24:46 +02:00
f0bf164873 update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.42 ==> 1.0.43 minor
@sapphirecode/eslint-config-ts: 1.1.12 ==> 1.1.13 minor
ava: 3.8.2 ==> 3.9.0 minor
2020-06-19 13:12:17 +02:00
a3b3f43812 update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.41 ==> 1.0.42 minor
@sapphirecode/eslint-config-ts: 1.1.11 ==> 1.1.12 minor
eslint: 7.1.0 ==> 7.2.0 minor
typescript: 3.9.3 ==> 3.9.5 minor
2020-06-11 20:34:19 +02:00
b11b2f5f2b Stream: allow edge attributes, autoclose nodes 2020-06-05 11:46:58 +02:00
920dc74d9c update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.40 ==> 1.0.41 minor
@sapphirecode/eslint-config-ts: 1.1.10 ==> 1.1.11 minor
nyc: 15.0.1 ==> 15.1.0 minor
2020-06-02 08:51:24 +02:00
8fcbcd2107 update-scanner: automatic update
@sapphirecode/eslint-config-ts: 1.1.9 ==> 1.1.10 minor
2020-05-28 08:54:08 +02:00
cc0e6bcbb0 update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.39 ==> 1.0.40 minor
@sapphirecode/eslint-config-ts: 1.1.7 ==> 1.1.9 minor
eslint: 7.0.0 ==> 7.1.0 minor
typescript: 3.9.2 ==> 3.9.3 minor
2020-05-23 18:25:39 +02:00
75b803f363 update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.38 ==> 1.0.39 minor
@sapphirecode/eslint-config-ts: 1.1.4 ==> 1.1.7 minor
2020-05-17 19:42:42 +02:00
d478ccd955 documentation 2020-05-17 17:53:01 +02:00
e11f9bea68 update 2020-05-17 17:17:39 +02:00
5b96458669 update jenkins.js 2020-05-15 13:17:25 +02:00
ab4e9eb368 adapt jenkins.js 2020-05-13 16:07:56 +02:00
cd43d2e457 update-scanner: automatic update
@sapphirecode/eslint-config-ts: 1.0.44 ==> 1.0.45 minor
eslint: 6.8.0 ==> 7.0.0 major
typescript: 3.8.3 ==> 3.9.2 minor
2020-05-13 11:12:44 +02:00
8baf87cd43 update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.36 ==> 1.0.37 minor
ava: 3.8.1 ==> 3.8.2 minor
eslint: 6.8.0 ==> 7.0.0 major
2020-05-09 21:56:29 +02:00
58b073fe05 update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.35 ==> 1.0.36 minor
@sapphirecode/eslint-config-ts: 1.0.43 ==> 1.0.44 minor
2020-05-08 13:46:10 +02:00
df00690b57 fix 2020-05-08 10:03:50 +02:00
7a351b7dab translate commands on error 2020-05-08 09:44:37 +02:00
6e53d8d260 tsdoc test 2020-05-07 19:22:16 +02:00
a491b86947 fix 2020-05-07 15:15:25 +02:00
63c32bb783 display current state on error 2020-05-07 15:14:27 +02:00
ebd8936dae fix 2020-05-07 15:09:25 +02:00
ac3c66bc1c update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.34 ==> 1.0.35 minor
@sapphirecode/eslint-config-ts: 1.0.40 ==> 1.0.41 minor
2020-05-07 10:35:52 +02:00
a34db64fca remove unnecessary log 2020-05-06 20:26:10 +02:00
8d6d91e562 GraphStream 2020-05-06 20:24:37 +02:00
acf8004497 fix 2020-05-06 11:07:09 +02:00
aae79c4f79 better error 2020-05-06 11:05:34 +02:00
c56a6616ca allow other return types 2020-05-06 10:52:04 +02:00
695867265d update-scanner: automatic update
@sapphirecode/encoding-helper: 1.0.33 ==> 1.0.34 minor
2020-05-06 10:02:42 +02:00
04c9fc5e8f fix 2020-05-06 08:33:22 +02:00
650351b201 update 2020-05-06 08:31:55 +02:00
f145126821 fix 2020-05-06 07:46:20 +02:00
1a93f59d9a fix 2020-05-06 07:44:44 +02:00
e0ea6b7302 fix 2020-05-06 07:33:02 +02:00
13b3d53c4c fix publish 2020-05-05 19:50:04 +02:00
378610bbd8 move to @sapphirecode scope 2020-05-05 19:23:05 +02:00
81aa911d8a allow more args for graphable 2020-05-05 14:39:25 +02:00
4f9741f785 update-scanner: automatic update
@scode/encoding-helper: 1.0.29 ==> 1.0.31 minor
@scode/eslint-config-ts: 1.0.29 ==> 1.0.31 minor
2020-05-04 21:12:42 +02:00
9ce39f4204 Merge branch 'master' of git.scode.ovh:timo/graphviz-builder 2020-05-04 20:31:06 +02:00
f0497f163d graphable interface 2020-05-04 20:31:03 +02:00
8e0dad1e04 update-scanner: automatic update
@scode/encoding-helper: 1.0.27 ==> 1.0.29 minor
@scode/eslint-config-ts: 1.0.27 ==> 1.0.29 minor
2020-05-03 18:28:06 +02:00
ed27c037dc update-scanner: automatic update
@scode/encoding-helper: 1.0.26 ==> 1.0.27 minor
2020-05-02 17:11:38 +02:00
de0edfc0ac fix 2020-04-29 22:24:45 +02:00
84bda96276 Merge branch 'master' of git.scode.ovh:timo/graphviz-builder 2020-04-29 22:22:42 +02:00
1c6af8fa9d fix 2020-04-29 22:19:08 +02:00
39 changed files with 2078 additions and 2269 deletions

14
.drone.yml Normal file
View File

@ -0,0 +1,14 @@
kind: pipeline
name: default
steps:
- name: setup
image: registry:5000/node-build
commands:
- yarn
- curl https://git.scode.ovh/Timo/standard/raw/branch/master/ci.js > ci.js
- name: build
image: registry:5000/node-build
commands:
- node ci.js

View File

@ -1,17 +1,22 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
'use strict';
module.exports = {
env: {
commonjs: true,
es6: true,
node: true
es6: true,
node: true
},
extends: [
'@scode'
],
extends: [ '@sapphirecode' ],
globals: {
Atomics: 'readonly',
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parserOptions: {
ecmaVersion: 2018
}
}
parserOptions: { ecmaVersion: 2018 }
};

8
.liconfig.json Normal file
View File

@ -0,0 +1,8 @@
{
"has_license": true,
"license": "MIT",
"author": "Timo Hocker",
"company": "Sapphirecode",
"email": "timo@scode.ovh",
"software": "graphviz-builder"
}

1
.npmrc
View File

@ -1 +0,0 @@
@scode:registry=https://npm.scode.ovh

26
CHANGELOG.md Normal file
View File

@ -0,0 +1,26 @@
# Changelog
## 1.4.0
Allow specifying shapes for nodes
## 1.3.0
Stream:
- property to read current node count
## 1.2.0
Stream:
- automatically end node instructions
- allow attributes on edges
## 1.1.0
Allow creating graphs using a stream
## 1.0.0
initial version

23
Jenkinsfile vendored
View File

@ -1,23 +0,0 @@
pipeline {
agent any
environment {
VERSION = VersionNumber([
versionNumberString:
'${BUILDS_ALL_TIME}',
versionPrefix: '1.0.',
worstResultForIncrement: 'SUCCESS'
])
}
stages {
stage('Building') {
steps {
script {
currentBuild.displayName = env.VERSION
}
sh 'yarn ci ${VERSION}'
}
}
}
}

7
LICENSE Normal file
View File

@ -0,0 +1,7 @@
MIT License Copyright (c) <year> <author>
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 (including the next paragraph) 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.

55
README.md Normal file
View File

@ -0,0 +1,55 @@
# @sapphirecode/graphviz-builder
version: 1.4.x
constructing graphviz files using an easy typescript interface
## Installation
npm:
> npm i --save @sapphirecode/graphviz-builder
yarn:
> yarn add @sapphirecode/graphviz-builder
## Usage
### Object structure
```js
import {Graph,Color} from '@sapphirecode/graphviz-builder';
// create a new graph
const g = new Graph('foo');
// add a node to the graph
// this function returns the full name of the node that's later used for creating edges
const bar = g.add_node('bar');
// if you want to specify attributes
const baz = g.add_node(n => {
n.name = 'baz';
n.label = 'node baz';
n.color = Color.red;
});
// connect nodes
g.add_edge(bar, baz);
// add a subgraph
g.add_graph(sg=>{
sg.name = 'subgraph';
sg.add_node('foo');
})
// get info about current stream state
g.node_count // count of nodes written
g.path // get current path (parent graph names separated by underscores)
```
## License
MIT © Timo Hocker <timo@scode.ovh>

14
jasmine.json Normal file
View File

@ -0,0 +1,14 @@
{
"spec_dir": "test",
"spec_files": [
"spec/*.js",
"spec/*.ts"
],
"helpers": [
"helpers/*.js",
"helpers/*.ts"
],
"stopSpecOnExpectationFailure": false,
"random": false
}

View File

@ -1,32 +0,0 @@
/* eslint-disable no-process-exit */
/* eslint-disable no-console */
/* eslint-disable no-sync */
'use strict';
const fs = require ('fs');
const child_process = require ('child_process');
const pkg = JSON.parse (fs.readFileSync ('package.json', 'utf-8'));
[
,, pkg.version
] = process.argv;
fs.writeFileSync ('package.json', JSON.stringify (pkg, null, 2));
child_process.execSync ('yarn lint', { stdio: 'inherit' });
if (typeof pkg.scripts !== 'undefined' && typeof pkg.scripts.test === 'string')
child_process.execSync ('yarn test', { stdio: 'inherit' });
if (
typeof pkg.scripts !== 'undefined'
&& typeof pkg.scripts.compile === 'string'
)
child_process.execSync ('yarn compile', { stdio: 'inherit' });
child_process.exec ('git log -1 | grep \'\\[no publish\\]\'')
.addListener ('exit', (code) => {
if (code === 0) {
console.log ('build not marked for deployment');
process.exit (1);
}
else { child_process.execSync ('yarn publish'); }
});

View File

@ -1,17 +1,24 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
/* eslint-disable */
'use strict';
module.exports = {
env: {
commonjs: true,
es6: true,
node: true
es6: true,
node: true
},
extends: [
'@scode/eslint-config-ts'
],
extends: [ '@sapphirecode/eslint-config-ts' ],
globals: {
Atomics: 'readonly',
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parserOptions: {
ecmaVersion: 2018
}
}
parserOptions: { ecmaVersion: 2018 }
};

View File

@ -1,10 +0,0 @@
export enum GraphLayouts {
neato = 'neato',
dot = 'dot',
circo = 'circo',
fdp = 'fdp',
sfdp = 'sfdp',
osage = 'osage',
twopi = 'twopi',
patchwork = 'patchwork'
}

23
lib/Helper.ts Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
/**
* removes invalid characters from a string and throws an error
* if left with an empty string
*
* @param name - name to check and transform
*/
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 };

View File

@ -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 };

View File

@ -1,5 +1,12 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
/* eslint-disable no-magic-numbers */
import { num_to_hex } from '@scode/encoding-helper';
import { num_to_hex } from '@sapphirecode/encoding-helper';
export class Color {
public static readonly black = new Color (0, 0, 0);

View File

@ -1,4 +1,11 @@
import { EdgeStyles } from './Styles';
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { EdgeStyles } from '../enums/Styles';
import { Color } from './Color';
export class Edge {

View File

@ -1,5 +1,14 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { validate_name } from '../Helper';
export class Element {
public name: string;
private _name = '';
protected parent_name: string;
public get full_name (): string {
@ -8,15 +17,19 @@ export class Element {
return this.name;
}
public get name (): string {
return this._name;
}
public set name (val: string) {
this._name = validate_name (val);
}
public get parent (): string {
return this.parent_name;
}
public constructor (name: string, parent = '') {
const regex = /^[a-z_][a-z_0-9]+$/iu;
if (!regex.test (name))
throw new Error ('invalid name specified');
this.name = name;
this.parent_name = parent;
}

View File

@ -1,16 +1,16 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { GraphStyles } 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;
label: string;
style: NodeStyles;
color: Color;
}
export class Graph extends Element {
public children: Array<Graph> = [];
@ -76,7 +76,7 @@ export class Graph extends Element {
.replace (/^\s+$/gmu, '');
}
public add_node (constructor: ((n: Node) => void) | string): string {
public add_node (constructor: string | ((n: Node) => void)): string {
const node = new Node ('unnamed', this.full_name);
if (typeof constructor === 'string') {
@ -89,7 +89,7 @@ export class Graph extends Element {
return node.full_name;
}
public add_graph (constructor: ((g: Graph) => void) | string): string {
public add_graph (constructor: string | ((g: Graph) => void)): string {
const graph = new Graph ('unnamed', this.full_name);
graph.directional = this.directional;

201
lib/classes/GraphStream.ts Normal file
View File

@ -0,0 +1,201 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
/* eslint-disable line-comment-position */
/* eslint-disable no-inline-comments */
import { Transform } from 'stream';
import { GraphStreamJSON } from '../interfaces/GraphStreamJSON';
import {
GraphStreamCommand,
translate_command
} from '../enums/GraphStreamCommand';
import { validate_name } from '../Helper';
interface Stringable {
// eslint-disable-next-line @typescript-eslint/naming-convention
toString(): string;
}
export class GraphStream extends Transform {
private _node_count = 0;
private _path: string[] = [];
private _state: (GraphStreamCommand | '')[] = [
'',
''
];
private _directional = false;
public get path (): string {
return this._path.join ('_');
}
public get node_count (): number {
return this._node_count;
}
private get level (): string {
return ' '.repeat (this._path.length);
}
private finish_node (): void {
if (
[
'ce',
'cn'
].includes (this._state[1])
)
this.push ('\n');
}
private expect_state (instr: GraphStreamCommand): void {
const states: (GraphStreamCommand|'')[] = [];
if ([
'cug',
'cdg'
].includes (instr))
states.push ('');
if ([
'eg',
'cn',
'csg',
'ce'
].includes (instr))
states.push ('at', 'eg', 'cug', 'cdg', 'csg', 'ce', 'cn');
switch (instr) {
case 'at':
states.push ('cn', 'cug', 'cdg', 'csg', 'ce');
break;
default:
break;
}
if (!states.includes (this._state[1])) {
throw new Error (`invalid state to execute command ${
translate_command (instr)}
expected: ${states.map ((s) => translate_command (s))
.join (', ')}
actual: ${translate_command (this._state[1])}`);
}
}
// 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.finish_node ();
this.push (
`${this.level}subgraph cluster_${this.path}_${instr.args[0]} {\n`
);
this._path.push (instr.args[0]);
break;
case 'eg': // end graph
this.finish_node ();
this._path.pop ();
this.push (`${this.level}}\n\n`);
break;
case 'cn': // create node
this.finish_node ();
this.push (`${this.level}${this.path}_${instr.args[0]}`);
this._node_count++;
break;
case 'at': // add attributes
if ([
'cn',
'ce'
].includes (this._state[1])) {
this.push (` [${instr.args.join (', ')}]\n`);
}
else {
this.push (`${this.level}${
instr.args.join (`\n${this.level}`)
.replace (/"/gu, '')
}\n\n`);
}
break;
case 'ce':
this.finish_node ();
this.push (`${this.level}${
instr.args[0]
} -${this._directional ? '>' : '-'} ${instr.args[1]}`);
break;
default:
break;
}
this._state.push (instr.type);
this._state.shift ();
callback ();
}
public write (
instr: GraphStreamJSON
): boolean {
return super.write (JSON.stringify (instr), 'utf-8');
}
public create_node (name: string): string {
const node_name = validate_name (name);
this.write ({ type: 'cn', args: [ node_name ] });
return `${this.path}_${node_name}`;
}
/**
* @deprecated calling this method is not needed anymore
*/
public end_node (): void {
// this.write ({ type: 'en', args: [] });
}
public create_graph (name: string, type: 'd' | 's' | 'u' = 's'): void {
const instr_type = `c${type}g` as GraphStreamCommand;
this.write ({ type: instr_type, args: [ validate_name (name) ] });
}
public end_graph (): void {
this.write ({ type: 'eg', args: [] });
}
public attributes (attrs: Record<string, Stringable>): void {
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}"`);
}
this.write ({ type: 'at', args: solved });
}
public create_edge (origin: string, target: string): void {
this.write ({
type: 'ce',
args: [
origin,
target
]
});
}
}

View File

@ -1,5 +1,13 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { NodeStyles } from '../enums/Styles';
import { NodeShapes } from '../enums/Shapes';
import { Element } from './Element';
import { NodeStyles } from './Styles';
import { Color } from './Color';
export class Node extends Element {
@ -8,6 +16,7 @@ export class Node extends Element {
public table_contents?: Array<Array<string>>;
public style?: NodeStyles;
public color?: Color;
public shape?: NodeShapes;
public constructor (name: string, parent: string, label?: string) {
super (name, parent);
@ -40,6 +49,8 @@ export class Node extends Element {
}
if (this.style)
attributes.push ({ name: 'style', value: this.style.toString () });
if (this.shape)
attributes.push ({ name: 'shape', value: this.shape.toString () });
if (this.color)
attributes.push ({ name: 'color', value: this.color.toString () });

View File

@ -0,0 +1,9 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
export type GraphLayouts =
'circo' | 'dot' | 'fdp' | 'neato' | 'osage' | 'patchwork' | 'sfdp' | 'twopi'

View File

@ -0,0 +1,27 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
/* eslint-disable line-comment-position */
/* eslint-disable no-inline-comments */
type GraphStreamCommand =
'at' | 'cdg' | 'ce' | 'cn' | 'csg' | 'cug' | 'eg'
function translate_command (cmd: GraphStreamCommand|''): string {
const translations = {
cn: 'create node',
cug: 'create unordered graph',
cdg: 'create directional graph',
csg: 'create subgraph',
eg: 'end graph',
at: 'attributes',
ce: 'create edge',
'': 'start'
};
return `'${translations[cmd]}'`;
}
export { GraphStreamCommand, translate_command };

14
lib/enums/Shapes.ts Normal file
View File

@ -0,0 +1,14 @@
type NodeShapes =
'' | 'assembly' | 'box' | 'box3d' | 'cds' | 'circle' | 'component'
| 'cylinder' | 'diamond' | 'doublecircle' | 'doubleoctagon' | 'egg'
| 'ellipse' | 'fivepoverhang' | 'folder' | 'hexagon' | 'house'
| 'insulator' | 'invhouse' | 'invtrapezium' | 'invtriangle' | 'larrow'
| 'lpromoter' | 'Mcircle' | 'Mdiamond' | 'Msquare' | 'none' | 'note'
| 'noverhang' | 'octagon' | 'oval' | 'parallelogram' | 'pentagon'
| 'plain' | 'plaintext' | 'point' | 'polygon' | 'primersite' | 'promoter'
| 'proteasesite' | 'proteinstab' | 'rarrow' | 'rect' | 'rectangle'
| 'restrictionsite' | 'ribosite' | 'rnastab' | 'rpromoter' | 'septagon'
| 'signature' | 'square' | 'star' | 'tab' | 'terminator' | 'threepoverhang'
| 'trapezium' | 'triangle' | 'tripleoctagon' | 'underline' | 'utr'
export { NodeShapes };

20
lib/enums/Styles.ts Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
type EdgeStyles =
'' | 'bold' | 'dashed' | 'dotted' | 'solid'
type NodeStyles =
'' | 'bold' | 'dashed' | 'diagonals' | 'dotted'
| 'filled' | 'invis' | 'rounded' | 'solid' | 'striped' | 'wedged'
type GraphStyles =
'bold' | 'dashed' | 'dotted' | 'filled' | 'rounded' | 'solid' | 'striped'
export { EdgeStyles, NodeStyles, GraphStyles };

View File

@ -1,7 +1,19 @@
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';
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
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;

View File

@ -0,0 +1,13 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { GraphStreamCommand } from '../enums/GraphStreamCommand';
export interface GraphStreamJSON {
type: GraphStreamCommand;
args: string[];
}

View File

@ -0,0 +1,12 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { Graph } from '../classes/Graph';
export interface Graphable {
to_graph(g: Graph, ...args: unknown[]): unknown;
}

View File

@ -1,20 +1,32 @@
{
"name": "@scode/graphviz-builder",
"name": "@sapphirecode/graphviz-builder",
"main": "dist/lib/index.js",
"author": "Timo Hocker <timo@scode.ovh>",
"version": "1.4.0",
"author": {
"name": "Timo Hocker",
"email": "timo@scode.ovh"
},
"bugs": "https://redmine.scode.ovh/projects/graphviz-builder",
"description": "constructing graphviz files using an easy typescript interface",
"repository": {
"type": "git",
"url": "https://git.scode.ovh:timo/graphviz-builder.git"
},
"license": "MIT",
"devDependencies": {
"@ava/typescript": "^1.1.1",
"@scode/eslint-config-ts": "^1.0.22",
"ava": "^3.7.1",
"eslint": "^6.8.0",
"@sapphirecode/eslint-config-ts": "^1.1.4",
"@types/jasmine": "^3.5.14",
"@types/node": "^14.11.2",
"eslint": "^7.0.0",
"jasmine": "^3.6.1",
"jasmine-ts": "^0.3.0",
"nyc": "^15.0.1",
"typescript": "^3.8.3"
"ts-node": "^9.0.0",
"typescript": "^4.0.2"
},
"scripts": {
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.vue,.mjs",
"test": "tsc && nyc ava",
"ci": "yarn && node jenkins.js",
"test": "nyc jasmine-ts --config=\"jasmine.json\"",
"compile": "tsc"
},
"files": [
@ -22,6 +34,10 @@
"LICENSE"
],
"dependencies": {
"@scode/encoding-helper": "^1.0.21"
}
"@sapphirecode/encoding-helper": "^1.0.38"
},
"keywords": [
"graphviz",
"generator"
]
}

View File

@ -1,20 +1,25 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
/* eslint-disable */
'use strict';
module.exports = {
env: {
commonjs: true,
es6: true,
node: true
es6: true,
node: true
},
extends: [
'@scode/eslint-config-ts'
],
extends: [ '@sapphirecode/eslint-config-ts' ],
globals: {
Atomics: 'readonly',
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parserOptions: {
ecmaVersion: 2018
},
rules: {
'node/no-unpublished-import': 'off'
}
}
parserOptions: { ecmaVersion: 2018 },
rules: { 'node/no-unpublished-import': 'off' }
};

View File

@ -1,10 +0,0 @@
import test from 'ava';
import { Color } from '../lib';
test ('serialize', (t) => {
const wh = Color.white;
const tr = Color.transparent;
t.is (wh.toString (), '#ffffff');
t.is (tr.toString (), '#00000000');
});

View File

@ -1,22 +0,0 @@
import test from 'ava';
import { Edge, Color, EdgeStyles } from '../lib';
test ('serialize', (t) => {
const e = new Edge ('foo', 'bar', false);
e.color = Color.white;
e.style = EdgeStyles.dashed;
const serialized = e.toString ();
t.is (serialized, 'foo -- bar [style="dashed",color="#ffffff"]');
});
test ('serialize directional', (t) => {
const e = new Edge ('foo', 'bar', true);
e.color = Color.white;
e.style = EdgeStyles.dashed;
const serialized = e.toString ();
t.is (serialized, 'foo -> bar [style="dashed",color="#ffffff"]');
});

View File

@ -1,121 +0,0 @@
import test from 'ava';
import { Graph, GraphStyles, Color, NodeStyles, GraphLayouts } from '../lib';
const result = `digraph foo {
subgraph cluster_foo_baz {
color = #ff0000
style = bold
subgraph cluster_foo_baz_nested {
color = #808080
style = dotted
subgraph cluster_foo_baz_nested_unnamed {
color = #808080
style = dotted
}
}
foo_baz_asd [label="asd"]
foo_baz_test [style="bold", color="#808080"]
}
foo_baz [label="baz"]
foo_foo [label="foo"]
foo_foo -> foo_baz
}`;
const non_directional = `graph foo {
subgraph cluster_foo_bar {
foo_bar_baz [label="baz"]
foo_bar_asd [label="asd"]
foo_bar_baz -- foo_bar_asd
}
foo_foo [label="foo"]
foo_bar_baz -- foo_foo
}`;
const attributes = `digraph attr {
color = #000000
style = bold
overlap = false
splines = true
layout = neato
}`;
test ('serialize', (t) => {
const g = new Graph ('foo');
t.is (g.full_name, 'foo');
g.add_graph ((graph) => {
graph.name = 'baz';
graph.add_node ('asd');
graph.add_node ((n) => {
n.name = 'test';
n.style = NodeStyles.bold;
n.color = Color.gray;
});
// eslint-disable-next-line no-shadow
graph.add_graph ((g) => {
g.style = GraphStyles.dotted;
g.color = Color.gray;
g.name = 'nested';
// eslint-disable-next-line no-shadow, max-nested-callbacks
g.add_graph ((g) => {
g.style = GraphStyles.dotted;
g.color = Color.gray;
});
});
graph.style = GraphStyles.bold;
graph.color = Color.red;
});
const baz = g.add_node ('baz');
const foo = g.add_node ('foo');
g.add_edge (foo, baz);
const serialized = g.toString ();
t.is (serialized, result);
});
test ('non directional', (t) => {
const g = new Graph ('foo');
g.directional = false;
let n = '';
g.add_graph ((sub) => {
sub.name = 'bar';
n = sub.add_node ('baz');
const n2 = sub.add_node ('asd');
sub.add_edge (n, n2);
});
const f = g.add_node ('foo');
g.add_edge (n, f);
t.is (g.toString (), non_directional);
});
test ('attributes', (t) => {
const g = new Graph ('attr');
g.layout = GraphLayouts.neato;
g.overlap = false;
g.splines = true;
g.color = Color.black;
g.style = GraphStyles.bold;
t.is (g.toString (), attributes);
});

View File

@ -1,61 +0,0 @@
import test from 'ava';
import { NodeStyles, Node, Color } from '../lib';
const serialized_simple
= 'bar_foo [label="baz", style="dashed", color="#00ff00"]';
const serialized_table = `bar_foo [label=<<table>
<tr><td>foo</td><td>bar</td><td>baz</td></tr>
<tr><td>bar</td><td>baz</td><td>foo</td></tr>
<tr><td>baz</td><td>foo</td><td>bar</td></tr>
</table>>, style="invis", color="#00ff00"]`;
test ('serialize simple', (t) => {
const g = new Node ('foo', 'bar', 'baz');
g.color = Color.green;
g.style = NodeStyles.dashed;
const serialized = g.toString ();
t.is (g.full_name, 'bar_foo');
t.is (serialized, serialized_simple);
});
test ('serialize table', (t) => {
const g = new Node ('foo', 'bar', 'baz');
g.color = Color.green;
g.style = NodeStyles.invisible;
g.table_contents = [
[
'foo',
'bar',
'baz'
],
[
'bar',
'baz',
'foo'
],
[
'baz',
'foo',
'bar'
]
];
g.is_table = true;
const serialized = g.toString ();
t.is (g.full_name, 'bar_foo');
t.is (serialized, serialized_table);
});
test ('adhere to naming convention', (t) => {
t.throws (() => {
const n = new Node ('invalid.name', 'parent');
return n.toString ();
}, { message: 'invalid name specified' });
});

20
test/spec/Color.ts Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { Color } from '../../lib';
describe ('color', () => {
it ('should serialize', () => {
const wh = Color.white;
const tr = Color.transparent;
expect (wh.toString ())
.toEqual ('#ffffff');
expect (tr.toString ())
.toEqual ('#00000000');
});
});

32
test/spec/Edge.ts Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { Edge, Color } from '../../lib';
describe ('edge', () => {
it ('should serialize', () => {
const e = new Edge ('foo', 'bar', false);
e.color = Color.white;
e.style = 'dashed';
const serialized = e.toString ();
expect (serialized)
.toEqual ('foo -- bar [style="dashed",color="#ffffff"]');
});
it ('should serialize directional', () => {
const e = new Edge ('foo', 'bar', true);
e.color = Color.white;
e.style = 'dashed';
const serialized = e.toString ();
expect (serialized)
.toEqual ('foo -> bar [style="dashed",color="#ffffff"]');
});
});

135
test/spec/Graph.ts Normal file
View File

@ -0,0 +1,135 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
/* eslint-disable max-nested-callbacks */
import { Graph, Color } from '../../lib';
// eslint-disable-next-line max-lines-per-function
describe ('graph', () => {
const result = `digraph foo {
subgraph cluster_foo_baz {
color = #ff0000
style = bold
subgraph cluster_foo_baz_nested {
color = #808080
style = dotted
subgraph cluster_foo_baz_nested_unnamed {
color = #808080
style = dotted
}
}
foo_baz_asd [label="asd"]
foo_baz_test [style="bold", color="#808080"]
}
foo_baz [label="baz"]
foo_foo [label="foo"]
foo_foo -> foo_baz
}`;
const non_directional = `graph foo {
subgraph cluster_foo_bar {
foo_bar_baz [label="baz"]
foo_bar_asd [label="asd"]
foo_bar_baz -- foo_bar_asd
}
foo_foo [label="foo"]
foo_bar_baz -- foo_foo
}`;
const attributes = `digraph attr {
color = #000000
style = bold
overlap = false
splines = true
layout = neato
}`;
it ('should serialize', () => {
const g = new Graph ('foo');
expect (g.full_name)
.toEqual ('foo');
g.add_graph ((graph) => {
graph.name = 'baz';
graph.add_node ('asd');
graph.add_node ((n) => {
n.name = 'test';
n.style = 'bold';
n.color = Color.gray;
});
// eslint-disable-next-line no-shadow
graph.add_graph ((g) => {
g.style = 'dotted';
g.color = Color.gray;
g.name = 'nested';
// eslint-disable-next-line no-shadow
g.add_graph ((g) => {
g.style = 'dotted';
g.color = Color.gray;
});
});
graph.style = 'bold';
graph.color = Color.red;
});
const baz = g.add_node ('baz');
const foo = g.add_node ('foo');
g.add_edge (foo, baz);
const serialized = g.toString ();
expect (serialized)
.toEqual (result);
});
it ('non directional', () => {
const g = new Graph ('foo');
g.directional = false;
let n = '';
g.add_graph ((sub) => {
sub.name = 'bar';
n = sub.add_node ('baz');
const n2 = sub.add_node ('asd');
sub.add_edge (n, n2);
});
const f = g.add_node ('foo');
g.add_edge (n, f);
expect (g.toString ())
.toEqual (non_directional);
});
it ('attributes', () => {
const g = new Graph ('attr');
g.layout = 'neato';
g.overlap = false;
g.splines = true;
g.color = Color.black;
g.style = 'bold';
expect (g.toString ())
.toEqual (attributes);
});
});

87
test/spec/Node.ts Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
*/
import { Node, Color } from '../../lib';
const serialized_simple
= 'bar_foo [label="baz", style="dashed",'
+ ' shape="tripleoctagon", color="#00ff00"]';
const serialized_table = `bar_foo [label=<<table>
<tr><td>foo</td><td>bar</td><td>baz</td></tr>
<tr><td>bar</td><td>baz</td><td>foo</td></tr>
<tr><td>baz</td><td>foo</td><td>bar</td></tr>
</table>>, style="invis", color="#00ff00"]`;
// eslint-disable-next-line max-lines-per-function
describe ('node', () => {
it ('should serialize simple', () => {
const g = new Node ('foo', 'bar', 'baz');
g.color = Color.green;
g.style = 'dashed';
g.shape = 'tripleoctagon';
const serialized = g.toString ();
expect (g.full_name)
.toEqual ('bar_foo');
expect (serialized)
.toEqual (serialized_simple);
});
it ('should serialize table', () => {
const g = new Node ('foo', 'bar', 'baz');
g.color = Color.green;
g.style = 'invis';
g.table_contents = [
[
'foo',
'bar',
'baz'
],
[
'bar',
'baz',
'foo'
],
[
'baz',
'foo',
'bar'
]
];
g.is_table = true;
const serialized = g.toString ();
expect (g.full_name)
.toEqual ('bar_foo');
expect (serialized)
.toEqual (serialized_table);
});
it ('should adhere to naming convention', () => {
const n = new Node ('invalid.name', 'parent');
expect (n.name)
.toEqual ('invalidname');
});
it ('should throw on invalid name', () => {
expect (() => {
const n = new Node ('564#+-.,/@', 'parent');
return n.toString ();
})
.toThrowError ('invalid node name 564#+-.,/@');
});
it ('should leave numbers after the first letter', () => {
const n = new Node ('i123nvalid.name', 'parent');
expect (n.name)
.toEqual ('i123nvalidname');
});
});

217
test/spec/Stream.ts Normal file
View File

@ -0,0 +1,217 @@
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of graphviz-builder which is released under MIT.
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, June 2020
*/
import { GraphStream, Color } from '../../lib/index';
const simple = `graph foo {
}
`;
const complex = `digraph foo {
subgraph cluster_foo_baz {
color = #ff0000
style = bold
subgraph cluster_foo_baz_nested {
color = #808080
style = dotted
subgraph cluster_foo_baz_nested_unnamed {
color = #808080
style = dotted
}
}
foo_baz_asd [label = "asd"]
foo_baz_test [style = "bold", color = "#808080"]
}
foo_baz [label = "baz"]
foo_foo [label = "foo"]
foo_foo -> foo_baz
foo_foo -> foo_baz_asd [label = "edge attr"]
}
`;
// eslint-disable-next-line max-lines-per-function
describe ('stream', () => {
it ('stream graph', () => new Promise<void> ((resolve) => {
let output = '';
const stream = (new GraphStream);
stream.on ('data', (data) => {
output += data;
});
stream.on ('end', () => {
expect (output)
.toEqual (simple);
resolve ();
});
stream.create_graph ('foo', 'u');
stream.end_graph ();
stream.end ();
}));
// eslint-disable-next-line max-statements
it ('complex stream graph', () => new Promise<void> ((resolve) => {
let output = '';
const stream = (new GraphStream);
stream.on ('data', (data) => {
output += data;
});
stream.on ('end', () => {
expect (output)
.toEqual (complex);
resolve ();
});
stream.create_graph ('foo', 'd');
stream.create_graph ('baz');
stream.attributes ({ color: Color.red, style: 'bold' });
stream.create_graph ('nested');
stream.attributes ({ color: Color.gray, style: 'dotted' });
stream.create_graph ('unnamed');
stream.attributes ({ color: Color.gray, style: 'dotted' });
stream.end_graph ();
stream.end_graph ();
const asd = stream.create_node ('asd');
stream.attributes ({ label: 'asd' });
stream.end_node ();
stream.create_node ('test');
stream.attributes ({ style: 'bold', color: Color.gray });
stream.end_graph ();
const baz = stream.create_node ('baz');
stream.attributes ({ label: 'baz' });
const foo = stream.create_node ('foo');
stream.attributes ({ label: 'foo' });
stream.create_edge (foo, baz);
stream.create_edge (foo, asd);
stream.attributes ({ label: 'edge attr' });
stream.end_graph ();
stream.end ();
}));
// eslint-disable-next-line max-lines-per-function
it ('should reject invalid command sequences', () => {
/**
* command valid invalid
* [s] cug, cdg eg, cn, csg, ce, at
* cn eg, cn, csg, ce, at cug, cdg
* cug eg, cn, csg, ce, at cug, cdg
* cdg eg, cn, csg, ce, at cug, cdg
* csg eg, cn, csg, ce, at cug, cdg
* eg eg, cn, csg, ce cug, cdg, at
* at eg, cn, csg, ce cug, cdg, at
* ce eg, cn, csg, ce, at cug, cdg
*/
const cn = (g: GraphStream) => {
g.create_node ('foo');
};
const cug = (g: GraphStream) => {
g.create_graph ('foo', 'u');
};
const cdg = (g: GraphStream) => {
g.create_graph ('foo', 'd');
};
const csg = (g: GraphStream) => {
g.create_graph ('foo', 's');
};
const eg = (g: GraphStream) => {
g.end_graph ();
};
const at = (g: GraphStream) => {
g.attributes ({ color: 'red' });
};
const ce = (g: GraphStream) => {
g.create_edge ('foo', 'bar');
};
const combinations = [
{
primary: (g: GraphStream) => {
cug (g);
cn (g);
},
secondary: [
cug,
cdg
]
},
{
primary: cug,
secondary: [
cug,
cdg
]
},
{
primary: cdg,
secondary: [
cug,
cdg
]
},
{
primary: (g: GraphStream) => {
cug (g);
csg (g);
},
secondary: [
cug,
cdg
]
},
{
primary: (g: GraphStream) => {
cug (g);
csg (g);
eg (g);
},
secondary: [
cug,
cdg,
at
]
},
{
primary: (g: GraphStream) => {
cug (g);
at (g);
},
secondary: [
cug,
cdg,
at
]
},
{
primary: (g: GraphStream) => {
cug (g);
ce (g);
},
secondary: [
cug,
cdg
]
}
];
for (const comb of combinations) {
for (const secondary of comb.secondary) {
const g = (new GraphStream);
comb.primary (g);
expect (() => secondary (g))
.toThrowError (
/invalid state to execute command.*?expected:.*?actual:/uis
);
}
}
});
});

2877
yarn.lock

File diff suppressed because it is too large Load Diff