complete basic structures
This commit is contained in:
parent
b586e57fd7
commit
e63ce1f8ed
@ -2,6 +2,11 @@ export class Edge {
|
|||||||
public origin: string;
|
public origin: string;
|
||||||
public target: string;
|
public target: string;
|
||||||
|
|
||||||
|
public constructor (origin: string, target: string) {
|
||||||
|
this.origin = origin;
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
public toString (): string {
|
public toString (): string {
|
||||||
return `${this.origin} -> ${this.target}`;
|
return `${this.origin} -> ${this.target}`;
|
||||||
|
17
lib/Element.ts
Normal file
17
lib/Element.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export class Element {
|
||||||
|
public name: string;
|
||||||
|
public parent: string;
|
||||||
|
public get full_name (): string {
|
||||||
|
return `${this.parent}_${this.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor (name: string, parent = '') {
|
||||||
|
this.name = name;
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
public toString (): string {
|
||||||
|
return this.full_name;
|
||||||
|
}
|
||||||
|
}
|
55
lib/Graph.ts
55
lib/Graph.ts
@ -1,23 +1,54 @@
|
|||||||
import { Node } from './Node';
|
import { Element } from './Element';
|
||||||
import { Edge } from './Edge';
|
import { Edge } from './Edge';
|
||||||
|
import { Node } from './Node';
|
||||||
|
|
||||||
export class Graph extends Node {
|
export class Graph extends Element {
|
||||||
public children: Array<Graph> = [];
|
public children: Array<Graph> = [];
|
||||||
public nodes: Array<GraphNode> = [];
|
public nodes: Array<Node> = [];
|
||||||
public is_root = false;
|
public is_root = false;
|
||||||
public edges: Array<Edge>;
|
public edges: Array<Edge> = [];
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
public toString (): string {
|
public toString (level = 0): string {
|
||||||
return `subgraph cluster_${this.full_name} {
|
return `subgraph cluster_${this.full_name} {
|
||||||
${this.children.map ((c) => c.toString ())
|
${this.children.map ((c) => c.toString (level + 1))
|
||||||
.join ('\n')}
|
.join ('\n ')}
|
||||||
|
|
||||||
${this.nodes.map ((c) => c.toString ())
|
${this.nodes.map ((c) => c.toString ())
|
||||||
.join ('\n')}
|
.join ('\n ')}
|
||||||
|
|
||||||
${this.edges.map ((c) => c.toString ())
|
${this.edges.map ((c) => c.toString ())
|
||||||
.join ('\n')}
|
.join ('\n ')}
|
||||||
}`;
|
}`.replace (/\n/gu, `\n${' '.repeat (level)}`)
|
||||||
|
.replace (/^\s+$/gmu, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
public add_node (constructor: () => Node): void {
|
||||||
|
const node = constructor ();
|
||||||
|
node.parent = this.full_name;
|
||||||
|
this.nodes.push (node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public add_graph (constructor: () => Graph): void {
|
||||||
|
const graph = constructor ();
|
||||||
|
graph.parent = this.full_name;
|
||||||
|
graph.update_parent ();
|
||||||
|
this.children.push (graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
public update_parent (): void {
|
||||||
|
for (const node of this.nodes)
|
||||||
|
node.parent = this.full_name;
|
||||||
|
|
||||||
|
for (const graph of this.children) {
|
||||||
|
graph.parent = this.full_name;
|
||||||
|
graph.update_parent ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public add_edge (origin: string, target: string): void {
|
||||||
|
this.edges.push (
|
||||||
|
new Edge (`${this.full_name}_${origin}`, `${this.full_name}_${target}`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import { Node } from './Node';
|
|
||||||
|
|
||||||
export class GraphNode extends Node {
|
|
||||||
public label: string;
|
|
||||||
public is_table: boolean;
|
|
||||||
public table_contents: Array<Array<string>>;
|
|
||||||
|
|
||||||
private get serialized_table (): string {
|
|
||||||
const mapped_columns = this.table_contents
|
|
||||||
.map ((val) => `<td>${val.join ('</td><td>')}</td>`);
|
|
||||||
return `<table><tr>${mapped_columns.join ('</tr><tr>')}</tr></table>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
||||||
public toString (): string {
|
|
||||||
return `${this.full_name}[label=<${this.is_table
|
|
||||||
? this._serialized_table
|
|
||||||
: this.label}>]`;
|
|
||||||
}
|
|
||||||
}
|
|
33
lib/Node.ts
33
lib/Node.ts
@ -1,12 +1,33 @@
|
|||||||
export class Node {
|
import { Element } from './Element';
|
||||||
public name;
|
|
||||||
public parent;
|
export class Node extends Element {
|
||||||
public get full_name (): string {
|
public label?: string;
|
||||||
return `${this.parent}_${this.name}`;
|
public is_table = false;
|
||||||
|
public table_contents?: Array<Array<string>>;
|
||||||
|
|
||||||
|
public constructor (name: string, parent?: string, label?: string) {
|
||||||
|
super (name, parent);
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get serialized_table (): string {
|
||||||
|
if (typeof this.table_contents === 'undefined')
|
||||||
|
throw new Error ('table contents are undefined');
|
||||||
|
|
||||||
|
const mapped_columns = this.table_contents
|
||||||
|
.map ((val) => `<td>${val.join ('</td><td>')}</td>`);
|
||||||
|
return `<table>\n <tr>${
|
||||||
|
mapped_columns.join ('</tr>\n <tr>')
|
||||||
|
}</tr>\n</table>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
public toString (): string {
|
public toString (): string {
|
||||||
return this.full_name;
|
if (this.is_table || typeof this.label !== 'undefined') {
|
||||||
|
return `${this.full_name} [label=<${this.is_table
|
||||||
|
? this.serialized_table
|
||||||
|
: this.label}>]`;
|
||||||
|
}
|
||||||
|
return `${this.full_name}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export { Graph } from './Graph';
|
export { Graph } from './Graph';
|
||||||
export { GraphNode } from './GraphNode';
|
|
||||||
export { Node } from './Node';
|
export { Node } from './Node';
|
||||||
|
export { Element } from './Element';
|
||||||
export { Edge } from './Edge';
|
export { Edge } from './Edge';
|
||||||
|
@ -2,18 +2,19 @@
|
|||||||
"name": "graphviz-builder",
|
"name": "graphviz-builder",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"author": "Timo Hocker <thocker@oas.de>",
|
"author": "Timo Hocker <timo@scode.ovh>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@scode/eslint-config-ts": "^1.0.19",
|
"@ava/typescript": "^1.1.1",
|
||||||
"ava": "^3.7.0",
|
"@scode/eslint-config-ts": "^1.0.22",
|
||||||
|
"ava": "^3.7.1",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"nyc": "^15.0.1",
|
"nyc": "^15.0.1",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.vue,.mjs",
|
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.vue,.mjs",
|
||||||
"test": "nyc ava",
|
"test": "tsc && nyc ava",
|
||||||
"ci": "yarn && node jenkins.js"
|
"ci": "yarn && node jenkins.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
test/.eslintrc.js
Normal file
20
test/.eslintrc.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
commonjs: true,
|
||||||
|
es6: true,
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'@scode/eslint-config-ts'
|
||||||
|
],
|
||||||
|
globals: {
|
||||||
|
Atomics: 'readonly',
|
||||||
|
SharedArrayBuffer: 'readonly'
|
||||||
|
},
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2018
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'node/no-unpublished-import': 'off'
|
||||||
|
}
|
||||||
|
}
|
8
test/Edge.ts
Normal file
8
test/Edge.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import test from 'ava';
|
||||||
|
import { Edge } from '../lib';
|
||||||
|
|
||||||
|
test ('serialize', (t) => {
|
||||||
|
const e = new Edge ('foo', 'bar');
|
||||||
|
const serialized = e.toString ();
|
||||||
|
t.is (serialized, 'foo -> bar');
|
||||||
|
});
|
35
test/Graph.ts
Normal file
35
test/Graph.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import test from 'ava';
|
||||||
|
import { Graph, Node } from '../lib';
|
||||||
|
|
||||||
|
const result = `subgraph cluster_bar_foo {
|
||||||
|
subgraph cluster_bar_foo_baz {
|
||||||
|
|
||||||
|
bar_foo_baz_asd
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bar_foo_baz
|
||||||
|
bar_foo_foo
|
||||||
|
|
||||||
|
bar_foo_foo -> bar_foo_baz
|
||||||
|
}`;
|
||||||
|
|
||||||
|
test ('serialize', (t) => {
|
||||||
|
const g = new Graph ('foo', 'bar');
|
||||||
|
|
||||||
|
t.is (g.full_name, 'bar_foo');
|
||||||
|
g.add_graph (() => {
|
||||||
|
const graph = new Graph ('baz');
|
||||||
|
graph.add_node (() => new Node ('asd'));
|
||||||
|
return graph;
|
||||||
|
});
|
||||||
|
|
||||||
|
g.add_node (() => new Node ('baz'));
|
||||||
|
g.add_node (() => new Node ('foo'));
|
||||||
|
g.add_edge ('foo', 'baz');
|
||||||
|
|
||||||
|
const serialized = g.toString ();
|
||||||
|
|
||||||
|
t.is (serialized, result);
|
||||||
|
});
|
44
test/Node.ts
Normal file
44
test/Node.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import test from 'ava';
|
||||||
|
import { Node } from '../lib/Node';
|
||||||
|
|
||||||
|
const serialized_simple = 'bar_foo [label=<baz>]';
|
||||||
|
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>>]`;
|
||||||
|
|
||||||
|
test ('serialize simple', (t) => {
|
||||||
|
const g = new Node ('foo', 'bar', 'baz');
|
||||||
|
|
||||||
|
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.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);
|
||||||
|
});
|
@ -13,7 +13,7 @@
|
|||||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
"outDir": "./dist", /* Redirect output structure to the directory. */
|
"outDir": "./dist", /* Redirect output structure to the directory. */
|
||||||
"rootDir": "./lib", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
// "rootDir": "./lib", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
// "composite": true, /* Enable project compilation */
|
// "composite": true, /* Enable project compilation */
|
||||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||||
// "removeComments": true, /* Do not emit comments to output. */
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
|
23
yarn.lock
23
yarn.lock
@ -2,6 +2,13 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@ava/typescript@^1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@ava/typescript/-/typescript-1.1.1.tgz#3dcaba3aced8026fdb584d927d809752854dc6e6"
|
||||||
|
integrity sha512-KbLUAe2cWXK63WLK6LnOJonjwEDU/8MNXCOA1ooX/YFZgKRmeAD1kZu+2K0ks5fnOCEcckNQAooyBNGdZUmMQA==
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp "^2.0.0"
|
||||||
|
|
||||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
|
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
|
||||||
version "7.8.3"
|
version "7.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
|
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
|
||||||
@ -228,10 +235,10 @@
|
|||||||
"@scode/eslint-config" "^2.0.1"
|
"@scode/eslint-config" "^2.0.1"
|
||||||
eslint-plugin-import "^2.20.1"
|
eslint-plugin-import "^2.20.1"
|
||||||
|
|
||||||
"@scode/eslint-config-ts@^1.0.19":
|
"@scode/eslint-config-ts@^1.0.22":
|
||||||
version "1.0.20"
|
version "1.0.22"
|
||||||
resolved "https://npm.scode.ovh/@scode%2feslint-config-ts/-/eslint-config-ts-1.0.20.tgz#2bd2265591e2605dff77c16d3d82f95948681b59"
|
resolved "https://npm.scode.ovh/@scode%2feslint-config-ts/-/eslint-config-ts-1.0.22.tgz#bedb57f187f2fca7ca661292b0ce15a26530bd95"
|
||||||
integrity sha512-9NgP8ksrlRZ29pys7bDLu23FhgfuZfukwh/XPmkflO208Vd1vSpecRS9nm+da0gsXCjIefJQEfQXYyRxNi+iJQ==
|
integrity sha512-QwRen8tNC/b4XtdIADr5J4WNM58f5lryINcLBObTzZVQfjr8Qlz7AkwgxFN57u//iP3fCXzn4nPI89J2ift7Hw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@scode/eslint-config-es6" "^1.0.1"
|
"@scode/eslint-config-es6" "^1.0.1"
|
||||||
"@typescript-eslint/eslint-plugin" "^2.26.0"
|
"@typescript-eslint/eslint-plugin" "^2.26.0"
|
||||||
@ -496,10 +503,10 @@ astral-regex@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
|
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
|
||||||
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
|
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
|
||||||
|
|
||||||
ava@^3.7.0:
|
ava@^3.7.1:
|
||||||
version "3.7.0"
|
version "3.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/ava/-/ava-3.7.0.tgz#86869f831628de31e817fe00d46b350849295092"
|
resolved "https://registry.yarnpkg.com/ava/-/ava-3.7.1.tgz#7baba69820242e0efcbfb4ab2060b500ec745421"
|
||||||
integrity sha512-SV1oqRpZ00qevETsNzcqTqaTnspJZZ1wBGOjyQzcLOMChnUF+17/RS4YiieClaV0eCFULLU/roICpJoQlNLHZw==
|
integrity sha512-UX7RSenUgFPhxe866doqOJy6tQZAXAVAU4yufYeBAcnEjnS/plIcG6lE2yGIqgjk5cIMpSi+sP4f6EsornlsuA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@concordance/react" "^2.0.0"
|
"@concordance/react" "^2.0.0"
|
||||||
ansi-styles "^4.2.1"
|
ansi-styles "^4.2.1"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user