@ts-graphviz/core 0.0.0-pr956-20240225073457

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +22 -0
  3. package/README.md +47 -0
  4. package/lib/core.cjs +397 -0
  5. package/lib/core.d.ts +323 -0
  6. package/lib/core.js +397 -0
  7. package/package.json +37 -0
  8. package/src/attribute.ts +18 -0
  9. package/src/core.ts +5 -0
  10. package/src/from-dot.ts +73 -0
  11. package/src/model-factory/index.ts +2 -0
  12. package/src/model-factory/model-factory-builder.test.ts +79 -0
  13. package/src/model-factory/model-factory-builder.ts +55 -0
  14. package/src/model-factory/model-factory.test.ts +61 -0
  15. package/src/model-factory/model-factory.ts +40 -0
  16. package/src/model-factory/types.ts +46 -0
  17. package/src/models/AttributeList.spec.ts +58 -0
  18. package/src/models/AttributeList.ts +32 -0
  19. package/src/models/AttributesBase.spec.ts +79 -0
  20. package/src/models/AttributesBase.ts +62 -0
  21. package/src/models/AttributesGroup.spec.ts +18 -0
  22. package/src/models/AttributesGroup.ts +13 -0
  23. package/src/models/Digraph.spec.ts +17 -0
  24. package/src/models/Digraph.ts +11 -0
  25. package/src/models/DotObject.ts +5 -0
  26. package/src/models/Edge.spec.ts +48 -0
  27. package/src/models/Edge.ts +40 -0
  28. package/src/models/Graph.spec.ts +18 -0
  29. package/src/models/Graph.ts +11 -0
  30. package/src/models/GraphBase.spec.ts +364 -0
  31. package/src/models/GraphBase.ts +263 -0
  32. package/src/models/Node.spec.ts +25 -0
  33. package/src/models/Node.ts +37 -0
  34. package/src/models/RootGraph.spec.ts +69 -0
  35. package/src/models/RootGraph.ts +48 -0
  36. package/src/models/Subgraph.spec.ts +196 -0
  37. package/src/models/Subgraph.ts +44 -0
  38. package/src/models/index.ts +15 -0
  39. package/src/models/registerModelContext.ts +14 -0
  40. package/src/to-dot.ts +36 -0
  41. package/tsconfig.json +8 -0
  42. package/typedoc.json +4 -0
  43. package/vite.config.ts +22 -0
