@eventcatalog/core 2.3.3 → 2.4.0

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # @eventcatalog/core
2
2
 
3
+ ## 2.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3a4b8ec: feat(c0re): add semantic version support, referencing services or messages can now be done with semver
8
+
9
+ ## 2.3.4
10
+
11
+ ### Patch Changes
12
+
13
+ - a99057e: feat(core): added ability to drag nodes in visualizer
14
+
3
15
  ## 2.3.3
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eventcatalog/core",
3
3
  "type": "module",
4
- "version": "2.3.3",
4
+ "version": "2.4.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -55,9 +55,10 @@
55
55
  "rapidoc": "^9.3.4",
56
56
  "react": "^18.3.1",
57
57
  "react-dom": "^18.3.1",
58
- "reactflow": "^11.11.3",
58
+ "reactflow": "^11.11.4",
59
59
  "rehype-slug": "^6.0.0",
60
60
  "remark-gfm": "^3.0.1",
61
+ "semver": "7.6.3",
61
62
  "tailwindcss": "^3.4.3",
62
63
  "typescript": "^5.4.5",
63
64
  "unist-util-visit": "^5.0.0"
@@ -1,6 +1,15 @@
1
1
  import { useEffect, useMemo, useState } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
- import ReactFlow, { Background, ConnectionLineType, Controls, Panel, ReactFlowProvider, type Edge, type Node } from 'reactflow';
3
+ import ReactFlow, {
4
+ Background,
5
+ ConnectionLineType,
6
+ Controls,
7
+ Panel,
8
+ ReactFlowProvider,
9
+ useNodesState,
10
+ type Edge,
11
+ type Node,
12
+ } from 'reactflow';
4
13
  import 'reactflow/dist/style.css';
5
14
  import ServiceNode from './Nodes/Service';
6
15
  import EventNode from './Nodes/Event';
@@ -29,21 +38,18 @@ const getVisualiserUrlForCollection = (collectionItem: CollectionEntry<Collectio
29
38
  };
30
39
 
31
40
  // const NodeGraphBuilder = ({ title, subtitle, includeBackground = true, includeControls = true }: Props) => {
