@ts-graphviz/ast 2.0.5 → 2.0.6-next-d7ff421ec861ca8fdede1a6bdf256f3455fb9797
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/lib/ast.cjs +138 -152
- package/lib/ast.d.ts +7 -3
- package/lib/ast.js +139 -153
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @ts-graphviz/ast
|
|
2
2
|
|
|
3
|
+
## 2.0.6-next-d7ff421ec861ca8fdede1a6bdf256f3455fb9797
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1218](https://github.com/ts-graphviz/ts-graphviz/pull/1218) [`d7ff421`](https://github.com/ts-graphviz/ts-graphviz/commit/d7ff421ec861ca8fdede1a6bdf256f3455fb9797) Thanks [@kamiazya](https://github.com/kamiazya)! - Fix AST printing not to be destroyed during stringify even in HTML-Like format
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`d7ff421`](https://github.com/ts-graphviz/ts-graphviz/commit/d7ff421ec861ca8fdede1a6bdf256f3455fb9797)]:
|
|
10
|
+
- @ts-graphviz/common@2.1.5-next-d7ff421ec861ca8fdede1a6bdf256f3455fb9797
|
|
11
|
+
|
|
3
12
|
## 2.0.5
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/lib/ast.cjs
CHANGED
|
@@ -34,95 +34,57 @@ class Builder {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
const createElement = Builder.prototype.createElement.bind(new Builder());
|
|
37
|
-
const EOL = /\r?\n/;
|
|
38
|
-
function joinBy(sep) {
|
|
39
|
-
return (value) => value.join(sep);
|
|
40
|
-
}
|
|
41
|
-
function wrapWith(wrapper) {
|
|
42
|
-
return (value) => wrapper + value + wrapper;
|
|
43
|
-
}
|
|
44
|
-
function wrapByPair(l, r) {
|
|
45
|
-
return (value) => l + value + r;
|
|
46
|
-
}
|
|
47
|
-
function leftPadWith(left) {
|
|
48
|
-
return (value) => left + value;
|
|
49
|
-
}
|
|
50
|
-
const escape = (value) => value.replace(/(?<!\\)"|[\r\n]/g, escapeReplacer);
|
|
51
|
-
function escapeReplacer(match) {
|
|
52
|
-
switch (match) {
|
|
53
|
-
case "\r":
|
|
54
|
-
return "\\r";
|
|
55
|
-
case "\n":
|
|
56
|
-
return "\\n";
|
|
57
|
-
default:
|
|
58
|
-
return '\\"';
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
const splitByLine = (value) => value.split(EOL);
|
|
62
|
-
const indent = (style, size, eol) => common.pipe(
|
|
63
|
-
splitByLine,
|
|
64
|
-
common.map(leftPadWith(style === "space" ? " ".repeat(size) : "\n")),
|
|
65
|
-
joinBy(eol)
|
|
66
|
-
);
|
|
67
|
-
const endOfLine = (eol) => {
|
|
68
|
-
switch (eol) {
|
|
69
|
-
case "crlf":
|
|
70
|
-
return "\r\n";
|
|
71
|
-
case "lf":
|
|
72
|
-
return "\n";
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
37
|
const AttributeListPrintPlugin = {
|
|
76
38
|
match(ast) {
|
|
77
39
|
return ast.type === "AttributeList";
|
|
78
40
|
},
|
|
79
|
-
print(context, ast) {
|
|
41
|
+
*print(context, ast) {
|
|
80
42
|
if (ast.children.length === 0) {
|
|
81
|
-
|
|
43
|
+
yield `${ast.kind.toLocaleLowerCase()} [];`;
|
|
44
|
+
} else {
|
|
45
|
+
yield `${ast.kind.toLocaleLowerCase()} [`;
|
|
46
|
+
yield* context.printChildren(ast.children);
|
|
47
|
+
yield "];";
|
|
82
48
|
}
|
|
83
|
-
const eol = endOfLine(context.endOfLine);
|
|
84
|
-
return common.pipe(
|
|
85
|
-
common.map(context.print),
|
|
86
|
-
joinBy(eol),
|
|
87
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
88
|
-
wrapByPair(`${ast.kind.toLocaleLowerCase()} [${eol}`, `${eol}];`)
|
|
89
|
-
)(ast.children);
|
|
90
49
|
}
|
|
91
50
|
};
|
|
92
51
|
const AttributePrintPlugin = {
|
|
93
52
|
match(ast) {
|
|
94
53
|
return ast.type === "Attribute";
|
|
95
54
|
},
|
|
96
|
-
print(context, ast) {
|
|
97
|
-
|
|
55
|
+
*print(context, ast) {
|
|
56
|
+
yield* context.print(ast.key);
|
|
57
|
+
yield " = ";
|
|
58
|
+
yield* context.print(ast.value);
|
|
59
|
+
yield ";";
|
|
98
60
|
}
|
|
99
61
|
};
|
|
62
|
+
const EOL_PATTERN = /\r?\n/;
|
|
63
|
+
const paddingMap = {
|
|
64
|
+
Block: " * ",
|
|
65
|
+
Macro: "# ",
|
|
66
|
+
Slash: "// "
|
|
67
|
+
};
|
|
100
68
|
const CommentPrintPlugin = {
|
|
101
69
|
match(ast) {
|
|
102
70
|
return ast.type === "Comment";
|
|
103
71
|
},
|
|
104
|
-
print(context, ast) {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
default:
|
|
121
|
-
return common.pipe(
|
|
122
|
-
splitByLine,
|
|
123
|
-
common.map(leftPadWith("// ")),
|
|
124
|
-
joinBy(eol)
|
|
125
|
-
)(ast.value);
|
|
72
|
+
*print(context, ast) {
|
|
73
|
+
const padding = paddingMap[ast.kind];
|
|
74
|
+
if (ast.kind === "Block") {
|
|
75
|
+
yield* ["/**", context.EOL];
|
|
76
|
+
}
|
|
77
|
+
const lines = ast.value.split(EOL_PATTERN);
|
|
78
|
+
const lineLength = lines.length;
|
|
79
|
+
for (let i = 0; i < lineLength; i++) {
|
|
80
|
+
yield padding;
|
|
81
|
+
yield lines[i];
|
|
82
|
+
if (i < lineLength - 1) {
|
|
83
|
+
yield context.EOL;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (ast.kind === "Block") {
|
|
87
|
+
yield* [context.EOL, " */"];
|
|
126
88
|
}
|
|
127
89
|
}
|
|
128
90
|
};
|
|
@@ -130,73 +92,74 @@ const DotPrintPlugin = {
|
|
|
130
92
|
match(ast) {
|
|
131
93
|
return ast.type === "Dot";
|
|
132
94
|
},
|
|
133
|
-
print(context, ast) {
|
|
134
|
-
|
|
95
|
+
*print(context, ast) {
|
|
96
|
+
yield* context.join(ast.children, context.EOL);
|
|
135
97
|
}
|
|
136
98
|
};
|
|
137
99
|
const EdgePrintPlugin = {
|
|
138
100
|
match(ast) {
|
|
139
101
|
return ast.type === "Edge";
|
|
140
102
|
},
|
|
141
|
-
print(context, ast) {
|
|
142
|
-
|
|
143
|
-
common.map(context.print),
|
|
144
|
-
joinBy(context.directed ? " -> " : " -- ")
|
|
145
|
-
)(ast.targets);
|
|
103
|
+
*print(context, ast) {
|
|
104
|
+
yield* context.join(ast.targets, context.directed ? " -> " : " -- ");
|
|
146
105
|
if (ast.children.length === 0) {
|
|
147
|
-
|
|
106
|
+
yield ";";
|
|
107
|
+
} else {
|
|
108
|
+
yield " [";
|
|
109
|
+
yield* context.printChildren(ast.children);
|
|
110
|
+
yield "];";
|
|
148
111
|
}
|
|
149
|
-
const eol = endOfLine(context.endOfLine);
|
|
150
|
-
const contents = common.pipe(
|
|
151
|
-
common.map(context.print),
|
|
152
|
-
joinBy(eol),
|
|
153
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
154
|
-
wrapByPair(`[${eol}`, `${eol}];`)
|
|
155
|
-
)(ast.children);
|
|
156
|
-
return `${targets} ${contents}`;
|
|
157
112
|
}
|
|
158
113
|
};
|
|
159
114
|
const GraphPrintPlugin = {
|
|
160
115
|
match(ast) {
|
|
161
116
|
return ast.type === "Graph";
|
|
162
117
|
},
|
|
163
|
-
print(context, ast) {
|
|
118
|
+
*print(context, ast) {
|
|
164
119
|
context.directed = ast.directed;
|
|
165
|
-
const parts = [];
|
|
166
120
|
if (ast.strict) {
|
|
167
|
-
|
|
121
|
+
yield "strict ";
|
|
168
122
|
}
|
|
169
|
-
|
|
123
|
+
yield ast.directed ? "digraph " : "graph ";
|
|
170
124
|
if (ast.id) {
|
|
171
|
-
|
|
125
|
+
yield* context.print(ast.id);
|
|
126
|
+
yield " ";
|
|
172
127
|
}
|
|
173
|
-
|
|
174
|
-
|
|
128
|
+
yield "{";
|
|
129
|
+
if (ast.children.length >= 1) {
|
|
130
|
+
yield* context.printChildren(ast.children);
|
|
175
131
|
}
|
|
176
|
-
|
|
177
|
-
const contents = common.pipe(
|
|
178
|
-
common.map(context.print),
|
|
179
|
-
joinBy(eol),
|
|
180
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
181
|
-
wrapByPair(`{${eol}`, `${eol}}`)
|
|
182
|
-
)(ast.children);
|
|
183
|
-
return `${parts.join(" ")} ${contents}`;
|
|
132
|
+
yield "}";
|
|
184
133
|
}
|
|
185
134
|
};
|
|
186
|
-
const
|
|
187
|
-
const
|
|
135
|
+
const escape = (value) => value.replace(/(?<!\\)"|[\r\n]/g, escapeReplacer);
|
|
136
|
+
const escapeMap = {
|
|
137
|
+
"\r": String.raw`\r`,
|
|
138
|
+
"\n": String.raw`\n`,
|
|
139
|
+
'"': String.raw`\"`
|
|
140
|
+
};
|
|
141
|
+
function escapeReplacer(match) {
|
|
142
|
+
return escapeMap[match];
|
|
143
|
+
}
|
|
188
144
|
const LiteralPrintPlugin = {
|
|
189
145
|
match(ast) {
|
|
190
146
|
return ast.type === "Literal";
|
|
191
147
|
},
|
|
192
|
-
print(context, ast) {
|
|
148
|
+
*print(context, ast) {
|
|
193
149
|
switch (ast.quoted) {
|
|
194
150
|
case "html":
|
|
195
|
-
|
|
151
|
+
yield "<";
|
|
152
|
+
yield ast.value;
|
|
153
|
+
yield ">";
|
|
154
|
+
return;
|
|
196
155
|
case true:
|
|
197
|
-
|
|
156
|
+
yield '"';
|
|
157
|
+
yield escape(ast.value);
|
|
158
|
+
yield '"';
|
|
159
|
+
return;
|
|
198
160
|
default:
|
|
199
|
-
|
|
161
|
+
yield ast.value;
|
|
162
|
+
return;
|
|
200
163
|
}
|
|
201
164
|
}
|
|
202
165
|
};
|
|
@@ -204,68 +167,57 @@ const NodePrintPlugin = {
|
|
|
204
167
|
match(ast) {
|
|
205
168
|
return ast.type === "Node";
|
|
206
169
|
},
|
|
207
|
-
print(context, ast) {
|
|
208
|
-
|
|
209
|
-
if (ast.children.length
|
|
210
|
-
|
|
170
|
+
*print(context, ast) {
|
|
171
|
+
yield* context.print(ast.id);
|
|
172
|
+
if (ast.children.length >= 1) {
|
|
173
|
+
yield " [";
|
|
174
|
+
yield* context.printChildren(ast.children);
|
|
175
|
+
yield "]";
|
|
211
176
|
}
|
|
212
|
-
|
|
213
|
-
const contents = common.pipe(
|
|
214
|
-
common.map(context.print),
|
|
215
|
-
joinBy(eol),
|
|
216
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
217
|
-
wrapByPair(`[${eol}`, `${eol}];`)
|
|
218
|
-
)(ast.children);
|
|
219
|
-
return `${id} ${contents}`;
|
|
177
|
+
yield ";";
|
|
220
178
|
}
|
|
221
179
|
};
|
|
222
180
|
const NodeRefGroupPrintPlugin = {
|
|
223
181
|
match(ast) {
|
|
224
182
|
return ast.type === "NodeRefGroup";
|
|
225
183
|
},
|
|
226
|
-
print(context, ast) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
wrapByPair("{", "}")
|
|
231
|
-
)(ast.children);
|
|
184
|
+
*print(context, ast) {
|
|
185
|
+
yield "{";
|
|
186
|
+
yield* context.join(ast.children, " ");
|
|
187
|
+
yield "}";
|
|
232
188
|
}
|
|
233
189
|
};
|
|
234
190
|
const NodeRefPrintPlugin = {
|
|
235
191
|
match(ast) {
|
|
236
192
|
return ast.type === "NodeRef";
|
|
237
193
|
},
|
|
238
|
-
print(context, ast) {
|
|
239
|
-
|
|
194
|
+
*print(context, ast) {
|
|
195
|
+
yield* context.print(ast.id);
|
|
240
196
|
if (ast.port) {
|
|
241
|
-
|
|
197
|
+
yield ":";
|
|
198
|
+
yield* context.print(ast.port);
|
|
242
199
|
}
|
|
243
200
|
if (ast.compass) {
|
|
244
|
-
|
|
201
|
+
yield ":";
|
|
202
|
+
yield* context.print(ast.compass);
|
|
245
203
|
}
|
|
246
|
-
return parts.join(":");
|
|
247
204
|
}
|
|
248
205
|
};
|
|
249
206
|
const SubgraphPrintPlugin = {
|
|
250
207
|
match(ast) {
|
|
251
208
|
return ast.type === "Subgraph";
|
|
252
209
|
},
|
|
253
|
-
print(context, ast) {
|
|
254
|
-
|
|
210
|
+
*print(context, ast) {
|
|
211
|
+
yield "subgraph";
|
|
255
212
|
if (ast.id) {
|
|
256
|
-
|
|
213
|
+
yield " ";
|
|
214
|
+
yield* context.print(ast.id);
|
|
257
215
|
}
|
|
258
|
-
|
|
259
|
-
|
|
216
|
+
yield " {";
|
|
217
|
+
if (ast.children.length >= 1) {
|
|
218
|
+
yield* context.printChildren(ast.children);
|
|
260
219
|
}
|
|
261
|
-
|
|
262
|
-
const contents = common.pipe(
|
|
263
|
-
common.map(context.print),
|
|
264
|
-
joinBy(eol),
|
|
265
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
266
|
-
wrapByPair(`{${eol}`, `${eol}}`)
|
|
267
|
-
)(ast.children);
|
|
268
|
-
return `${parts.join(" ")} ${contents}`;
|
|
220
|
+
yield "}";
|
|
269
221
|
}
|
|
270
222
|
};
|
|
271
223
|
const defaultPlugins$2 = [
|
|
@@ -296,27 +248,61 @@ class Printer {
|
|
|
296
248
|
* @returns The DOT string generated from the ASTNode.
|
|
297
249
|
*/
|
|
298
250
|
print(ast) {
|
|
251
|
+
return Array.from(this.toChunks(ast)).join("");
|
|
252
|
+
}
|
|
253
|
+
toChunks(ast) {
|
|
299
254
|
const plugins = [...this.#plugins];
|
|
300
255
|
const {
|
|
301
256
|
indentSize = 2,
|
|
302
257
|
indentStyle = "space",
|
|
303
|
-
endOfLine
|
|
258
|
+
endOfLine = "lf"
|
|
304
259
|
} = this.options;
|
|
260
|
+
const EOL = endOfLine === "crlf" ? "\r\n" : "\n";
|
|
261
|
+
const PADDING = indentStyle === "space" ? " ".repeat(indentSize) : " ";
|
|
305
262
|
const context = {
|
|
306
263
|
directed: true,
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
264
|
+
EOL,
|
|
265
|
+
*printChildren(children) {
|
|
266
|
+
yield* indent(function* () {
|
|
267
|
+
yield EOL;
|
|
268
|
+
yield* context.join(children, EOL);
|
|
269
|
+
});
|
|
270
|
+
yield EOL;
|
|
271
|
+
},
|
|
272
|
+
*print(a) {
|
|
311
273
|
for (const plugin of plugins) {
|
|
312
274
|
if (plugin.match(a)) {
|
|
313
|
-
|
|
275
|
+
yield* plugin.print(this, a);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
throw new Error(
|
|
280
|
+
`No matching plugin found for AST node: ${JSON.stringify(a)}`
|
|
281
|
+
);
|
|
282
|
+
},
|
|
283
|
+
*join(array, separator) {
|
|
284
|
+
const childrenLength = array.length;
|
|
285
|
+
for (let i = 0; i < childrenLength; i++) {
|
|
286
|
+
yield* context.print(array[i]);
|
|
287
|
+
if (i < childrenLength - 1) {
|
|
288
|
+
yield separator;
|
|
314
289
|
}
|
|
315
290
|
}
|
|
316
|
-
throw Error();
|
|
317
291
|
}
|
|
318
292
|
};
|
|
319
|
-
return
|
|
293
|
+
return {
|
|
294
|
+
[Symbol.iterator]: function* () {
|
|
295
|
+
yield* context.print(ast);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
function* indent(tokens) {
|
|
299
|
+
for (const token of tokens()) {
|
|
300
|
+
yield token;
|
|
301
|
+
if (token === EOL) {
|
|
302
|
+
yield PADDING;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
320
306
|
}
|
|
321
307
|
}
|
|
322
308
|
function stringify(ast, options) {
|
package/lib/ast.d.ts
CHANGED
|
@@ -736,15 +736,18 @@ declare interface OtherExpectation {
|
|
|
736
736
|
* PrintContext interface provides an interface for printing an ASTNode with a set of options.
|
|
737
737
|
* @group Convert AST to DOT
|
|
738
738
|
*/
|
|
739
|
-
export declare interface PrintContext
|
|
739
|
+
export declare interface PrintContext {
|
|
740
740
|
/**
|
|
741
741
|
* Indicates if the AST should be printed in a directed graph.
|
|
742
742
|
*/
|
|
743
743
|
directed: boolean;
|
|
744
|
+
readonly EOL: string;
|
|
744
745
|
/**
|
|
745
746
|
* A function to print an ASTNode, taking in an ASTNode as an argument. Returns a string.
|
|
746
747
|
*/
|
|
747
|
-
print(ast: ASTNode): string
|
|
748
|
+
print(ast: ASTNode): Iterable<string>;
|
|
749
|
+
printChildren(children: ASTNode[]): Iterable<string>;
|
|
750
|
+
join(children: ASTNode[], separator: string): Iterable<string>;
|
|
748
751
|
}
|
|
749
752
|
|
|
750
753
|
/**
|
|
@@ -764,6 +767,7 @@ declare interface OtherExpectation {
|
|
|
764
767
|
* @returns The DOT string generated from the ASTNode.
|
|
765
768
|
*/
|
|
766
769
|
print(ast: ASTNode): string;
|
|
770
|
+
private toChunks;
|
|
767
771
|
}
|
|
768
772
|
|
|
769
773
|
/**
|
|
@@ -809,7 +813,7 @@ declare interface OtherExpectation {
|
|
|
809
813
|
* @returns printed string
|
|
810
814
|
* @memberof PrintPlugin
|
|
811
815
|
*/
|
|
812
|
-
print(context: PrintContext, ast: T): string
|
|
816
|
+
print(context: PrintContext, ast: T): Generator<string>;
|
|
813
817
|
}
|
|
814
818
|
|
|
815
819
|
/**
|
package/lib/ast.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isNodeModel, isForwardRefNode, createModelsContext } from "@ts-graphviz/common";
|
|
2
2
|
class Builder {
|
|
3
3
|
/**
|
|
4
4
|
* Constructor of Builder
|
|
@@ -32,95 +32,57 @@ class Builder {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
const createElement = Builder.prototype.createElement.bind(new Builder());
|
|
35
|
-
const EOL = /\r?\n/;
|
|
36
|
-
function joinBy(sep) {
|
|
37
|
-
return (value) => value.join(sep);
|
|
38
|
-
}
|
|
39
|
-
function wrapWith(wrapper) {
|
|
40
|
-
return (value) => wrapper + value + wrapper;
|
|
41
|
-
}
|
|
42
|
-
function wrapByPair(l, r) {
|
|
43
|
-
return (value) => l + value + r;
|
|
44
|
-
}
|
|
45
|
-
function leftPadWith(left) {
|
|
46
|
-
return (value) => left + value;
|
|
47
|
-
}
|
|
48
|
-
const escape = (value) => value.replace(/(?<!\\)"|[\r\n]/g, escapeReplacer);
|
|
49
|
-
function escapeReplacer(match) {
|
|
50
|
-
switch (match) {
|
|
51
|
-
case "\r":
|
|
52
|
-
return "\\r";
|
|
53
|
-
case "\n":
|
|
54
|
-
return "\\n";
|
|
55
|
-
default:
|
|
56
|
-
return '\\"';
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
const splitByLine = (value) => value.split(EOL);
|
|
60
|
-
const indent = (style, size, eol) => pipe(
|
|
61
|
-
splitByLine,
|
|
62
|
-
map(leftPadWith(style === "space" ? " ".repeat(size) : "\n")),
|
|
63
|
-
joinBy(eol)
|
|
64
|
-
);
|
|
65
|
-
const endOfLine = (eol) => {
|
|
66
|
-
switch (eol) {
|
|
67
|
-
case "crlf":
|
|
68
|
-
return "\r\n";
|
|
69
|
-
case "lf":
|
|
70
|
-
return "\n";
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
35
|
const AttributeListPrintPlugin = {
|
|
74
36
|
match(ast) {
|
|
75
37
|
return ast.type === "AttributeList";
|
|
76
38
|
},
|
|
77
|
-
print(context, ast) {
|
|
39
|
+
*print(context, ast) {
|
|
78
40
|
if (ast.children.length === 0) {
|
|
79
|
-
|
|
41
|
+
yield `${ast.kind.toLocaleLowerCase()} [];`;
|
|
42
|
+
} else {
|
|
43
|
+
yield `${ast.kind.toLocaleLowerCase()} [`;
|
|
44
|
+
yield* context.printChildren(ast.children);
|
|
45
|
+
yield "];";
|
|
80
46
|
}
|
|
81
|
-
const eol = endOfLine(context.endOfLine);
|
|
82
|
-
return pipe(
|
|
83
|
-
map(context.print),
|
|
84
|
-
joinBy(eol),
|
|
85
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
86
|
-
wrapByPair(`${ast.kind.toLocaleLowerCase()} [${eol}`, `${eol}];`)
|
|
87
|
-
)(ast.children);
|
|
88
47
|
}
|
|
89
48
|
};
|
|
90
49
|
const AttributePrintPlugin = {
|
|
91
50
|
match(ast) {
|
|
92
51
|
return ast.type === "Attribute";
|
|
93
52
|
},
|
|
94
|
-
print(context, ast) {
|
|
95
|
-
|
|
53
|
+
*print(context, ast) {
|
|
54
|
+
yield* context.print(ast.key);
|
|
55
|
+
yield " = ";
|
|
56
|
+
yield* context.print(ast.value);
|
|
57
|
+
yield ";";
|
|
96
58
|
}
|
|
97
59
|
};
|
|
60
|
+
const EOL_PATTERN = /\r?\n/;
|
|
61
|
+
const paddingMap = {
|
|
62
|
+
Block: " * ",
|
|
63
|
+
Macro: "# ",
|
|
64
|
+
Slash: "// "
|
|
65
|
+
};
|
|
98
66
|
const CommentPrintPlugin = {
|
|
99
67
|
match(ast) {
|
|
100
68
|
return ast.type === "Comment";
|
|
101
69
|
},
|
|
102
|
-
print(context, ast) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
default:
|
|
119
|
-
return pipe(
|
|
120
|
-
splitByLine,
|
|
121
|
-
map(leftPadWith("// ")),
|
|
122
|
-
joinBy(eol)
|
|
123
|
-
)(ast.value);
|
|
70
|
+
*print(context, ast) {
|
|
71
|
+
const padding = paddingMap[ast.kind];
|
|
72
|
+
if (ast.kind === "Block") {
|
|
73
|
+
yield* ["/**", context.EOL];
|
|
74
|
+
}
|
|
75
|
+
const lines = ast.value.split(EOL_PATTERN);
|
|
76
|
+
const lineLength = lines.length;
|
|
77
|
+
for (let i = 0; i < lineLength; i++) {
|
|
78
|
+
yield padding;
|
|
79
|
+
yield lines[i];
|
|
80
|
+
if (i < lineLength - 1) {
|
|
81
|
+
yield context.EOL;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (ast.kind === "Block") {
|
|
85
|
+
yield* [context.EOL, " */"];
|
|
124
86
|
}
|
|
125
87
|
}
|
|
126
88
|
};
|
|
@@ -128,73 +90,74 @@ const DotPrintPlugin = {
|
|
|
128
90
|
match(ast) {
|
|
129
91
|
return ast.type === "Dot";
|
|
130
92
|
},
|
|
131
|
-
print(context, ast) {
|
|
132
|
-
|
|
93
|
+
*print(context, ast) {
|
|
94
|
+
yield* context.join(ast.children, context.EOL);
|
|
133
95
|
}
|
|
134
96
|
};
|
|
135
97
|
const EdgePrintPlugin = {
|
|
136
98
|
match(ast) {
|
|
137
99
|
return ast.type === "Edge";
|
|
138
100
|
},
|
|
139
|
-
print(context, ast) {
|
|
140
|
-
|
|
141
|
-
map(context.print),
|
|
142
|
-
joinBy(context.directed ? " -> " : " -- ")
|
|
143
|
-
)(ast.targets);
|
|
101
|
+
*print(context, ast) {
|
|
102
|
+
yield* context.join(ast.targets, context.directed ? " -> " : " -- ");
|
|
144
103
|
if (ast.children.length === 0) {
|
|
145
|
-
|
|
104
|
+
yield ";";
|
|
105
|
+
} else {
|
|
106
|
+
yield " [";
|
|
107
|
+
yield* context.printChildren(ast.children);
|
|
108
|
+
yield "];";
|
|
146
109
|
}
|
|
147
|
-
const eol = endOfLine(context.endOfLine);
|
|
148
|
-
const contents = pipe(
|
|
149
|
-
map(context.print),
|
|
150
|
-
joinBy(eol),
|
|
151
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
152
|
-
wrapByPair(`[${eol}`, `${eol}];`)
|
|
153
|
-
)(ast.children);
|
|
154
|
-
return `${targets} ${contents}`;
|
|
155
110
|
}
|
|
156
111
|
};
|
|
157
112
|
const GraphPrintPlugin = {
|
|
158
113
|
match(ast) {
|
|
159
114
|
return ast.type === "Graph";
|
|
160
115
|
},
|
|
161
|
-
print(context, ast) {
|
|
116
|
+
*print(context, ast) {
|
|
162
117
|
context.directed = ast.directed;
|
|
163
|
-
const parts = [];
|
|
164
118
|
if (ast.strict) {
|
|
165
|
-
|
|
119
|
+
yield "strict ";
|
|
166
120
|
}
|
|
167
|
-
|
|
121
|
+
yield ast.directed ? "digraph " : "graph ";
|
|
168
122
|
if (ast.id) {
|
|
169
|
-
|
|
123
|
+
yield* context.print(ast.id);
|
|
124
|
+
yield " ";
|
|
170
125
|
}
|
|
171
|
-
|
|
172
|
-
|
|
126
|
+
yield "{";
|
|
127
|
+
if (ast.children.length >= 1) {
|
|
128
|
+
yield* context.printChildren(ast.children);
|
|
173
129
|
}
|
|
174
|
-
|
|
175
|
-
const contents = pipe(
|
|
176
|
-
map(context.print),
|
|
177
|
-
joinBy(eol),
|
|
178
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
179
|
-
wrapByPair(`{${eol}`, `${eol}}`)
|
|
180
|
-
)(ast.children);
|
|
181
|
-
return `${parts.join(" ")} ${contents}`;
|
|
130
|
+
yield "}";
|
|
182
131
|
}
|
|
183
132
|
};
|
|
184
|
-
const
|
|
185
|
-
const
|
|
133
|
+
const escape = (value) => value.replace(/(?<!\\)"|[\r\n]/g, escapeReplacer);
|
|
134
|
+
const escapeMap = {
|
|
135
|
+
"\r": String.raw`\r`,
|
|
136
|
+
"\n": String.raw`\n`,
|
|
137
|
+
'"': String.raw`\"`
|
|
138
|
+
};
|
|
139
|
+
function escapeReplacer(match) {
|
|
140
|
+
return escapeMap[match];
|
|
141
|
+
}
|
|
186
142
|
const LiteralPrintPlugin = {
|
|
187
143
|
match(ast) {
|
|
188
144
|
return ast.type === "Literal";
|
|
189
145
|
},
|
|
190
|
-
print(context, ast) {
|
|
146
|
+
*print(context, ast) {
|
|
191
147
|
switch (ast.quoted) {
|
|
192
148
|
case "html":
|
|
193
|
-
|
|
149
|
+
yield "<";
|
|
150
|
+
yield ast.value;
|
|
151
|
+
yield ">";
|
|
152
|
+
return;
|
|
194
153
|
case true:
|
|
195
|
-
|
|
154
|
+
yield '"';
|
|
155
|
+
yield escape(ast.value);
|
|
156
|
+
yield '"';
|
|
157
|
+
return;
|
|
196
158
|
default:
|
|
197
|
-
|
|
159
|
+
yield ast.value;
|
|
160
|
+
return;
|
|
198
161
|
}
|
|
199
162
|
}
|
|
200
163
|
};
|
|
@@ -202,68 +165,57 @@ const NodePrintPlugin = {
|
|
|
202
165
|
match(ast) {
|
|
203
166
|
return ast.type === "Node";
|
|
204
167
|
},
|
|
205
|
-
print(context, ast) {
|
|
206
|
-
|
|
207
|
-
if (ast.children.length
|
|
208
|
-
|
|
168
|
+
*print(context, ast) {
|
|
169
|
+
yield* context.print(ast.id);
|
|
170
|
+
if (ast.children.length >= 1) {
|
|
171
|
+
yield " [";
|
|
172
|
+
yield* context.printChildren(ast.children);
|
|
173
|
+
yield "]";
|
|
209
174
|
}
|
|
210
|
-
|
|
211
|
-
const contents = pipe(
|
|
212
|
-
map(context.print),
|
|
213
|
-
joinBy(eol),
|
|
214
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
215
|
-
wrapByPair(`[${eol}`, `${eol}];`)
|
|
216
|
-
)(ast.children);
|
|
217
|
-
return `${id} ${contents}`;
|
|
175
|
+
yield ";";
|
|
218
176
|
}
|
|
219
177
|
};
|
|
220
178
|
const NodeRefGroupPrintPlugin = {
|
|
221
179
|
match(ast) {
|
|
222
180
|
return ast.type === "NodeRefGroup";
|
|
223
181
|
},
|
|
224
|
-
print(context, ast) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
wrapByPair("{", "}")
|
|
229
|
-
)(ast.children);
|
|
182
|
+
*print(context, ast) {
|
|
183
|
+
yield "{";
|
|
184
|
+
yield* context.join(ast.children, " ");
|
|
185
|
+
yield "}";
|
|
230
186
|
}
|
|
231
187
|
};
|
|
232
188
|
const NodeRefPrintPlugin = {
|
|
233
189
|
match(ast) {
|
|
234
190
|
return ast.type === "NodeRef";
|
|
235
191
|
},
|
|
236
|
-
print(context, ast) {
|
|
237
|
-
|
|
192
|
+
*print(context, ast) {
|
|
193
|
+
yield* context.print(ast.id);
|
|
238
194
|
if (ast.port) {
|
|
239
|
-
|
|
195
|
+
yield ":";
|
|
196
|
+
yield* context.print(ast.port);
|
|
240
197
|
}
|
|
241
198
|
if (ast.compass) {
|
|
242
|
-
|
|
199
|
+
yield ":";
|
|
200
|
+
yield* context.print(ast.compass);
|
|
243
201
|
}
|
|
244
|
-
return parts.join(":");
|
|
245
202
|
}
|
|
246
203
|
};
|
|
247
204
|
const SubgraphPrintPlugin = {
|
|
248
205
|
match(ast) {
|
|
249
206
|
return ast.type === "Subgraph";
|
|
250
207
|
},
|
|
251
|
-
print(context, ast) {
|
|
252
|
-
|
|
208
|
+
*print(context, ast) {
|
|
209
|
+
yield "subgraph";
|
|
253
210
|
if (ast.id) {
|
|
254
|
-
|
|
211
|
+
yield " ";
|
|
212
|
+
yield* context.print(ast.id);
|
|
255
213
|
}
|
|
256
|
-
|
|
257
|
-
|
|
214
|
+
yield " {";
|
|
215
|
+
if (ast.children.length >= 1) {
|
|
216
|
+
yield* context.printChildren(ast.children);
|
|
258
217
|
}
|
|
259
|
-
|
|
260
|
-
const contents = pipe(
|
|
261
|
-
map(context.print),
|
|
262
|
-
joinBy(eol),
|
|
263
|
-
indent(context.indentStyle, context.indentSize, eol),
|
|
264
|
-
wrapByPair(`{${eol}`, `${eol}}`)
|
|
265
|
-
)(ast.children);
|
|
266
|
-
return `${parts.join(" ")} ${contents}`;
|
|
218
|
+
yield "}";
|
|
267
219
|
}
|
|
268
220
|
};
|
|
269
221
|
const defaultPlugins$2 = [
|
|
@@ -294,27 +246,61 @@ class Printer {
|
|
|
294
246
|
* @returns The DOT string generated from the ASTNode.
|
|
295
247
|
*/
|
|
296
248
|
print(ast) {
|
|
249
|
+
return Array.from(this.toChunks(ast)).join("");
|
|
250
|
+
}
|
|
251
|
+
toChunks(ast) {
|
|
297
252
|
const plugins = [...this.#plugins];
|
|
298
253
|
const {
|
|
299
254
|
indentSize = 2,
|
|
300
255
|
indentStyle = "space",
|
|
301
|
-
endOfLine
|
|
256
|
+
endOfLine = "lf"
|
|
302
257
|
} = this.options;
|
|
258
|
+
const EOL = endOfLine === "crlf" ? "\r\n" : "\n";
|
|
259
|
+
const PADDING = indentStyle === "space" ? " ".repeat(indentSize) : " ";
|
|
303
260
|
const context = {
|
|
304
261
|
directed: true,
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
262
|
+
EOL,
|
|
263
|
+
*printChildren(children) {
|
|
264
|
+
yield* indent(function* () {
|
|
265
|
+
yield EOL;
|
|
266
|
+
yield* context.join(children, EOL);
|
|
267
|
+
});
|
|
268
|
+
yield EOL;
|
|
269
|
+
},
|
|
270
|
+
*print(a) {
|
|
309
271
|
for (const plugin of plugins) {
|
|
310
272
|
if (plugin.match(a)) {
|
|
311
|
-
|
|
273
|
+
yield* plugin.print(this, a);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
throw new Error(
|
|
278
|
+
`No matching plugin found for AST node: ${JSON.stringify(a)}`
|
|
279
|
+
);
|
|
280
|
+
},
|
|
281
|
+
*join(array, separator) {
|
|
282
|
+
const childrenLength = array.length;
|
|
283
|
+
for (let i = 0; i < childrenLength; i++) {
|
|
284
|
+
yield* context.print(array[i]);
|
|
285
|
+
if (i < childrenLength - 1) {
|
|
286
|
+
yield separator;
|
|
312
287
|
}
|
|
313
288
|
}
|
|
314
|
-
throw Error();
|
|
315
289
|
}
|
|
316
290
|
};
|
|
317
|
-
return
|
|
291
|
+
return {
|
|
292
|
+
[Symbol.iterator]: function* () {
|
|
293
|
+
yield* context.print(ast);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
function* indent(tokens) {
|
|
297
|
+
for (const token of tokens()) {
|
|
298
|
+
yield token;
|
|
299
|
+
if (token === EOL) {
|
|
300
|
+
yield PADDING;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
318
304
|
}
|
|
319
305
|
}
|
|
320
306
|
function stringify(ast, options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-graphviz/ast",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6-next-d7ff421ec861ca8fdede1a6bdf256f3455fb9797",
|
|
4
4
|
"description": "Graphviz AST(Abstract Syntax Tree) Utilities",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/ts-graphviz/ts-graphviz#readme",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"module": "lib/ast.js",
|
|
38
38
|
"types": "lib/ast.d.ts",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@ts-graphviz/common": "^2.1.
|
|
40
|
+
"@ts-graphviz/common": "^2.1.5-next-d7ff421ec861ca8fdede1a6bdf256f3455fb9797"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"peggy": "^4.0.3",
|