@eventcatalog/core 2.21.5 → 2.23.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.
Files changed (30) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-FZHOYLWJ.js → chunk-CLNIEHVG.js} +1 -1
  6. package/dist/{chunk-UYXIOPEC.js → chunk-F55C3RGO.js} +1 -1
  7. package/dist/{chunk-XLSTKMWD.js → chunk-WNRZ5O5C.js} +1 -1
  8. package/dist/constants.cjs +1 -1
  9. package/dist/constants.js +1 -1
  10. package/dist/eventcatalog.cjs +1 -1
  11. package/dist/eventcatalog.config.d.cts +7 -0
  12. package/dist/eventcatalog.config.d.ts +7 -0
  13. package/dist/eventcatalog.js +3 -3
  14. package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/getCatalogResources.ts +65 -0
  15. package/eventcatalog/src/components/{SideBars → SideNav}/CatalogResourcesSideBar/index.tsx +1 -1
  16. package/eventcatalog/src/components/SideNav/SideNav.astro +31 -0
  17. package/eventcatalog/src/components/SideNav/TreeView/getTreeView.ts +189 -0
  18. package/eventcatalog/src/components/SideNav/TreeView/index.tsx +94 -0
  19. package/eventcatalog/src/components/TreeView/index.tsx +328 -0
  20. package/eventcatalog/src/components/TreeView/styles.module.css +264 -0
  21. package/eventcatalog/src/components/TreeView/useSlots.ts +95 -0
  22. package/eventcatalog/src/content/config.ts +2 -0
  23. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +5 -51
  24. package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +55 -0
  25. package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +31 -0
  26. package/eventcatalog/src/pages/docs/llm/llms.txt.ts +47 -0
  27. package/eventcatalog/src/pages/docs/teams/[id].md.ts +40 -0
  28. package/eventcatalog/src/pages/docs/users/[id].md.ts +36 -0
  29. package/package.json +1 -1
  30. /package/eventcatalog/src/components/{SideBars → SideNav}/CatalogResourcesSideBar/styles.css +0 -0
@@ -37,7 +37,7 @@ var import_axios = __toESM(require("axios"), 1);
37
37
  var import_os = __toESM(require("os"), 1);
38
38
 
39
39
  // package.json
40
- var version = "2.21.5";
40
+ var version = "2.23.0";
41
41
 
42
42
  // src/constants.ts
43
43
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-FZHOYLWJ.js";
4
- import "../chunk-XLSTKMWD.js";
3
+ } from "../chunk-CLNIEHVG.js";
4
+ import "../chunk-WNRZ5O5C.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -106,7 +106,7 @@ var import_axios = __toESM(require("axios"), 1);
106
106
  var import_os = __toESM(require("os"), 1);
107
107
 
108
108
  // package.json
109
- var version = "2.21.5";
109
+ var version = "2.23.0";
110
110
 
111
111
  // src/constants.ts
112
112
  var VERSION = version;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-UYXIOPEC.js";
4
- import "../chunk-FZHOYLWJ.js";
5
- import "../chunk-XLSTKMWD.js";
3
+ } from "../chunk-F55C3RGO.js";
4
+ import "../chunk-CLNIEHVG.js";
5
+ import "../chunk-WNRZ5O5C.js";
6
6
  import "../chunk-E7TXTI7G.js";
7
7
  export {
8
8
  log_build_default as default
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-XLSTKMWD.js";
3
+ } from "./chunk-WNRZ5O5C.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-FZHOYLWJ.js";
3
+ } from "./chunk-CLNIEHVG.js";
4
4
  import {
5
5
  getEventCatalogConfigFile,
6
6
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "2.21.5";
2
+ var version = "2.23.0";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "2.21.5";
28
+ var version = "2.23.0";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-XLSTKMWD.js";
3
+ } from "./chunk-WNRZ5O5C.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -161,7 +161,7 @@ var import_axios = __toESM(require("axios"), 1);
161
161
  var import_os = __toESM(require("os"), 1);
162
162
 
163
163
  // package.json
164
- var version = "2.21.5";
164
+ var version = "2.23.0";
165
165
 
166
166
  // src/constants.ts
167
167
  var VERSION = version;
@@ -19,6 +19,9 @@ interface Config {
19
19
  enabled: boolean;
20
20
  limit: number;
21
21
  };