32
- const NodeGraphBuilder = ({ nodes, edges, title, includeBackground = true, linkTo = 'docs' }: Props) => {
33
- // const { fitView, viewportInitialized } = useReactFlow();
41
+ const NodeGraphBuilder = ({ nodes: initialNodes, edges, title, includeBackground = true, linkTo = 'docs' }: Props) => {
42
+ const [nodes, _, onNodesChange] = useNodesState(initialNodes);
34
43
 
35
- // const nodeTypes = useMemo(() => ({ service: ServiceNode, event: EventNode, command: CommandNode }), []);
36
44
  const nodeTypes = useMemo(() => ({ services: ServiceNode, events: EventNode, commands: CommandNode }), []);
37
45
  const nodeOrigin = [0.5, 0.5];
38
46
 
39
47
  const handleNodeClick = (_: any, node: Node) => {
40
48
  if (node.type === 'events' || node.type === 'commands') {
41
- // return (window.location.href = linkTo === 'docs' ? getDocUrlForCollection(node.data.message) : getVisualiserUrlForCollection(node.data.message));
42
49
  navigate(linkTo === 'docs' ? getDocUrlForCollection(node.data.message) : getVisualiserUrlForCollection(node.data.message));
43
50
  }
44
51
  if (node.type === 'services') {
45
52
  navigate(linkTo === 'docs' ? getDocUrlForCollection(node.data.service) : getVisualiserUrlForCollection(node.data.service));
46
- // return (window.location.href = linkTo === 'docs' ? getDocUrlForCollection(node.data.service) : getVisualiserUrlForCollection(node.data.service));
47
53
  }
48
54
  };
49
55
 
@@ -55,6 +61,7 @@ const NodeGraphBuilder = ({ nodes, edges, title, includeBackground = true, linkT
55
61
  edges={edges}
56
62
  fitView
57
63
  nodesDraggable
64
+ onNodesChange={onNodesChange}
58
65
  connectionLineType={ConnectionLineType.SmoothStep}
59
66
  // @ts-ignore
60
67
  nodeOrigin={nodeOrigin}
@@ -80,7 +80,7 @@ const commands = defineCollection({
80
80
 
81
81
  const pointer = z.object({
82
82
  id: z.string(),
83
- version: z.string(),
83
+ version: z.string().optional().default('latest'),
84
84
  });
85
85
 
86
86
  const services = defineCollection({
@@ -13,7 +13,7 @@ interface Props {
13
13
  }
14
14
 
15
15
  export const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simple' }: Props) => {
16
- const flow = defaultFlow || createDagreGraph({ ranksep: 180, nodesep: 50 });
16
+ const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
17
17
  const nodes = [] as any,
18
18
  edges = [] as any;
19
19
 
@@ -2,6 +2,7 @@ import { getCollection } from 'astro:content';
2
2
  import type { CollectionEntry } from 'astro:content';
3
3
  import path from 'path';
4
4
  import { getVersionForCollectionItem } from './collections/util';
5
+ import { satisfies } from 'semver';
5
6
 
6
7
  const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
7
8
 
@@ -29,16 +30,16 @@ export const getCommands = async ({ getAllVersions = true }: Props = {}): Promis
29
30
  const producers = services.filter((service) => {
30
31
  if (!service.data.sends) return false;
31
32
  return service.data.sends.find((item) => {
32
- if (item.version) return item.id === command.data.id && item.version === command.data.version;
33
- return item.id == command.data.id;
33
+ if (item.version) return item.id === command.data.id && satisfies(command.data.version, item.version);
34
+ return item.id == command.data.id; // ??
34
35
  });
35
36
  });
36
37
 
37
38
  const consumers = services.filter((service) => {
38
39
  if (!service.data.receives) return false;
39
40
  return service.data.receives.find((item) => {
40
- if (item.version) return item.id === command.data.id && item.version === command.data.version;
41
- return item.id == command.data.id;
41
+ if (item.version) return item.id === command.data.id && satisfies(command.data.version, item.version);
42
+ return item.id == command.data.id; // ??
42
43
  });
43
44
  });
44
45
 
@@ -14,7 +14,7 @@ interface Props {
14
14
  }
15
15
 
16
16
  export const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simple' }: Props) => {
17
- const flow = defaultFlow || createDagreGraph({ ranksep: 180, nodesep: 50 });
17
+ const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
18
18
  const nodes = [] as any,
19
19
  edges = [] as any;
20
20
 
@@ -2,6 +2,7 @@ import { getCollection } from 'astro:content';
2
2
  import type { CollectionEntry } from 'astro:content';
3
3
  import path from 'path';
4
4
  import { getVersionForCollectionItem } from './collections/util';
5
+ import { satisfies } from 'semver';
5
6
 
6
7
  const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
7
8
 
@@ -30,14 +31,14 @@ export const getEvents = async ({ getAllVersions = true }: Props = {}): Promise<
30
31
  const producers = services.filter((service) => {
31
32
  if (!service.data.sends) return false;
32
33
  return service.data.sends.find((item) => {
33
- return item.id === event.data.id && item.version === event.data.version;
34
+ return item.id === event.data.id && satisfies(event.data.version, item.version);
34
35
  });
35
36
  });
36
37
 
37
38
  const consumers = services.filter((service) => {
38
39
  if (!service.data.receives) return false;
39
40
  return service.data.receives.find((item) => {
40
- return item.id === event.data.id && item.version === event.data.version;
41
+ return item.id === event.data.id && satisfies(event.data.version, item.version);
41
42
 
42
43
  // If no version has been found, then get try find the latest one
43
44
  // return item.id == event.data.id
@@ -15,7 +15,7 @@ interface Props {
15
15
  }
16
16
 
17
17
  export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simple', renderAllEdges = false }: Props) => {
18
- const flow = defaultFlow || createDagreGraph({ ranksep: 200, nodesep: 50 });
18
+ const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
19
19
  const nodes = [] as any,
20
20
  edges = [] as any;
21
21
 
@@ -40,16 +40,13 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
40
40
  const messages = [...events, ...commands];
41
41
 
42
42
  const receivesHydrated = receivesRaw
43
- .map((message) => {
44
- return getVersion(messages, message.id, message.version);
45
- })
43
+ .map((message) => getVersion(messages, message.id, message.version))
44
+ .flat()
46
45
  .filter((e) => e !== undefined);
47
46
 
48
47
  const sendsHydrated = sendsRaw
49
- .map((message) => {
50
- return getVersion(messages, message.id, message.version);
51
- // return messages.find((message) => message.data.id === messageId);
52
- })
48
+ .map((message) => getVersion(messages, message.id, message.version))
49
+ .flat()
53
50
  .filter((e) => e !== undefined);
54
51
 
55
52
  const receives = (receivesHydrated as CollectionEntry<'events' | 'commands'>[]) || [];
@@ -1,16 +1,23 @@
1
- import { getVersionForCollectionItem, getVersions } from '@utils/collections/util';
1
+ import { getVersionForCollectionItem } from '@utils/collections/util';
2
2
  import { getCollection } from 'astro:content';
3
3
  import type { CollectionEntry } from 'astro:content';
4
4
  import path from 'path';
5
+ import { satisfies, validRange } from 'semver';
5
6
 
6
7
  const PROJECT_DIR = process.env.PROJECT_DIR || process.cwd();
7
8
 
8
9
  export type Service = CollectionEntry<'services'>;
9
10
 
10
- export const getVersion = (collection: CollectionEntry<'events' | 'commands'>[], id: string, version?: string) => {
11
+ export const getVersion = (
12
+ collection: CollectionEntry<'events' | 'commands'>[],
13
+ id: string,
14
+ version?: string
15
+ ): CollectionEntry<'events' | 'commands'>[] => {
11
16
  const data = collection;
12
- if (version) {
13
- return data.find((event) => event.data.version === version && event.data.id === id);
17
+ const semverRange = validRange(version);
18
+
19
+ if (semverRange) {
20
+ return data.filter((msg) => msg.data.id == id).filter((msg) => satisfies(msg.data.version, semverRange));
14
21
  }
15
22
 
16
23
  const filteredEvents = data.filter((event) => event.data.id === id);
@@ -21,7 +28,7 @@ export const getVersion = (collection: CollectionEntry<'events' | 'commands'>[],
21
28
  });
22
29
 
23
30
  // latest version
24
- return sorted[sorted.length - 1];
31
+ return [sorted[sorted.length - 1]];
25
32
  };
26
33
 
27
34
  interface Props {
@@ -42,24 +49,17 @@ export const getServices = async ({ getAllVersions = true }: Props = {}): Promis
42
49
  return services.map((service) => {
43
50
  const { latestVersion, versions } = getVersionForCollectionItem(service, services);
44
51
 
45
- // const receives = service.data.receives || [];
46
52
  const sendsMessages = service.data.sends || [];
47
53
  const receivesMessages = service.data.receives || [];
48
54
 
49
55
  const sends = sendsMessages
50
- .map((message) => {
51
- const event = getVersion(allMessages, message.id, message.version);
52
- // const event = allMessages.find((_message) => _message.data.id === message.id && _message.data.version === message.version);
53
- return event;
54
- })
56
+ .map((message) => getVersion(allMessages, message.id, message.version))
57
+ .flat()
55
58
  .filter((e) => e !== undefined);
56
59
 
57
60
  const receives = receivesMessages
58
- .map((message) => {
59
- const event = getVersion(allMessages, message.id, message.version);
60
- // const event = allMessages.find((_message) => _message.data.id === message.id && _message.data.version === message.version);
61
- return event;
62
- })
61
+ .map((message) => getVersion(allMessages, message.id, message.version))
62
+ .flat()
63
63
  .filter((e) => e !== undefined);
64
64
 
65
65
  return {