Skip to content
This repository has been archived by the owner on Dec 12, 2022. It is now read-only.

Commit

Permalink
add @ts-graphviz/[email protected] as parser/mode.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
kamiazya committed May 8, 2021
1 parent 49db23d commit 2503b99
Show file tree
Hide file tree
Showing 10 changed files with 5,163 additions and 36 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ fetch_latest:
@deno fmt
@deno fmt

fetch_parser:
@deno run --unstable --allow-run --allow-read --allow-write scripts/fetch_parser.ts
@deno fmt
@deno fmt

examples:
@deno run --unstable --allow-run --allow-read --allow-write examples/callback.ts
@deno run --unstable --allow-run --allow-read --allow-write examples/callback.ts
Expand Down
61 changes: 25 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
## Usages

### Callback style
### Draw diagrams

`renderDot` function outputs the dot command execution result to the specified
path by supplying diagram object.
Expand Down Expand Up @@ -58,50 +58,39 @@ await renderDot(G, path.resolve(__dirname, "./example.svg"), {
});
```

### Script Style
### Parse DOT Language

Convert the diagram object to dot format with toDot function.
The `https://deno.land/x/graphviz/perser/mod.ts` provide `parse` function
that parses a string written in dot language and convert it to a model.

```typescript
import { digraph, toDot } from "https://deno.land/x/graphviz/mod.ts";
The return value is a Graph or Digraph that inherits from RootCluster.

const g = digraph("G");
```typescript
import { parse } from "https://deno.land/x/graphviz/perser/mod.ts";

const subgraphA = g.createSubgraph("A");
const nodeA1 = subgraphA.createNode("A_node1");
const nodeA2 = subgraphA.createNode("A_node2");
subgraphA.createEdge([nodeA1, nodeA2]);
const G = parse(`
digraph G {
a -> b;
}
`);
```

const subgraphB = g.createSubgraph("B");
const nodeB1 = subgraphB.createNode("B_node1");
const nodeB2 = subgraphB.createNode("B_node2");
subgraphA.createEdge([nodeB1, nodeB2]);
This is equivalent to the code below.

const node1 = g.createNode("node1");
const node2 = g.createNode("node2");
g.createEdge([node1, node2]);
```typescript
import { digraph } from "https://deno.land/x/graphviz/mod.ts";