package/lib/core.js ADDED
@@ -0,0 +1,397 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ var __accessCheck = (obj, member, msg) => {
8
+ if (!member.has(obj))
9
+ throw TypeError("Cannot " + msg);
10
+ };
11
+ var __privateGet = (obj, member, getter) => {
12
+ __accessCheck(obj, member, "read from private field");
13
+ return getter ? getter.call(obj) : member.get(obj);
14
+ };
15
+ var __privateAdd = (obj, member, value) => {
16
+ if (member.has(obj))
17
+ throw TypeError("Cannot add the same private member more than once");
18
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
19
+ };
20
+ var __privateSet = (obj, member, value, setter) => {
21
+ __accessCheck(obj, member, "write to private field");
22
+ setter ? setter.call(obj, value) : member.set(obj, value);
23
+ return value;
24
+ };
25
+ var _attrs, _models, _objects;
26
+ import { RootModelsContext, createModelsContext, isNodeRefGroupLike, toNodeRefGroup, toNodeRef, isNodeRefLike } from "@ts-graphviz/common";
27
+ import { fromModel, stringify, parse, toModel } from "@ts-graphviz/ast";
28
+ const attribute = new Proxy(
29
+ Object.freeze({}),
30
+ {
31
+ get: (_, key) => key
32
+ }
33
+ );
34
+ class DotObject {
35
+ }
36
+ class AttributesBase extends DotObject {
37
+ constructor(attributes) {
38
+ super();
39
+ /** @hidden */
40
+ __privateAdd(this, _attrs, /* @__PURE__ */ new Map());
41
+ if (attributes !== void 0) {
42
+ this.apply(attributes);
43
+ }
44
+ }
45
+ get values() {
46
+ return Array.from(__privateGet(this, _attrs).entries());
47
+ }
48
+ get size() {
49
+ return __privateGet(this, _attrs).size;
50
+ }
51
+ get(key) {
52
+ return __privateGet(this, _attrs).get(key);
53
+ }
54
+ set(key, value) {
55
+ if (value !== null && value !== void 0) {
56
+ __privateGet(this, _attrs).set(key, value);
57
+ }
58
+ }
59
+ delete(key) {
60
+ __privateGet(this, _attrs).delete(key);
61
+ }
62
+ apply(attributes) {
63
+ const entries = Array.isArray(attributes) ? attributes : Object.entries(attributes);
64
+ for (const [key, value] of entries) {
65
+ this.set(key, value);
66
+ }
67
+ }
68
+ clear() {
69
+ __privateGet(this, _attrs).clear();
70
+ }
71
+ }
72
+ _attrs = new WeakMap();
73
+ class AttributeList extends AttributesBase {
74
+ constructor($$kind, attributes) {
75
+ super(attributes);
76
+ __publicField(this, "comment");
77
+ this.$$kind = $$kind;
78
+ }
79
+ get $$type() {
80
+ return "AttributeList";
81
+ }
82
+ }
83
+ class GraphBase extends AttributesBase {
84
+ constructor() {
85
+ super(...arguments);
86
+ /** @hidden */
87
+ __privateAdd(this, _models, RootModelsContext);
88
+ __publicField(this, "id");
89
+ __publicField(this, "comment");
90
+ __publicField(this, "attributes", Object.freeze({
91
+ graph: new AttributeList("Graph"),
92
+ edge: new AttributeList("Edge"),
93
+ node: new AttributeList("Node")
94
+ }));
95
+ /** @hidden */
96
+ __privateAdd(this, _objects, {
97
+ nodes: /* @__PURE__ */ new Map(),
98
+ edges: /* @__PURE__ */ new Set(),
99
+ subgraphs: /* @__PURE__ */ new Set()
100
+ });
101
+ }
102
+ get nodes() {
103
+ return Array.from(__privateGet(this, _objects).nodes.values());
104
+ }
105
+ get edges() {
106
+ return Array.from(__privateGet(this, _objects).edges.values());
107
+ }
108
+ get subgraphs() {
109
+ return Array.from(__privateGet(this, _objects).subgraphs.values());
110
+ }
111
+ with(models) {
112
+ __privateSet(this, _models, createModelsContext(models));
113
+ }
114
+ addNode(node) {
115
+ __privateGet(this, _objects).nodes.set(node.id, node);
116
+ }
117
+ addEdge(edge) {
118
+ __privateGet(this, _objects).edges.add(edge);
119
+ }
120
+ addSubgraph(subgraph) {
121
+ __privateGet(this, _objects).subgraphs.add(subgraph);
122
+ }
123
+ existNode(nodeId) {
124
+ return __privateGet(this, _objects).nodes.has(nodeId);
125
+ }
126
+ existEdge(edge) {
127
+ return __privateGet(this, _objects).edges.has(edge);
128
+ }
129
+ existSubgraph(subgraph) {
130
+ return __privateGet(this, _objects).subgraphs.has(subgraph);
131
+ }
132
+ createSubgraph(...args) {
133
+ const subgraph = new (__privateGet(this, _models)).Subgraph(...args);
134
+ subgraph.with(__privateGet(this, _models));
135
+ this.addSubgraph(subgraph);
136
+ return subgraph;
137
+ }
138
+ removeNode(node) {
139
+ __privateGet(this, _objects).nodes.delete(typeof node === "string" ? node : node.id);
140
+ }
141
+ removeEdge(edge) {
142
+ __privateGet(this, _objects).edges.delete(edge);
143
+ }
144
+ removeSubgraph(subgraph) {
145
+ __privateGet(this, _objects).subgraphs.delete(subgraph);
146
+ }
147
+ createNode(id, attributes) {
148
+ const node = new (__privateGet(this, _models)).Node(id, attributes);
149
+ this.addNode(node);
150
+ return node;
151
+ }
152
+ getSubgraph(id) {
153
+ return Array.from(__privateGet(this, _objects).subgraphs.values()).find(
154
+ (subgraph) => subgraph.id === id
155
+ );
156
+ }
157
+ getNode(id) {
158
+ return __privateGet(this, _objects).nodes.get(id);
159
+ }
160
+ createEdge(targets, attributes) {
161
+ const ts = targets.map(
162
+ (t) => isNodeRefGroupLike(t) ? toNodeRefGroup(t) : toNodeRef(t)
163
+ );
164
+ const edge = new (__privateGet(this, _models)).Edge(ts, attributes);
165
+ this.addEdge(edge);
166
+ return edge;
167
+ }
168
+ subgraph(...args) {
169
+ const id = args.find(
170
+ (arg) => typeof arg === "string"
171
+ );
172
+ const attributes = args.find(
173
+ (arg) => typeof arg === "object" && arg !== null
174
+ );
175
+ const callback = args.find(
176
+ (arg) => typeof arg === "function"
177
+ );
178
+ const subgraph = id ? this.getSubgraph(id) ?? this.createSubgraph(id) : this.createSubgraph();
179
+ if (attributes !== void 0) {
180
+ subgraph.apply(attributes);
181
+ }
182
+ if (callback !== void 0) {
183
+ callback(subgraph);
184
+ }
185
+ return subgraph;
186
+ }
187
+ node(firstArg, ...args) {
188
+ if (typeof firstArg === "string") {
189
+ const id = firstArg;
190
+ const attributes = args.find(
191
+ (arg) => typeof arg === "object" && arg !== null
192
+ );
193
+ const callback = args.find(
194
+ (arg) => typeof arg === "function"
195
+ );
196
+ const node = this.getNode(id) ?? this.createNode(id);
197
+ if (attributes !== void 0) {
198
+ node.attributes.apply(attributes);
199
+ }
200
+ if (callback !== void 0) {
201
+ callback(node);
202
+ }
203
+ return node;
204
+ }
205
+ if (typeof firstArg === "object" && firstArg !== null) {
206
+ this.attributes.node.apply(firstArg);
207
+ }
208
+ }
209
+ edge(firstArg, ...args) {
210
+ if (Array.isArray(firstArg)) {
211
+ const targets = firstArg;
212
+ const attributes = args.find(
213
+ (arg) => typeof arg === "object"
214
+ );
215
+ const callback = args.find(
216
+ (arg) => typeof arg === "function"
217
+ );
218
+ const edge = this.createEdge(targets, attributes);
219
+ if (callback !== void 0) {
220
+ callback(edge);
221
+ }
222
+ return edge;
223
+ }
224
+ if (typeof firstArg === "object" && firstArg !== null) {
225
+ this.attributes.edge.apply(firstArg);
226
+ }
227
+ }
228
+ graph(attributes) {
229
+ this.attributes.graph.apply(attributes);
230
+ }
231
+ }
232
+ _models = new WeakMap();
233
+ _objects = new WeakMap();
234
+ class RootGraph extends GraphBase {
235
+ constructor(...args) {
236
+ super();
237
+ __publicField(this, "id");
238
+ __publicField(this, "strict");
239
+ this.id = args.find((arg) => typeof arg === "string");
240
+ this.strict = args.find((arg) => typeof arg === "boolean") ?? false;
241
+ const attributes = args.find(
242
+ (arg) => typeof arg === "object" && arg !== null
243
+ );
244
+ if (attributes !== void 0) {
245
+ this.apply(attributes);
246
+ }
247
+ }
248
+ get $$type() {
249
+ return "Graph";
250
+ }
251
+ }
252
+ class Digraph extends RootGraph {
253
+ get directed() {
254
+ return true;
255
+ }
256
+ }
257
+ class AttributesGroup extends AttributesBase {
258
+ constructor() {
259
+ super(...arguments);
260
+ __publicField(this, "comment");
261
+ }
262
+ }
263
+ class Edge extends DotObject {
264
+ constructor(targets, attributes) {
265
+ super();
266
+ __publicField(this, "comment");
267
+ __publicField(this, "attributes");
268
+ this.targets = targets;
269
+ if (targets.length < 2 && (isNodeRefLike(targets[0]) && isNodeRefLike(targets[1])) === false) {
270
+ throw Error(
271
+ "The element of Edge target is missing or not satisfied as Edge target."
272
+ );
273
+ }
274
+ this.attributes = new AttributesGroup(attributes);
275
+ }
276
+ get $$type() {
277
+ return "Edge";
278
+ }
279
+ }
280
+ class Graph extends RootGraph {
281
+ get directed() {
282
+ return false;
283
+ }
284
+ }
285
+ class Node extends DotObject {
286
+ constructor(id, attributes) {
287
+ super();
288
+ __publicField(this, "comment");
289
+ __publicField(this, "attributes");
290
+ this.id = id;
291
+ this.attributes = new AttributesGroup(attributes);
292
+ }
293
+ get $$type() {
294
+ return "Node";
295
+ }
296
+ port(port) {
297
+ if (typeof port === "string") {
298
+ return { id: this.id, port };
299
+ }
300
+ return { id: this.id, ...port };
301
+ }
302
+ }
303
+ class Subgraph extends GraphBase {
304
+ constructor(...args) {
305
+ super();
306
+ __publicField(this, "id");
307
+ this.id = args.find((arg) => typeof arg === "string");
308
+ const attributes = args.find(
309
+ (arg) => typeof arg === "object" && arg !== null
310
+ );
311
+ if (attributes !== void 0) {
312
+ this.apply(attributes);
313
+ }
314
+ }
315
+ get $$type() {
316
+ return "Subgraph";
317
+ }
318
+ isSubgraphCluster() {
319
+ if (typeof this.id === "string") {
320
+ return this.id.startsWith("cluster");
321
+ }
322
+ return false;
323
+ }
324
+ }
325
+ Object.assign(RootModelsContext, {
326
+ Graph,
327
+ Digraph,
328
+ Subgraph,
329
+ Node,
330
+ Edge
331
+ });
332
+ function ModelFactoryBuilder(directed, strictMode) {
333
+ return (...args) => {
334
+ const G = directed ? this.Digraph : this.Graph;
335
+ const id = args.find((arg) => typeof arg === "string");
336
+ const attributes = args.find(
337
+ (arg) => typeof arg === "object"
338
+ );
339
+ const callback = args.find(
340
+ (arg) => typeof arg === "function"
341
+ );
342
+ const g = new G(id, strictMode, attributes);
343
+ g.with(this);
344
+ if (typeof callback === "function") {
345
+ callback(g);
346
+ }
347
+ return g;
348
+ };
349
+ }
350
+ function createModelFactories(strict2, context = RootModelsContext) {
351
+ return Object.freeze({
352
+ digraph: ModelFactoryBuilder.call(context, true, strict2),
353
+ graph: ModelFactoryBuilder.call(context, false, strict2)
354
+ });
355
+ }
356
+ const noStrict = createModelFactories(false);
357
+ const digraph = noStrict.digraph;
358
+ const graph = noStrict.graph;
359
+ const strict = createModelFactories(true);
360
+ function withContext(models) {
361
+ const context = createModelsContext(models);
362
+ return Object.freeze({
363
+ ...createModelFactories(false, context),
364
+ strict: createModelFactories(true, context)
365
+ });
366
+ }
367
+ function toDot(model, options) {
368
+ const ast = fromModel(model, options == null ? void 0 : options.convert);
369
+ return stringify(ast, options == null ? void 0 : options.print);
370
+ }
371
+ function fromDot(dot, options) {
372
+ const ast = parse(dot, options == null ? void 0 : options.parse);
373
+ if (Array.isArray(ast) || ast.type === "Attribute" || ast.type === "AttributeList" || ast.type === "Comment" || ast.type === "NodeRef" || ast.type === "NodeRefGroup" || ast.type === "Literal") {
374
+ throw new Error();
375
+ }
376
+ return toModel(ast, options == null ? void 0 : options.convert);
377
+ }
378
+ export {
379
+ AttributeList,
380
+ AttributesBase,
381
+ AttributesGroup,
382
+ Digraph,
383
+ DotObject,
384
+ Edge,
385
+ Graph,
386
+ GraphBase,
387
+ Node,
388
+ RootGraph,
389
+ Subgraph,
390
+ attribute,
391
+ digraph,
392
+ fromDot,
393
+ graph,
394
+ strict,
395
+ toDot,
396
+ withContext
397
+ };
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@ts-graphviz/core",
3
+ "version": "0.0.0-pr956-20240225073457",
4
+ "description": "",
5
+ "type": "module",
6
+ "main": "lib/core.cjs",
7
+ "module": "lib/core.js",
8
+ "types": "lib/core.d.ts",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/ts-graphviz/ts-graphviz.git",
12
+ "directory": "packages/core"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "provenance": true
17
+ },
18
+ "author": "Yuki Yamazaki <yuki@kamiazya.tech>",
19
+ "license": "MIT",
20
+ "bugs": {
21
+ "url": "https://github.com/ts-graphviz/ts-graphviz/issues"
22
+ },
23
+ "homepage": "https://github.com/ts-graphviz/ts-graphviz#readme",
24
+ "sideEffects": true,
25
+ "dependencies": {
26
+ "@ts-graphviz/ast": "^0.0.0-pr956-20240225073457",
27
+ "@ts-graphviz/common": "^0.0.0-pr956-20240225073457"
28
+ },
29
+ "devDependencies": {
30
+ "typescript": "^5.3.3",
31
+ "vite": "^5.1.3",
32
+ "vite-plugin-dts": "^3.7.2"
33
+ },
34
+ "scripts": {
35
+ "build": "vite build"
36
+ }
37
+ }
@@ -0,0 +1,18 @@
1
+ import { Attribute } from '@ts-graphviz/common';
2
+
3
+ /**
4
+ * @group Attribute
5
+ *
6
+ * @deprecated Use {@link Attribute.keys} instead.
7
+ */
8
+ export type AttributeKeyDict = Attribute.keys;
9
+
10
+ /**
11
+ * @group Attribute
12
+ */
13
+ export const attribute: Attribute.keys = new Proxy(
14
+ Object.freeze({}) as Attribute.keys,
15
+ {
16
+ get: (_, key: string) => key,
17
+ },
18
+ );
package/src/core.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './attribute.js';
2
+ export * from './models/index.js';
3
+ export * from './model-factory/index.js';
4
+ export * from './to-dot.js';
5
+ export * from './from-dot.js';
@@ -0,0 +1,73 @@
1
+ import {
2
+ ConvertToModelOptions,
3
+ ParseOptions,
4
+ parse,
5
+ toModel,
6
+ } from '@ts-graphviz/ast';
7
+ import {
8
+ EdgeModel,
9
+ NodeModel,
10
+ RootGraphModel,
11
+ SubgraphModel,
12
+ } from '@ts-graphviz/common';
13
+
14
+ /**
15
+ * This interface provides options for converting DOT to a model.
16
+ * @group Convert DOT to Model
17
+ */
18
+ export interface FromDotOptions<
19
+ T extends 'Dot' | 'Graph' | 'Node' | 'Edge' | 'Subgraph',
20
+ > {
21
+ /**
22
+ * Options for parsing DOT.
23
+ */
24
+ parse?: ParseOptions<T>;
25
+ /**
26
+ * Options for converting the parsed DOT to a model.
27
+ */
28
+ convert?: ConvertToModelOptions;
29
+ }
30
+
31
+ /**
32
+ * fromDot is a function that converts a DOT string to a model.
33
+ *
34
+ * @group Convert DOT to Model
35
+ *
36
+ * @param dot The DOT string to convert.
37
+ * @param options Options for converting the DOT string to a model.
38
+ * @returns A model of type {@link RootGraphModel}, {@link NodeModel}, {@link EdgeModel}, or {@link SubgraphModel},
39
+ * depending on the type specified in the options.
40
+ */
41
+ export function fromDot(
42
+ dot: string,
43
+ options?: FromDotOptions<'Dot' | 'Graph'>,
44
+ ): RootGraphModel;
45
+ export function fromDot(
46
+ dot: string,
47
+ options?: FromDotOptions<'Node'>,
48
+ ): NodeModel;
49
+ export function fromDot(
50
+ dot: string,
51
+ options?: FromDotOptions<'Edge'>,
52
+ ): EdgeModel;
53
+ export function fromDot(
54
+ dot: string,
55
+ options?: FromDotOptions<'Subgraph'>,
56
+ ): SubgraphModel;
57
+ export function fromDot<
58
+ T extends 'Dot' | 'Graph' | 'Node' | 'Edge' | 'Subgraph',
59
+ >(dot: string, options?: FromDotOptions<T>) {
60
+ const ast = parse(dot, options?.parse);
61
+ if (
62
+ Array.isArray(ast) ||
63
+ ast.type === 'Attribute' ||
64
+ ast.type === 'AttributeList' ||
65
+ ast.type === 'Comment' ||
66
+ ast.type === 'NodeRef' ||
67
+ ast.type === 'NodeRefGroup' ||
68
+ ast.type === 'Literal'
69
+ ) {
70
+ throw new Error();
71
+ }
72
+ return toModel(ast, options?.convert);
73
+ }
@@ -0,0 +1,2 @@
1
+ export * from './types.js';
2
+ export * from './model-factory.js';
@@ -0,0 +1,79 @@
1
+ import { describe, expect, test, vi } from 'vitest';
2
+
3
+ import { RootModelsContext } from '@ts-graphviz/common';
4
+ import { attribute as _ } from '../attribute.js';
5
+ import '../models/registerModelContext.js';
6
+ import { ModelFactoryBuilder } from './model-factory-builder.js';
7
+
8
+ describe.each([
9
+ { directed: true, strict: true },
10
+ { directed: false, strict: true },
11
+ { directed: false, strict: false },
12
+ { directed: true, strict: false },
13
+ ])('strict: %s, directed: %s', ({ strict, directed }) => {
14
+ const factory = ModelFactoryBuilder.call(RootModelsContext, directed, strict);
15
+
16
+ test('no arguments', () => {
17
+ const g = factory();
18
+ expect(g.directed).toStrictEqual(directed);
19
+ expect(g.strict).toStrictEqual(strict);
20
+ });
21
+
22
+ test('first argument is id', () => {
23
+ const g = factory('foo');
24
+ expect(g.id).toStrictEqual('foo');
25
+
26
+ expect(g.directed).toStrictEqual(directed);
27
+ expect(g.strict).toStrictEqual(strict);
28
+ });
29
+
30
+ test('first argument is callback', () => {
31
+ const callback = vi.fn();
32
+ const g = factory(callback);
33
+ expect(g.id).toBeUndefined();
34
+ expect(callback).toHaveBeenCalledWith(g);
35
+
36
+ expect(g.directed).toStrictEqual(directed);
37
+ expect(g.strict).toStrictEqual(strict);
38
+ });
39
+
40
+ test('first argument is attribute object', () => {
41
+ const g = factory({ [_.label]: 'Test label' });
42
+ expect(g.id).toBeUndefined();
43
+ expect(g.values).toStrictEqual([[_.label, 'Test label']]);
44
+
45
+ expect(g.directed).toStrictEqual(directed);
46
+ expect(g.strict).toStrictEqual(strict);
47
+ });
48
+
49
+ test('first argument is attribute object, seccond argument is callback', () => {
50
+ const callback = vi.fn();
51
+ const g = factory({ [_.label]: 'Test label' }, callback);
52
+ expect(g.id).toBeUndefined();
53
+ expect(g.values).toStrictEqual([[_.label, 'Test label']]);
54
+ expect(callback).toHaveBeenCalledWith(g);
55
+
56
+ expect(g.directed).toStrictEqual(directed);
57
+ expect(g.strict).toStrictEqual(strict);
58
+ });
59
+
60
+ test('first argument is id, seccond argument is attribute object', () => {
61
+ const g = factory('foo', { [_.label]: 'Test label' });
62
+ expect(g.id).toStrictEqual('foo');
63
+ expect(g.values).toStrictEqual([[_.label, 'Test label']]);
64
+
65
+ expect(g.directed).toStrictEqual(directed);
66
+ expect(g.strict).toStrictEqual(strict);
67
+ });
68
+
69
+ test('first argument is id, seccond argument is attribute object, third arguments is callback', () => {
70
+ const callback = vi.fn();
71
+ const g = factory('foo', { [_.label]: 'Test label' }, callback);
72
+ expect(g.id).toStrictEqual('foo');
73
+ expect(g.values).toStrictEqual([[_.label, 'Test label']]);
74
+ expect(callback).toHaveBeenCalledWith(g);
75
+
76
+ expect(g.directed).toStrictEqual(directed);
77
+ expect(g.strict).toStrictEqual(strict);
78
+ });
79
+ });
@@ -0,0 +1,55 @@
1
+ import {
2
+ GraphAttributesObject,
3
+ ModelsContext,
4
+ RootGraphModel,
5
+ RootModelsContext,
6
+ } from '@ts-graphviz/common';
7
+ import { ModelFactory } from './types.js';
8
+
9
+ /**
10
+ * ModelFactoryBuilder is a function that takes two parameters, directed and strictMode, and returns a ModelFactory.
11
+ *
12
+ * @param directed A boolean value indicating whether the graph should be directed or not.
13
+ * @param strictMode A boolean value indicating whether the graph should be in strict mode or not.
14
+ * @returns A ModelFactory that takes an array of unknowns as parameters and returns a RootGraphModel.
15
+ * @hidden
16
+ */
17
+ export function ModelFactoryBuilder(
18
+ this: ModelsContext,
19
+ directed: boolean,
20
+ strictMode: boolean,
21
+ ): ModelFactory {
22
+ return (...args: unknown[]) => {
23
+ const G = directed ? this.Digraph : this.Graph;
24
+ const id = args.find((arg): arg is string => typeof arg === 'string');
25
+ const attributes = args.find(
26
+ (arg): arg is GraphAttributesObject => typeof arg === 'object',
27
+ );
28
+ const callback = args.find(
29
+ (arg): arg is (g: RootGraphModel) => void => typeof arg === 'function',
30
+ );
31
+ const g = new G(id, strictMode, attributes);
32
+ g.with(this);
33
+ if (typeof callback === 'function') {
34
+ callback(g);
35
+ }
36
+ return g;
37
+ };
38
+ }
39
+
40
+ /**
41
+ * createModelFactories is a function that takes a boolean value, strict, and an optional ModelsContext parameter, context, and returns an object containing two ModelFactories.
42
+ *
43
+ * @param strict A boolean value indicating whether the graph should be in strict mode or not.
44
+ * @param context An optional ModelsContext parameter.
45
+ * @returns An object containing two ModelFactories, one for directed graphs and one for undirected graphs.
46
+ */
47
+ export function createModelFactories(
48
+ strict: boolean,
49
+ context: ModelsContext = RootModelsContext,
50
+ ) {
51
+ return Object.freeze({
52
+ digraph: ModelFactoryBuilder.call(context, true, strict),
53
+ graph: ModelFactoryBuilder.call(context, false, strict),
54
+ });
55
+ }