@eventcatalog/cli 0.3.0 → 0.3.2
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 +584 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +584 -9
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/logo.png +0 -0
- package/dist/cli-docs.js +31 -0
- package/dist/cli-docs.js.map +1 -1
- package/dist/cli-docs.mjs +31 -0
- package/dist/cli-docs.mjs.map +1 -1
- package/package.json +5 -2
package/dist/cli/index.js
CHANGED
|
@@ -25,8 +25,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/cli/index.ts
|
|
27
27
|
var import_commander = require("commander");
|
|
28
|
-
var
|
|
29
|
-
var
|
|
28
|
+
var import_node_fs4 = require("fs");
|
|
29
|
+
var import_node_path3 = require("path");
|
|
30
30
|
|
|
31
31
|
// src/cli/executor.ts
|
|
32
32
|
var import_node_fs = require("fs");
|
|
@@ -267,7 +267,7 @@ ${vizBlock}` : grouped;
|
|
|
267
267
|
const lines = ["", ` Exported full catalog to ${filepath}`];
|
|
268
268
|
if (playground) {
|
|
269
269
|
const encoded = Buffer.from(dsl).toString("base64");
|
|
270
|
-
const playgroundUrl = `
|
|
270
|
+
const playgroundUrl = `https://playground.eventcatalog.dev/?code=${encoded}`;
|
|
271
271
|
await (0, import_open.default)(playgroundUrl);
|
|
272
272
|
lines.push("", ` Opening in playground...`);
|
|
273
273
|
} else {
|
|
@@ -285,8 +285,8 @@ async function exportAll(options) {
|
|
|
285
285
|
const plural = pluralize(type);
|
|
286
286
|
const sdk = (0, import_sdk3.default)(dir);
|
|
287
287
|
const fetcher = getCollectionFetcher(sdk, type);
|
|
288
|
-
const allResources = await fetcher({ latestOnly: true });
|
|
289
|
-
if (
|
|
288
|
+
const allResources = await fetcher({ latestOnly: true }) || [];
|
|
289
|
+
if (allResources.length === 0) {
|
|
290
290
|
throw new Error(`No ${plural} found in catalog at '${dir}'`);
|
|
291
291
|
}
|
|
292
292
|
const rawDsl = await sdk.toDSL(allResources, { type, hydrate });
|
|
@@ -303,7 +303,7 @@ ${vizBlock}` : grouped;
|
|
|
303
303
|
const lines = ["", ` Exported ${allResources.length} ${plural} to ${filepath}`];
|
|
304
304
|
if (playground) {
|
|
305
305
|
const encoded = Buffer.from(dsl).toString("base64");
|
|
306
|
-
const playgroundUrl = `
|
|
306
|
+
const playgroundUrl = `https://playground.eventcatalog.dev/?code=${encoded}`;
|
|
307
307
|
await (0, import_open.default)(playgroundUrl);
|
|
308
308
|
lines.push("", ` Opening in playground...`);
|
|
309
309
|
} else {
|
|
@@ -342,7 +342,7 @@ ${vizBlock}` : grouped;
|
|
|
342
342
|
const lines = ["", ` Exported ${type} '${id}' to ${filepath}`];
|
|
343
343
|
if (playground) {
|
|
344
344
|
const encoded = Buffer.from(dsl).toString("base64");
|
|
345
|
-
const playgroundUrl = `
|
|
345
|
+
const playgroundUrl = `https://playground.eventcatalog.dev/?code=${encoded}`;
|
|
346
346
|
await (0, import_open.default)(playgroundUrl);
|
|
347
347
|
lines.push("", ` Opening in playground...`);
|
|
348
348
|
} else {
|
|
@@ -352,11 +352,568 @@ ${vizBlock}` : grouped;
|
|
|
352
352
|
return lines.join("\n");
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
+
// src/cli/import.ts
|
|
356
|
+
var import_node_fs3 = require("fs");
|
|
357
|
+
var import_node_path2 = require("path");
|
|
358
|
+
var import_node_crypto = require("crypto");
|
|
359
|
+
var import_node_readline = require("readline");
|
|
360
|
+
var import_gray_matter = __toESM(require("gray-matter"));
|
|
361
|
+
var import_sdk4 = __toESM(require("@eventcatalog/sdk"));
|
|
362
|
+
var RESOURCE_TYPE_FROM_FOLDER = {
|
|
363
|
+
events: "event",
|
|
364
|
+
commands: "command",
|
|
365
|
+
queries: "query",
|
|
366
|
+
services: "service",
|
|
367
|
+
domains: "domain",
|
|
368
|
+
channels: "channel",
|
|
369
|
+
flows: "flow",
|
|
370
|
+
containers: "container",
|
|
371
|
+
"data-products": "dataProduct",
|
|
372
|
+
diagrams: "diagram",
|
|
373
|
+
users: "user",
|
|
374
|
+
teams: "team"
|
|
375
|
+
};
|
|
376
|
+
async function parseDSL(source, options) {
|
|
377
|
+
const { createEcServices, compile } = await import("@eventcatalog/language-server");
|
|
378
|
+
const { EmptyFileSystem, URI } = await import("langium");
|
|
379
|
+
const services = createEcServices(EmptyFileSystem);
|
|
380
|
+
const uri = URI.parse(`file:///import-${Date.now()}.ec`);
|
|
381
|
+
const document = services.shared.workspace.LangiumDocumentFactory.fromString(source, uri);
|
|
382
|
+
services.shared.workspace.LangiumDocuments.addDocument(document);
|
|
383
|
+
await services.shared.workspace.DocumentBuilder.build([document]);
|
|
384
|
+
const parserErrors = document.parseResult.parserErrors;
|
|
385
|
+
if (parserErrors.length > 0) {
|
|
386
|
+
const messages = parserErrors.map((e) => ` Line ${e.token?.startLine ?? "?"}: ${e.message}`);
|
|
387
|
+
throw new Error(`Parse errors:
|
|
388
|
+
${messages.join("\n")}`);
|
|
389
|
+
}
|
|
390
|
+
const program2 = document.parseResult.value;
|
|
391
|
+
const outputs = compile(program2, { nested: options?.nested });
|
|
392
|
+
try {
|
|
393
|
+
services.shared.workspace.LangiumDocuments.deleteDocument(uri);
|
|
394
|
+
} catch {
|
|
395
|
+
}
|
|
396
|
+
return outputs;
|
|
397
|
+
}
|
|
398
|
+
function extractResourceTypeFolder(path) {
|
|
399
|
+
const segments = path.split("/");
|
|
400
|
+
let lastTypeFolder = segments[0];
|
|
401
|
+
for (const seg of segments) {
|
|
402
|
+
if (RESOURCE_TYPE_FROM_FOLDER[seg]) {
|
|
403
|
+
lastTypeFolder = seg;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return lastTypeFolder;
|
|
407
|
+
}
|
|
408
|
+
function parseCompiledOutput(output) {
|
|
409
|
+
const { data: frontmatter, content: markdown } = (0, import_gray_matter.default)(output.content);
|
|
410
|
+
const typeFolder = extractResourceTypeFolder(output.path);
|
|
411
|
+
const type = RESOURCE_TYPE_FROM_FOLDER[typeFolder] || typeFolder;
|
|
412
|
+
return {
|
|
413
|
+
type,
|
|
414
|
+
id: frontmatter.id,
|
|
415
|
+
version: frontmatter.version,
|
|
416
|
+
frontmatter,
|
|
417
|
+
markdown: markdown.trim(),
|
|
418
|
+
path: output.path
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
var MESSAGE_TYPE_FOLDER = {
|
|
422
|
+
event: "events",
|
|
423
|
+
command: "commands",
|
|
424
|
+
query: "queries",
|
|
425
|
+
channel: "channels"
|
|
426
|
+
};
|
|
427
|
+
var DEFAULT_STUB_VERSION = "0.0.1";
|
|
428
|
+
async function extractMessageStubs(source, compiledIds, nested = false) {
|
|
429
|
+
const { createEcServices } = await import("@eventcatalog/language-server");
|
|
430
|
+
const { EmptyFileSystem, URI } = await import("langium");
|
|
431
|
+
const services = createEcServices(EmptyFileSystem);
|
|
432
|
+
const uri = URI.parse(`file:///stub-extract-${Date.now()}.ec`);
|
|
433
|
+
const document = services.shared.workspace.LangiumDocumentFactory.fromString(source, uri);
|
|
434
|
+
services.shared.workspace.LangiumDocuments.addDocument(document);
|
|
435
|
+
await services.shared.workspace.DocumentBuilder.build([document]);
|
|
436
|
+
const program2 = document.parseResult.value;
|
|
437
|
+
const stubs = [];
|
|
438
|
+
const stubIds = /* @__PURE__ */ new Set();
|
|
439
|
+
function processDefinitions(definitions, parentPath = "") {
|
|
440
|
+
for (const def of definitions) {
|
|
441
|
+
if (def.$type === "VisualizerDef" && def.body) {
|
|
442
|
+
processDefinitions(def.body, parentPath);
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (def.$type === "DomainDef") {
|
|
446
|
+
const domainPath = nested ? `domains/${def.name}` : "";
|
|
447
|
+
const domainBody = def.body || [];
|
|
448
|
+
const domainServices = domainBody.filter((d) => d.$type === "ServiceDef");
|
|
449
|
+
processDefinitions(domainServices, domainPath);
|
|
450
|
+
const subdomains = domainBody.filter((d) => d.$type === "SubdomainDef");
|
|
451
|
+
for (const sub of subdomains) {
|
|
452
|
+
const subPath = nested ? `domains/${def.name}/subdomains/${sub.name}` : "";
|
|
453
|
+
const subServices = (sub.body || []).filter((d) => d.$type === "ServiceDef");
|
|
454
|
+
processDefinitions(subServices, subPath);
|
|
455
|
+
}
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (def.$type !== "ServiceDef") continue;
|
|
459
|
+
const servicePath = nested ? parentPath ? `${parentPath}/services/${def.name}` : `services/${def.name}` : "";
|
|
460
|
+
const body = def.body || [];
|
|
461
|
+
for (const stmt of body) {
|
|
462
|
+
if (stmt.$type !== "SendsStmt" && stmt.$type !== "ReceivesStmt") continue;
|
|
463
|
+
const msgType = stmt.messageType;
|
|
464
|
+
const msgName = stmt.messageName;
|
|
465
|
+
const hasBody = stmt.body && stmt.body.length > 0;
|
|
466
|
+
if (hasBody) continue;
|
|
467
|
+
const key = `${msgType}:${msgName}`;
|
|
468
|
+
if (compiledIds.has(key) || stubIds.has(key)) continue;
|
|
469
|
+
const folder = MESSAGE_TYPE_FOLDER[msgType];
|
|
470
|
+
if (!folder) continue;
|
|
471
|
+
const version2 = stmt.version || DEFAULT_STUB_VERSION;
|
|
472
|
+
const stubFolder = nested && servicePath ? `${servicePath}/${folder}` : folder;
|
|
473
|
+
stubIds.add(key);
|
|
474
|
+
stubs.push({
|
|
475
|
+
type: msgType,
|
|
476
|
+
id: msgName,
|
|
477
|
+
version: version2,
|
|
478
|
+
frontmatter: {
|
|
479
|
+
id: msgName,
|
|
480
|
+
name: msgName,
|
|
481
|
+
version: version2
|
|
482
|
+
},
|
|
483
|
+
markdown: "",
|
|
484
|
+
path: `${stubFolder}/${msgName}/versioned/${version2}/index.md`
|
|
485
|
+
});
|
|
486
|
+
if (stmt.channelClause) {
|
|
487
|
+
const channels = stmt.channelClause.channels || [];
|
|
488
|
+
for (const ch of channels) {
|
|
489
|
+
const chName = ch.channelName;
|
|
490
|
+
const chKey = `channel:${chName}`;
|
|
491
|
+
if (compiledIds.has(chKey) || stubIds.has(chKey)) continue;
|
|
492
|
+
const chVersion = ch.channelVersion || DEFAULT_STUB_VERSION;
|
|
493
|
+
const chFolder = nested && parentPath ? `${parentPath}/channels` : "channels";
|
|
494
|
+
stubIds.add(chKey);
|
|
495
|
+
stubs.push({
|
|
496
|
+
type: "channel",
|
|
497
|
+
id: chName,
|
|
498
|
+
version: chVersion,
|
|
499
|
+
frontmatter: {
|
|
500
|
+
id: chName,
|
|
501
|
+
name: chName,
|
|
502
|
+
version: chVersion
|
|
503
|
+
},
|
|
504
|
+
markdown: "",
|
|
505
|
+
path: `${chFolder}/${chName}/versioned/${chVersion}/index.md`
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
processDefinitions(program2.definitions);
|
|
513
|
+
try {
|
|
514
|
+
services.shared.workspace.LangiumDocuments.deleteDocument(uri);
|
|
515
|
+
} catch {
|
|
516
|
+
}
|
|
517
|
+
return stubs;
|
|
518
|
+
}
|
|
519
|
+
var SDK_WRITER_BASE = {
|
|
520
|
+
event: "events",
|
|
521
|
+
command: "commands",
|
|
522
|
+
query: "queries",
|
|
523
|
+
service: "services",
|
|
524
|
+
domain: "domains",
|
|
525
|
+
channel: "channels",
|
|
526
|
+
container: "containers",
|
|
527
|
+
team: "teams",
|
|
528
|
+
user: "users"
|
|
529
|
+
};
|
|
530
|
+
function extractSdkPath(compiledPath, resourceType) {
|
|
531
|
+
const dirPath = compiledPath.replace(/\/versioned\/[^/]+\/index\.md$/, "").replace(/\/index\.md$/, "").replace(/\.md$/, "");
|
|
532
|
+
const baseFolder = SDK_WRITER_BASE[resourceType];
|
|
533
|
+
if (!baseFolder) return "";
|
|
534
|
+
if (dirPath.startsWith(`${baseFolder}/`)) {
|
|
535
|
+
const relative = dirPath.slice(baseFolder.length + 1);
|
|
536
|
+
if (!relative.includes("/")) return "";
|
|
537
|
+
return relative;
|
|
538
|
+
}
|
|
539
|
+
return `../${dirPath}`;
|
|
540
|
+
}
|
|
541
|
+
var TYPES_WITH_NODE_GRAPH = /* @__PURE__ */ new Set(["event", "command", "query", "service", "domain", "channel", "flow"]);
|
|
542
|
+
function getWriter(sdk, type) {
|
|
543
|
+
switch (type) {
|
|
544
|
+
case "event":
|
|
545
|
+
return sdk.writeEvent;
|
|
546
|
+
case "command":
|
|
547
|
+
return sdk.writeCommand;
|
|
548
|
+
case "query":
|
|
549
|
+
return sdk.writeQuery;
|
|
550
|
+
case "service":
|
|
551
|
+
return sdk.writeService;
|
|
552
|
+
case "domain":
|
|
553
|
+
return sdk.writeDomain;
|
|
554
|
+
case "channel":
|
|
555
|
+
return sdk.writeChannel;
|
|
556
|
+
case "team":
|
|
557
|
+
return sdk.writeTeam;
|
|
558
|
+
case "user":
|
|
559
|
+
return sdk.writeUser;
|
|
560
|
+
default:
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
function getReader(sdk, type) {
|
|
565
|
+
switch (type) {
|
|
566
|
+
case "event":
|
|
567
|
+
return sdk.getEvent;
|
|
568
|
+
case "command":
|
|
569
|
+
return sdk.getCommand;
|
|
570
|
+
case "query":
|
|
571
|
+
return sdk.getQuery;
|
|
572
|
+
case "service":
|
|
573
|
+
return sdk.getService;
|
|
574
|
+
case "domain":
|
|
575
|
+
return sdk.getDomain;
|
|
576
|
+
case "channel":
|
|
577
|
+
return sdk.getChannel;
|
|
578
|
+
case "team":
|
|
579
|
+
return sdk.getTeam;
|
|
580
|
+
case "user":
|
|
581
|
+
return sdk.getUser;
|
|
582
|
+
default:
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
function promptConfirm(message) {
|
|
587
|
+
return new Promise((resolve4) => {
|
|
588
|
+
const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
|
|
589
|
+
rl.question(`${message} `, (answer) => {
|
|
590
|
+
rl.close();
|
|
591
|
+
const normalized = answer.trim().toLowerCase();
|
|
592
|
+
resolve4(normalized === "" || normalized === "y" || normalized === "yes");
|
|
593
|
+
});
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
function promptInput(message, defaultValue) {
|
|
597
|
+
return new Promise((resolve4) => {
|
|
598
|
+
const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
|
|
599
|
+
rl.question(`${message} `, (answer) => {
|
|
600
|
+
rl.close();
|
|
601
|
+
resolve4(answer.trim() || defaultValue);
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
function initCatalog(dir, organizationName = "My Organization") {
|
|
606
|
+
const catalogDir = (0, import_node_path2.resolve)(dir);
|
|
607
|
+
(0, import_node_fs3.mkdirSync)(catalogDir, { recursive: true });
|
|
608
|
+
const packageJson = {
|
|
609
|
+
name: "my-catalog",
|
|
610
|
+
version: "0.1.0",
|
|
611
|
+
private: true,
|
|
612
|
+
scripts: {
|
|
613
|
+
dev: "eventcatalog dev",
|
|
614
|
+
build: "eventcatalog build",
|
|
615
|
+
start: "eventcatalog start",
|
|
616
|
+
preview: "eventcatalog preview",
|
|
617
|
+
generate: "eventcatalog generate",
|
|
618
|
+
lint: "eventcatalog-linter",
|
|
619
|
+
test: 'echo "Error: no test specified" && exit 1'
|
|
620
|
+
},
|
|
621
|
+
dependencies: {
|
|
622
|
+
"@eventcatalog/core": "latest",
|
|
623
|
+
"@eventcatalog/linter": "latest"
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, "package.json"), JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
|
|
627
|
+
const cId = (0, import_node_crypto.randomUUID)();
|
|
628
|
+
const config = `/** @type {import('@eventcatalog/core/bin/eventcatalog.config').Config} */
|
|
629
|
+
export default {
|
|
630
|
+
title: 'EventCatalog',
|
|
631
|
+
tagline: 'Discover, Explore and Document your Event Driven Architectures',
|
|
632
|
+
organizationName: '${organizationName}',
|
|
633
|
+
homepageLink: 'https://eventcatalog.dev/',
|
|
634
|
+
output: 'static',
|
|
635
|
+
trailingSlash: false,
|
|
636
|
+
base: '/',
|
|
637
|
+
logo: {
|
|
638
|
+
alt: 'EventCatalog Logo',
|
|
639
|
+
src: '/logo.png',
|
|
640
|
+
text: 'EventCatalog',
|
|
641
|
+
},
|
|
642
|
+
cId: '${cId}',
|
|
643
|
+
};
|
|
644
|
+
`;
|
|
645
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, "eventcatalog.config.js"), config, "utf-8");
|
|
646
|
+
const gitignore = `# Dependencies
|
|
647
|
+
/node_modules
|
|
648
|
+
|
|
649
|
+
# Production
|
|
650
|
+
/build
|
|
651
|
+
|
|
652
|
+
# Generated files
|
|
653
|
+
.astro
|
|
654
|
+
out
|
|
655
|
+
dist
|
|
656
|
+
|
|
657
|
+
# Misc
|
|
658
|
+
.DS_Store
|
|
659
|
+
.env.local
|
|
660
|
+
.env.development.local
|
|
661
|
+
.env.test.local
|
|
662
|
+
.env.production.local
|
|
663
|
+
|
|
664
|
+
npm-debug.log*
|
|
665
|
+
yarn-debug.log*
|
|
666
|
+
yarn-error.log*
|
|
667
|
+
|
|
668
|
+
.eventcatalog-core
|
|
669
|
+
|
|
670
|
+
.env
|
|
671
|
+
.env-*
|
|
672
|
+
`;
|
|
673
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, ".gitignore"), gitignore, "utf-8");
|
|
674
|
+
const envFile = `# EventCatalog Scale License Key, if you want to unlock the scale features
|
|
675
|
+
# You can get a 14 day trial license key from https://eventcatalog.cloud
|
|
676
|
+
|
|
677
|
+
EVENTCATALOG_SCALE_LICENSE_KEY=
|
|
678
|
+
|
|
679
|
+
# Optional key if you are using EventCatalog Chat with OpenAI Models.
|
|
680
|
+
# You need to set \`output\` to \`server\` in your eventcatalog.config.js file.
|
|
681
|
+
# See documentation for more details: https://www.eventcatalog.dev/features/ai-assistant
|
|
682
|
+
OPENAI_API_KEY=
|
|
683
|
+
`;
|
|
684
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, ".env"), envFile, "utf-8");
|
|
685
|
+
(0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, ".npmrc"), "strict-peer-dependencies=false\n", "utf-8");
|
|
686
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path2.join)(catalogDir, "public"), { recursive: true });
|
|
687
|
+
(0, import_node_fs3.copyFileSync)((0, import_node_path2.join)(__dirname, "logo.png"), (0, import_node_path2.join)(catalogDir, "public", "logo.png"));
|
|
688
|
+
}
|
|
689
|
+
async function importDSL(options) {
|
|
690
|
+
const { files, stdin = false, dryRun = false, flat = false, noInit = false, dir } = options;
|
|
691
|
+
const nested = !flat;
|
|
692
|
+
let source;
|
|
693
|
+
if (stdin) {
|
|
694
|
+
source = await readStdin();
|
|
695
|
+
} else if (files && files.length > 0) {
|
|
696
|
+
const parts = [];
|
|
697
|
+
for (const file of files) {
|
|
698
|
+
const filepath = (0, import_node_path2.resolve)(file);
|
|
699
|
+
if (!(0, import_node_fs3.existsSync)(filepath)) {
|
|
700
|
+
throw new Error(`File not found: ${filepath}`);
|
|
701
|
+
}
|
|
702
|
+
parts.push((0, import_node_fs3.readFileSync)(filepath, "utf-8"));
|
|
703
|
+
}
|
|
704
|
+
source = parts.join("\n\n");
|
|
705
|
+
} else {
|
|
706
|
+
throw new Error("Either provide .ec file paths or use --stdin");
|
|
707
|
+
}
|
|
708
|
+
if (!source.trim()) {
|
|
709
|
+
throw new Error("No DSL content to import");
|
|
710
|
+
}
|
|
711
|
+
const catalogDir = (0, import_node_path2.resolve)(dir);
|
|
712
|
+
let didInit = false;
|
|
713
|
+
if (!noInit && !(0, import_node_fs3.existsSync)((0, import_node_path2.join)(catalogDir, "eventcatalog.config.js")) && process.stdin.isTTY) {
|
|
714
|
+
const confirmed = await promptConfirm(`Initialize a new EventCatalog at ${catalogDir}? (Y/n)`);
|
|
715
|
+
if (confirmed) {
|
|
716
|
+
const organizationName = await promptInput("Organization name (My Organization):", "My Organization");
|
|
717
|
+
initCatalog(dir, organizationName);
|
|
718
|
+
didInit = true;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
const outputs = await parseDSL(source, { nested });
|
|
722
|
+
if (outputs.length === 0) {
|
|
723
|
+
throw new Error("No resources found in DSL content");
|
|
724
|
+
}
|
|
725
|
+
const sdk = (0, import_sdk4.default)(catalogDir);
|
|
726
|
+
const result = { created: [], updated: [], versioned: [], errors: [] };
|
|
727
|
+
const resources = outputs.map(parseCompiledOutput);
|
|
728
|
+
const compiledIds = new Set(resources.map((r) => `${r.type}:${r.id}`));
|
|
729
|
+
const stubs = await extractMessageStubs(source, compiledIds, nested);
|
|
730
|
+
resources.push(...stubs);
|
|
731
|
+
for (const resource of resources) {
|
|
732
|
+
const label = resource.version ? `${resource.type} ${resource.id}@${resource.version}` : `${resource.type} ${resource.id}`;
|
|
733
|
+
if (dryRun) {
|
|
734
|
+
const reader = getReader(sdk, resource.type);
|
|
735
|
+
if (reader) {
|
|
736
|
+
const existing = await reader(resource.id, resource.version).catch(() => void 0);
|
|
737
|
+
if (existing) {
|
|
738
|
+
result.updated.push(label);
|
|
739
|
+
} else {
|
|
740
|
+
const latest = await reader(resource.id).catch(() => void 0);
|
|
741
|
+
if (latest && latest.version && latest.version !== resource.version) {
|
|
742
|
+
result.versioned.push(`${resource.type} ${resource.id}@${latest.version}`);
|
|
743
|
+
}
|
|
744
|
+
result.created.push(label);
|
|
745
|
+
}
|
|
746
|
+
} else {
|
|
747
|
+
result.created.push(label);
|
|
748
|
+
}
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
const writer = getWriter(sdk, resource.type);
|
|
752
|
+
if (!writer) {
|
|
753
|
+
result.errors.push(`${label}: unsupported resource type '${resource.type}'`);
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
try {
|
|
757
|
+
const reader = getReader(sdk, resource.type);
|
|
758
|
+
const existing = reader ? await reader(resource.id, resource.version).catch(() => void 0) : void 0;
|
|
759
|
+
let markdown = resource.markdown;
|
|
760
|
+
if (!existing && TYPES_WITH_NODE_GRAPH.has(resource.type)) {
|
|
761
|
+
markdown = markdown ? `${markdown}
|
|
762
|
+
|
|
763
|
+
<NodeGraph />` : "<NodeGraph />";
|
|
764
|
+
}
|
|
765
|
+
const resourceData = {
|
|
766
|
+
...resource.frontmatter,
|
|
767
|
+
markdown
|
|
768
|
+
};
|
|
769
|
+
const writeOptions = {
|
|
770
|
+
override: true,
|
|
771
|
+
versionExistingContent: true
|
|
772
|
+
};
|
|
773
|
+
if (!existing && nested) {
|
|
774
|
+
const sdkPath = extractSdkPath(resource.path, resource.type);
|
|
775
|
+
if (sdkPath) {
|
|
776
|
+
writeOptions.path = sdkPath;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
await writer(resourceData, writeOptions);
|
|
780
|
+
if (existing) {
|
|
781
|
+
result.updated.push(label);
|
|
782
|
+
} else {
|
|
783
|
+
result.created.push(label);
|
|
784
|
+
}
|
|
785
|
+
} catch (error) {
|
|
786
|
+
result.errors.push(`${label}: ${error instanceof Error ? error.message : String(error)}`);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
let output = formatResult(result, dryRun);
|
|
790
|
+
if (didInit) {
|
|
791
|
+
output += ` Tip: Run 'npm install' in ${catalogDir} to install dependencies
|
|
792
|
+
`;
|
|
793
|
+
}
|
|
794
|
+
return output;
|
|
795
|
+
}
|
|
796
|
+
var c = {
|
|
797
|
+
reset: "\x1B[0m",
|
|
798
|
+
bold: "\x1B[1m",
|
|
799
|
+
dim: "\x1B[2m",
|
|
800
|
+
green: "\x1B[32m",
|
|
801
|
+
yellow: "\x1B[33m",
|
|
802
|
+
blue: "\x1B[34m",
|
|
803
|
+
magenta: "\x1B[35m",
|
|
804
|
+
cyan: "\x1B[36m",
|
|
805
|
+
red: "\x1B[31m",
|
|
806
|
+
white: "\x1B[37m",
|
|
807
|
+
gray: "\x1B[90m"
|
|
808
|
+
};
|
|
809
|
+
var TYPE_CONFIG = {
|
|
810
|
+
domain: { color: c.magenta, label: "domain", order: 0 },
|
|
811
|
+
service: { color: c.blue, label: "service", order: 1 },
|
|
812
|
+
event: { color: c.green, label: "event", order: 2 },
|
|
813
|
+
command: { color: c.yellow, label: "command", order: 3 },
|
|
814
|
+
query: { color: c.cyan, label: "query", order: 4 },
|
|
815
|
+
channel: { color: c.gray, label: "channel", order: 5 },
|
|
816
|
+
flow: { color: c.white, label: "flow", order: 6 },
|
|
817
|
+
user: { color: c.blue, label: "user", order: 7 },
|
|
818
|
+
team: { color: c.blue, label: "team", order: 8 }
|
|
819
|
+
};
|
|
820
|
+
var DEFAULT_TYPE_CONFIG = { color: c.white, label: "resource", order: 99 };
|
|
821
|
+
function parseLabel(label) {
|
|
822
|
+
const spaceIdx = label.indexOf(" ");
|
|
823
|
+
if (spaceIdx === -1) return { type: "", name: label };
|
|
824
|
+
return { type: label.slice(0, spaceIdx), name: label.slice(spaceIdx + 1) };
|
|
825
|
+
}
|
|
826
|
+
function groupByType(labels) {
|
|
827
|
+
const groups = /* @__PURE__ */ new Map();
|
|
828
|
+
for (const label of labels) {
|
|
829
|
+
const { type, name } = parseLabel(label);
|
|
830
|
+
if (!groups.has(type)) groups.set(type, []);
|
|
831
|
+
groups.get(type).push(name);
|
|
832
|
+
}
|
|
833
|
+
const sorted = new Map(
|
|
834
|
+
[...groups.entries()].sort((a, b) => {
|
|
835
|
+
const orderA = (TYPE_CONFIG[a[0]] || DEFAULT_TYPE_CONFIG).order;
|
|
836
|
+
const orderB = (TYPE_CONFIG[b[0]] || DEFAULT_TYPE_CONFIG).order;
|
|
837
|
+
return orderA - orderB;
|
|
838
|
+
})
|
|
839
|
+
);
|
|
840
|
+
for (const [, names] of sorted) {
|
|
841
|
+
names.sort();
|
|
842
|
+
}
|
|
843
|
+
return sorted;
|
|
844
|
+
}
|
|
845
|
+
function typeBadge(type) {
|
|
846
|
+
const cfg = TYPE_CONFIG[type] || DEFAULT_TYPE_CONFIG;
|
|
847
|
+
const padded = ` ${cfg.label} `;
|
|
848
|
+
return `${cfg.color}\x1B[7m${padded}${c.reset}`;
|
|
849
|
+
}
|
|
850
|
+
function formatResourceList(labels) {
|
|
851
|
+
const lines = [];
|
|
852
|
+
const groups = groupByType(labels);
|
|
853
|
+
for (const [type, names] of groups) {
|
|
854
|
+
const cfg = TYPE_CONFIG[type] || DEFAULT_TYPE_CONFIG;
|
|
855
|
+
const plural = names.length === 1 ? cfg.label : `${cfg.label}s`;
|
|
856
|
+
lines.push("");
|
|
857
|
+
lines.push(` ${typeBadge(type)} ${c.dim}${names.length} ${plural}${c.reset}`);
|
|
858
|
+
for (const name of names) {
|
|
859
|
+
lines.push(` ${cfg.color}\u2502${c.reset} ${name}`);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
return lines;
|
|
863
|
+
}
|
|
864
|
+
function formatResult(result, dryRun) {
|
|
865
|
+
const lines = [""];
|
|
866
|
+
const prefix = dryRun ? `${c.yellow}${c.bold}DRY RUN${c.reset} ` : "";
|
|
867
|
+
const total = result.created.length + result.updated.length + result.versioned.length;
|
|
868
|
+
if (total > 0 || result.errors.length > 0) {
|
|
869
|
+
lines.push(` ${prefix}${c.bold}Import complete${c.reset}`);
|
|
870
|
+
lines.push(` ${c.dim}${"\u2500".repeat(40)}${c.reset}`);
|
|
871
|
+
}
|
|
872
|
+
if (result.created.length > 0) {
|
|
873
|
+
const verb = dryRun ? "Would create" : "Created";
|
|
874
|
+
lines.push("");
|
|
875
|
+
lines.push(` ${c.green}${c.bold}+ ${verb} ${result.created.length} resource(s)${c.reset}`);
|
|
876
|
+
lines.push(...formatResourceList(result.created));
|
|
877
|
+
}
|
|
878
|
+
if (result.updated.length > 0) {
|
|
879
|
+
const verb = dryRun ? "Would update" : "Updated";
|
|
880
|
+
lines.push("");
|
|
881
|
+
lines.push(` ${c.blue}${c.bold}~ ${verb} ${result.updated.length} resource(s)${c.reset}`);
|
|
882
|
+
lines.push(...formatResourceList(result.updated));
|
|
883
|
+
}
|
|
884
|
+
if (result.versioned.length > 0) {
|
|
885
|
+
const verb = dryRun ? "Would version" : "Versioned";
|
|
886
|
+
lines.push("");
|
|
887
|
+
lines.push(` ${c.yellow}${c.bold}\u2191 ${verb} ${result.versioned.length} existing resource(s)${c.reset}`);
|
|
888
|
+
lines.push(...formatResourceList(result.versioned));
|
|
889
|
+
}
|
|
890
|
+
if (result.errors.length > 0) {
|
|
891
|
+
lines.push("");
|
|
892
|
+
lines.push(` ${c.red}${c.bold}\u2718 ${result.errors.length} error(s)${c.reset}`);
|
|
893
|
+
for (const e of result.errors) {
|
|
894
|
+
lines.push(` ${c.red}\u2502${c.reset} ${c.red}${e}${c.reset}`);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (result.created.length === 0 && result.updated.length === 0 && result.errors.length === 0) {
|
|
898
|
+
lines.push(` ${c.dim}No resources to write.${c.reset}`);
|
|
899
|
+
}
|
|
900
|
+
lines.push("");
|
|
901
|
+
return lines.join("\n");
|
|
902
|
+
}
|
|
903
|
+
function readStdin() {
|
|
904
|
+
return new Promise((resolve4, reject) => {
|
|
905
|
+
const chunks = [];
|
|
906
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
907
|
+
process.stdin.on("end", () => resolve4(Buffer.concat(chunks).toString("utf-8")));
|
|
908
|
+
process.stdin.on("error", reject);
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
|
|
355
912
|
// src/cli/index.ts
|
|
356
913
|
var version = "1.0.0";
|
|
357
914
|
try {
|
|
358
|
-
const packageJsonPath = (0,
|
|
359
|
-
const packageJson = JSON.parse((0,
|
|
915
|
+
const packageJsonPath = (0, import_node_path3.resolve)(__dirname, "../../package.json");
|
|
916
|
+
const packageJson = JSON.parse((0, import_node_fs4.readFileSync)(packageJsonPath, "utf-8"));
|
|
360
917
|
version = packageJson.version;
|
|
361
918
|
} catch {
|
|
362
919
|
}
|
|
@@ -406,6 +963,24 @@ import_commander.program.command("export").description("Export a catalog resourc
|
|
|
406
963
|
process.exit(1);
|
|
407
964
|
}
|
|
408
965
|
});
|
|
966
|
+
import_commander.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) => {
|
|
967
|
+
try {
|
|
968
|
+
const globalOpts = import_commander.program.opts();
|
|
969
|
+
const dir = globalOpts.dir || ".";
|
|
970
|
+
const result = await importDSL({
|
|
971
|
+
files: files.length > 0 ? files : void 0,
|
|
972
|
+
stdin: opts.stdin,
|
|
973
|
+
dryRun: opts.dryRun,
|
|
974
|
+
flat: opts.flat,
|
|
975
|
+
noInit: !opts.init,
|
|
976
|
+
dir
|
|
977
|
+
});
|
|
978
|
+
console.log(result);
|
|
979
|
+
} catch (error) {
|
|
980
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
981
|
+
process.exit(1);
|
|
982
|
+
}
|
|
983
|
+
});
|
|
409
984
|
import_commander.program.arguments("<function> [args...]").action(async (functionName, args) => {
|
|
410
985
|
try {
|
|
411
986
|
const options = import_commander.program.opts();
|