@eventcatalog/cli 0.3.1 → 0.3.3
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/cli/index.js +789 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +789 -25
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/logo.png +0 -0
- package/dist/cli-docs.js +53 -2
- package/dist/cli-docs.js.map +1 -1
- package/dist/cli-docs.mjs +53 -2
- package/dist/cli-docs.mjs.map +1 -1
- package/package.json +6 -2
package/dist/cli/index.mjs
CHANGED
|
@@ -9,8 +9,8 @@ var __dirname = /* @__PURE__ */ getDirname();
|
|
|
9
9
|
|
|
10
10
|
// src/cli/index.ts
|
|
11
11
|
import { program } from "commander";
|
|
12
|
-
import { readFileSync } from "fs";
|
|
13
|
-
import { resolve as
|
|
12
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
13
|
+
import { resolve as resolve3 } from "path";
|
|
14
14
|
|
|
15
15
|
// src/cli/executor.ts
|
|
16
16
|
import { existsSync } from "fs";
|
|
@@ -124,6 +124,7 @@ import { resolve } from "path";
|
|
|
124
124
|
import open from "open";
|
|
125
125
|
import createSDK3 from "@eventcatalog/sdk";
|
|
126
126
|
var RESOURCE_TYPES = ["event", "command", "query", "service", "domain"];
|
|
127
|
+
var SUPPORTED_RESOURCE_TYPES = RESOURCE_TYPES.join(", ");
|
|
127
128
|
var PLURAL_MAP = {
|
|
128
129
|
events: "event",
|
|
129
130
|
commands: "command",
|
|
@@ -131,11 +132,40 @@ var PLURAL_MAP = {
|
|
|
131
132
|
services: "service",
|
|
132
133
|
domains: "domain"
|
|
133
134
|
};
|
|
135
|
+
var KNOWN_UNSUPPORTED_EXPORT_TYPES = /* @__PURE__ */ new Set([
|
|
136
|
+
"channel",
|
|
137
|
+
"channels",
|
|
138
|
+
"team",
|
|
139
|
+
"teams",
|
|
140
|
+
"user",
|
|
141
|
+
"users",
|
|
142
|
+
"container",
|
|
143
|
+
"containers",
|
|
144
|
+
"data-product",
|
|
145
|
+
"data-products",
|
|
146
|
+
"dataproduct",
|
|
147
|
+
"dataproducts",
|
|
148
|
+
"diagram",
|
|
149
|
+
"diagrams",
|
|
150
|
+
"flow",
|
|
151
|
+
"flows"
|
|
152
|
+
]);
|
|
134
153
|
function normalizeResourceType(resource) {
|
|
135
154
|
const lower = resource.toLowerCase();
|
|
136
155
|
if (PLURAL_MAP[lower]) return PLURAL_MAP[lower];
|
|
137
156
|
return lower;
|
|
138
157
|
}
|
|
158
|
+
function assertSupportedExportType(resource, type) {
|
|
159
|
+
const lower = resource.toLowerCase();
|
|
160
|
+
if (KNOWN_UNSUPPORTED_EXPORT_TYPES.has(lower)) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Resource type '${resource}' is not yet supported for DSL export. Supported types: ${SUPPORTED_RESOURCE_TYPES}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
if (!RESOURCE_TYPES.includes(type)) {
|
|
166
|
+
throw new Error(`Invalid resource type '${resource}'. Must be one of: ${SUPPORTED_RESOURCE_TYPES}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
139
169
|
function getResourceFetcher(sdk, type) {
|
|
140
170
|
switch (type) {
|
|
141
171
|
case "event":
|
|
@@ -226,14 +256,14 @@ ${entries.join("\n")}
|
|
|
226
256
|
async function exportCatalog(options) {
|
|
227
257
|
const { hydrate = false, stdout = false, playground = false, output, dir } = options;
|
|
228
258
|
const sdk = createSDK3(dir);
|
|
229
|
-
const dslParts =
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
259
|
+
const dslParts = (await Promise.all(
|
|
260
|
+
RESOURCE_TYPES.map(async (type) => {
|
|
261
|
+
const fetcher = getCollectionFetcher(sdk, type);
|
|
262
|
+
const resources = await fetcher({ latestOnly: true });
|
|
263
|
+
if (!resources || resources.length === 0) return "";
|
|
264
|
+
return sdk.toDSL(resources, { type, hydrate });
|
|
265
|
+
})
|
|
266
|
+
)).filter((dsl2) => Boolean(dsl2));
|
|
237
267
|
if (dslParts.length === 0) {
|
|
238
268
|
throw new Error(`No resources found in catalog at '${dir}'`);
|
|
239
269
|
}
|
|
@@ -253,9 +283,9 @@ ${vizBlock}` : grouped;
|
|
|
253
283
|
const encoded = Buffer.from(dsl).toString("base64");
|
|
254
284
|
const playgroundUrl = `https://playground.eventcatalog.dev/?code=${encoded}`;
|
|
255
285
|
await open(playgroundUrl);
|
|
256
|
-
lines.push("", ` Opening in
|
|
286
|
+
lines.push("", ` Opening in EventCatalog Modelling...`);
|
|
257
287
|
} else {
|
|
258
|
-
lines.push("", ` Tip: Use --playground to open in
|
|
288
|
+
lines.push("", ` Tip: Use --playground to open in EventCatalog Modelling`);
|
|
259
289
|
}
|
|
260
290
|
lines.push("");
|
|
261
291
|
return lines.join("\n");
|
|
@@ -263,9 +293,7 @@ ${vizBlock}` : grouped;
|
|
|
263
293
|
async function exportAll(options) {
|
|
264
294
|
const { resource, hydrate = false, stdout = false, playground = false, output, dir } = options;
|
|
265
295
|
const type = normalizeResourceType(resource);
|
|
266
|
-
|
|
267
|
-
throw new Error(`Invalid resource type '${resource}'. Must be one of: ${RESOURCE_TYPES.join(", ")}`);
|
|
268
|
-
}
|
|
296
|
+
assertSupportedExportType(resource, type);
|
|
269
297
|
const plural = pluralize(type);
|
|
270
298
|
const sdk = createSDK3(dir);
|
|
271
299
|
const fetcher = getCollectionFetcher(sdk, type);
|
|
@@ -289,9 +317,9 @@ ${vizBlock}` : grouped;
|
|
|
289
317
|
const encoded = Buffer.from(dsl).toString("base64");
|
|
290
318
|
const playgroundUrl = `https://playground.eventcatalog.dev/?code=${encoded}`;
|
|
291
319
|
await open(playgroundUrl);
|
|
292
|
-
lines.push("", ` Opening in
|
|
320
|
+
lines.push("", ` Opening in EventCatalog Modelling...`);
|
|
293
321
|
} else {
|
|
294
|
-
lines.push("", ` Tip: Use --playground to open in
|
|
322
|
+
lines.push("", ` Tip: Use --playground to open in EventCatalog Modelling`);
|
|
295
323
|
}
|
|
296
324
|
lines.push("");
|
|
297
325
|
return lines.join("\n");
|
|
@@ -302,9 +330,7 @@ async function exportResource(options) {
|
|
|
302
330
|
return exportAll(options);
|
|
303
331
|
}
|
|
304
332
|
const type = normalizeResourceType(resource);
|
|
305
|
-
|
|
306
|
-
throw new Error(`Invalid resource type '${resource}'. Must be one of: ${RESOURCE_TYPES.join(", ")}`);
|
|
307
|
-
}
|
|
333
|
+
assertSupportedExportType(resource, type);
|
|
308
334
|
const sdk = createSDK3(dir);
|
|
309
335
|
const fetcher = getResourceFetcher(sdk, type);
|
|
310
336
|
const data = await fetcher(id, version2);
|
|
@@ -328,19 +354,739 @@ ${vizBlock}` : grouped;
|
|
|
328
354
|
const encoded = Buffer.from(dsl).toString("base64");
|
|
329
355
|
const playgroundUrl = `https://playground.eventcatalog.dev/?code=${encoded}`;
|
|
330
356
|
await open(playgroundUrl);
|
|
331
|
-
lines.push("", ` Opening in
|
|
357
|
+
lines.push("", ` Opening in EventCatalog Modelling...`);
|
|
332
358
|
} else {
|
|
333
|
-
lines.push("", ` Tip: Use --playground to open in
|
|
359
|
+
lines.push("", ` Tip: Use --playground to open in EventCatalog Modelling`);
|
|
334
360
|
}
|
|
335
361
|
lines.push("");
|
|
336
362
|
return lines.join("\n");
|
|
337
363
|
}
|
|
338
364
|
|
|
365
|
+
// src/cli/import.ts
|
|
366
|
+
import { readFileSync, existsSync as existsSync2, mkdirSync, writeFileSync as writeFileSync2, copyFileSync } from "fs";
|
|
367
|
+
import { resolve as resolve2, join } from "path";
|
|
368
|
+
import { randomUUID } from "crypto";
|
|
369
|
+
import { createInterface } from "readline";
|
|
370
|
+
import matter from "gray-matter";
|
|
371
|
+
import createSDK4 from "@eventcatalog/sdk";
|
|
372
|
+
function normalizeImportedFrontmatter(type, frontmatter) {
|
|
373
|
+
const normalized = { ...frontmatter };
|
|
374
|
+
if (type === "container") {
|
|
375
|
+
if (normalized.container_type === void 0 && normalized.containerType !== void 0) {
|
|
376
|
+
normalized.container_type = normalized.containerType;
|
|
377
|
+
delete normalized.containerType;
|
|
378
|
+
}
|
|
379
|
+
if (normalized.access_mode === void 0 && normalized.accessMode !== void 0) {
|
|
380
|
+
normalized.access_mode = normalized.accessMode;
|
|
381
|
+
delete normalized.accessMode;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return normalized;
|
|
385
|
+
}
|
|
386
|
+
var RESOURCE_TYPE_FROM_FOLDER = {
|
|
387
|
+
events: "event",
|
|
388
|
+
commands: "command",
|
|
389
|
+
queries: "query",
|
|
390
|
+
services: "service",
|
|
391
|
+
domains: "domain",
|
|
392
|
+
channels: "channel",
|
|
393
|
+
flows: "flow",
|
|
394
|
+
containers: "container",
|
|
395
|
+
"data-products": "dataProduct",
|
|
396
|
+
diagrams: "diagram",
|
|
397
|
+
users: "user",
|
|
398
|
+
teams: "team"
|
|
399
|
+
};
|
|
400
|
+
async function parseDSL(source, options) {
|
|
401
|
+
const { createEcServices, compile } = await import("@eventcatalog/language-server");
|
|
402
|
+
const { EmptyFileSystem, URI } = await import("langium");
|
|
403
|
+
const services = createEcServices(EmptyFileSystem);
|
|
404
|
+
const uri = URI.parse(`file:///import-${Date.now()}.ec`);
|
|
405
|
+
const document = services.shared.workspace.LangiumDocumentFactory.fromString(source, uri);
|
|
406
|
+
services.shared.workspace.LangiumDocuments.addDocument(document);
|
|
407
|
+
await services.shared.workspace.DocumentBuilder.build([document]);
|
|
408
|
+
const parserErrors = document.parseResult.parserErrors;
|
|
409
|
+
if (parserErrors.length > 0) {
|
|
410
|
+
const messages = parserErrors.map((e) => ` Line ${e.token?.startLine ?? "?"}: ${e.message}`);
|
|
411
|
+
throw new Error(`Parse errors:
|
|
412
|
+
${messages.join("\n")}`);
|
|
413
|
+
}
|
|
414
|
+
const program2 = document.parseResult.value;
|
|
415
|
+
const outputs = compile(program2, { nested: options?.nested });
|
|
416
|
+
try {
|
|
417
|
+
services.shared.workspace.LangiumDocuments.deleteDocument(uri);
|
|
418
|
+
} catch {
|
|
419
|
+
}
|
|
420
|
+
return { outputs, program: program2 };
|
|
421
|
+
}
|
|
422
|
+
function extractResourceTypeFolder(path2) {
|
|
423
|
+
const segments = path2.split("/");
|
|
424
|
+
let lastTypeFolder = segments[0];
|
|
425
|
+
for (const seg of segments) {
|
|
426
|
+
if (RESOURCE_TYPE_FROM_FOLDER[seg]) {
|
|
427
|
+
lastTypeFolder = seg;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return lastTypeFolder;
|
|
431
|
+
}
|
|
432
|
+
function parseCompiledOutput(output) {
|
|
433
|
+
const { data: frontmatter, content: markdown } = matter(output.content);
|
|
434
|
+
const typeFolder = extractResourceTypeFolder(output.path);
|
|
435
|
+
const type = RESOURCE_TYPE_FROM_FOLDER[typeFolder] || typeFolder;
|
|
436
|
+
return {
|
|
437
|
+
type,
|
|
438
|
+
id: frontmatter.id,
|
|
439
|
+
version: frontmatter.version,
|
|
440
|
+
frontmatter,
|
|
441
|
+
markdown: markdown.trim(),
|
|
442
|
+
path: output.path
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
var MESSAGE_TYPE_FOLDER = {
|
|
446
|
+
event: "events",
|
|
447
|
+
command: "commands",
|
|
448
|
+
query: "queries",
|
|
449
|
+
channel: "channels"
|
|
450
|
+
};
|
|
451
|
+
var DEFAULT_STUB_VERSION = "0.0.1";
|
|
452
|
+
var NO_VERSION_KEY = "__no_version__";
|
|
453
|
+
function getResourceNameKey(type, id) {
|
|
454
|
+
return `${type}:${id}`;
|
|
455
|
+
}
|
|
456
|
+
function getResourceVersionKey(type, id, version2) {
|
|
457
|
+
return `${type}:${id}@${version2 || NO_VERSION_KEY}`;
|
|
458
|
+
}
|
|
459
|
+
function hasReferenceStatements(source) {
|
|
460
|
+
return /\b(?:sends|receives|writes-to|reads-from)\b/.test(source);
|
|
461
|
+
}
|
|
462
|
+
async function extractMessageStubs(program2, compiledIds, nested = false) {
|
|
463
|
+
const stubs = [];
|
|
464
|
+
const stubIds = /* @__PURE__ */ new Set();
|
|
465
|
+
function processDefinitions(definitions, parentPath = "") {
|
|
466
|
+
for (const def of definitions) {
|
|
467
|
+
if (def.$type === "VisualizerDef" && def.body) {
|
|
468
|
+
processDefinitions(def.body, parentPath);
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
if (def.$type === "DomainDef") {
|
|
472
|
+
const domainPath = nested ? `domains/${def.name}` : "";
|
|
473
|
+
const domainBody = def.body || [];
|
|
474
|
+
const domainServices = domainBody.filter((d) => d.$type === "ServiceDef");
|
|
475
|
+
processDefinitions(domainServices, domainPath);
|
|
476
|
+
const subdomains = domainBody.filter((d) => d.$type === "SubdomainDef");
|
|
477
|
+
for (const sub of subdomains) {
|
|
478
|
+
const subPath = nested ? `domains/${def.name}/subdomains/${sub.name}` : "";
|
|
479
|
+
const subServices = (sub.body || []).filter((d) => d.$type === "ServiceDef");
|
|
480
|
+
processDefinitions(subServices, subPath);
|
|
481
|
+
}
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if (def.$type !== "ServiceDef") continue;
|
|
485
|
+
const servicePath = nested ? parentPath ? `${parentPath}/services/${def.name}` : `services/${def.name}` : "";
|
|
486
|
+
const body = def.body || [];
|
|
487
|
+
for (const stmt of body) {
|
|
488
|
+
if (stmt.$type === "SendsStmt" || stmt.$type === "ReceivesStmt") {
|
|
489
|
+
const msgType = stmt.messageType;
|
|
490
|
+
const msgName = stmt.messageName;
|
|
491
|
+
const hasBody = stmt.body && stmt.body.length > 0;
|
|
492
|
+
const version2 = stmt.version || DEFAULT_STUB_VERSION;
|
|
493
|
+
if (!hasBody) {
|
|
494
|
+
const folder = MESSAGE_TYPE_FOLDER[msgType];
|
|
495
|
+
if (folder) {
|
|
496
|
+
const key = getResourceVersionKey(msgType, msgName, version2);
|
|
497
|
+
const anyVersionKey = getResourceNameKey(msgType, msgName);
|
|
498
|
+
if (!compiledIds.has(key) && !stubIds.has(key) && !(!stmt.version && compiledIds.has(anyVersionKey))) {
|
|
499
|
+
const stubFolder = nested && servicePath ? `${servicePath}/${folder}` : folder;
|
|
500
|
+
stubIds.add(key);
|
|
501
|
+
stubs.push({
|
|
502
|
+
type: msgType,
|
|
503
|
+
id: msgName,
|
|
504
|
+
version: version2,
|
|
505
|
+
frontmatter: {
|
|
506
|
+
id: msgName,
|
|
507
|
+
name: msgName,
|
|
508
|
+
version: version2
|
|
509
|
+
},
|
|
510
|
+
markdown: "",
|
|
511
|
+
path: `${stubFolder}/${msgName}/versioned/${version2}/index.md`
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (stmt.channelClause) {
|
|
517
|
+
const channels = stmt.channelClause.channels || [];
|
|
518
|
+
for (const ch of channels) {
|
|
519
|
+
const chName = ch.channelName;
|
|
520
|
+
const chVersion = ch.channelVersion || DEFAULT_STUB_VERSION;
|
|
521
|
+
const chKey = getResourceVersionKey("channel", chName, chVersion);
|
|
522
|
+
const chAnyVersionKey = getResourceNameKey("channel", chName);
|
|
523
|
+
if (compiledIds.has(chKey) || stubIds.has(chKey)) continue;
|
|
524
|
+
if (!ch.channelVersion && compiledIds.has(chAnyVersionKey)) continue;
|
|
525
|
+
const chFolder = nested && parentPath ? `${parentPath}/channels` : "channels";
|
|
526
|
+
stubIds.add(chKey);
|
|
527
|
+
stubs.push({
|
|
528
|
+
type: "channel",
|
|
529
|
+
id: chName,
|
|
530
|
+
version: chVersion,
|
|
531
|
+
frontmatter: {
|
|
532
|
+
id: chName,
|
|
533
|
+
name: chName,
|
|
534
|
+
version: chVersion
|
|
535
|
+
},
|
|
536
|
+
markdown: "",
|
|
537
|
+
path: `${chFolder}/${chName}/versioned/${chVersion}/index.md`
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
if (stmt.$type === "WritesToStmt" || stmt.$type === "ReadsFromStmt") {
|
|
544
|
+
const containerName = stmt.ref?.name;
|
|
545
|
+
if (!containerName) continue;
|
|
546
|
+
const containerVersion = stmt.ref?.version || DEFAULT_STUB_VERSION;
|
|
547
|
+
const containerKey = getResourceVersionKey("container", containerName, containerVersion);
|
|
548
|
+
const containerAnyVersionKey = getResourceNameKey("container", containerName);
|
|
549
|
+
if (compiledIds.has(containerKey) || stubIds.has(containerKey)) continue;
|
|
550
|
+
if (!stmt.ref?.version && compiledIds.has(containerAnyVersionKey)) continue;
|
|
551
|
+
const containerFolder = nested && parentPath ? `${parentPath}/containers` : "containers";
|
|
552
|
+
stubIds.add(containerKey);
|
|
553
|
+
stubs.push({
|
|
554
|
+
type: "container",
|
|
555
|
+
id: containerName,
|
|
556
|
+
version: containerVersion,
|
|
557
|
+
frontmatter: {
|
|
558
|
+
id: containerName,
|
|
559
|
+
name: containerName,
|
|
560
|
+
version: containerVersion
|
|
561
|
+
},
|
|
562
|
+
markdown: "",
|
|
563
|
+
path: `${containerFolder}/${containerName}/versioned/${containerVersion}/index.md`
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
processDefinitions(program2.definitions);
|
|
570
|
+
return stubs;
|
|
571
|
+
}
|
|
572
|
+
function getVersionFromBody(body) {
|
|
573
|
+
if (!body) return void 0;
|
|
574
|
+
const versionStmt = body.find((stmt) => stmt?.$type === "VersionStmt");
|
|
575
|
+
return versionStmt?.value;
|
|
576
|
+
}
|
|
577
|
+
function buildServiceOutputPath(serviceName, body, nested, parentPath) {
|
|
578
|
+
const folder = nested && parentPath ? `${parentPath}/services` : "services";
|
|
579
|
+
const version2 = getVersionFromBody(body);
|
|
580
|
+
if (version2) return `${folder}/${serviceName}/versioned/${version2}/index.md`;
|
|
581
|
+
return `${folder}/${serviceName}/index.md`;
|
|
582
|
+
}
|
|
583
|
+
function extractServiceContainerRefs(program2, nested = false) {
|
|
584
|
+
const refsByPath = /* @__PURE__ */ new Map();
|
|
585
|
+
function processDefinitions(definitions, parentPath = "") {
|
|
586
|
+
for (const def of definitions || []) {
|
|
587
|
+
if (def.$type === "VisualizerDef" && def.body) {
|
|
588
|
+
processDefinitions(def.body, parentPath);
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
if (def.$type === "DomainDef") {
|
|
592
|
+
const domainPath = nested ? `domains/${def.name}` : "";
|
|
593
|
+
const domainBody = def.body || [];
|
|
594
|
+
const domainServices = domainBody.filter((d) => d.$type === "ServiceDef");
|
|
595
|
+
processDefinitions(domainServices, domainPath);
|
|
596
|
+
const subdomains = domainBody.filter((d) => d.$type === "SubdomainDef");
|
|
597
|
+
for (const sub of subdomains) {
|
|
598
|
+
const subPath = nested ? `domains/${def.name}/subdomains/${sub.name}` : "";
|
|
599
|
+
const subServices = (sub.body || []).filter((d) => d.$type === "ServiceDef");
|
|
600
|
+
processDefinitions(subServices, subPath);
|
|
601
|
+
}
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
if (def.$type !== "ServiceDef") continue;
|
|
605
|
+
const body = def.body || [];
|
|
606
|
+
const writesTo = body.filter((stmt) => stmt.$type === "WritesToStmt" && stmt.ref?.name).map((stmt) => ({
|
|
607
|
+
id: stmt.ref.name,
|
|
608
|
+
...stmt.ref.version ? { version: stmt.ref.version } : {}
|
|
609
|
+
}));
|
|
610
|
+
const readsFrom = body.filter((stmt) => stmt.$type === "ReadsFromStmt" && stmt.ref?.name).map((stmt) => ({
|
|
611
|
+
id: stmt.ref.name,
|
|
612
|
+
...stmt.ref.version ? { version: stmt.ref.version } : {}
|
|
613
|
+
}));
|
|
614
|
+
if (writesTo.length === 0 && readsFrom.length === 0) continue;
|
|
615
|
+
const path2 = buildServiceOutputPath(def.name, body, nested, parentPath);
|
|
616
|
+
refsByPath.set(path2, {
|
|
617
|
+
...writesTo.length > 0 ? { writesTo } : {},
|
|
618
|
+
...readsFrom.length > 0 ? { readsFrom } : {}
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
processDefinitions(program2.definitions || []);
|
|
623
|
+
return refsByPath;
|
|
624
|
+
}
|
|
625
|
+
var SDK_WRITER_BASE = {
|
|
626
|
+
event: "events",
|
|
627
|
+
command: "commands",
|
|
628
|
+
query: "queries",
|
|
629
|
+
service: "services",
|
|
630
|
+
domain: "domains",
|
|
631
|
+
channel: "channels",
|
|
632
|
+
container: "containers",
|
|
633
|
+
dataProduct: "data-products",
|
|
634
|
+
diagram: "diagrams",
|
|
635
|
+
team: "teams",
|
|
636
|
+
user: "users"
|
|
637
|
+
};
|
|
638
|
+
function extractSdkPath(compiledPath, resourceType) {
|
|
639
|
+
const dirPath = compiledPath.replace(/\/versioned\/[^/]+\/index\.md$/, "").replace(/\/index\.md$/, "").replace(/\.md$/, "");
|
|
640
|
+
const baseFolder = SDK_WRITER_BASE[resourceType];
|
|
641
|
+
if (!baseFolder) return "";
|
|
642
|
+
if (dirPath.startsWith(`${baseFolder}/`)) {
|
|
643
|
+
const relative = dirPath.slice(baseFolder.length + 1);
|
|
644
|
+
if (!relative.includes("/")) return "";
|
|
645
|
+
return relative;
|
|
646
|
+
}
|
|
647
|
+
return `../${dirPath}`;
|
|
648
|
+
}
|
|
649
|
+
var TYPES_WITH_NODE_GRAPH = /* @__PURE__ */ new Set(["event", "command", "query", "service", "domain", "channel", "flow"]);
|
|
650
|
+
function getWriter(sdk, type) {
|
|
651
|
+
switch (type) {
|
|
652
|
+
case "event":
|
|
653
|
+
return sdk.writeEvent;
|
|
654
|
+
case "command":
|
|
655
|
+
return sdk.writeCommand;
|
|
656
|
+
case "query":
|
|
657
|
+
return sdk.writeQuery;
|
|
658
|
+
case "service":
|
|
659
|
+
return sdk.writeService;
|
|
660
|
+
case "domain":
|
|
661
|
+
return sdk.writeDomain;
|
|
662
|
+
case "channel":
|
|
663
|
+
return sdk.writeChannel;
|
|
664
|
+
case "container":
|
|
665
|
+
return sdk.writeDataStore;
|
|
666
|
+
case "dataProduct":
|
|
667
|
+
return sdk.writeDataProduct;
|
|
668
|
+
case "diagram":
|
|
669
|
+
return sdk.writeDiagram;
|
|
670
|
+
case "team":
|
|
671
|
+
return sdk.writeTeam;
|
|
672
|
+
case "user":
|
|
673
|
+
return sdk.writeUser;
|
|
674
|
+
default:
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
function getReader(sdk, type) {
|
|
679
|
+
switch (type) {
|
|
680
|
+
case "event":
|
|
681
|
+
return sdk.getEvent;
|
|
682
|
+
case "command":
|
|
683
|
+
return sdk.getCommand;
|
|
684
|
+
case "query":
|
|
685
|
+
return sdk.getQuery;
|
|
686
|
+
case "service":
|
|
687
|
+
return sdk.getService;
|
|
688
|
+
case "domain":
|
|
689
|
+
return sdk.getDomain;
|
|
690
|
+
case "channel":
|
|
691
|
+
return sdk.getChannel;
|
|
692
|
+
case "container":
|
|
693
|
+
return sdk.getDataStore;
|
|
694
|
+
case "dataProduct":
|
|
695
|
+
return sdk.getDataProduct;
|
|
696
|
+
case "diagram":
|
|
697
|
+
return sdk.getDiagram;
|
|
698
|
+
case "team":
|
|
699
|
+
return sdk.getTeam;
|
|
700
|
+
case "user":
|
|
701
|
+
return sdk.getUser;
|
|
702
|
+
default:
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
function promptConfirm(message) {
|
|
707
|
+
return new Promise((resolve4) => {
|
|
708
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
709
|
+
rl.question(`${message} `, (answer) => {
|
|
710
|
+
rl.close();
|
|
711
|
+
const normalized = answer.trim().toLowerCase();
|
|
712
|
+
resolve4(normalized === "" || normalized === "y" || normalized === "yes");
|
|
713
|
+
});
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
function promptInput(message, defaultValue) {
|
|
717
|
+
return new Promise((resolve4) => {
|
|
718
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
719
|
+
rl.question(`${message} `, (answer) => {
|
|
720
|
+
rl.close();
|
|
721
|
+
resolve4(answer.trim() || defaultValue);
|
|
722
|
+
});
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
function initCatalog(dir, organizationName = "My Organization") {
|
|
726
|
+
const catalogDir = resolve2(dir);
|
|
727
|
+
mkdirSync(catalogDir, { recursive: true });
|
|
728
|
+
const packageJson = {
|
|
729
|
+
name: "my-catalog",
|
|
730
|
+
version: "0.1.0",
|
|
731
|
+
private: true,
|
|
732
|
+
scripts: {
|
|
733
|
+
dev: "eventcatalog dev",
|
|
734
|
+
build: "eventcatalog build",
|
|
735
|
+
start: "eventcatalog start",
|
|
736
|
+
preview: "eventcatalog preview",
|
|
737
|
+
generate: "eventcatalog generate",
|
|
738
|
+
lint: "eventcatalog-linter",
|
|
739
|
+
test: 'echo "Error: no test specified" && exit 1'
|
|
740
|
+
},
|
|
741
|
+
dependencies: {
|
|
742
|
+
"@eventcatalog/core": "latest",
|
|
743
|
+
"@eventcatalog/linter": "latest"
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
writeFileSync2(join(catalogDir, "package.json"), JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
|
|
747
|
+
const cId = randomUUID();
|
|
748
|
+
const config = `/** @type {import('@eventcatalog/core/bin/eventcatalog.config').Config} */
|
|
749
|
+
export default {
|
|
750
|
+
title: 'EventCatalog',
|
|
751
|
+
tagline: 'Discover, Explore and Document your Event Driven Architectures',
|
|
752
|
+
organizationName: '${organizationName}',
|
|
753
|
+
homepageLink: 'https://eventcatalog.dev/',
|
|
754
|
+
output: 'static',
|
|
755
|
+
trailingSlash: false,
|
|
756
|
+
base: '/',
|
|
757
|
+
logo: {
|
|
758
|
+
alt: 'EventCatalog Logo',
|
|
759
|
+
src: '/logo.png',
|
|
760
|
+
text: 'EventCatalog',
|
|
761
|
+
},
|
|
762
|
+
cId: '${cId}',
|
|
763
|
+
};
|
|
764
|
+
`;
|
|
765
|
+
writeFileSync2(join(catalogDir, "eventcatalog.config.js"), config, "utf-8");
|
|
766
|
+
const gitignore = `# Dependencies
|
|
767
|
+
/node_modules
|
|
768
|
+
|
|
769
|
+
# Production
|
|
770
|
+
/build
|
|
771
|
+
|
|
772
|
+
# Generated files
|
|
773
|
+
.astro
|
|
774
|
+
out
|
|
775
|
+
dist
|
|
776
|
+
|
|
777
|
+
# Misc
|
|
778
|
+
.DS_Store
|
|
779
|
+
.env.local
|
|
780
|
+
.env.development.local
|
|
781
|
+
.env.test.local
|
|
782
|
+
.env.production.local
|
|
783
|
+
|
|
784
|
+
npm-debug.log*
|
|
785
|
+
yarn-debug.log*
|
|
786
|
+
yarn-error.log*
|
|
787
|
+
|
|
788
|
+
.eventcatalog-core
|
|
789
|
+
|
|
790
|
+
.env
|
|
791
|
+
.env-*
|
|
792
|
+
`;
|
|
793
|
+
writeFileSync2(join(catalogDir, ".gitignore"), gitignore, "utf-8");
|
|
794
|
+
const envFile = `# EventCatalog Scale License Key, if you want to unlock the scale features
|
|
795
|
+
# You can get a 14 day trial license key from https://eventcatalog.cloud
|
|
796
|
+
|
|
797
|
+
EVENTCATALOG_SCALE_LICENSE_KEY=
|
|
798
|
+
|
|
799
|
+
# Optional key if you are using EventCatalog Chat with OpenAI Models.
|
|
800
|
+
# You need to set \`output\` to \`server\` in your eventcatalog.config.js file.
|
|
801
|
+
# See documentation for more details: https://www.eventcatalog.dev/features/ai-assistant
|
|
802
|
+
OPENAI_API_KEY=
|
|
803
|
+
`;
|
|
804
|
+
writeFileSync2(join(catalogDir, ".env"), envFile, "utf-8");
|
|
805
|
+
writeFileSync2(join(catalogDir, ".npmrc"), "strict-peer-dependencies=false\n", "utf-8");
|
|
806
|
+
mkdirSync(join(catalogDir, "public"), { recursive: true });
|
|
807
|
+
copyFileSync(join(__dirname, "logo.png"), join(catalogDir, "public", "logo.png"));
|
|
808
|
+
}
|
|
809
|
+
async function importDSL(options) {
|
|
810
|
+
const { files, stdin = false, dryRun = false, flat = false, noInit = false, dir } = options;
|
|
811
|
+
const nested = !flat;
|
|
812
|
+
let source;
|
|
813
|
+
if (stdin) {
|
|
814
|
+
source = await readStdin();
|
|
815
|
+
} else if (files && files.length > 0) {
|
|
816
|
+
const parts = [];
|
|
817
|
+
for (const file of files) {
|
|
818
|
+
const filepath = resolve2(file);
|
|
819
|
+
if (!existsSync2(filepath)) {
|
|
820
|
+
throw new Error(`File not found: ${filepath}`);
|
|
821
|
+
}
|
|
822
|
+
parts.push(readFileSync(filepath, "utf-8"));
|
|
823
|
+
}
|
|
824
|
+
source = parts.join("\n\n");
|
|
825
|
+
} else {
|
|
826
|
+
throw new Error("Either provide .ec file paths or use --stdin");
|
|
827
|
+
}
|
|
828
|
+
if (!source.trim()) {
|
|
829
|
+
throw new Error("No DSL content to import");
|
|
830
|
+
}
|
|
831
|
+
const catalogDir = resolve2(dir);
|
|
832
|
+
let didInit = false;
|
|
833
|
+
if (!noInit && !existsSync2(join(catalogDir, "eventcatalog.config.js")) && process.stdin.isTTY) {
|
|
834
|
+
const confirmed = await promptConfirm(`Initialize a new EventCatalog at ${catalogDir}? (Y/n)`);
|
|
835
|
+
if (confirmed) {
|
|
836
|
+
const organizationName = await promptInput("Organization name (My Organization):", "My Organization");
|
|
837
|
+
initCatalog(dir, organizationName);
|
|
838
|
+
didInit = true;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
const parsed = await parseDSL(source, { nested });
|
|
842
|
+
const outputs = parsed.outputs;
|
|
843
|
+
if (outputs.length === 0) {
|
|
844
|
+
throw new Error("No resources found in DSL content");
|
|
845
|
+
}
|
|
846
|
+
const sdk = createSDK4(catalogDir);
|
|
847
|
+
const result = { created: [], updated: [], versioned: [], errors: [] };
|
|
848
|
+
const readerCache = /* @__PURE__ */ new Map();
|
|
849
|
+
const readResourceCached = async (reader, type, id, version2) => {
|
|
850
|
+
if (!reader) return void 0;
|
|
851
|
+
const cacheKey = getResourceVersionKey(type, id, version2);
|
|
852
|
+
if (!readerCache.has(cacheKey)) {
|
|
853
|
+
readerCache.set(
|
|
854
|
+
cacheKey,
|
|
855
|
+
reader(id, version2).catch(() => void 0)
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
return await readerCache.get(cacheKey);
|
|
859
|
+
};
|
|
860
|
+
const invalidateReaderCache = (type, id, version2) => {
|
|
861
|
+
readerCache.delete(getResourceVersionKey(type, id));
|
|
862
|
+
readerCache.delete(getResourceVersionKey(type, id, version2));
|
|
863
|
+
};
|
|
864
|
+
const resources = outputs.map(parseCompiledOutput);
|
|
865
|
+
const serviceContainerRefsByPath = extractServiceContainerRefs(parsed.program, nested);
|
|
866
|
+
for (const resource of resources) {
|
|
867
|
+
if (resource.type !== "service") continue;
|
|
868
|
+
const refs = serviceContainerRefsByPath.get(resource.path);
|
|
869
|
+
if (!refs) continue;
|
|
870
|
+
resource.frontmatter = {
|
|
871
|
+
...resource.frontmatter,
|
|
872
|
+
...refs
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
const compiledIds = /* @__PURE__ */ new Set();
|
|
876
|
+
for (const resource of resources) {
|
|
877
|
+
compiledIds.add(getResourceNameKey(resource.type, resource.id));
|
|
878
|
+
compiledIds.add(getResourceVersionKey(resource.type, resource.id, resource.version));
|
|
879
|
+
}
|
|
880
|
+
const stubs = hasReferenceStatements(source) ? await extractMessageStubs(parsed.program, compiledIds, nested) : [];
|
|
881
|
+
resources.push(...stubs);
|
|
882
|
+
for (const resource of resources) {
|
|
883
|
+
const label = resource.version ? `${resource.type} ${resource.id}@${resource.version}` : `${resource.type} ${resource.id}`;
|
|
884
|
+
if (dryRun) {
|
|
885
|
+
const reader = getReader(sdk, resource.type);
|
|
886
|
+
if (reader) {
|
|
887
|
+
const existing = await readResourceCached(reader, resource.type, resource.id, resource.version);
|
|
888
|
+
if (existing) {
|
|
889
|
+
result.updated.push(label);
|
|
890
|
+
} else {
|
|
891
|
+
const latest = await readResourceCached(reader, resource.type, resource.id);
|
|
892
|
+
if (latest && latest.version && latest.version !== resource.version) {
|
|
893
|
+
result.versioned.push(`${resource.type} ${resource.id}@${latest.version}`);
|
|
894
|
+
}
|
|
895
|
+
result.created.push(label);
|
|
896
|
+
}
|
|
897
|
+
} else {
|
|
898
|
+
result.created.push(label);
|
|
899
|
+
}
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
const writer = getWriter(sdk, resource.type);
|
|
903
|
+
if (!writer) {
|
|
904
|
+
result.errors.push(`${label}: unsupported resource type '${resource.type}'`);
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
try {
|
|
908
|
+
const reader = getReader(sdk, resource.type);
|
|
909
|
+
const existing = await readResourceCached(reader, resource.type, resource.id, resource.version);
|
|
910
|
+
const latest = !existing && resource.version ? await readResourceCached(reader, resource.type, resource.id) : void 0;
|
|
911
|
+
const versionedFrom = !existing && resource.version && latest?.version && latest.version !== resource.version ? latest.version : void 0;
|
|
912
|
+
const incomingMarkdown = resource.markdown;
|
|
913
|
+
const hasIncomingMarkdown = incomingMarkdown.trim().length > 0;
|
|
914
|
+
let markdown = incomingMarkdown;
|
|
915
|
+
if (!hasIncomingMarkdown) {
|
|
916
|
+
if (existing?.markdown) {
|
|
917
|
+
markdown = existing.markdown;
|
|
918
|
+
} else if (!existing && latest?.markdown) {
|
|
919
|
+
markdown = latest.markdown;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
if (!existing && TYPES_WITH_NODE_GRAPH.has(resource.type)) {
|
|
923
|
+
if (!markdown) {
|
|
924
|
+
markdown = "<NodeGraph />";
|
|
925
|
+
} else if (!markdown.includes("<NodeGraph />")) {
|
|
926
|
+
markdown = `${markdown}
|
|
927
|
+
|
|
928
|
+
<NodeGraph />`;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
const resourceData = {
|
|
932
|
+
...normalizeImportedFrontmatter(resource.type, resource.frontmatter),
|
|
933
|
+
markdown
|
|
934
|
+
};
|
|
935
|
+
const writeOptions = {
|
|
936
|
+
override: true,
|
|
937
|
+
versionExistingContent: Boolean(versionedFrom)
|
|
938
|
+
};
|
|
939
|
+
if (!existing && nested) {
|
|
940
|
+
const sdkPath = extractSdkPath(resource.path, resource.type);
|
|
941
|
+
if (sdkPath) {
|
|
942
|
+
writeOptions.path = sdkPath;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
await writer(resourceData, writeOptions);
|
|
946
|
+
invalidateReaderCache(resource.type, resource.id, resource.version);
|
|
947
|
+
if (existing) {
|
|
948
|
+
result.updated.push(label);
|
|
949
|
+
} else {
|
|
950
|
+
result.created.push(label);
|
|
951
|
+
if (versionedFrom) {
|
|
952
|
+
result.versioned.push(`${resource.type} ${resource.id}@${versionedFrom}`);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
} catch (error) {
|
|
956
|
+
result.errors.push(`${label}: ${error instanceof Error ? error.message : String(error)}`);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
let output = formatResult(result, dryRun);
|
|
960
|
+
if (didInit) {
|
|
961
|
+
output += ` Tip: Run 'npm install' in ${catalogDir} to install dependencies
|
|
962
|
+
`;
|
|
963
|
+
}
|
|
964
|
+
return output;
|
|
965
|
+
}
|
|
966
|
+
var c = {
|
|
967
|
+
reset: "\x1B[0m",
|
|
968
|
+
bold: "\x1B[1m",
|
|
969
|
+
dim: "\x1B[2m",
|
|
970
|
+
green: "\x1B[32m",
|
|
971
|
+
yellow: "\x1B[33m",
|
|
972
|
+
blue: "\x1B[34m",
|
|
973
|
+
magenta: "\x1B[35m",
|
|
974
|
+
cyan: "\x1B[36m",
|
|
975
|
+
red: "\x1B[31m",
|
|
976
|
+
white: "\x1B[37m",
|
|
977
|
+
gray: "\x1B[90m"
|
|
978
|
+
};
|
|
979
|
+
var TYPE_CONFIG = {
|
|
980
|
+
domain: { color: c.magenta, label: "domain", order: 0 },
|
|
981
|
+
service: { color: c.blue, label: "service", order: 1 },
|
|
982
|
+
event: { color: c.green, label: "event", order: 2 },
|
|
983
|
+
command: { color: c.yellow, label: "command", order: 3 },
|
|
984
|
+
query: { color: c.cyan, label: "query", order: 4 },
|
|
985
|
+
channel: { color: c.gray, label: "channel", order: 5 },
|
|
986
|
+
flow: { color: c.white, label: "flow", order: 6 },
|
|
987
|
+
container: { color: c.white, label: "container", order: 7 },
|
|
988
|
+
dataProduct: { color: c.white, label: "data product", order: 8 },
|
|
989
|
+
diagram: { color: c.white, label: "diagram", order: 9 },
|
|
990
|
+
user: { color: c.blue, label: "user", order: 10 },
|
|
991
|
+
team: { color: c.blue, label: "team", order: 11 }
|
|
992
|
+
};
|
|
993
|
+
var DEFAULT_TYPE_CONFIG = { color: c.white, label: "resource", order: 99 };
|
|
994
|
+
function parseLabel(label) {
|
|
995
|
+
const spaceIdx = label.indexOf(" ");
|
|
996
|
+
if (spaceIdx === -1) return { type: "", name: label };
|
|
997
|
+
return { type: label.slice(0, spaceIdx), name: label.slice(spaceIdx + 1) };
|
|
998
|
+
}
|
|
999
|
+
function groupByType(labels) {
|
|
1000
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1001
|
+
for (const label of labels) {
|
|
1002
|
+
const { type, name } = parseLabel(label);
|
|
1003
|
+
if (!groups.has(type)) groups.set(type, []);
|
|
1004
|
+
groups.get(type).push(name);
|
|
1005
|
+
}
|
|
1006
|
+
const sorted = new Map(
|
|
1007
|
+
[...groups.entries()].sort((a, b) => {
|
|
1008
|
+
const orderA = (TYPE_CONFIG[a[0]] || DEFAULT_TYPE_CONFIG).order;
|
|
1009
|
+
const orderB = (TYPE_CONFIG[b[0]] || DEFAULT_TYPE_CONFIG).order;
|
|
1010
|
+
return orderA - orderB;
|
|
1011
|
+
})
|
|
1012
|
+
);
|
|
1013
|
+
for (const [, names] of sorted) {
|
|
1014
|
+
names.sort();
|
|
1015
|
+
}
|
|
1016
|
+
return sorted;
|
|
1017
|
+
}
|
|
1018
|
+
function typeBadge(type) {
|
|
1019
|
+
const cfg = TYPE_CONFIG[type] || DEFAULT_TYPE_CONFIG;
|
|
1020
|
+
const padded = ` ${cfg.label} `;
|
|
1021
|
+
return `${cfg.color}\x1B[7m${padded}${c.reset}`;
|
|
1022
|
+
}
|
|
1023
|
+
function formatResourceList(labels) {
|
|
1024
|
+
const lines = [];
|
|
1025
|
+
const groups = groupByType(labels);
|
|
1026
|
+
for (const [type, names] of groups) {
|
|
1027
|
+
const cfg = TYPE_CONFIG[type] || DEFAULT_TYPE_CONFIG;
|
|
1028
|
+
const plural = names.length === 1 ? cfg.label : `${cfg.label}s`;
|
|
1029
|
+
lines.push("");
|
|
1030
|
+
lines.push(` ${typeBadge(type)} ${c.dim}${names.length} ${plural}${c.reset}`);
|
|
1031
|
+
for (const name of names) {
|
|
1032
|
+
lines.push(` ${cfg.color}\u2502${c.reset} ${name}`);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
return lines;
|
|
1036
|
+
}
|
|
1037
|
+
function formatResult(result, dryRun) {
|
|
1038
|
+
const lines = [""];
|
|
1039
|
+
const prefix = dryRun ? `${c.yellow}${c.bold}DRY RUN${c.reset} ` : "";
|
|
1040
|
+
const total = result.created.length + result.updated.length + result.versioned.length;
|
|
1041
|
+
if (total > 0 || result.errors.length > 0) {
|
|
1042
|
+
lines.push(` ${prefix}${c.bold}Import complete${c.reset}`);
|
|
1043
|
+
lines.push(` ${c.dim}${"\u2500".repeat(40)}${c.reset}`);
|
|
1044
|
+
}
|
|
1045
|
+
if (result.created.length > 0) {
|
|
1046
|
+
const verb = dryRun ? "Would create" : "Created";
|
|
1047
|
+
lines.push("");
|
|
1048
|
+
lines.push(` ${c.green}${c.bold}+ ${verb} ${result.created.length} resource(s)${c.reset}`);
|
|
1049
|
+
lines.push(...formatResourceList(result.created));
|
|
1050
|
+
}
|
|
1051
|
+
if (result.updated.length > 0) {
|
|
1052
|
+
const verb = dryRun ? "Would update" : "Updated";
|
|
1053
|
+
lines.push("");
|
|
1054
|
+
lines.push(` ${c.blue}${c.bold}~ ${verb} ${result.updated.length} resource(s)${c.reset}`);
|
|
1055
|
+
lines.push(...formatResourceList(result.updated));
|
|
1056
|
+
}
|
|
1057
|
+
if (result.versioned.length > 0) {
|
|
1058
|
+
const verb = dryRun ? "Would version" : "Versioned";
|
|
1059
|
+
lines.push("");
|
|
1060
|
+
lines.push(` ${c.yellow}${c.bold}\u2191 ${verb} ${result.versioned.length} existing resource(s)${c.reset}`);
|
|
1061
|
+
lines.push(...formatResourceList(result.versioned));
|
|
1062
|
+
}
|
|
1063
|
+
if (result.errors.length > 0) {
|
|
1064
|
+
lines.push("");
|
|
1065
|
+
lines.push(` ${c.red}${c.bold}\u2718 ${result.errors.length} error(s)${c.reset}`);
|
|
1066
|
+
for (const e of result.errors) {
|
|
1067
|
+
lines.push(` ${c.red}\u2502${c.reset} ${c.red}${e}${c.reset}`);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
if (result.created.length === 0 && result.updated.length === 0 && result.errors.length === 0) {
|
|
1071
|
+
lines.push(` ${c.dim}No resources to write.${c.reset}`);
|
|
1072
|
+
}
|
|
1073
|
+
lines.push("");
|
|
1074
|
+
return lines.join("\n");
|
|
1075
|
+
}
|
|
1076
|
+
function readStdin() {
|
|
1077
|
+
return new Promise((resolve4, reject) => {
|
|
1078
|
+
const chunks = [];
|
|
1079
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
1080
|
+
process.stdin.on("end", () => resolve4(Buffer.concat(chunks).toString("utf-8")));
|
|
1081
|
+
process.stdin.on("error", reject);
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
|
|
339
1085
|
// src/cli/index.ts
|
|
340
1086
|
var version = "1.0.0";
|
|
341
1087
|
try {
|
|
342
|
-
const packageJsonPath =
|
|
343
|
-
const packageJson = JSON.parse(
|
|
1088
|
+
const packageJsonPath = resolve3(__dirname, "../../package.json");
|
|
1089
|
+
const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
|
|
344
1090
|
version = packageJson.version;
|
|
345
1091
|
} catch {
|
|
346
1092
|
}
|
|
@@ -355,7 +1101,7 @@ program.command("list").description("List all available SDK functions").action((
|
|
|
355
1101
|
process.exit(1);
|
|
356
1102
|
}
|
|
357
1103
|
});
|
|
358
|
-
program.command("export").description("Export a catalog resource to EventCatalog DSL (.ec) format").option("-a, --all", "Export the entire catalog (all resource types)", false).option("-r, --resource <type>", "Resource type (event, command, query, service, domain)").option("--id <id>", "Resource ID (omit to export all resources of the given type)").option("-v, --version <version>", "Resource version (defaults to latest)").option("--hydrate", "Include referenced resources (messages, channels, owners)", false).option("--stdout", "Print to stdout instead of writing a file", false).option("--playground", "Open the exported DSL in
|
|
1104
|
+
program.command("export").description("Export a catalog resource to EventCatalog DSL (.ec) format").option("-a, --all", "Export the entire catalog (all resource types)", false).option("-r, --resource <type>", "Resource type (event, command, query, service, domain)").option("--id <id>", "Resource ID (omit to export all resources of the given type)").option("-v, --version <version>", "Resource version (defaults to latest)").option("--hydrate", "Include referenced resources (messages, channels, owners)", false).option("--stdout", "Print to stdout instead of writing a file", false).option("--playground", "Open the exported DSL in EventCatalog Modelling", false).option("-o, --output <path>", "Output file path (defaults to <id>.ec or catalog.ec)").action(async (opts) => {
|
|
359
1105
|
try {
|
|
360
1106
|
const globalOpts = program.opts();
|
|
361
1107
|
const dir = globalOpts.dir || ".";
|
|
@@ -390,6 +1136,24 @@ program.command("export").description("Export a catalog resource to EventCatalog
|
|
|
390
1136
|
process.exit(1);
|
|
391
1137
|
}
|
|
392
1138
|
});
|
|
1139
|
+
program.command("import [files...]").description("Import EventCatalog DSL (.ec) files into catalog markdown").option("--stdin", "Read DSL from stdin", false).option("--dry-run", "Preview resources without writing", false).option("--flat", "Write resources in flat structure (no nesting under domains/services)", false).option("--no-init", "Skip catalog initialization prompt").action(async (files, opts) => {
|
|
1140
|
+
try {
|
|
1141
|
+
const globalOpts = program.opts();
|
|
1142
|
+
const dir = globalOpts.dir || ".";
|
|
1143
|
+
const result = await importDSL({
|
|
1144
|
+
files: files.length > 0 ? files : void 0,
|
|
1145
|
+
stdin: opts.stdin,
|
|
1146
|
+
dryRun: opts.dryRun,
|
|
1147
|
+
flat: opts.flat,
|
|
1148
|
+
noInit: !opts.init,
|
|
1149
|
+
dir
|
|
1150
|
+
});
|
|
1151
|
+
console.log(result);
|
|
1152
|
+
} catch (error) {
|
|
1153
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1154
|
+
process.exit(1);
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
393
1157
|
program.arguments("<function> [args...]").action(async (functionName, args) => {
|
|
394
1158
|
try {
|
|
395
1159
|
const options = program.opts();
|