const dot = toDot(g);
console.log(dot);
const G = digraph("G", (g) => {
g.edge(["a", "b"]);
});
```

```dot
digraph "G" {
"node1";
"node2";
subgraph "A" {
"A_node1";
"A_node2";
"A_node1" -> "A_node2";
"B_node1" -> "B_node2";
}
subgraph "B" {
"B_node1";
"B_node2";
}
"node1" -> "node2";
}
```
The `"https://deno.land/x/graphviz/mod.ts"` module also provides other features such as handling AST.

> This module is a translation of [@ts-graphviz/parser](https://github.com/ts-graphviz/parser)
> to work with the Deno runtime.
>
> Please refer to the repository for details of the provided API.
## License

Expand Down
5 changes: 5 additions & 0 deletions parser/.denolized
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
usecase.ts
ast.ts
convert.ts
dot_pegjs.ts
mod.ts
143 changes: 143 additions & 0 deletions parser/ast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { Compass } from "../mod.ts";
import { parse as _parse, SyntaxError } from "./dot_pegjs.ts";
export namespace AST {
type ValueOf<T> = T[keyof T];
export const Types = Object.freeze(
{
Graph: "graph",
Attribute: "attribute",
Attributes: "attributes",
Edge: "edge",
Node: "node",
Subgraph: "subgraph",
} as const,
);
export type Types = ValueOf<typeof Types>;
export interface Graph {
type: typeof Types.Graph;
id?: string;
directed: boolean;
strict: boolean;
children: GraphObject[];
}
export interface KeyValue {
key: string;
value: string;
}
export interface Attribute extends KeyValue {
type: typeof Types.Attribute;
}
export namespace Attributes {
export const Target = Object.freeze(
{
Graph: "graph",
Edge: "edge",
Node: "node",
} as const,
);
export type Target = ValueOf<typeof Target>;
}
export interface Attributes {
type: typeof Types.Attributes;
target: Attributes.Target;
attributes: KeyValue[];
}
export interface ID {
id: string;
port?: string;
commpass?: Compass;
}
export interface Edge {
type: typeof Types.Edge;
targets: ID[];
attributes: KeyValue[];
}
export interface Node {
type: typeof Types.Node;
id: string;
attributes: KeyValue[];
}
export interface Subgraph {
type: typeof Types.Subgraph;
id?: string;
children: GraphObject[];
}
export type GraphObject = Attribute | Attributes | Edge | Node | Subgraph;
/**
* The basic usage is the same as the `parse` function,
* except that it returns the dot language AST.
*
* ```ts
* import { inspect } from 'util';
* import { AST } from '@ts-graphviz/parser';
*
* const ast = AST.parse(`
* strict digraph example {
* subgraph cluster_0 {
* label="Subgraph A";
* a -> b -> c -> d;
* }
*
* subgraph cluster_1 {
* label="Subgraph B";
* a -> f;
* f -> c;
* }
* }
* `);
*
* console.log(inspect(ast, false, 6));
* ```
*
* In the case of the above code, the structure of AST is as follows.
*
* ```ts
* {
* kind: 'graph',
* id: 'example',
* directed: true,
* strict: true,
* children: [
* {
* kind: 'subgraph',
* id: 'cluster_0',
* children: [
* { kind: 'attribute', key: 'label', value: 'Subgraph A' },
* {
* kind: 'edge',
* targets: [ { id: 'a' }, { id: 'b' }, { id: 'c' }, { id: 'd' } ],
* attributes: []
* }
* ]
* },
* {
* kind: 'subgraph',
* id: 'cluster_1',
* children: [
* { kind: 'attribute', key: 'label', value: 'Subgraph B' },
* {
* kind: 'edge',
* targets: [ { id: 'a' }, { id: 'f' } ],
* attributes: []
* },
* {
* kind: 'edge',
* targets: [ { id: 'f' }, { id: 'c' } ],
* attributes: []
* }
* ]
* }
* ]
* }
* ```
* @throws {SyntaxError}
*/
export function parse(dot: string): Graph {
try {
return _parse(dot);
} catch (error) {
Object.setPrototypeOf(error, SyntaxError.prototype);
throw error;
}
}
}
62 changes: 62 additions & 0 deletions parser/convert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Digraph, Graph, ICluster, RootCluster } from "../mod.ts";
import { AST } from "./ast.ts";
function applyToCluster(cluster: ICluster, stmts: AST.GraphObject[]): void {
for (const stmt of stmts) {
switch (stmt.type) {
case AST.Types.Subgraph:
const subgraph = stmt.id
? cluster.subgraph(stmt.id)
: cluster.subgraph();
applyToCluster(subgraph, stmt.children);
break;
case AST.Types.Attribute:
cluster.set(stmt.key, stmt.value);
break;
case AST.Types.Node:
cluster.node(
stmt.id,
stmt.attributes.reduce(
(prev, curr) => ({ ...prev, [curr.key]: curr.value }),
{},
),
);
break;
case AST.Types.Edge:
cluster.edge(
stmt.targets.map((t) => ({
id: t.id,
port: t.port,
compass: t.commpass,
})),
stmt.attributes.reduce(
(prev, curr) => ({ ...prev, [curr.key]: curr.value }),
{},
),
);
break;
case AST.Types.Attributes:
const attrs = stmt.attributes.reduce(
(prev, curr) => ({ ...prev, [curr.key]: curr.value }),
{},
);
switch (stmt.target) {
case AST.Attributes.Target.Edge:
cluster.edge(attrs);
break;
case AST.Attributes.Target.Node:
cluster.node(attrs);
break;
case AST.Attributes.Target.Graph:
cluster.graph(attrs);
break;
}
break;
}
}
}
export function convert(root: AST.Graph): RootCluster {
const Root = root.directed ? Digraph : Graph;
const g = new Root(root.id, root.strict);
applyToCluster(g, root.children);
return g;
}
Loading

0 comments on commit 2503b99

Please sign in to comment.