22
+ llmsTxt?: {
23
+ enabled: boolean;
24
+ };
22
25
  logo?: {
23
26
  alt: string;
24
27
  src: string;
@@ -30,6 +33,10 @@ interface Config {
30
33
  mdxOptimize?: boolean;
31
34
  docs: {
32
35
  sidebar: {
36
+ /**
37
+ * @default 'FLAT_VIEW'
38
+ */
39
+ type?: 'FLAT_VIEW' | 'TREE_VIEW';
33
40
  showPageHeadings: true;
34
41
  services?: SideBarConfig;
35
42
  messages?: SideBarConfig;
@@ -19,6 +19,9 @@ interface Config {
19
19
  enabled: boolean;
20
20
  limit: number;
21
21
  };
22
+ llmsTxt?: {
23
+ enabled: boolean;
24
+ };
22
25
  logo?: {
23
26
  alt: string;
24
27
  src: string;
@@ -30,6 +33,10 @@ interface Config {
30
33
  mdxOptimize?: boolean;
31
34
  docs: {
32
35
  sidebar: {
36
+ /**
37
+ * @default 'FLAT_VIEW'
38
+ */
39
+ type?: 'FLAT_VIEW' | 'TREE_VIEW';
33
40
  showPageHeadings: true;
34
41
  services?: SideBarConfig;
35
42
  messages?: SideBarConfig;
@@ -6,14 +6,14 @@ import {
6
6
  } from "./chunk-OW2FQPYP.js";
7
7
  import {
8
8
  log_build_default
9
- } from "./chunk-UYXIOPEC.js";
10
- import "./chunk-FZHOYLWJ.js";
9
+ } from "./chunk-F55C3RGO.js";
10
+ import "./chunk-CLNIEHVG.js";
11
11
  import {
12
12
  catalogToAstro
13
13
  } from "./chunk-CXKIF3EI.js";
14
14
  import {
15
15
  VERSION
16
- } from "./chunk-XLSTKMWD.js";
16
+ } from "./chunk-WNRZ5O5C.js";
17
17
  import {
18
18
  isBackstagePluginEnabled
19
19
  } from "./chunk-XMDPVKIJ.js";
@@ -0,0 +1,65 @@
1
+ import { isCollectionVisibleInCatalog } from '@eventcatalog';
2
+ import { buildUrl } from '@utils/url-builder';
3
+ import { getChannels } from '@utils/channels';
4
+ import { getDomains } from '@utils/collections/domains';
5
+ import { getFlows } from '@utils/collections/flows';
6
+ import { getServices } from '@utils/collections/services';
7
+ import { getCommands } from '@utils/commands';
8
+ import { getEvents } from '@utils/events';
9
+ import { getQueries } from '@utils/queries';
10
+ import { getTeams } from '@utils/teams';
11
+ import { getUsers } from '@utils/users';
12
+
13
+ export async function getCatalogResources({ currentPath }: { currentPath: string }) {
14
+ const events = await getEvents({ getAllVersions: false });
15
+ const commands = await getCommands({ getAllVersions: false });
16
+ const queries = await getQueries({ getAllVersions: false });
17
+ const services = await getServices({ getAllVersions: false });
18
+ const domains = await getDomains({ getAllVersions: false });
19
+ const channels = await getChannels({ getAllVersions: false });
20
+ const flows = await getFlows({ getAllVersions: false });
21
+
22
+ const messages = [...events, ...commands, ...queries];
23
+
24
+ // @ts-ignore for large catalogs https://github.com/event-catalog/eventcatalog/issues/552
25
+ const allData = [...domains, ...services, ...messages, ...channels, ...flows];
26
+
27
+ const allDataAsSideNav = allData.reduce((acc, item) => {
28
+ const title = item.collection;
29
+ const group = acc[title] || [];
30
+ const route = currentPath.includes('visualiser') ? 'visualiser' : 'docs';
31
+
32
+ const navigationItem = {
33
+ label: item.data.name,
34
+ version: item.data.version,
35
+ // items: item.collection === 'users' ? [] : item.headings,
36
+ visible: isCollectionVisibleInCatalog(item.collection),
37
+ // @ts-ignore
38
+ href: item.data.version
39
+ ? // @ts-ignore
40
+ buildUrl(`/${route}/${item.collection}/${item.data.id}/${item.data.version}`)
41
+ : buildUrl(`/${route}/${item.collection}/${item.data.id}`),
42
+ collection: item.collection,
43
+ };
44
+
45
+ group.push(navigationItem);
46
+
47
+ return {
48
+ ...acc,
49
+ [title]: group,
50
+ };
51
+ }, {} as any);
52
+
53
+ const sideNav = {
54
+ ...(currentPath.includes('visualiser')
55
+ ? {
56
+ 'bounded context map': [
57
+ { label: 'Domain map', href: buildUrl('/visualiser/context-map'), collection: 'bounded-context-map' },
58
+ ],
59
+ }
60
+ : {}),
61
+ ...allDataAsSideNav,
62
+ };
63
+
64
+ return sideNav;
65
+ }
@@ -75,7 +75,7 @@ const CatalogResourcesSideBar: React.FC<CatalogResourcesSideBarProps> = ({ resou
75
75
  if (!isInitialized) return null;
76
76
 
77
77
  return (
78
- <nav className="space-y-6 text-black ">
78
+ <nav className="space-y-6 text-black px-5 py-4 ">
79
79
  <div className="space-y-2">
80
80
  <div className="mb-4 px-1">
81
81
  <input
@@ -0,0 +1,31 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+ import config from '@config';
4
+
5
+ // FlatView
6
+ import CatalogResourcesSideBar from './CatalogResourcesSideBar';
7
+ import { getCatalogResources } from './CatalogResourcesSideBar/getCatalogResources';
8
+
9
+ // TreeView
10
+ import { SideNavTreeView } from './TreeView';
11
+ import { getTreeView } from './TreeView/getTreeView';
12
+
13
+ interface Props extends Omit<HTMLAttributes<'div'>, 'children'> {}
14
+
15
+ const currentPath = Astro.url.pathname;
16
+
17
+ let props;
18
+
19
+ const SIDENAV_TYPE = config?.docs?.sidebar?.type ?? 'FLAT_VIEW';
20
+
21
+ if (SIDENAV_TYPE === 'FLAT_VIEW') {
22
+ props = await getCatalogResources({ currentPath });
23
+ } else if (SIDENAV_TYPE === 'TREE_VIEW') {
24
+ props = getTreeView({ projectDir: process.env.PROJECT_DIR!, currentPath });
25
+ }
26
+ ---
27
+
28
+ <div {...Astro.props}>
29
+ {SIDENAV_TYPE === 'FLAT_VIEW' && <CatalogResourcesSideBar resources={props} currentPath={currentPath} client:load />}
30
+ {SIDENAV_TYPE === 'TREE_VIEW' && <SideNavTreeView client:only transition:persist tree={props} />}
31
+ </div>
@@ -0,0 +1,189 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import gm from 'gray-matter';
4
+ import { globSync } from 'glob';
5
+ import type { CollectionKey } from 'astro:content';
6
+ import { buildUrl } from '@utils/url-builder';
7
+
8
+ export type TreeNode = {
9
+ id: string;
10
+ name: string;
11
+ version: string;
12
+ href?: string;
13
+ type: CollectionKey | null;
14
+ children: TreeNode[];
15
+ };
16
+
17
+ /**
18
+ * Resource types that should be in the sidenav
19
+ */
20
+ const RESOURCE_TYPES = ['domains', 'services', 'events', 'commands', 'queries', 'flows', 'channels'];
21
+ // const RESOURCE_TYPES = ['domains', 'services', 'events', 'commands', 'queries', 'flows', 'channels'];
22
+
23
+ /**
24
+ * Check if the path has a RESOURCE_TYPE on path
25
+ */
26
+ function canBeResource(dirPath: string) {
27
+ const parts = dirPath.split(path.sep);
28
+ for (let i = parts.length - 1; i >= 0; i--) {
29
+ if (RESOURCE_TYPES.includes(parts[i])) return true;
30
+ }
31
+ return false;
32
+ }
33
+
34
+ function isNotVersioned(dirPath: string) {
35
+ const parts = dirPath.split(path.sep);
36
+ return parts.every((p) => p !== 'versioned');
37
+ }
38
+
39
+ function getResourceType(filePath: string): CollectionKey | null {
40
+ const parts = filePath.split(path.sep);
41
+ for (let i = parts.length - 1; i >= 0; i--) {
42
+ if (RESOURCE_TYPES.includes(parts[i])) return parts[i] as CollectionKey;
43
+ }
44
+ return null;
45
+ }
46
+
47
+ function buildTreeOfDir(directory: string, parentNode: TreeNode, options: { ignore?: CollectionKey[] }) {
48
+ let node: TreeNode | null = null;
49
+
50
+ const resourceType = getResourceType(directory);
51
+
52
+ const markdownFiles = globSync(path.join(directory, '/*.md'));
53
+ const isResourceIgnored = options?.ignore && resourceType && options.ignore.includes(resourceType);
54
+
55
+ if (markdownFiles.length > 0 && !isResourceIgnored) {
56
+ const resourceFilePath = markdownFiles.find((md) => md.endsWith('index.md'));
57
+ if (resourceFilePath) {
58
+ const resourceDef = gm.read(resourceFilePath);
59
+ node = {
60
+ id: resourceDef.data.id,
61
+ name: resourceDef.data.name,
62
+ type: resourceType,
63
+ version: resourceDef.data.version,
64
+ children: [],
65
+ };
66
+ parentNode.children.push(node);
67
+ }
68
+ }
69
+
70
+ const directories = fs.readdirSync(directory).filter((name) => {
71
+ const dirPath = path.join(directory, name);
72
+ return fs.statSync(dirPath).isDirectory() && isNotVersioned(dirPath) && canBeResource(dirPath);
73
+ });
74
+ for (const dir of directories) {
75
+ buildTreeOfDir(path.join(directory, dir), node || parentNode, options);
76
+ }
77
+ }
78
+
79
+ function forEachTreeNodeOf(node: TreeNode, ...callbacks: Array<(node: TreeNode) => void>) {
80
+ const next = node.children;
81
+
82
+ callbacks.forEach((cb) => cb(node));
83
+
84
+ // Go to next level
85
+ next.forEach((n) => {
86
+ forEachTreeNodeOf(n, ...callbacks);
87
+ });
88
+ }
89
+
90
+ function addHrefToNode(basePathname: 'docs' | 'visualiser') {
91
+ return (node: TreeNode) => {
92
+ node.href = encodeURI(
93
+ buildUrl(
94
+ `/${basePathname}/${node.type}/${node.id}${node.type === 'teams' || node.type === 'users' ? '' : `/${node.version}`}`
95
+ )
96
+ );
97
+ };
98
+ }
99
+
100
+ function orderChildrenByName(parentNode: TreeNode) {
101
+ parentNode.children.sort((a, b) => a.name.localeCompare(b.name));
102
+ }
103
+
104
+ function groupChildrenByType(parentNode: TreeNode) {
105
+ if (parentNode.children.length === 0) return; // Only group if there are children
106
+
107
+ const acc: Record<string, TreeNode[]> = {};
108
+
109
+ // Flows and messages are collapsed by default
110
+
111
+ parentNode.children.forEach((n) => {
112
+ if (n.type === null) return; // TODO: Just ignore or remove the type null???
113
+ if (!(n.type in acc)) acc[n.type] = [];
114
+ acc[n.type].push(n);
115
+ });
116
+
117
+ // Collapse all messages
118
+ const AUTO_EXPANDED_TYPES = ['domains', 'services', 'channels'];
119
+
120
+ parentNode.children = Object.entries(acc)
121
+ // Order label nodes by RESOURCE_TYPES
122
+ .sort(([aType], [bType]) => RESOURCE_TYPES.indexOf(aType) - RESOURCE_TYPES.indexOf(bType))
123
+ // Construct the label nodes
124
+ .map(([type, nodes]) => {
125
+ return {
126
+ id: `${parentNode.id}/${type}`,
127
+ name: type,
128
+ type: type as CollectionKey,
129
+ version: '0',
130
+ children: nodes,
131
+ isExpanded: AUTO_EXPANDED_TYPES.includes(type),
132
+ isLabel: true,
133
+ };
134
+ });
135
+ }
136
+
137
+ const treeViewCache = new Map<string, TreeNode>();
138
+
139
+ export function getTreeView({ projectDir, currentPath }: { projectDir: string; currentPath: string }): TreeNode {
140
+ const basePathname = currentPath.split('/')[1] as 'docs' | 'visualiser';
141
+
142
+ const cacheKey = `${projectDir}:${basePathname}`;
143
+ if (treeViewCache.has(cacheKey)) return treeViewCache.get(cacheKey)!;
144
+
145
+ const rootNode: TreeNode = {
146
+ id: '/',
147
+ name: 'root',
148
+ type: null,
149
+ version: '0',
150
+ children: [],
151
+ };
152
+
153
+ buildTreeOfDir(projectDir, rootNode, {
154
+ ignore: basePathname === 'visualiser' ? ['teams', 'users', 'channels'] : undefined,
155
+ });
156
+
157
+ // prettier-ignore
158
+ forEachTreeNodeOf(
159
+ rootNode,
160
+ addHrefToNode(basePathname),
161
+ orderChildrenByName,
162
+ groupChildrenByType,
163
+ );
164
+
165
+ if (basePathname === 'visualiser') {
166
+ rootNode.children.unshift({
167
+ id: '/bounded-context-map',
168
+ name: 'bounded context map',
169
+ type: 'bounded-context-map' as any,
170
+ version: '0',
171
+ isLabel: true,
172
+ children: [
173
+ {
174
+ id: '/domain-map',
175
+ name: 'Domain map',
176
+ href: buildUrl('/visualiser/context-map'),
177
+ type: 'bounded-context-map' as any,
178
+ version: '',
179
+ children: [],
180
+ },
181
+ ],
182
+ } as TreeNode);
183
+ }
184
+
185
+ // Store in cache before returning
186
+ treeViewCache.set(cacheKey, rootNode);
187
+
188
+ return rootNode;
189
+ }
@@ -0,0 +1,94 @@
1
+ import { gray } from 'tailwindcss/colors';
2
+ import { TreeView } from '@components/TreeView';
3
+ import { navigate } from 'astro:transitions/client';
4
+ import type { TreeNode as RawTreeNode } from './getTreeView';
5
+ import { getIconForCollection } from '@utils/collections/icons';
6
+ import { useEffect, useState } from 'react';
7
+
8
+ type TreeNode = RawTreeNode & { isLabel?: true; isDefaultExpanded?: boolean; isExpanded?: boolean };
9
+
10
+ function isCurrentNode(node: TreeNode, currentPathname: string) {
11
+ return currentPathname === node.href;
12
+ }
13
+
14
+ function TreeNode({ node }: { node: TreeNode }) {
15
+ const Icon = getIconForCollection(node.type ?? '');
16
+ const [isCurrent, setIsCurrent] = useState(document.location.pathname === node.href);
17
+
18
+ useEffect(() => {
19
+ const abortCtrl = new AbortController();
20
+ // prettier-ignore
21
+ document.addEventListener(
22
+ 'astro:page-load',
23
+ () => setIsCurrent(document.location.pathname === node.href),
24
+ { signal: abortCtrl.signal },
25
+ );
26
+ return () => abortCtrl.abort();
27
+ }, [document, node]);
28
+
29
+ return (
30
+ <TreeView.Item
31
+ key={node.id}
32
+ id={node.id}
33
+ current={isCurrent}
34
+ defaultExpanded={node?.isExpanded || node?.isDefaultExpanded}
35
+ onSelect={node?.isLabel || !node?.href ? undefined : () => navigate(node.href!)}
36
+ >
37
+ {!node?.isLabel && (
38
+ <TreeView.LeadingVisual>
39
+ <Icon className="w-3 -ml-1" />
40
+ </TreeView.LeadingVisual>
41
+ )}
42
+ <span
43
+ className={node?.isLabel ? ' capitalize text-[13px] text-purple-900 font-extrabold' : 'font-light text-[14px] -ml-0.5'}
44
+ >
45
+ {node.name} {node.isLabel ? `(${node.children.length})` : ''}
46
+ </span>
47
+ {(node.children || []).length > 0 && (
48
+ <TreeView.SubTree>
49
+ {node.children!.map((childNode) => (
50
+ <TreeNode key={childNode.id} node={childNode} />
51
+ ))}
52
+ </TreeView.SubTree>
53
+ )}
54
+ </TreeView.Item>
55
+ );
56
+ }
57
+
58
+ export function SideNavTreeView({ tree }: { tree: TreeNode }) {
59
+ function bubbleUpExpanded(parentNode: TreeNode) {
60
+ if (isCurrentNode(parentNode, document.location.pathname)) return true;
61
+ return (parentNode.isDefaultExpanded = parentNode.children.some(bubbleUpExpanded));
62
+ }
63
+ bubbleUpExpanded(tree);
64
+
65
+ return (
66
+ <nav id="resources-tree" className="px-2 py-2">
67
+ <TreeView
68
+ truncate={false}
69
+ style={{
70
+ // @ts-expect-error inline css var
71
+ '--base-size-8': '0.5rem',
72
+ '--base-size-12': '0.75rem',
73
+ '--borderColor-muted': '#fff',
74
+ '--borderRadius-medium': '0.375rem',
75
+ '--borderWidth-thick': '0.125rem',
76
+ '--borderWidth-thin': '0.0625rem',
77
+ '--boxShadow-thick': 'inset 0 0 0 var(--borderWidth-thick)',
78
+ '--control-transparent-bgColor-hover': '#656c7626',
79
+ '--control-transparent-bgColor-selected': '#656c761a',
80
+ // '--fgColor-accent': purple[700],
81
+ '--fgColor-default': gray[600],
82
+ '--fgColor-muted': gray[600],
83
+ '--text-body-size-medium': '0.875rem',
84
+ '--stack-gap-condensed': '0.5rem',
85
+ '--treeViewItem-leadingVisual-iconColor-rest': 'var(--fgColor-muted)',
86
+ }}
87
+ >
88
+ {tree.children.map((n) => (
89
+ <TreeNode key={n.id} node={n} />
90
+ ))}
91
+ </TreeView>
92
+ </nav>
93
+ );
94
+ }