ts-graphviz 1.1.0 → 1.2.1
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/README.ja.md +118 -14
- package/README.md +118 -14
- package/lib/ast/index.cjs +226 -18
- package/lib/ast/index.d.ts +94 -4
- package/lib/ast/index.js +237 -20
- package/lib/common/index.cjs +0 -2
- package/lib/common/index.js +0 -2
- package/lib/core/index.cjs +18 -1
- package/lib/core/index.d.ts +27 -2
- package/lib/core/index.js +19 -2
- package/media/state-machine.svg +1 -1
- package/media/ts-graphviz.svg +1 -1
- package/package.json +1 -1
- package/test/class-base.test.ts +109 -1
- package/test/from-dot.test.ts +58 -0
package/README.ja.md
CHANGED
|
@@ -101,6 +101,8 @@ const dot = toDot(G);
|
|
|
101
101
|
<details>
|
|
102
102
|
<summary>高度な使い方</summary>
|
|
103
103
|
|
|
104
|
+
##### カスタム・クラス 🤖
|
|
105
|
+
|
|
104
106
|
クラスを継承することで独自の実装を加えることもできます。
|
|
105
107
|
|
|
106
108
|
```typescript
|
|
@@ -114,9 +116,9 @@ class MyCustomDigraph extends Digraph {
|
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
class MyCustomNode extends Node {
|
|
117
|
-
constructor(id:
|
|
118
|
-
super(`
|
|
119
|
-
[_.label]: `This is Custom Node ${id}
|
|
119
|
+
constructor(id: string) {
|
|
120
|
+
super(`node_${id}`, {
|
|
121
|
+
[_.label]: `This is Custom Node ${id}`,
|
|
120
122
|
});
|
|
121
123
|
}
|
|
122
124
|
}
|
|
@@ -124,33 +126,92 @@ class MyCustomNode extends Node {
|
|
|
124
126
|
class MyCustomEdge extends Edge {
|
|
125
127
|
constructor(targets: EdgeTargetTuple) {
|
|
126
128
|
super(targets, {
|
|
127
|
-
[_.label]: 'This is Custom Edge'
|
|
129
|
+
[_.label]: 'This is Custom Edge',
|
|
128
130
|
});
|
|
129
131
|
}
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
const digraph = new MyCustomDigraph();
|
|
133
|
-
const node1 = new MyCustomNode(
|
|
134
|
-
const node2 = new MyCustomNode(
|
|
135
|
+
const node1 = new MyCustomNode('A');
|
|
136
|
+
const node2 = new MyCustomNode('B');
|
|
135
137
|
const edge = new MyCustomEdge([node1, node2]);
|
|
136
138
|
digraph.addNode(node1);
|
|
137
139
|
digraph.addNode(node2);
|
|
138
140
|
digraph.addEdge(edge);
|
|
139
|
-
const dot = toDot(
|
|
141
|
+
const dot = toDot(digraph);
|
|
140
142
|
// digraph "G" {
|
|
141
143
|
// label = "This is Custom Digraph";
|
|
142
|
-
// "
|
|
143
|
-
// label = "This is Custom Node
|
|
144
|
+
// "node_A" [
|
|
145
|
+
// label = "This is Custom Node A";
|
|
144
146
|
// ];
|
|
145
|
-
// "
|
|
146
|
-
// label = "This is Custom Node
|
|
147
|
+
// "node_B" [
|
|
148
|
+
// label = "This is Custom Node B";
|
|
147
149
|
// ];
|
|
148
|
-
// "
|
|
149
|
-
// label = "This is Custom Edge"
|
|
150
|
+
// "node_A" -> "node_B" [
|
|
151
|
+
// label = "This is Custom Edge";
|
|
150
152
|
// ];
|
|
151
153
|
// }
|
|
152
154
|
```
|
|
153
155
|
|
|
156
|
+
##### Models Context API ( `with` メソッド) 🧅
|
|
157
|
+
|
|
158
|
+
あなたは _Models Context API_ をつかうことで、Graphの内部で生成されるオブジェクトもカスタムクラスにすることができます。
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
`GraphBaseModel` の実装である `Digraph`, `Graph`, `Subgraph` が持つ `with` メソッドは、 カスタムモデルを事前定義するために提供されています。
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
const g = new Digraph();
|
|
165
|
+
g.with({
|
|
166
|
+
Node: MyCustomNode,
|
|
167
|
+
Edge: MyCustomEdge,
|
|
168
|
+
});
|
|
169
|
+
const a = g.createNode('A'); // MyCustomNode
|
|
170
|
+
const b = g.createNode('B'); // MyCustomNode
|
|
171
|
+
g.createEdge([a, b]); // MyCustomEdge
|
|
172
|
+
const dot = toDot(g);
|
|
173
|
+
// digraph {
|
|
174
|
+
// "node_A" [
|
|
175
|
+
// label = "This is Custom Node A";
|
|
176
|
+
// ];
|
|
177
|
+
// "node_B" [
|
|
178
|
+
// label = "This is Custom Node B";
|
|
179
|
+
// ];
|
|
180
|
+
// "node_A" -> "node_B" [
|
|
181
|
+
// label = "This is Custom Edge";
|
|
182
|
+
// ];
|
|
183
|
+
// }
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
##### `fromDot` 関数 ⏪
|
|
187
|
+
|
|
188
|
+
> この関数のステータスは  です。
|
|
189
|
+
|
|
190
|
+
このライブラリを使用するメインシナリオは `toDot` 関数を使用することにありますが、逆方向の変換もサポートしています。
|
|
191
|
+
|
|
192
|
+
**DOT** を **Model** に変換により、コードの一部をDOT言語で記述することができます。
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const G = fromDot(
|
|
197
|
+
`digraph {
|
|
198
|
+
node_A [
|
|
199
|
+
label = "This is a Label of Node A";
|
|
200
|
+
];
|
|
201
|
+
}`,
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
G.edge(['node_A', 'node_B']);
|
|
205
|
+
|
|
206
|
+
const dot = toDot(G)
|
|
207
|
+
// digraph {
|
|
208
|
+
// "node_A" [
|
|
209
|
+
// label = "This is a Label of Node A";
|
|
210
|
+
// ];
|
|
211
|
+
// "node_A" -> "node_B";
|
|
212
|
+
// }
|
|
213
|
+
```
|
|
214
|
+
|
|
154
215
|
</details>
|
|
155
216
|
|
|
156
217
|
|
|
@@ -219,6 +280,48 @@ const dot = toDot(G);
|
|
|
219
280
|
> // }
|
|
220
281
|
> ```
|
|
221
282
|
|
|
283
|
+
|
|
284
|
+
<details>
|
|
285
|
+
<summary>高度な使い方</summary>
|
|
286
|
+
|
|
287
|
+
##### Models Context API ( `withContext` 関数 ) 💈
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
`withContext` 関数は、 _Model Factory_ 関数を返します。
|
|
291
|
+
|
|
292
|
+
この _Model Factory_ は、 `Digraph` や `Graph` など、 `RootGraphModel` をカスタムクラスに置き換える手段を提供します。
|
|
293
|
+
|
|
294
|
+
これのAPIにより、宣言的APIとカスタムクラスを統合する手段を提供します。
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
const { digraph } = withContext({
|
|
298
|
+
Digraph: MyCustomDigraph,
|
|
299
|
+
Node: MyCustomNode,
|
|
300
|
+
Edge: MyCustomEdge,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const G = digraph((g) => {
|
|
304
|
+
const a = g.node('A'); // MyCustomNode
|
|
305
|
+
const b = g.node('B'); // MyCustomNode
|
|
306
|
+
g.edge([a, b]); // MyCustomEdge
|
|
307
|
+
});
|
|
308
|
+
const dot = toDot(g);
|
|
309
|
+
// digraph "G" {
|
|
310
|
+
// label = "This is Custom Digraph";
|
|
311
|
+
// "node_A" [
|
|
312
|
+
// label = "This is Custom Node A";
|
|
313
|
+
// ];
|
|
314
|
+
// "node_B" [
|
|
315
|
+
// label = "This is Custom Node B";
|
|
316
|
+
// ];
|
|
317
|
+
// "node_A" -> "node_B" [
|
|
318
|
+
// label = "This is Custom Edge";
|
|
319
|
+
// ];
|
|
320
|
+
// }
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
</details>
|
|
324
|
+
|
|
222
325
|
### `ts-graphviz/ast` モジュール 🔢
|
|
223
326
|
|
|
224
327
|
> このパッケージのステータスは  です。
|
|
@@ -230,10 +333,11 @@ const dot = toDot(G);
|
|
|
230
333
|
状態遷移図で記載している通り、下記の関数を提供しています。
|
|
231
334
|
|
|
232
335
|
- **Model** から **AST** に変換する `fromModel` 関数
|
|
336
|
+
- **AST** から **Model** に変換する `toModel` 関数
|
|
233
337
|
- **AST** から **DOT** に変換する `stringify` 関数
|
|
234
338
|
- **DOT** から **AST** に変換する `parse` 関数
|
|
235
339
|
|
|
236
|
-
> **Note** 上記の図からわかるように、`ts-graphviz` パッケージで提供している `toDot` 関数は、 `fromModel` と `stringify` の合成関数です。
|
|
340
|
+
> **Note** 上記の図からわかるように、`ts-graphviz` パッケージで提供している `toDot` 関数は、 `fromModel` と `stringify` の合成関数です。また、`fromDot` 関数は、 `parse` と `toModel` の合成関数です。
|
|
237
341
|
|
|
238
342
|
詳しい利用方法は整備中です。
|
|
239
343
|
TypeScriptの型定義を参考にしてください。
|
package/README.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
[](https://app.codacy.com/gh/ts-graphviz/ts-graphviz?utm_source=github.com&utm_medium=referral&utm_content=ts-graphviz/ts-graphviz&utm_campaign=Badge_Grade_Settings)
|
|
1
2
|
[](https://github.com/kamiazya/ts-graphviz/actions?workflow=NodeCI)
|
|
2
3
|
[](https://badge.fury.io/js/ts-graphviz)
|
|
3
4
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -101,6 +102,8 @@ const dot = toDot(G);
|
|
|
101
102
|
<details>
|
|
102
103
|
<summary>Advanced Usage</summary>
|
|
103
104
|
|
|
105
|
+
##### Custom Class 🤖
|
|
106
|
+
|
|
104
107
|
You can also add your own implementation by inheriting from the class.
|
|
105
108
|
|
|
106
109
|
```typescript
|
|
@@ -114,9 +117,9 @@ class MyCustomDigraph extends Digraph {
|
|
|
114
117
|
}
|
|
115
118
|
}
|
|
116
119
|
class MyCustomNode extends Node {
|
|
117
|
-
constructor(id:
|
|
118
|
-
super(`
|
|
119
|
-
[_.label]: `This is Custom Node ${id}
|
|
120
|
+
constructor(id: string) {
|
|
121
|
+
super(`node_${id}`, {
|
|
122
|
+
[_.label]: `This is Custom Node ${id}`,
|
|
120
123
|
});
|
|
121
124
|
}
|
|
122
125
|
}
|
|
@@ -124,30 +127,88 @@ class MyCustomNode extends Node {
|
|
|
124
127
|
class MyCustomEdge extends Edge {
|
|
125
128
|
constructor(targets: EdgeTargetTuple) {
|
|
126
129
|
super(targets, {
|
|
127
|
-
[_.label]: 'This is Custom Edge'
|
|
130
|
+
[_.label]: 'This is Custom Edge',
|
|
128
131
|
});
|
|
129
132
|
}
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
const digraph = new MyCustomDigraph();
|
|
133
|
-
const node1 = new MyCustomNode(
|
|
134
|
-
const node2 = new MyCustomNode(
|
|
136
|
+
const node1 = new MyCustomNode('A');
|
|
137
|
+
const node2 = new MyCustomNode('B');
|
|
135
138
|
const edge = new MyCustomEdge([node1, node2]);
|
|
136
139
|
digraph.addNode(node1);
|
|
137
140
|
digraph.addNode(node2);
|
|
138
141
|
digraph.addEdge(edge);
|
|
139
|
-
const dot = toDot(
|
|
142
|
+
const dot = toDot(digraph);
|
|
140
143
|
// digraph "G" {
|
|
141
144
|
// label = "This is Custom Digraph";
|
|
142
|
-
// "
|
|
143
|
-
// label = "This is Custom Node
|
|
145
|
+
// "node_A" [
|
|
146
|
+
// label = "This is Custom Node A";
|
|
147
|
+
// ];
|
|
148
|
+
// "node_B" [
|
|
149
|
+
// label = "This is Custom Node B";
|
|
150
|
+
// ];
|
|
151
|
+
// "node_A" -> "node_B" [
|
|
152
|
+
// label = "This is Custom Edge";
|
|
153
|
+
// ];
|
|
154
|
+
// }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
##### Models Context API ( `with` method) 🧅
|
|
158
|
+
|
|
159
|
+
You can also use the _Models Context API_ to create custom classes for objects generated inside of Graph.
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
The `with` methods of `Digraph`, `Graph`, and `Subgraph`, which are implementations of `GraphBaseModel`, are provided to predefine custom models.
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const g = new Digraph();
|
|
166
|
+
g.with({
|
|
167
|
+
Node: MyCustomNode,
|
|
168
|
+
Edge: MyCustomEdge,
|
|
169
|
+
});
|
|
170
|
+
const a = g.createNode('A'); // MyCustomNode
|
|
171
|
+
const b = g.createNode('B'); // MyCustomNode
|
|
172
|
+
g.createEdge([a, b]); // MyCustomEdge
|
|
173
|
+
const dot = toDot(g);
|
|
174
|
+
// digraph {
|
|
175
|
+
// "node_A" [
|
|
176
|
+
// label = "This is Custom Node A";
|
|
177
|
+
// ];
|
|
178
|
+
// "node_B" [
|
|
179
|
+
// label = "This is Custom Node B";
|
|
144
180
|
// ];
|
|
145
|
-
// "
|
|
146
|
-
// label = "This is Custom
|
|
181
|
+
// "node_A" -> "node_B" [
|
|
182
|
+
// label = "This is Custom Edge";
|
|
147
183
|
// ];
|
|
148
|
-
//
|
|
149
|
-
|
|
184
|
+
// }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
##### `fromDot` function ⏪
|
|
188
|
+
|
|
189
|
+
> The status of this function is ! [beta](https://img.shields.io/badge/-beta-orange).
|
|
190
|
+
|
|
191
|
+
The main scenario for using this library is to use the `toDot` function, but it also supports conversions in the reverse direction.
|
|
192
|
+
|
|
193
|
+
By converting **DOT** to **Model**, a portion of the code can be written in the DOT language.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const G = fromDot(
|
|
197
|
+
`digraph {
|
|
198
|
+
node_A [
|
|
199
|
+
label = "This is a Label of Node A";
|
|
200
|
+
];
|
|
201
|
+
}`,
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
G.edge(['node_A', 'node_B']);
|
|
205
|
+
|
|
206
|
+
const dot = toDot(G)
|
|
207
|
+
// digraph {
|
|
208
|
+
// "node_A" [
|
|
209
|
+
// label = "This is a Label of Node A";
|
|
150
210
|
// ];
|
|
211
|
+
// "node_A" -> "node_B";
|
|
151
212
|
// }
|
|
152
213
|
```
|
|
153
214
|
|
|
@@ -219,6 +280,48 @@ const dot = toDot(G);
|
|
|
219
280
|
> // }
|
|
220
281
|
> ```
|
|
221
282
|
|
|
283
|
+
|
|
284
|
+
<details>
|
|
285
|
+
<summary>Advanced Usage</summary>
|
|
286
|
+
|
|
287
|
+
##### Models Context API ( `withContext` function ) 💈
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
The `withContext` function returns a _Model Factory_ function.
|
|
291
|
+
|
|
292
|
+
This _Model Factory_ provides a means to replace `RootGraphModel` with a custom class, such as `Digraph` or `Graph`.
|
|
293
|
+
|
|
294
|
+
This API provides a way to integrate declarative APIs and custom classes.
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
const { digraph } = withContext({
|
|
298
|
+
Digraph: MyCustomDigraph,
|
|
299
|
+
Node: MyCustomNode,
|
|
300
|
+
Edge: MyCustomEdge,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const G = digraph((g) => {
|
|
304
|
+
const a = g.node('A'); // MyCustomNode
|
|
305
|
+
const b = g.node('B'); // MyCustomNode
|
|
306
|
+
g.edge([a, b]); // MyCustomEdge
|
|
307
|
+
});
|
|
308
|
+
const dot = toDot(g);
|
|
309
|
+
// digraph "G" {
|
|
310
|
+
// label = "This is Custom Digraph";
|
|
311
|
+
// "node_A" [
|
|
312
|
+
// label = "This is Custom Node A";
|
|
313
|
+
// ];
|
|
314
|
+
// "node_B" [
|
|
315
|
+
// label = "This is Custom Node B";
|
|
316
|
+
// ];
|
|
317
|
+
// "node_A" -> "node_B" [
|
|
318
|
+
// label = "This is Custom Edge";
|
|
319
|
+
// ];
|
|
320
|
+
// }
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
</details>
|
|
324
|
+
|
|
222
325
|
### `ts-graphviz/ast` Module 🔢
|
|
223
326
|
|
|
224
327
|
> This module status is .
|
|
@@ -230,10 +333,11 @@ An API is provided to handle ASTs for advanced use.
|
|
|
230
333
|
The following functions are provided as described in the state transition diagram.
|
|
231
334
|
|
|
232
335
|
- The `fromModel` function converts **Model** to **AST**.
|
|
336
|
+
- The `toModel` function converts **AST** to **Model**.
|
|
233
337
|
- The `stringify` function converts **AST** to **DOT**.
|
|
234
338
|
- The `parse` function to convert from **DOT** to **AST**.
|
|
235
339
|
|
|
236
|
-
> **Note** As you can see from the above figure, the `toDot` function provided by the `ts-graphviz` package is a composite
|
|
340
|
+
> **Note** As you can see from the above figure, the `toDot` function provided by the `ts-graphviz` package is a composite of `fromModel` and `stringify`. The `fromDot` function is a composite of `parse` and `toModel`.
|
|
237
341
|
|
|
238
342
|
Detailed usage is TODO.
|
|
239
343
|
Please refer to the TypeScript type definition.
|
package/lib/ast/index.cjs
CHANGED
|
@@ -59,7 +59,7 @@ const endOfLine = (eol) => {
|
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
const AttributeListPrintPlugin
|
|
62
|
+
const AttributeListPrintPlugin = {
|
|
63
63
|
match(ast) {
|
|
64
64
|
return ast.type === 'AttributeList';
|
|
65
65
|
},
|
|
@@ -253,8 +253,8 @@ const SubgraphPrintPlugin = {
|
|
|
253
253
|
},
|
|
254
254
|
};
|
|
255
255
|
|
|
256
|
-
const defaultPlugins$
|
|
257
|
-
AttributeListPrintPlugin
|
|
256
|
+
const defaultPlugins$2 = [
|
|
257
|
+
AttributeListPrintPlugin,
|
|
258
258
|
AttributePrintPlugin,
|
|
259
259
|
CommentPrintPlugin,
|
|
260
260
|
DotPrintPlugin,
|
|
@@ -273,7 +273,7 @@ const defaultPlugins$1 = [
|
|
|
273
273
|
class Printer {
|
|
274
274
|
options;
|
|
275
275
|
/** @internal */
|
|
276
|
-
#plugins = [...defaultPlugins$
|
|
276
|
+
#plugins = [...defaultPlugins$2];
|
|
277
277
|
constructor(options = {}) {
|
|
278
278
|
this.options = options;
|
|
279
279
|
}
|
|
@@ -5342,7 +5342,7 @@ function convertClusterChildren(context, model) {
|
|
|
5342
5342
|
);
|
|
5343
5343
|
}
|
|
5344
5344
|
|
|
5345
|
-
const
|
|
5345
|
+
const AttributeListPlugin = {
|
|
5346
5346
|
match(model) {
|
|
5347
5347
|
return model.$$type === 'AttributeList';
|
|
5348
5348
|
},
|
|
@@ -5357,7 +5357,7 @@ const AttributeListPrintPlugin = {
|
|
|
5357
5357
|
},
|
|
5358
5358
|
};
|
|
5359
5359
|
|
|
5360
|
-
const
|
|
5360
|
+
const EdgePlugin$1 = {
|
|
5361
5361
|
match(model) {
|
|
5362
5362
|
return model.$$type === 'Edge';
|
|
5363
5363
|
},
|
|
@@ -5427,7 +5427,7 @@ const EdgeConvertPlugin = {
|
|
|
5427
5427
|
},
|
|
5428
5428
|
};
|
|
5429
5429
|
|
|
5430
|
-
const
|
|
5430
|
+
const GraphPlugin$1 = {
|
|
5431
5431
|
match(model) {
|
|
5432
5432
|
return model.$$type === 'Graph';
|
|
5433
5433
|
},
|
|
@@ -5456,7 +5456,7 @@ const GraphConvertPlugin = {
|
|
|
5456
5456
|
},
|
|
5457
5457
|
};
|
|
5458
5458
|
|
|
5459
|
-
const
|
|
5459
|
+
const NodePlugin$1 = {
|
|
5460
5460
|
match(model) {
|
|
5461
5461
|
return model.$$type === 'Node';
|
|
5462
5462
|
},
|
|
@@ -5481,7 +5481,7 @@ const NodeConvertPlugin = {
|
|
|
5481
5481
|
},
|
|
5482
5482
|
};
|
|
5483
5483
|
|
|
5484
|
-
const
|
|
5484
|
+
const SubgraphPlugin$1 = {
|
|
5485
5485
|
match(model) {
|
|
5486
5486
|
return model.$$type === 'Subgraph';
|
|
5487
5487
|
},
|
|
@@ -5505,13 +5505,7 @@ const SubgraphConvertPlugin = {
|
|
|
5505
5505
|
},
|
|
5506
5506
|
};
|
|
5507
5507
|
|
|
5508
|
-
const defaultPlugins = [
|
|
5509
|
-
AttributeListPrintPlugin,
|
|
5510
|
-
EdgeConvertPlugin,
|
|
5511
|
-
NodeConvertPlugin,
|
|
5512
|
-
GraphConvertPlugin,
|
|
5513
|
-
SubgraphConvertPlugin,
|
|
5514
|
-
];
|
|
5508
|
+
const defaultPlugins$1 = [AttributeListPlugin, EdgePlugin$1, NodePlugin$1, GraphPlugin$1, SubgraphPlugin$1];
|
|
5515
5509
|
|
|
5516
5510
|
/**
|
|
5517
5511
|
* @group Convert Model to AST
|
|
@@ -5519,7 +5513,7 @@ const defaultPlugins = [
|
|
|
5519
5513
|
class FromModelConverter {
|
|
5520
5514
|
options;
|
|
5521
5515
|
/** @hidden */
|
|
5522
|
-
#plugins = [...defaultPlugins];
|
|
5516
|
+
#plugins = [...defaultPlugins$1];
|
|
5523
5517
|
constructor(options = {}) {
|
|
5524
5518
|
this.options = options;
|
|
5525
5519
|
}
|
|
@@ -5530,7 +5524,6 @@ class FromModelConverter {
|
|
|
5530
5524
|
commentKind,
|
|
5531
5525
|
convert(m) {
|
|
5532
5526
|
for (const plugin of plugins) {
|
|
5533
|
-
/* */
|
|
5534
5527
|
if (plugin.match(m)) {
|
|
5535
5528
|
return plugin.convert(context, m);
|
|
5536
5529
|
}
|
|
@@ -5549,11 +5542,226 @@ function fromModel(model, options) {
|
|
|
5549
5542
|
return new FromModelConverter(options).convert(model);
|
|
5550
5543
|
}
|
|
5551
5544
|
|
|
5545
|
+
class CommentHolder {
|
|
5546
|
+
comment = null;
|
|
5547
|
+
set(comment) {
|
|
5548
|
+
this.comment = comment;
|
|
5549
|
+
}
|
|
5550
|
+
reset() {
|
|
5551
|
+
this.comment = null;
|
|
5552
|
+
}
|
|
5553
|
+
apply(model, location) {
|
|
5554
|
+
if (location && this.comment?.location) {
|
|
5555
|
+
if (this.comment?.kind === 'Block') {
|
|
5556
|
+
if (this.comment.location.end.line === location.start.line - 1) {
|
|
5557
|
+
model.comment = this.comment.value;
|
|
5558
|
+
}
|
|
5559
|
+
} else {
|
|
5560
|
+
if (this.comment.location.end.line === location.start.line) {
|
|
5561
|
+
model.comment = this.comment.value;
|
|
5562
|
+
}
|
|
5563
|
+
}
|
|
5564
|
+
} else {
|
|
5565
|
+
model.comment = this.comment?.value;
|
|
5566
|
+
}
|
|
5567
|
+
this.reset();
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
|
|
5571
|
+
const DotPlugin = {
|
|
5572
|
+
match(ast) {
|
|
5573
|
+
return ast.type === 'Dot';
|
|
5574
|
+
},
|
|
5575
|
+
convert(context, ast) {
|
|
5576
|
+
const commentHolder = new CommentHolder();
|
|
5577
|
+
for (const stmt of ast.children) {
|
|
5578
|
+
switch (stmt.type) {
|
|
5579
|
+
case 'Comment':
|
|
5580
|
+
commentHolder.set(stmt);
|
|
5581
|
+
break;
|
|
5582
|
+
case 'Graph':
|
|
5583
|
+
const graph = context.convert(stmt);
|
|
5584
|
+
commentHolder.apply(graph, stmt.location);
|
|
5585
|
+
return graph;
|
|
5586
|
+
}
|
|
5587
|
+
}
|
|
5588
|
+
throw Error();
|
|
5589
|
+
},
|
|
5590
|
+
};
|
|
5591
|
+
|
|
5592
|
+
function convertToEdgeTargetTuple(edge) {
|
|
5593
|
+
return edge.targets.map((t) => {
|
|
5594
|
+
switch (t.type) {
|
|
5595
|
+
case 'NodeRef':
|
|
5596
|
+
return { id: t.id.value, port: t.port?.value, compass: t.compass?.value };
|
|
5597
|
+
case 'NodeRefGroup':
|
|
5598
|
+
return t.children.map((t) => ({ id: t.id.value, port: t.port?.value, compass: t.compass?.value }));
|
|
5599
|
+
}
|
|
5600
|
+
});
|
|
5601
|
+
}
|
|
5602
|
+
|
|
5603
|
+
const EdgePlugin = {
|
|
5604
|
+
match(ast) {
|
|
5605
|
+
return ast.type === 'Edge';
|
|
5606
|
+
},
|
|
5607
|
+
convert(context, ast) {
|
|
5608
|
+
const edge = new context.models.Edge(
|
|
5609
|
+
convertToEdgeTargetTuple(ast),
|
|
5610
|
+
ast.children
|
|
5611
|
+
.filter((v) => v.type === 'Attribute')
|
|
5612
|
+
.reduce((prev, curr) => ({ ...prev, [curr.key.value]: curr.value.value }), {}),
|
|
5613
|
+
);
|
|
5614
|
+
return edge;
|
|
5615
|
+
},
|
|
5616
|
+
};
|
|
5617
|
+
|
|
5618
|
+
function applyStatements(graph, statements) {
|
|
5619
|
+
const commentHolder = new CommentHolder();
|
|
5620
|
+
for (const stmt of statements) {
|
|
5621
|
+
switch (stmt.type) {
|
|
5622
|
+
case 'Subgraph':
|
|
5623
|
+
const subgraph = stmt.id ? graph.subgraph(stmt.id.value) : graph.subgraph();
|
|
5624
|
+
applyStatements(subgraph, stmt.children);
|
|
5625
|
+
commentHolder.apply(subgraph, stmt.location);
|
|
5626
|
+
break;
|
|
5627
|
+
case 'Attribute':
|
|
5628
|
+
graph.set(stmt.key.value, stmt.value.value);
|
|
5629
|
+
commentHolder.reset();
|
|
5630
|
+
break;
|
|
5631
|
+
case 'Node':
|
|
5632
|
+
commentHolder.apply(
|
|
5633
|
+
graph.node(
|
|
5634
|
+
stmt.id.value,
|
|
5635
|
+
stmt.children
|
|
5636
|
+
.filter((v) => v.type === 'Attribute')
|
|
5637
|
+
.reduce((prev, curr) => ({ ...prev, [curr.key.value]: curr.value.value }), {}),
|
|
5638
|
+
),
|
|
5639
|
+
stmt.location,
|
|
5640
|
+
);
|
|
5641
|
+
break;
|
|
5642
|
+
case 'Edge':
|
|
5643
|
+
commentHolder.apply(
|
|
5644
|
+
graph.edge(
|
|
5645
|
+
convertToEdgeTargetTuple(stmt),
|
|
5646
|
+
stmt.children
|
|
5647
|
+
.filter((v) => v.type === 'Attribute')
|
|
5648
|
+
.reduce((prev, curr) => ({ ...prev, [curr.key.value]: curr.value.value }), {}),
|
|
5649
|
+
),
|
|
5650
|
+
stmt.location,
|
|
5651
|
+
);
|
|
5652
|
+
break;
|
|
5653
|
+
case 'AttributeList':
|
|
5654
|
+
const attrs = stmt.children
|
|
5655
|
+
.filter((v) => v.type === 'Attribute')
|
|
5656
|
+
.reduce((prev, curr) => ({ ...prev, [curr.key.value]: curr.value.value }), {});
|
|
5657
|
+
switch (stmt.kind) {
|
|
5658
|
+
case 'Edge':
|
|
5659
|
+
graph.edge(attrs);
|
|
5660
|
+
break;
|
|
5661
|
+
case 'Node':
|
|
5662
|
+
graph.node(attrs);
|
|
5663
|
+
break;
|
|
5664
|
+
case 'Graph':
|
|
5665
|
+
graph.graph(attrs);
|
|
5666
|
+
break;
|
|
5667
|
+
}
|
|
5668
|
+
commentHolder.reset();
|
|
5669
|
+
break;
|
|
5670
|
+
case 'Comment':
|
|
5671
|
+
commentHolder.set(stmt);
|
|
5672
|
+
}
|
|
5673
|
+
}
|
|
5674
|
+
}
|
|
5675
|
+
|
|
5676
|
+
const GraphPlugin = {
|
|
5677
|
+
match(ast) {
|
|
5678
|
+
return ast.type === 'Graph';
|
|
5679
|
+
},
|
|
5680
|
+
convert(context, ast) {
|
|
5681
|
+
const G = ast.directed ? context.models.Digraph : context.models.Graph;
|
|
5682
|
+
const graph = new G(ast.id?.value, ast.strict);
|
|
5683
|
+
applyStatements(graph, ast.children);
|
|
5684
|
+
return graph;
|
|
5685
|
+
},
|
|
5686
|
+
};
|
|
5687
|
+
|
|
5688
|
+
const SubgraphPlugin = {
|
|
5689
|
+
match(ast) {
|
|
5690
|
+
return ast.type === 'Subgraph';
|
|
5691
|
+
},
|
|
5692
|
+
convert(context, ast) {
|
|
5693
|
+
const subgraph = new context.models.Subgraph(ast.id?.value);
|
|
5694
|
+
applyStatements(subgraph, ast.children);
|
|
5695
|
+
return subgraph;
|
|
5696
|
+
},
|
|
5697
|
+
};
|
|
5698
|
+
|
|
5699
|
+
const NodePlugin = {
|
|
5700
|
+
match(ast) {
|
|
5701
|
+
return ast.type === 'Node';
|
|
5702
|
+
},
|
|
5703
|
+
convert(context, ast) {
|
|
5704
|
+
const node = new context.models.Node(
|
|
5705
|
+
ast.id.value,
|
|
5706
|
+
ast.children
|
|
5707
|
+
.filter((v) => v.type === 'Attribute')
|
|
5708
|
+
.reduce((prev, curr) => ({ ...prev, [curr.key.value]: curr.value.value }), {}),
|
|
5709
|
+
);
|
|
5710
|
+
return node;
|
|
5711
|
+
},
|
|
5712
|
+
};
|
|
5713
|
+
|
|
5714
|
+
const defaultPlugins = [NodePlugin, EdgePlugin, SubgraphPlugin, GraphPlugin, DotPlugin];
|
|
5715
|
+
|
|
5716
|
+
/**
|
|
5717
|
+
* @group Convert AST to Model
|
|
5718
|
+
* @alpha
|
|
5719
|
+
*/
|
|
5720
|
+
class ToModelConverter {
|
|
5721
|
+
options;
|
|
5722
|
+
/** @hidden */
|
|
5723
|
+
plugins = [...defaultPlugins];
|
|
5724
|
+
constructor(options = {}) {
|
|
5725
|
+
this.options = options;
|
|
5726
|
+
}
|
|
5727
|
+
/**
|
|
5728
|
+
* Convert AST to Model.
|
|
5729
|
+
*
|
|
5730
|
+
* @param ast AST node.
|
|
5731
|
+
* @alpha
|
|
5732
|
+
*/
|
|
5733
|
+
convert(ast) {
|
|
5734
|
+
const plugins = [...this.plugins];
|
|
5735
|
+
const context = {
|
|
5736
|
+
models: common.createModelsContext(this.options.models ?? {}),
|
|
5737
|
+
convert(m) {
|
|
5738
|
+
for (const plugin of plugins) {
|
|
5739
|
+
if (plugin.match(m)) {
|
|
5740
|
+
return plugin.convert(context, m);
|
|
5741
|
+
}
|
|
5742
|
+
}
|
|
5743
|
+
throw Error();
|
|
5744
|
+
},
|
|
5745
|
+
};
|
|
5746
|
+
return context.convert(ast);
|
|
5747
|
+
}
|
|
5748
|
+
}
|
|
5749
|
+
|
|
5750
|
+
/**
|
|
5751
|
+
* @group Convert AST to Model
|
|
5752
|
+
* @beta
|
|
5753
|
+
*/
|
|
5754
|
+
function toModel(ast, options) {
|
|
5755
|
+
return new ToModelConverter(options).convert(ast);
|
|
5756
|
+
}
|
|
5757
|
+
|
|
5552
5758
|
exports.Builder = Builder;
|
|
5553
5759
|
exports.FromModelConverter = FromModelConverter;
|
|
5554
5760
|
exports.Printer = Printer;
|
|
5555
5761
|
exports.SyntaxError = SyntaxError;
|
|
5762
|
+
exports.ToModelConverter = ToModelConverter;
|
|
5556
5763
|
exports.createElement = createElement;
|
|
5557
5764
|
exports.fromModel = fromModel;
|
|
5558
5765
|
exports.parse = parse;
|
|
5559
5766
|
exports.stringify = stringify;
|
|
5767
|
+
exports.toModel = toModel;
|