@eventcatalog/core 4.10.15 → 4.11.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/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-HBVTU6ZP.js → chunk-DWC5GRFX.js} +1 -1
- package/dist/{chunk-A4JRWRCV.js → chunk-H3324DNT.js} +1 -1
- package/dist/{chunk-I6HUOX4R.js → chunk-SW7SJZIX.js} +1 -1
- package/dist/{chunk-7LWOCX4R.js → chunk-W4LDIMUI.js} +1 -1
- package/dist/{chunk-Q2ATWE7N.js → chunk-XJOKK5ZO.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +5 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/astro.config.mjs +2 -1
- package/eventcatalog/public/icons/languages/android.svg +1 -0
- package/eventcatalog/public/icons/languages/angular.svg +1 -0
- package/eventcatalog/public/icons/languages/apple.svg +1 -0
- package/eventcatalog/public/icons/languages/arduino.svg +1 -0
- package/eventcatalog/public/icons/languages/bash.svg +1 -0
- package/eventcatalog/public/icons/languages/bun.svg +1 -0
- package/eventcatalog/public/icons/languages/c.svg +1 -0
- package/eventcatalog/public/icons/languages/clojure.svg +1 -0
- package/eventcatalog/public/icons/languages/cpp.svg +1 -0
- package/eventcatalog/public/icons/languages/crystal.svg +1 -0
- package/eventcatalog/public/icons/languages/csharp.svg +1 -0
- package/eventcatalog/public/icons/languages/css.svg +1 -0
- package/eventcatalog/public/icons/languages/curl.svg +1 -0
- package/eventcatalog/public/icons/languages/dart.svg +1 -0
- package/eventcatalog/public/icons/languages/deno.svg +1 -0
- package/eventcatalog/public/icons/languages/docker.svg +1 -0
- package/eventcatalog/public/icons/languages/elm.svg +1 -0
- package/eventcatalog/public/icons/languages/erlang.svg +1 -0
- package/eventcatalog/public/icons/languages/flutter.svg +1 -0
- package/eventcatalog/public/icons/languages/fortran.svg +1 -0
- package/eventcatalog/public/icons/languages/fsharp.svg +1 -0
- package/eventcatalog/public/icons/languages/git.svg +1 -0
- package/eventcatalog/public/icons/languages/gradle.svg +1 -0
- package/eventcatalog/public/icons/languages/graphql.svg +1 -0
- package/eventcatalog/public/icons/languages/grpc.svg +1 -0
- package/eventcatalog/public/icons/languages/haskell.svg +1 -0
- package/eventcatalog/public/icons/languages/hasura.svg +1 -0
- package/eventcatalog/public/icons/languages/html.svg +1 -0
- package/eventcatalog/public/icons/languages/httpie.svg +1 -0
- package/eventcatalog/public/icons/languages/javascript.svg +1 -0
- package/eventcatalog/public/icons/languages/json-schema.svg +1 -0
- package/eventcatalog/public/icons/languages/json.svg +1 -0
- package/eventcatalog/public/icons/languages/julia.svg +1 -0
- package/eventcatalog/public/icons/languages/jupyter.svg +1 -0
- package/eventcatalog/public/icons/languages/kafka.svg +1 -0
- package/eventcatalog/public/icons/languages/kotlin.svg +1 -0
- package/eventcatalog/public/icons/languages/lua.svg +1 -0
- package/eventcatalog/public/icons/languages/markdown.svg +1 -0
- package/eventcatalog/public/icons/languages/maven.svg +1 -0
- package/eventcatalog/public/icons/languages/mongodb.svg +1 -0
- package/eventcatalog/public/icons/languages/mysql.svg +1 -0
- package/eventcatalog/public/icons/languages/nginx.svg +1 -0
- package/eventcatalog/public/icons/languages/nim.svg +1 -0
- package/eventcatalog/public/icons/languages/ocaml.svg +1 -0
- package/eventcatalog/public/icons/languages/perl.svg +1 -0
- package/eventcatalog/public/icons/languages/php.svg +1 -0
- package/eventcatalog/public/icons/languages/postgresql.svg +1 -0
- package/eventcatalog/public/icons/languages/prisma.svg +1 -0
- package/eventcatalog/public/icons/languages/purescript.svg +1 -0
- package/eventcatalog/public/icons/languages/python.svg +1 -0
- package/eventcatalog/public/icons/languages/r.svg +1 -0
- package/eventcatalog/public/icons/languages/react.svg +1 -0
- package/eventcatalog/public/icons/languages/reasonml.svg +1 -0
- package/eventcatalog/public/icons/languages/redis.svg +1 -0
- package/eventcatalog/public/icons/languages/ruby.svg +1 -0
- package/eventcatalog/public/icons/languages/rust.svg +1 -0
- package/eventcatalog/public/icons/languages/sass.svg +1 -0
- package/eventcatalog/public/icons/languages/scala.svg +1 -0
- package/eventcatalog/public/icons/languages/solidity.svg +1 -0
- package/eventcatalog/public/icons/languages/spring.svg +1 -0
- package/eventcatalog/public/icons/languages/sqlite.svg +1 -0
- package/eventcatalog/public/icons/languages/svelte.svg +1 -0
- package/eventcatalog/public/icons/languages/swagger.svg +1 -0
- package/eventcatalog/public/icons/languages/swift.svg +1 -0
- package/eventcatalog/public/icons/languages/tailwind.svg +1 -0
- package/eventcatalog/public/icons/languages/terraform.svg +1 -0
- package/eventcatalog/public/icons/languages/toml.svg +1 -0
- package/eventcatalog/public/icons/languages/typescript.svg +1 -0
- package/eventcatalog/public/icons/languages/unity.svg +1 -0
- package/eventcatalog/public/icons/languages/vim.svg +1 -0
- package/eventcatalog/public/icons/languages/vue.svg +1 -0
- package/eventcatalog/public/icons/languages/webassembly.svg +1 -0
- package/eventcatalog/public/icons/languages/yaml.svg +1 -0
- package/eventcatalog/public/icons/languages/zig.svg +1 -0
- package/eventcatalog/src/components/MDX/CodeGroup/CodeGroup.astro +12 -0
- package/eventcatalog/src/components/MDX/CodeGroup/CodeGroup.tsx +176 -0
- package/eventcatalog/src/components/MDX/CodeGroup/MarkdownCodeGroup.tsx +22 -0
- package/eventcatalog/src/components/MDX/CodeGroup/code-group-icons.ts +345 -0
- package/eventcatalog/src/components/MDX/CodeGroup/code-group.css +22 -0
- package/eventcatalog/src/components/MDX/CodeGroup/code-group.spec.tsx +89 -0
- package/eventcatalog/src/components/MDX/CodeGroup/parse-panels.ts +11 -0
- package/eventcatalog/src/components/MDX/Columns/Column.astro +10 -0
- package/eventcatalog/src/components/MDX/Columns/Columns.astro +14 -0
- package/eventcatalog/src/components/MDX/Columns/MarkdownColumns.tsx +37 -0
- package/eventcatalog/src/components/MDX/Columns/columns.spec.tsx +66 -0
- package/eventcatalog/src/components/MDX/Columns/layout.ts +16 -0
- package/eventcatalog/src/components/MDX/components.tsx +6 -0
- package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +1 -1
- package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +151 -114
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +510 -248
- package/eventcatalog/src/components/SchemaExplorer/SchemaFlows.tsx +76 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaGraph.tsx +47 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +11 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaUsage.tsx +17 -0
- package/eventcatalog/src/components/SchemaExplorer/types.ts +48 -3
- package/eventcatalog/src/components/SchemaExplorer/utils.ts +28 -1
- package/eventcatalog/src/content.config.ts +28 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/[...filename].astro +38 -7
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +144 -37
- package/eventcatalog/src/pages/schemas/explorer/index.astro +5 -0
- package/eventcatalog/src/remark-plugins/code-group.ts +39 -0
- package/eventcatalog/src/remark-plugins/markdown-code-group.ts +59 -0
- package/eventcatalog/src/remark-plugins/markdown-columns.ts +66 -0
- package/eventcatalog/src/utils/collections/examples.ts +133 -41
- package/eventcatalog/src/utils/collections/flows.ts +43 -0
- package/eventcatalog/src/utils/collections/messages.ts +2 -2
- package/eventcatalog/src/utils/collections/schemas.ts +15 -0
- package/eventcatalog/src/utils/schema-explorer.ts +73 -7
- package/eventcatalog/src/utils/schema-usage-graph.ts +92 -0
- package/package.json +4 -4
|
@@ -146,3 +146,46 @@ export const getFlowsNotInAnyResource = async (): Promise<Flow[]> => {
|
|
|
146
146
|
});
|
|
147
147
|
return flowsNotInAnyResource;
|
|
148
148
|
};
|
|
149
|
+
|
|
150
|
+
/** A flow that includes a message in one of its steps, reduced to what the schema pages display. */
|
|
151
|
+
export interface FlowReference {
|
|
152
|
+
id: string;
|
|
153
|
+
version: string;
|
|
154
|
+
name?: string;
|
|
155
|
+
summary?: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Finds the flows whose steps send or receive each of the given messages. Step pointers are
|
|
160
|
+
* matched the same way flow diagrams resolve them (exact version, then semver range, then
|
|
161
|
+
* latest). Returns a map keyed by `${collection}:${id}:${version}` of the resolved message.
|
|
162
|
+
*/
|
|
163
|
+
export const getFlowsForMessages = async (
|
|
164
|
+
messages: { collection: string; data: { id: string; version: string } }[]
|
|
165
|
+
): Promise<Map<string, FlowReference[]>> => {
|
|
166
|
+
const flows = await getCollection('flows');
|
|
167
|
+
const messageMap = createVersionedMap(messages);
|
|
168
|
+
const flowsByMessage = new Map<string, FlowReference[]>();
|
|
169
|
+
|
|
170
|
+
for (const flow of flows) {
|
|
171
|
+
if (flow.data.hidden === true) continue;
|
|
172
|
+
const reference: FlowReference = {
|
|
173
|
+
id: flow.data.id,
|
|
174
|
+
version: flow.data.version,
|
|
175
|
+
...(flow.data.name ? { name: flow.data.name } : {}),
|
|
176
|
+
...(flow.data.summary ? { summary: flow.data.summary } : {}),
|
|
177
|
+
};
|
|
178
|
+
const seen = new Set<string>();
|
|
179
|
+
for (const step of flow.data.steps ?? []) {
|
|
180
|
+
if (!step.message) continue;
|
|
181
|
+
const message = findInMap(messageMap, step.message.id, step.message.version);
|
|
182
|
+
if (!message) continue;
|
|
183
|
+
const key = `${message.collection}:${message.data.id}:${message.data.version}`;
|
|
184
|
+
if (seen.has(key)) continue;
|
|
185
|
+
seen.add(key);
|
|
186
|
+
flowsByMessage.set(key, [...(flowsByMessage.get(key) ?? []), reference]);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return flowsByMessage;
|
|
191
|
+
};
|
|
@@ -49,7 +49,7 @@ export const hydrateProducersAndConsumers = ({
|
|
|
49
49
|
const toResult = <T extends CollectionEntry<'agents'> | CollectionEntry<'services'> | CollectionEntry<'data-products'>>(
|
|
50
50
|
resource: T
|
|
51
51
|
) => {
|
|
52
|
-
if (!hydrate) return { id: resource.data.id, version: resource.data.version };
|
|
52
|
+
if (!hydrate) return { id: resource.data.id, version: resource.data.version, collection: resource.collection };
|
|
53
53
|
return resource;
|
|
54
54
|
};
|
|
55
55
|
|
|
@@ -193,7 +193,7 @@ export const lookupProducersAndConsumers = ({ message, index, hydrate = true }:
|
|
|
193
193
|
const toResult = <T extends CollectionEntry<'agents'> | CollectionEntry<'services'> | CollectionEntry<'data-products'>>(
|
|
194
194
|
resource: T
|
|
195
195
|
) => {
|
|
196
|
-
if (!hydrate) return { id: resource.data.id, version: resource.data.version };
|
|
196
|
+
if (!hydrate) return { id: resource.data.id, version: resource.data.version, collection: resource.collection };
|
|
197
197
|
return resource;
|
|
198
198
|
};
|
|
199
199
|
|
|
@@ -39,6 +39,21 @@ export const getSchemaURL = (resource: CollectionEntry<PageTypes> | any) => {
|
|
|
39
39
|
return path.join(publicPath, schemaFilePath ?? '');
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
+
/** File extension EventCatalog uses for a schema format, for schemas that have no file name. */
|
|
43
|
+
export const getSchemaExtensionForFormat = (format?: string) => {
|
|
44
|
+
switch (format?.toLowerCase()) {
|
|
45
|
+
case 'jsonschema':
|
|
46
|
+
case 'json':
|
|
47
|
+
return 'json';
|
|
48
|
+
case 'avro':
|
|
49
|
+
return 'avsc';
|
|
50
|
+
case 'protobuf':
|
|
51
|
+
return 'proto';
|
|
52
|
+
default:
|
|
53
|
+
return format ?? '';
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
42
57
|
export const getSchemaFormatFromURL = (url: string) => {
|
|
43
58
|
const pathParts = url.split('.');
|
|
44
59
|
const format = pathParts[pathParts.length - 1];
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import type { SchemaItem, SchemaDetails, Producer, Consumer } from '@components/SchemaExplorer/types';
|
|
2
|
+
import type { SchemaItem, SchemaDetails, Producer, Consumer, MessageChannel } from '@components/SchemaExplorer/types';
|
|
3
3
|
import { getEvents } from '@utils/collections/events';
|
|
4
4
|
import { getCommands } from '@utils/collections/commands';
|
|
5
5
|
import { getQueries } from '@utils/collections/queries';
|
|
6
6
|
import { getServices, getSpecificationsForService } from '@utils/collections/services';
|
|
7
7
|
import { getDomains, getSpecificationsForDomain } from '@utils/collections/domains';
|
|
8
8
|
import { getDataProducts } from '@utils/collections/data-products';
|
|
9
|
+
import { getAgents } from '@utils/collections/agents';
|
|
10
|
+
import { getFlowsForMessages } from '@utils/collections/flows';
|
|
9
11
|
import { getOwner } from '@utils/collections/owners';
|
|
10
12
|
import { buildUrl } from '@utils/url-builder';
|
|
13
|
+
import { getSchemaExtensionForFormat } from '@utils/collections/schemas';
|
|
11
14
|
import { resourceFileExists, readResourceFile } from '@utils/resource-files';
|
|
12
15
|
import { getExamplesForResource } from '@utils/collections/examples';
|
|
16
|
+
import { attachFlowGraphs, getMessageUsageGraph } from '@utils/schema-usage-graph';
|
|
13
17
|
import { getCollection } from 'astro:content';
|
|
14
18
|
import path from 'path';
|
|
15
19
|
|
|
@@ -37,12 +41,51 @@ async function buildRegistry() {
|
|
|
37
41
|
|
|
38
42
|
// Fetch all services
|
|
39
43
|
const services = await getServices({ getAllVersions: true });
|
|
44
|
+
// Producers and consumers can be services, agents, or data products. Index all three so
|
|
45
|
+
// compact { id, version } references can be resolved to a resource for display.
|
|
46
|
+
const [agents, dataProductsForRelationships] = await Promise.all([
|
|
47
|
+
getAgents({ getAllVersions: true }),
|
|
48
|
+
getDataProducts({ getAllVersions: true }),
|
|
49
|
+
]);
|
|
50
|
+
type RelationshipResource = (typeof services)[number] | (typeof agents)[number] | (typeof dataProductsForRelationships)[number];
|
|
51
|
+
const relationshipResources: RelationshipResource[] = [...services, ...agents, ...dataProductsForRelationships];
|
|
52
|
+
const resourcesByReference = new Map<string, RelationshipResource>();
|
|
53
|
+
const latestResourceByCollectionAndId = new Map<string, RelationshipResource>();
|
|
54
|
+
for (const resource of relationshipResources) {
|
|
55
|
+
const collectionAndId = `${resource.collection}:${resource.data.id}`;
|
|
56
|
+
resourcesByReference.set(`${collectionAndId}:${resource.data.version}`, resource);
|
|
57
|
+
if (!latestResourceByCollectionAndId.has(collectionAndId)) latestResourceByCollectionAndId.set(collectionAndId, resource);
|
|
58
|
+
}
|
|
59
|
+
const toSchemaRelationships = (references: unknown): Producer[] =>
|
|
60
|
+
((references as { id: string; version: string; collection?: Producer['collection'] }[] | undefined) ?? []).map(
|
|
61
|
+
(reference) => {
|
|
62
|
+
const collection = reference.collection ?? 'services';
|
|
63
|
+
const collectionAndId = `${collection}:${reference.id}`;
|
|
64
|
+
const resource =
|
|
65
|
+
resourcesByReference.get(`${collectionAndId}:${reference.version}`) ??
|
|
66
|
+
latestResourceByCollectionAndId.get(collectionAndId);
|
|
67
|
+
return {
|
|
68
|
+
id: reference.id,
|
|
69
|
+
version: reference.version,
|
|
70
|
+
collection,
|
|
71
|
+
...(resource?.data.name ? { name: resource.data.name } : {}),
|
|
72
|
+
...(resource?.data.summary ? { summary: resource.data.summary } : {}),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
const toMessageChannels = (channels: unknown): MessageChannel[] =>
|
|
77
|
+
((channels as { data: { id: string; version: string; name?: string } }[] | undefined) ?? []).map((channel) => ({
|
|
78
|
+
id: channel.data.id,
|
|
79
|
+
version: channel.data.version,
|
|
80
|
+
...(channel.data.name ? { name: channel.data.name } : {}),
|
|
81
|
+
}));
|
|
40
82
|
|
|
41
83
|
// Combine all messages
|
|
42
84
|
const allMessages = [...events, ...commands, ...queries];
|
|
43
85
|
const messagesBySchemaReference = new Map(
|
|
44
86
|
allMessages.map((message) => [`${message.collection}:${message.data.id}:${message.data.version}`, message])
|
|
45
87
|
);
|
|
88
|
+
const flowsByMessage = await getFlowsForMessages(allMessages);
|
|
46
89
|
|
|
47
90
|
// Read message schemas from the generated schemas collection.
|
|
48
91
|
const messagesWithSchemas = await Promise.all(
|
|
@@ -51,11 +94,16 @@ async function buildRegistry() {
|
|
|
51
94
|
`${schema.data.message.collectionName}:${schema.data.message.id}:${schema.data.message.version}`
|
|
52
95
|
);
|
|
53
96
|
const schemaPath = schema.data.file || schema.data.source.path || '';
|
|
54
|
-
const schemaExtension = path.extname(schemaPath).slice(1) || schema.data.format;
|
|
97
|
+
const schemaExtension = path.extname(schemaPath).slice(1) || getSchemaExtensionForFormat(schema.data.format);
|
|
55
98
|
// The collection types describe raw content references. With
|
|
56
|
-
// hydrateServices: false, the loaders return compact { id, version } pairs
|
|
57
|
-
|
|
58
|
-
const
|
|
99
|
+
// hydrateServices: false, the loaders return compact { id, version } pairs,
|
|
100
|
+
// so look the service name and summary up for display.
|
|
101
|
+
const producers = toSchemaRelationships(message?.data.producers);
|
|
102
|
+
const consumers = toSchemaRelationships(message?.data.consumers);
|
|
103
|
+
const channels = toMessageChannels(message?.data.messageChannels);
|
|
104
|
+
const flows =
|
|
105
|
+
flowsByMessage.get(`${schema.data.message.collectionName}:${schema.data.message.id}:${schema.data.message.version}`) ??
|
|
106
|
+
[];
|
|
59
107
|
|
|
60
108
|
return {
|
|
61
109
|
collection: schema.data.message.collectionName,
|
|
@@ -70,22 +118,40 @@ async function buildRegistry() {
|
|
|
70
118
|
// regardless of how many resources reference the message.
|
|
71
119
|
producerName: producers[0]?.id,
|
|
72
120
|
},
|
|
73
|
-
loadDetails: () => {
|
|
121
|
+
loadDetails: async () => {
|
|
74
122
|
let examples: SchemaDetails['examples'] = [];
|
|
123
|
+
let graph: SchemaDetails['graph'];
|
|
75
124
|
if (message) {
|
|
76
125
|
try {
|
|
77
126
|
examples = getExamplesForResource(message);
|
|
78
127
|
} catch (error) {
|
|
79
128
|
console.error(`Error reading examples for ${message.data.id}:`, error);
|
|
80
129
|
}
|
|
130
|
+
try {
|
|
131
|
+
graph = await getMessageUsageGraph({
|
|
132
|
+
collection: message.collection,
|
|
133
|
+
id: message.data.id,
|
|
134
|
+
version: message.data.version,
|
|
135
|
+
});
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error(`Error building usage graph for ${message.data.id}:`, error);
|
|
138
|
+
}
|
|
81
139
|
}
|
|
82
140
|
return {
|
|
83
141
|
schemaContent: schema.data.content || '',
|
|
84
142
|
examples,
|
|
85
|
-
|
|
143
|
+
...(graph ? { graph } : {}),
|
|
144
|
+
data: {
|
|
145
|
+
producers,
|
|
146
|
+
consumers,
|
|
147
|
+
flows: await attachFlowGraphs(flows, { id: schema.data.message.id, version: schema.data.message.version }),
|
|
148
|
+
channels,
|
|
149
|
+
},
|
|
86
150
|
};
|
|
87
151
|
},
|
|
88
152
|
schemaExtension,
|
|
153
|
+
...(schema.data.name ? { schemaName: schema.data.name } : {}),
|
|
154
|
+
...(schema.data.ref ? { schemaRef: schema.data.ref, source: schema.data.source } : {}),
|
|
89
155
|
};
|
|
90
156
|
})
|
|
91
157
|
);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Edge, Node } from '@xyflow/react';
|
|
2
|
+
import config from '@config';
|
|
3
|
+
import {
|
|
4
|
+
getNodesAndEdgesForCommands,
|
|
5
|
+
getNodesAndEdgesForEvents,
|
|
6
|
+
getNodesAndEdgesForQueries,
|
|
7
|
+
} from '@utils/node-graphs/message-node-graph';
|
|
8
|
+
import { getNodesAndEdges as getNodesAndEdgesForFlow } from '@utils/node-graphs/flows-node-graph';
|
|
9
|
+
import { compactVisualiserGraph } from '@utils/node-graphs/compact-visualiser-graph';
|
|
10
|
+
|
|
11
|
+
export interface MessageUsageGraph {
|
|
12
|
+
nodes: Node[];
|
|
13
|
+
edges: Edge[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const graphBuilders = {
|
|
17
|
+
events: getNodesAndEdgesForEvents,
|
|
18
|
+
commands: getNodesAndEdgesForCommands,
|
|
19
|
+
queries: getNodesAndEdgesForQueries,
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The same producer → message → consumer graph the message docs page renders, reduced to the
|
|
24
|
+
* fields the visualiser needs so it can be sent to the schema pages.
|
|
25
|
+
*/
|
|
26
|
+
export const getMessageUsageGraph = async ({
|
|
27
|
+
collection,
|
|
28
|
+
id,
|
|
29
|
+
version,
|
|
30
|
+
}: {
|
|
31
|
+
collection: string;
|
|
32
|
+
id: string;
|
|
33
|
+
version: string;
|
|
34
|
+
}): Promise<MessageUsageGraph | undefined> => {
|
|
35
|
+
const build = graphBuilders[collection as keyof typeof graphBuilders];
|
|
36
|
+
if (!build) return undefined;
|
|
37
|
+
const { nodes, edges } = await build({
|
|
38
|
+
id,
|
|
39
|
+
version,
|
|
40
|
+
mode: 'simple',
|
|
41
|
+
channelRenderMode: config.visualiser?.channels?.renderMode === 'single' ? 'single' : 'flat',
|
|
42
|
+
});
|
|
43
|
+
return compactVisualiserGraph(nodes as Node[], edges as Edge[]);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** Identifies the message a diagram is being viewed from, so its node can be highlighted. */
|
|
47
|
+
export interface FocusedMessage {
|
|
48
|
+
id: string;
|
|
49
|
+
version: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The flow diagram the flow docs page renders, compacted for the schema pages. Steps that
|
|
54
|
+
* send or receive the focused message get the visualiser's "Viewing" indicator.
|
|
55
|
+
*/
|
|
56
|
+
export const getFlowGraph = async ({
|
|
57
|
+
id,
|
|
58
|
+
version,
|
|
59
|
+
focus,
|
|
60
|
+
}: {
|
|
61
|
+
id: string;
|
|
62
|
+
version: string;
|
|
63
|
+
focus?: FocusedMessage;
|
|
64
|
+
}): Promise<MessageUsageGraph> => {
|
|
65
|
+
const { nodes, edges } = await getNodesAndEdgesForFlow({ id, version, mode: 'simple' });
|
|
66
|
+
const focused = (nodes as Node[]).map((node) => {
|
|
67
|
+
const message = node.data?.message as { id?: string; version?: string } | undefined;
|
|
68
|
+
return focus && message?.id === focus.id && message?.version === focus.version
|
|
69
|
+
? { ...node, data: { ...node.data, isFocused: true } }
|
|
70
|
+
: node;
|
|
71
|
+
});
|
|
72
|
+
return compactVisualiserGraph(focused, edges as Edge[]);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Adds each flow's diagram to the flow usages, highlighting the focused message's steps.
|
|
77
|
+
* A flow whose diagram fails to build is kept without one.
|
|
78
|
+
*/
|
|
79
|
+
export const attachFlowGraphs = <T extends { id: string; version: string }>(
|
|
80
|
+
flows: T[],
|
|
81
|
+
focus?: FocusedMessage
|
|
82
|
+
): Promise<(T & { graph?: MessageUsageGraph })[]> =>
|
|
83
|
+
Promise.all(
|
|
84
|
+
flows.map(async (flow) => {
|
|
85
|
+
try {
|
|
86
|
+
return { ...flow, graph: await getFlowGraph({ ...flow, focus }) };
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error(`Error building flow graph for ${flow.id}:`, error);
|
|
89
|
+
return flow;
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
);
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE",
|
|
9
9
|
"type": "module",
|
|
10
|
-
"version": "4.
|
|
10
|
+
"version": "4.11.0",
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
@@ -119,9 +119,9 @@
|
|
|
119
119
|
"update-notifier": "^7.3.1",
|
|
120
120
|
"uuid": "^11.1.1",
|
|
121
121
|
"zod": "^4.3.6",
|
|
122
|
-
"@eventcatalog/linter": "1.1.
|
|
123
|
-
"@eventcatalog/
|
|
124
|
-
"@eventcatalog/
|
|
122
|
+
"@eventcatalog/linter": "1.1.20",
|
|
123
|
+
"@eventcatalog/visualiser": "^4.1.4",
|
|
124
|
+
"@eventcatalog/sdk": "2.29.1"
|
|
125
125
|
},
|
|
126
126
|
"devDependencies": {
|
|
127
127
|
"@astrojs/check": "^0.9.10",
|