@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
@@ -0,0 +1,61 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { Digraph, Graph } from '../models/index.js';
3
+ import { digraph, graph, strict, withContext } from './model-factory.js';
4
+
5
+ test('digraph function returns an object of Digraph, and the strict property is false', () => {
6
+ const g = digraph();
7
+ expect(g).toBeInstanceOf(Digraph);
8
+ expect(g.strict).toStrictEqual(false);
9
+ });
10
+
11
+ test('graph function returns an object of Graph, and the strict property is false', () => {
12
+ const g = graph();
13
+ expect(g).toBeInstanceOf(Graph);
14
+ expect(g.strict).toStrictEqual(false);
15
+ });
16
+
17
+ test('strict.digraph function returns an object of Digraph', () => {
18
+ const g = strict.digraph();
19
+ expect(g).toBeInstanceOf(Digraph);
20
+ expect(g.strict).toStrictEqual(true);
21
+ });
22
+
23
+ test('strict.graph function returns an object of Graph', () => {
24
+ const g = strict.graph();
25
+ expect(g).toBeInstanceOf(Graph);
26
+ expect(g.strict).toStrictEqual(true);
27
+ });
28
+
29
+ describe('withContext function allows the class RootGraph to be generated with a custom class.', () => {
30
+ class TestDigraph extends Digraph {}
31
+ class TestGraph extends Graph {}
32
+
33
+ const { digraph, graph, strict } = withContext({
34
+ Digraph: TestDigraph,
35
+ Graph: TestGraph,
36
+ });
37
+
38
+ test('digraph function returns an object of TestDigraph, and the strict property is false', () => {
39
+ const g = digraph();
40
+ expect(g).toBeInstanceOf(TestDigraph);
41
+ expect(g.strict).toStrictEqual(false);
42
+ });
43
+
44
+ test('graph function returns an object of TestGraph, and the strict property is false', () => {
45
+ const g = graph();
46
+ expect(g).toBeInstanceOf(TestGraph);
47
+ expect(g.strict).toStrictEqual(false);
48
+ });
49
+
50
+ test('strict.digraph function returns an object of TestDigraph', () => {
51
+ const g = strict.digraph();
52
+ expect(g).toBeInstanceOf(TestDigraph);
53
+ expect(g.strict).toStrictEqual(true);
54
+ });
55
+
56
+ test('strict.graph function returns an object of TestGraph', () => {
57
+ const g = strict.graph();
58
+ expect(g).toBeInstanceOf(TestGraph);
59
+ expect(g.strict).toStrictEqual(true);
60
+ });
61
+ });
@@ -0,0 +1,40 @@
1
+ import { ModelsContext, createModelsContext } from '@ts-graphviz/common';
2
+ import { createModelFactories } from './model-factory-builder.js';
3
+ import { ModelFactories, ModelFactoriesWithStrict } from './types.js';
4
+
5
+ const noStrict: ModelFactories = createModelFactories(false);
6
+
7
+ /**
8
+ * digraph is a factory for creating Digraph objects.
9
+ * @group Model Factory
10
+ */
11
+ export const digraph = noStrict.digraph;
12
+
13
+ /**
14
+ * graph is a factory for creating Graph objects.
15
+ * @group Model Factory
16
+ */
17
+ export const graph = noStrict.graph;
18
+
19
+ /**
20
+ * Provides a strict mode API.
21
+ * @group Model Factory
22
+ */
23
+ export const strict: ModelFactories = createModelFactories(true);
24
+
25
+ /**
26
+ * withContext creates a {@link ModelFactoriesWithStrict} object with the given context.
27
+ *
28
+ * @param models - An object containing the models to be used in the context.
29
+ *
30
+ * @returns A ModelFactoriesWithStrict object containing the factories. * @group Model Factory
31
+ */
32
+ export function withContext(
33
+ models: Partial<ModelsContext>,
34
+ ): ModelFactoriesWithStrict {
35
+ const context = createModelsContext(models);
36
+ return Object.freeze({
37
+ ...createModelFactories(false, context),
38
+ strict: createModelFactories(true, context),
39
+ });
40
+ }
@@ -0,0 +1,46 @@
1
+ import { GraphAttributesObject, RootGraphModel } from '@ts-graphviz/common';
2
+
3
+ /**
4
+ * ModelFactory is an interface that provides a way to create a {@link RootGraphModel} object.
5
+ *
6
+ * @param id - Optional string parameter that specifies the id of the {@link RootGraphModel} object.
7
+ * @param attributes - Optional GraphAttributesObject parameter that specifies the attributes of the {@link RootGraphModel} object.
8
+ * @param callback - Optional callback function that takes a {@link RootGraphModel} object as a parameter.
9
+ *
10
+ * @returns {@link RootGraphModel} - Returns a {@link RootGraphModel} object.
11
+ * @group Model Factory
12
+ */
13
+ export interface ModelFactory {
14
+ (
15
+ id?: string,
16
+ attributes?: GraphAttributesObject,
17
+ callback?: (g: RootGraphModel) => void,
18
+ ): RootGraphModel;
19
+ (
20
+ attributes?: GraphAttributesObject,
21
+ callback?: (g: RootGraphModel) => void,
22
+ ): RootGraphModel;
23
+ (id?: string, callback?: (g: RootGraphModel) => void): RootGraphModel;
24
+ (callback?: (g: RootGraphModel) => void): RootGraphModel;
25
+ }
26
+
27
+ /**
28
+ * @group Model Factory
29
+ */
30
+ export interface ModelFactories {
31
+ /**
32
+ * API for creating directional graph objects.
33
+ */
34
+ digraph: ModelFactory;
35
+ /**
36
+ * API for creating omnidirectional graph objects.
37
+ */
38
+ graph: ModelFactory;
39
+ }
40
+
41
+ /**
42
+ * @group Model Factory
43
+ */
44
+ export interface ModelFactoriesWithStrict extends ModelFactories {
45
+ strict: ModelFactories;
46
+ }
@@ -0,0 +1,58 @@
1
+ import { AttributeListKind } from '@ts-graphviz/common';
2
+ import { beforeEach, describe, expect, it, test } from 'vitest';
3
+ import { attribute as _ } from '../attribute.js';
4
+ import { AttributeList } from './AttributeList.js';
5
+ import { AttributesBase } from './AttributesBase.js';
6
+ import { DotObject } from './DotObject.js';
7
+
8
+ let attrs: AttributeList<AttributeListKind>;
9
+ beforeEach(() => {
10
+ attrs = new AttributeList('Node');
11
+ });
12
+
13
+ describe('object', () => {
14
+ it('should be instance of AttributeList/AttributesBase/DotObject', () => {
15
+ expect(attrs).toBeInstanceOf(AttributeList);
16
+ expect(attrs).toBeInstanceOf(AttributesBase);
17
+ expect(attrs).toBeInstanceOf(DotObject);
18
+ });
19
+
20
+ it('size should be 0 by default', () => {
21
+ expect(attrs.size).toBe(0);
22
+ });
23
+
24
+ it('$$type property should returns "AttributeList"', () => {
25
+ expect(attrs.$$type).toStrictEqual('AttributeList');
26
+ });
27
+ });
28
+
29
+ describe('constructor', () => {
30
+ describe('1st argument is kind of AttributeList', () => {
31
+ test.each(['Node', 'Edge', 'Graph'] as AttributeListKind[])(
32
+ 'AttributeList kind is %s',
33
+ (kind) => {
34
+ attrs = new AttributeList(kind);
35
+ expect(attrs.$$kind).toStrictEqual(kind);
36
+ },
37
+ );
38
+ });
39
+
40
+ test('2nd argument is attribute object', () => {
41
+ attrs = new AttributeList('Node', {
42
+ [_.label]: 'Label',
43
+ });
44
+ expect(attrs.size).toBe(1);
45
+ expect(attrs.get(_.label)).toBe('Label');
46
+ });
47
+ });
48
+
49
+ describe('comment', () => {
50
+ test('default value to be undefined', () => {
51
+ expect(attrs.comment).toBeUndefined();
52
+ });
53
+
54
+ test('comment can be set', () => {
55
+ attrs.comment = 'test';
56
+ expect(attrs.comment).toStrictEqual('test');
57
+ });
58
+ });
@@ -0,0 +1,32 @@
1
+ import {
2
+ AttributeKey,
3
+ AttributeListKind,
4
+ AttributeListModel,
5
+ AttributesObject,
6
+ } from '@ts-graphviz/common';
7
+ import { AttributesBase } from './AttributesBase.js';
8
+
9
+ /**
10
+ * A set of attribute values for any object.
11
+ * @group Models
12
+ */
13
+ export class AttributeList<
14
+ K extends AttributeListKind,
15
+ T extends AttributeKey = AttributeKey,
16
+ >
17
+ extends AttributesBase<T>
18
+ implements AttributeListModel<K, T>
19
+ {
20
+ public get $$type(): 'AttributeList' {
21
+ return 'AttributeList';
22
+ }
23
+
24
+ public comment?: string;
25
+
26
+ constructor(
27
+ public readonly $$kind: K,
28
+ attributes?: AttributesObject<T>,
29
+ ) {
30
+ super(attributes);
31
+ }
32
+ }
@@ -0,0 +1,79 @@
1
+ import { Attributes } from '@ts-graphviz/common';
2
+ import { beforeEach, describe, expect, it, test } from 'vitest';
3
+ import { attribute as _ } from '../attribute.js';
4
+ import { AttributesBase } from './AttributesBase.js';
5
+ import { DotObject } from './DotObject.js';
6
+
7
+ class TestAttributes extends AttributesBase<any> {}
8
+
9
+ let attrs: Attributes<any>;
10
+ beforeEach(() => {
11
+ attrs = new TestAttributes();
12
+ });
13
+
14
+ describe('object', () => {
15
+ it('should be instance of AttributesBase/DotObject', () => {
16
+ expect(attrs).toBeInstanceOf(DotObject);
17
+ expect(attrs).toBeInstanceOf(AttributesBase);
18
+ });
19
+
20
+ it('size should be 0 by default', () => {
21
+ expect(attrs.size).toBe(0);
22
+ });
23
+ });
24
+
25
+ describe('constructor', () => {
26
+ test('with no attribute object', () => {
27
+ attrs = new TestAttributes();
28
+ expect(attrs.size).toBe(0);
29
+ expect(attrs.get(_.label)).toBeUndefined();
30
+ });
31
+
32
+ test('with attribute object', () => {
33
+ attrs = new TestAttributes({
34
+ [_.label]: 'Label',
35
+ });
36
+ expect(attrs.size).toBe(1);
37
+ expect(attrs.get(_.label)).toBe('Label');
38
+ });
39
+ });
40
+
41
+ describe('apply method', () => {
42
+ test('with attributes object', () => {
43
+ attrs.apply({
44
+ [_.label]: 'this is test',
45
+ [_.color]: 'red',
46
+ [_.fontsize]: 16,
47
+ });
48
+ expect(attrs.size).toBe(3);
49
+ });
50
+
51
+ test('with attributes entities', () => {
52
+ attrs.apply([
53
+ [_.label, 'this is test'],
54
+ [_.color, 'red'],
55
+ [_.fontsize, 16],
56
+ ]);
57
+ expect(attrs.size).toBe(3);
58
+ });
59
+ });
60
+
61
+ test('clear method', () => {
62
+ attrs = new TestAttributes({
63
+ [_.label]: 'this is test',
64
+ [_.color]: 'red',
65
+ [_.fontsize]: 16,
66
+ });
67
+
68
+ expect(attrs.size).toBe(3);
69
+ attrs.clear();
70
+ expect(attrs.size).toBe(0);
71
+ });
72
+
73
+ test('set/get/delete methods', () => {
74
+ const id = 'test';
75
+ attrs.set('label', id);
76
+ expect(attrs.get('label')).toBe(id);
77
+ attrs.delete('label');
78
+ expect(attrs.get('label')).toBeUndefined();
79
+ });
@@ -0,0 +1,62 @@
1
+ import {
2
+ Attribute,
3
+ AttributeKey,
4
+ Attributes,
5
+ AttributesEntities,
6
+ AttributesObject,
7
+ } from '@ts-graphviz/common';
8
+ import { DotObject } from './DotObject.js';
9
+
10
+ /**
11
+ * Base class for DOT objects with attributes.
12
+ * @group Models
13
+ */
14
+ export abstract class AttributesBase<T extends AttributeKey>
15
+ extends DotObject
16
+ implements Attributes<T>
17
+ {
18
+ /** @hidden */
19
+ #attrs: Map<T, Attribute<T>> = new Map();
20
+
21
+ constructor(attributes?: AttributesObject<T>) {
22
+ super();
23
+ if (attributes !== undefined) {
24
+ this.apply(attributes);
25
+ }
26
+ }
27
+
28
+ get values(): ReadonlyArray<[T, Attribute<T>]> {
29
+ return Array.from(this.#attrs.entries());
30
+ }
31
+
32
+ get size(): number {
33
+ return this.#attrs.size;
34
+ }
35
+
36
+ public get<K extends T>(key: K): Attribute<K> | undefined {
37
+ return this.#attrs.get(key) as Attribute<K> | undefined;
38
+ }
39
+
40
+ public set<K extends T>(key: K, value: Attribute<K>): void {
41
+ if (value !== null && value !== undefined) {
42
+ this.#attrs.set(key, value);
43
+ }
44
+ }
45
+
46
+ public delete(key: T): void {
47
+ this.#attrs.delete(key);
48
+ }
49
+
50
+ public apply(attributes: AttributesObject<T> | AttributesEntities<T>): void {
51
+ const entries = Array.isArray(attributes)
52
+ ? attributes
53
+ : Object.entries(attributes);
54
+ for (const [key, value] of entries) {
55
+ this.set(key, value);
56
+ }
57
+ }
58
+
59
+ public clear(): void {
60
+ this.#attrs.clear();
61
+ }
62
+ }
@@ -0,0 +1,18 @@
1
+ import { beforeEach, describe, expect, test } from 'vitest';
2
+ import { AttributesGroup } from './AttributesGroup.js';
3
+
4
+ let attrs: AttributesGroup;
5
+ beforeEach(() => {
6
+ attrs = new AttributesGroup();
7
+ });
8
+
9
+ describe('comment', () => {
10
+ test('default value to be undefined', () => {
11
+ expect(attrs.comment).toBeUndefined();
12
+ });
13
+
14
+ test('comment can be set', () => {
15
+ attrs.comment = 'test';
16
+ expect(attrs.comment).toStrictEqual('test');
17
+ });
18
+ });
@@ -0,0 +1,13 @@
1
+ import { AttributeKey, AttributesGroupModel } from '@ts-graphviz/common';
2
+ import { AttributesBase } from './AttributesBase.js';
3
+
4
+ /**
5
+ * A set of attribute values for any object.
6
+ * @group Models
7
+ */
8
+ export class AttributesGroup<T extends AttributeKey = AttributeKey>
9
+ extends AttributesBase<T>
10
+ implements AttributesGroupModel<T>
11
+ {
12
+ public comment?: string;
13
+ }
@@ -0,0 +1,17 @@
1
+ import { expect, it, test } from 'vitest';
2
+ import { Digraph } from './Digraph.js';
3
+ import { DotObject } from './DotObject.js';
4
+ import { GraphBase } from './GraphBase.js';
5
+ import './registerModelContext.js';
6
+
7
+ const g = new Digraph();
8
+
9
+ test('directed propaty should be true', () => {
10
+ expect(g.directed).toStrictEqual(true);
11
+ });
12
+
13
+ it('should be instance of Digraph/GraphBase/DotObject', () => {
14
+ expect(g).toBeInstanceOf(Digraph);
15
+ expect(g).toBeInstanceOf(GraphBase);
16
+ expect(g).toBeInstanceOf(DotObject);
17
+ });
@@ -0,0 +1,11 @@
1
+ import { RootGraph } from './RootGraph.js';
2
+
3
+ /**
4
+ * DOT object class representing a digraph.
5
+ * @group Models
6
+ */
7
+ export class Digraph extends RootGraph {
8
+ public get directed(): boolean {
9
+ return true;
10
+ }
11
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Base class for DOT objects.
3
+ * @group Models
4
+ */
5
+ export abstract class DotObject {}
@@ -0,0 +1,48 @@
1
+ import { beforeEach, describe, expect, it, test } from 'vitest';
2
+
3
+ import './registerModelContext.js';
4
+
5
+ import { EdgeTargetTuple } from '@ts-graphviz/common';
6
+ import { attribute as _ } from '../attribute.js';
7
+ import { DotObject } from './DotObject.js';
8
+ import { Edge } from './Edge.js';
9
+ import { Node } from './Node.js';
10
+
11
+ let edge: Edge;
12
+
13
+ const targets = [...Array(2)].map(
14
+ (_, i) => new Node(`node${i + 1}`),
15
+ ) as unknown as EdgeTargetTuple;
16
+
17
+ beforeEach(() => {
18
+ edge = new Edge(targets);
19
+ });
20
+
21
+ it('should be instance of Edge/DotObject', () => {
22
+ expect(edge).toBeInstanceOf(Edge);
23
+ expect(edge).toBeInstanceOf(DotObject);
24
+ });
25
+
26
+ describe('Constructor', () => {
27
+ test('first argument is targets, and second attributes object', () => {
28
+ edge = new Edge(targets, {
29
+ [_.label]: 'Label',
30
+ });
31
+ expect(edge.attributes.size).toBe(1);
32
+ expect(edge.attributes.get(_.label)).toBe('Label');
33
+ });
34
+ });
35
+
36
+ it('throws an error when the EdgeTarget element is missing', () => {
37
+ const n = new Node('id');
38
+ expect(
39
+ () => new Edge([] as unknown as EdgeTargetTuple),
40
+ ).toThrowErrorMatchingInlineSnapshot(
41
+ `[Error: The element of Edge target is missing or not satisfied as Edge target.]`,
42
+ );
43
+ expect(
44
+ () => new Edge([n] as unknown as EdgeTargetTuple),
45
+ ).toThrowErrorMatchingInlineSnapshot(
46
+ `[Error: The element of Edge target is missing or not satisfied as Edge target.]`,
47
+ );
48
+ });
@@ -0,0 +1,40 @@
1
+ import {
2
+ AttributesGroupModel,
3
+ EdgeAttributeKey,
4
+ EdgeAttributesObject,
5
+ EdgeModel,
6
+ EdgeTargetTuple,
7
+ isNodeRefLike,
8
+ } from '@ts-graphviz/common';
9
+ import { AttributesGroup } from './AttributesGroup.js';
10
+ import { DotObject } from './DotObject.js';
11
+
12
+ /**
13
+ * DOT object class representing a edge.
14
+ * @group Models
15
+ */
16
+ export class Edge extends DotObject implements EdgeModel {
17
+ public get $$type(): 'Edge' {
18
+ return 'Edge';
19
+ }
20
+
21
+ public comment?: string;
22
+
23
+ public readonly attributes: AttributesGroupModel<EdgeAttributeKey>;
24
+
25
+ constructor(
26
+ public readonly targets: EdgeTargetTuple,
27
+ attributes?: EdgeAttributesObject,
28
+ ) {
29
+ super();
30
+ if (
31
+ targets.length < 2 &&
32
+ (isNodeRefLike(targets[0]) && isNodeRefLike(targets[1])) === false
33
+ ) {
34
+ throw Error(
35
+ 'The element of Edge target is missing or not satisfied as Edge target.',
36
+ );
37
+ }
38
+ this.attributes = new AttributesGroup(attributes);
39
+ }
40
+ }
@@ -0,0 +1,18 @@
1
+ import { expect, it, test } from 'vitest';
2
+ import { DotObject } from './DotObject.js';
3
+ import { Graph } from './Graph.js';
4
+ import { GraphBase } from './GraphBase.js';
5
+
6
+ import './registerModelContext.js';
7
+
8
+ const g = new Graph();
9
+
10
+ test('directed propaty should be false', () => {
11
+ expect(g.directed).toStrictEqual(false);
12
+ });
13
+
14
+ it('should be instance of Graph/GraphBase/DotObject', () => {
15
+ expect(g).toBeInstanceOf(Graph);
16
+ expect(g).toBeInstanceOf(GraphBase);
17
+ expect(g).toBeInstanceOf(DotObject);
18
+ });
@@ -0,0 +1,11 @@
1
+ import { RootGraph } from './RootGraph.js';
2
+
3
+ /**
4
+ * DOT object class representing a graph.
5
+ * @group Models
6
+ */
7
+ export class Graph extends RootGraph {
8
+ get directed(): boolean {
9
+ return false;
10
+ }
11
+ }