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

Commit

Permalink
add stringify function #30
Browse files Browse the repository at this point in the history
  • Loading branch information
kamiazya committed Aug 2, 2021
1 parent 7e83c87 commit 2631b76
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { SyntaxError } from './dot.peggy';
export { AST } from './ast';
export { convert } from './convert';
export { stringify } from './stringify';
export { parse } from './parse';
export { dot } from './dot';
88 changes: 88 additions & 0 deletions src/stringify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { AST } from './ast';

export interface StringifyOption {
directed?: boolean;
indentSize?: number;
}

class Compiler {
private directed: boolean;
private indentSize: number;
constructor({ directed = true, indentSize = 2 }: StringifyOption = {}) {
this.directed = directed;
this.indentSize = indentSize;
}

private indent(line: string): string {
return ' '.repeat(this.indentSize) + line;
}
private pad(pad: string): (l: string) => string {
return (l: string) => pad + l;
}
public stringify(ast: AST.ASTNode): string {
switch (ast.type) {
case AST.Types.Attribute:
return `${this.stringify(ast.key)} = ${this.stringify(ast.value)};`;
case AST.Types.Attributes:
return `${ast.kind} [\n${ast.body.map(this.stringify.bind(this)).map(this.indent).join('\n')}\n]`;
case AST.Types.Comment:
switch (ast.kind) {
case AST.Comment.Kind.Block:
return '/**\n' + ast.value.split('\n').map(this.pad(' * ')).join('\n') + '\n */';
case AST.Comment.Kind.Slash:
return ast.value.split('\n').map(this.pad('// ')).join('\n');
case AST.Comment.Kind.Macro:
return ast.value.split('\n').map(this.pad('# ')).join('\n');
}
case AST.Types.Dot:
return ast.body.map(this.stringify.bind(this)).join('\n');
case AST.Types.Edge:
return `${ast.targets.map(this.stringify.bind(this)).join(this.directed ? ' -> ' : ' -- ')} [\n${ast.body
.map(this.stringify.bind(this))
.map(this.indent)
.join('\n')}\n];`;
case AST.Types.Node:
return `${this.stringify(ast.id)} [\n${ast.body
.map(this.stringify.bind(this))
.map(this.indent)
.join('\n')}\n];`;
case AST.Types.NodeRef:
return [this.stringify(ast.id), ast.port ? this.stringify(ast.port) : null, ast.compass ? ast.compass : null]
.filter((v) => v !== null)
.join(':');
case AST.Types.NodeRefGroup:
return `{${ast.body.map(this.stringify).join(' ')}}`;
case AST.Types.Graph:
this.directed = ast.directed;
return [
ast.strict ? 'strict' : null,
ast.directed ? 'digraph' : 'graph',
ast.id ? this.stringify(ast.id) : null,
`{\n${ast.body.map(this.stringify).map(this.indent).join('\n')}\n}`,
]
.filter((v) => v !== null)
.join(' ');
case AST.Types.Subgraph:
return [
'subgraph',
ast.id ? this.stringify(ast.id) : null,
`{\n${ast.body.map(this.stringify).map(this.indent).join('\n')}\n}`,
]
.filter((v) => v !== null)
.join(' ');
case AST.Types.Literal:
switch (ast.quoted) {
case true:
return `"${ast.value}"`;
case false:
return ast.value;
case 'html':
return `<${ast.value}>`;
}
}
}
}

export function stringify(ast: AST.ASTNode, options?: StringifyOption): string {
return new Compiler(options).stringify(ast);
}

0 comments on commit 2631b76

Please sign in to comment.