@eventcatalog/sdk 2.13.2 → 2.14.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/index.js CHANGED
@@ -35,12 +35,409 @@ __export(src_exports, {
35
35
  module.exports = __toCommonJS(src_exports);
36
36
  var import_node_path20 = require("path");
37
37
 
38
+ // src/dsl/utils.ts
39
+ var import_glob = require("glob");
40
+ function serializeBaseFields(resource, indent = " ") {
41
+ const lines = [];
42
+ if (resource.version) {
43
+ lines.push(`${indent}version ${resource.version}`);
44
+ }
45
+ if (resource.name) {
46
+ lines.push(`${indent}name "${resource.name}"`);
47
+ }
48
+ if (resource.summary) {
49
+ lines.push(`${indent}summary "${resource.summary.trim()}"`);
50
+ }
51
+ if (resource.owners && resource.owners.length > 0) {
52
+ for (const owner of resource.owners) {
53
+ lines.push(`${indent}owner ${owner}`);
54
+ }
55
+ }
56
+ if (resource.deprecated === true) {
57
+ lines.push(`${indent}deprecated true`);
58
+ }
59
+ if (resource.draft === true) {
60
+ lines.push(`${indent}draft true`);
61
+ }
62
+ return lines.join("\n");
63
+ }
64
+ function resolveMessageType(catalogDir, id) {
65
+ if ((0, import_glob.globSync)(`**/events/${id}/index.{md,mdx}`, { cwd: catalogDir }).length > 0) return "event";
66
+ if ((0, import_glob.globSync)(`**/commands/${id}/index.{md,mdx}`, { cwd: catalogDir }).length > 0) return "command";
67
+ if ((0, import_glob.globSync)(`**/queries/${id}/index.{md,mdx}`, { cwd: catalogDir }).length > 0) return "query";
68
+ return void 0;
69
+ }
70
+ function serializeChannelRef(channel) {
71
+ let ref = channel.id;
72
+ if (channel.version) ref += `@${channel.version}`;
73
+ return ref;
74
+ }
75
+ function serializeMessagePointers(items, direction, catalogDir, indent = " ") {
76
+ const lines = [];
77
+ for (const item of items) {
78
+ const msgType = resolveMessageType(catalogDir, item.id);
79
+ if (!msgType) continue;
80
+ let ref = `${item.id}`;
81
+ if (item.version) ref += `@${item.version}`;
82
+ const channels = direction === "sends" ? item.to : item.from;
83
+ const channelKeyword = direction === "sends" ? "to" : "from";
84
+ if (channels && channels.length === 1) {
85
+ lines.push(`${indent}${direction} ${msgType} ${ref} ${channelKeyword} ${serializeChannelRef(channels[0])}`);
86
+ } else if (channels && channels.length > 1) {
87
+ const channelRefs = channels.map(serializeChannelRef).join(", ");
88
+ lines.push(`${indent}${direction} ${msgType} ${ref} ${channelKeyword} ${channelRefs}`);
89
+ } else {
90
+ lines.push(`${indent}${direction} ${msgType} ${ref}`);
91
+ }
92
+ }
93
+ return lines.join("\n");
94
+ }
95
+
96
+ // src/dsl/message.ts
97
+ function messageToDSL(resource, type) {
98
+ const body = serializeBaseFields(resource);
99
+ if (!body) {
100
+ return `${type} ${resource.id}`;
101
+ }
102
+ return `${type} ${resource.id} {
103
+ ${body}
104
+ }`;
105
+ }
106
+
107
+ // src/dsl/service.ts
108
+ async function serviceToDSL(resource, options, getMessageFn) {
109
+ const { catalogDir, hydrate = false, _seen = /* @__PURE__ */ new Set() } = options;
110
+ const parts = [];
111
+ if (hydrate && getMessageFn) {
112
+ const allMessages = [...resource.sends || [], ...resource.receives || []];
113
+ for (const msg of allMessages) {
114
+ const key = `${msg.id}@${msg.version || "latest"}`;
115
+ if (_seen.has(key)) continue;
116
+ _seen.add(key);
117
+ const msgType = resolveMessageType(catalogDir, msg.id);
118
+ if (!msgType) continue;
119
+ const msgResource = await getMessageFn(msg.id, msg.version);
120
+ if (msgResource) {
121
+ parts.push(messageToDSL(msgResource, msgType));
122
+ }
123
+ }
124
+ }
125
+ const lines = [];
126
+ const baseFields = serializeBaseFields(resource);
127
+ if (baseFields) lines.push(baseFields);
128
+ if (resource.sends && resource.sends.length > 0) {
129
+ const sendsStr = serializeMessagePointers(resource.sends, "sends", catalogDir);
130
+ if (sendsStr) lines.push(sendsStr);
131
+ }
132
+ if (resource.receives && resource.receives.length > 0) {
133
+ const recvStr = serializeMessagePointers(resource.receives, "receives", catalogDir);
134
+ if (recvStr) lines.push(recvStr);
135
+ }
136
+ if (resource.writesTo && resource.writesTo.length > 0) {
137
+ for (const container of resource.writesTo) {
138
+ let ref = container.id;
139
+ if (container.version) ref += `@${container.version}`;
140
+ lines.push(` writes-to container ${ref}`);
141
+ }
142
+ }
143
+ if (resource.readsFrom && resource.readsFrom.length > 0) {
144
+ for (const container of resource.readsFrom) {
145
+ let ref = container.id;
146
+ if (container.version) ref += `@${container.version}`;
147
+ lines.push(` reads-from container ${ref}`);
148
+ }
149
+ }
150
+ const body = lines.join("\n");
151
+ parts.push(`service ${resource.id} {
152
+ ${body}
153
+ }`);
154
+ return parts.join("\n\n");
155
+ }
156
+
157
+ // src/dsl/channel.ts
158
+ function channelToDSL(resource) {
159
+ const lines = [];
160
+ if (resource.version) {
161
+ lines.push(` version ${resource.version}`);
162
+ }
163
+ if (resource.name) {
164
+ lines.push(` name "${resource.name}"`);
165
+ }
166
+ if (resource.address) {
167
+ lines.push(` address "${resource.address}"`);
168
+ }
169
+ if (resource.protocols && resource.protocols.length > 0) {
170
+ for (const protocol of resource.protocols) {
171
+ lines.push(` protocol "${protocol}"`);
172
+ }
173
+ }
174
+ if (resource.summary) {
175
+ lines.push(` summary "${resource.summary.trim()}"`);
176
+ }
177
+ if (!lines.length) {
178
+ return `channel ${resource.id}`;
179
+ }
180
+ return `channel ${resource.id} {
181
+ ${lines.join("\n")}
182
+ }`;
183
+ }
184
+
185
+ // src/dsl/owner.ts
186
+ function teamToDSL(team) {
187
+ const lines = [];
188
+ if (team.name) lines.push(` name "${team.name}"`);
189
+ if (team.avatarUrl) lines.push(` avatar "${team.avatarUrl}"`);
190
+ if (team.role) lines.push(` role "${team.role}"`);
191
+ if (team.summary) lines.push(` summary "${team.summary}"`);
192
+ if (team.email) lines.push(` email "${team.email}"`);
193
+ if (team.slackDirectMessageUrl) lines.push(` slack "${team.slackDirectMessageUrl}"`);
194
+ return `team ${team.id} {
195
+ ${lines.join("\n")}
196
+ }`;
197
+ }
198
+ function userToDSL(user) {
199
+ const lines = [];
200
+ if (user.name) lines.push(` name "${user.name}"`);
201
+ if (user.avatarUrl) lines.push(` avatar "${user.avatarUrl}"`);
202
+ if (user.role) lines.push(` role "${user.role}"`);
203
+ if (user.email) lines.push(` email "${user.email}"`);
204
+ if (user.slackDirectMessageUrl) lines.push(` slack "${user.slackDirectMessageUrl}"`);
205
+ return `user ${user.id} {
206
+ ${lines.join("\n")}
207
+ }`;
208
+ }
209
+
210
+ // src/dsl/domain.ts
211
+ async function hydrateOwners(owners, resolvers, seen, parts) {
212
+ if (!owners || !resolvers.getTeam || !resolvers.getUser) return;
213
+ for (const ownerId of owners) {
214
+ const key = `owner:${ownerId}`;
215
+ if (seen.has(key)) continue;
216
+ seen.add(key);
217
+ const team = await resolvers.getTeam(ownerId);
218
+ if (team) {
219
+ parts.push(teamToDSL(team));
220
+ continue;
221
+ }
222
+ const user = await resolvers.getUser(ownerId);
223
+ if (user) {
224
+ parts.push(userToDSL(user));
225
+ }
226
+ }
227
+ }
228
+ async function hydrateChannelsFromMessages(messages, resolvers, seen, parts) {
229
+ if (!resolvers.getChannel) return;
230
+ for (const msg of messages) {
231
+ const channels = msg.to || msg.from;
232
+ if (!channels) continue;
233
+ for (const ch of channels) {
234
+ const key = `channel:${ch.id}@${ch.version || "latest"}`;
235
+ if (seen.has(key)) continue;
236
+ seen.add(key);
237
+ const channel = await resolvers.getChannel(ch.id, ch.version);
238
+ if (channel) {
239
+ parts.push(channelToDSL(channel));
240
+ }
241
+ }
242
+ }
243
+ }
244
+ async function buildDomainBody(resource, options, resolvers, keyword) {
245
+ const { catalogDir, hydrate = false, _seen = /* @__PURE__ */ new Set() } = options;
246
+ const topLevelParts = [];
247
+ if (hydrate && resolvers) {
248
+ if (resource.services && resource.services.length > 0 && resolvers.getService) {
249
+ for (const svcRef of resource.services) {
250
+ const svcKey = `service:${svcRef.id}@${svcRef.version || "latest"}`;
251
+ if (_seen.has(svcKey)) continue;
252
+ _seen.add(svcKey);
253
+ const svc = await resolvers.getService(svcRef.id, svcRef.version);
254
+ if (svc) {
255
+ await hydrateOwners(svc.owners, resolvers, _seen, topLevelParts);
256
+ const svcMessages = [...svc.sends || [], ...svc.receives || []];
257
+ await hydrateChannelsFromMessages(svcMessages, resolvers, _seen, topLevelParts);
258
+ const svcDsl = await serviceToDSL(svc, { catalogDir, hydrate: true, _seen }, resolvers.getMessage);
259
+ topLevelParts.push(svcDsl);
260
+ }
261
+ }
262
+ }
263
+ const domainMessages = [...resource.sends || [], ...resource.receives || []];
264
+ await hydrateChannelsFromMessages(domainMessages, resolvers, _seen, topLevelParts);
265
+ if (resolvers.getMessage) {
266
+ for (const msg of domainMessages) {
267
+ const key = `${msg.id}@${msg.version || "latest"}`;
268
+ if (_seen.has(key)) continue;
269
+ _seen.add(key);
270
+ const msgType = resolveMessageType(catalogDir, msg.id);
271
+ if (!msgType) continue;
272
+ const msgResource = await resolvers.getMessage(msg.id, msg.version);
273
+ if (msgResource) {
274
+ topLevelParts.push(messageToDSL(msgResource, msgType));
275
+ }
276
+ }
277
+ }
278
+ }
279
+ const lines = [];
280
+ const baseFields = serializeBaseFields(resource);
281
+ if (baseFields) lines.push(baseFields);
282
+ if (resource.services && resource.services.length > 0) {
283
+ for (const svc of resource.services) {
284
+ let ref = svc.id;
285
+ if (svc.version) ref += `@${svc.version}`;
286
+ lines.push(` service ${ref}`);
287
+ }
288
+ }
289
+ if (resource.sends && resource.sends.length > 0) {
290
+ const sendsStr = serializeMessagePointers(resource.sends, "sends", catalogDir);
291
+ if (sendsStr) lines.push(sendsStr);
292
+ }
293
+ if (resource.receives && resource.receives.length > 0) {
294
+ const recvStr = serializeMessagePointers(resource.receives, "receives", catalogDir);
295
+ if (recvStr) lines.push(recvStr);
296
+ }
297
+ if (resource.domains && resource.domains.length > 0) {
298
+ if (hydrate && resolvers?.getDomain) {
299
+ for (const subRef of resource.domains) {
300
+ const subKey = `domain:${subRef.id}@${subRef.version || "latest"}`;
301
+ if (_seen.has(subKey)) continue;
302
+ _seen.add(subKey);
303
+ const subDomain = await resolvers.getDomain(subRef.id, subRef.version);
304
+ if (subDomain) {
305
+ await hydrateOwners(subDomain.owners, resolvers, _seen, topLevelParts);
306
+ const sub = await buildDomainBody(subDomain, { catalogDir, hydrate, _seen }, resolvers, "subdomain");
307
+ topLevelParts.push(...sub.topLevelParts);
308
+ const indented = sub.block.split("\n").map((line) => ` ${line}`).join("\n");
309
+ lines.push(indented);
310
+ }
311
+ }
312
+ } else {
313
+ for (const sub of resource.domains) {
314
+ let ref = sub.id;
315
+ if (sub.version) ref += `@${sub.version}`;
316
+ lines.push(` subdomain ${ref}`);
317
+ }
318
+ }
319
+ }
320
+ const body = lines.join("\n");
321
+ const block = `${keyword} ${resource.id} {
322
+ ${body}
323
+ }`;
324
+ return { topLevelParts, block };
325
+ }
326
+ async function domainToDSL(resource, options, resolvers) {
327
+ const { catalogDir, hydrate = false, _seen = /* @__PURE__ */ new Set() } = options;
328
+ const result = await buildDomainBody(resource, { catalogDir, hydrate, _seen }, resolvers, "domain");
329
+ const parts = [...result.topLevelParts, result.block];
330
+ return parts.join("\n\n");
331
+ }
332
+
333
+ // src/dsl/index.ts
334
+ function getMessage(resolvers, catalogDir) {
335
+ return async (id, version) => {
336
+ const msgType = resolveMessageType(catalogDir, id);
337
+ if (!msgType) return void 0;
338
+ switch (msgType) {
339
+ case "event":
340
+ return resolvers.getEvent(id, version);
341
+ case "command":
342
+ return resolvers.getCommand(id, version);
343
+ case "query":
344
+ return resolvers.getQuery(id, version);
345
+ }
346
+ };
347
+ }
348
+ async function hydrateChannels(resource, resolvers, seen, parts) {
349
+ const allMessages = [...resource.sends || [], ...resource.receives || []];
350
+ for (const msg of allMessages) {
351
+ const channels = "to" in msg ? msg.to : "from" in msg ? msg.from : void 0;
352
+ if (!channels) continue;
353
+ for (const ch of channels) {
354
+ const key = `channel:${ch.id}@${ch.version || "latest"}`;
355
+ if (seen.has(key)) continue;
356
+ seen.add(key);
357
+ const channel = await resolvers.getChannel(ch.id, ch.version);
358
+ if (channel) {
359
+ parts.push(channelToDSL(channel));
360
+ }
361
+ }
362
+ }
363
+ }
364
+ async function hydrateOwners2(owners, resolvers, seen, parts) {
365
+ if (!owners) return;
366
+ for (const ownerId of owners) {
367
+ const key = `owner:${ownerId}`;
368
+ if (seen.has(key)) continue;
369
+ seen.add(key);
370
+ const team = await resolvers.getTeam(ownerId);
371
+ if (team) {
372
+ parts.push(teamToDSL(team));
373
+ continue;
374
+ }
375
+ const user = await resolvers.getUser(ownerId);
376
+ if (user) {
377
+ parts.push(userToDSL(user));
378
+ }
379
+ }
380
+ }
381
+ var toDSL = (catalogDir, resolvers) => async (resource, options) => {
382
+ const resources = Array.isArray(resource) ? resource : [resource];
383
+ const seen = /* @__PURE__ */ new Set();
384
+ const parts = [];
385
+ for (const res of resources) {
386
+ const key = `${options.type}:${res.id}@${res.version || "latest"}`;
387
+ if (seen.has(key)) continue;
388
+ seen.add(key);
389
+ switch (options.type) {
390
+ case "event":
391
+ case "command":
392
+ case "query":
393
+ if (options.hydrate) {
394
+ await hydrateOwners2(res.owners, resolvers, seen, parts);
395
+ }
396
+ parts.push(messageToDSL(res, options.type));
397
+ break;
398
+ case "service":
399
+ if (options.hydrate) {
400
+ await hydrateOwners2(res.owners, resolvers, seen, parts);
401
+ await hydrateChannels(res, resolvers, seen, parts);
402
+ }
403
+ parts.push(
404
+ await serviceToDSL(
405
+ res,
406
+ { catalogDir, hydrate: options.hydrate, _seen: seen },
407
+ getMessage(resolvers, catalogDir)
408
+ )
409
+ );
410
+ break;
411
+ case "domain":
412
+ if (options.hydrate) {
413
+ await hydrateOwners2(res.owners, resolvers, seen, parts);
414
+ }
415
+ parts.push(
416
+ await domainToDSL(
417
+ res,
418
+ { catalogDir, hydrate: options.hydrate, _seen: seen },
419
+ {
420
+ getService: resolvers.getService,
421
+ getDomain: resolvers.getDomain,
422
+ getMessage: getMessage(resolvers, catalogDir),
423
+ getChannel: resolvers.getChannel,
424
+ getTeam: resolvers.getTeam,
425
+ getUser: resolvers.getUser
426
+ }
427
+ )
428
+ );
429
+ break;
430
+ }
431
+ }
432
+ return parts.join("\n\n");
433
+ };
434
+
38
435
  // src/events.ts
39
436
  var import_promises2 = __toESM(require("fs/promises"));
40
437
  var import_node_path4 = require("path");
41
438
 
42
439
  // src/internal/utils.ts
43
- var import_glob = require("glob");
440
+ var import_glob2 = require("glob");
44
441
  var import_node_fs = __toESM(require("fs"));
45
442
  var import_fs_extra = require("fs-extra");
46
443
  var import_node_path = require("path");
@@ -91,7 +488,7 @@ var getFiles = async (pattern, ignore = "") => {
91
488
  let relativePattern = (0, import_node_path.relative)(absoluteBaseDir, normalizedInputPattern);
92
489
  relativePattern = relativePattern.replace(/\\/g, "/");
93
490
  const ignoreList = Array.isArray(ignore) ? ignore : [ignore];
94
- const files = (0, import_glob.globSync)(relativePattern, {
491
+ const files = (0, import_glob2.globSync)(relativePattern, {
95
492
  cwd: absoluteBaseDir,
96
493
  ignore: ["node_modules/**", ...ignoreList],
97
494
  absolute: true,
@@ -493,7 +890,18 @@ var getServiceByPath = (directory) => async (path6) => {
493
890
  };
494
891
  var getServices = (directory) => async (options) => getResources(directory, {
495
892
  type: "services",
496
- ignore: ["**/events/**", "**/commands/**", "**/queries/**", "**/entities/**", "**/subdomains/**/entities/**"],
893
+ ignore: [
894
+ "**/events/**",
895
+ "**/commands/**",
896
+ "**/queries/**",
897
+ "**/entities/**",
898
+ "**/channels/**",
899
+ "**/containers/**",
900
+ "**/data-products/**",
901
+ "**/data-stores/**",
902
+ "**/flows/**",
903
+ "**/subdomains/**/entities/**"
904
+ ],
497
905
  ...options
498
906
  });
499
907
  var writeService = (directory) => async (service, options = {
@@ -856,8 +1264,8 @@ var addMessageToChannel = (directory, collection) => async (id, _message, versio
856
1264
  writeMessage: writeQuery
857
1265
  }
858
1266
  };
859
- const { getMessage, rmMessageById, writeMessage } = functions[collection];
860
- const message = await getMessage(directory)(_message.id, _message.version);
1267
+ const { getMessage: getMessage2, rmMessageById, writeMessage } = functions[collection];
1268
+ const message = await getMessage2(directory)(_message.id, _message.version);
861
1269
  const messagePath = await getResourcePath(directory, _message.id, _message.version);
862
1270
  const extension = (0, import_node_path9.extname)(messagePath?.fullPath || "");
863
1271
  if (!message) throw new Error(`Message ${_message.id} with version ${_message.version} not found`);
@@ -2428,7 +2836,35 @@ var src_default = (path6) => {
2428
2836
  * @param version - Optional version of the diagram to add the file to
2429
2837
  * @returns
2430
2838
  */
2431
- addFileToDiagram: addFileToDiagram((0, import_node_path20.join)(path6))
2839
+ addFileToDiagram: addFileToDiagram((0, import_node_path20.join)(path6)),
2840
+ /**
2841
+ * ================================
2842
+ * DSL
2843
+ * ================================
2844
+ */
2845
+ /**
2846
+ * Converts catalog resources to EventCatalog DSL (.ec) format strings.
2847
+ *
2848
+ * @param resource - A resource or array of resources to convert
2849
+ * @param options - Options including type ('event'|'command'|'query'|'service'|'domain') and optional hydrate flag
2850
+ * @returns A DSL string representation
2851
+ *
2852
+ * @example
2853
+ * ```ts
2854
+ * const dsl = await sdk.toDSL(event, { type: 'event' });
2855
+ * const dsl = await sdk.toDSL(services, { type: 'service', hydrate: true });
2856
+ * ```
2857
+ */
2858
+ toDSL: toDSL((0, import_node_path20.join)(path6), {
2859
+ getEvent: getEvent((0, import_node_path20.join)(path6)),
2860
+ getCommand: getCommand((0, import_node_path20.join)(path6)),
2861
+ getQuery: getQuery((0, import_node_path20.join)(path6)),
2862
+ getService: getService((0, import_node_path20.join)(path6)),
2863
+ getDomain: getDomain((0, import_node_path20.join)(path6, "domains")),
2864
+ getChannel: getChannel((0, import_node_path20.join)(path6)),
2865
+ getTeam: getTeam((0, import_node_path20.join)(path6, "teams")),
2866
+ getUser: getUser((0, import_node_path20.join)(path6, "users"))
2867
+ })
2432
2868
  };
2433
2869
  };
2434
2870
  //# sourceMappingURL=index.js.map