[verified] feat: add semantic diagram lifecycle
This commit is contained in:
@@ -22,13 +22,14 @@
|
||||
|
||||
import { parseArgs } from "node:util";
|
||||
import * as yaml from "js-yaml";
|
||||
import type { LifecycleActionOptions } from "../services/semantic-lifecycle/lifecycle-io.js";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Action registry
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type ActionModule = {
|
||||
run: (filePath: string, pageIndex?: number, outputPath?: string) => Record<string, unknown>;
|
||||
run: (filePath: string, pageIndex?: number, outputPath?: string, options?: LifecycleActionOptions) => Record<string, unknown>;
|
||||
};
|
||||
|
||||
const ACTIONS: Record<string, () => Promise<ActionModule>> = {
|
||||
@@ -46,6 +47,15 @@ const ACTIONS: Record<string, () => Promise<ActionModule>> = {
|
||||
"page-negative-space-summary":() => import("../actions/page-negative-space-summary/action.js"),
|
||||
"validate": () => import("../actions/validate/action.js"),
|
||||
"quality": () => import("../actions/quality/action.js"),
|
||||
"import": () => import("../actions/import/action.js"),
|
||||
"edit": () => import("../actions/edit/action.js"),
|
||||
"views": () => import("../actions/views/action.js"),
|
||||
"query": () => import("../actions/query/action.js"),
|
||||
"test": () => import("../actions/test/action.js"),
|
||||
"what-if": () => import("../actions/what-if/action.js"),
|
||||
"sync": () => import("../actions/sync/action.js"),
|
||||
"story": () => import("../actions/story/action.js"),
|
||||
"doctor": () => import("../actions/doctor/action.js"),
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -53,7 +63,7 @@ const ACTIONS: Record<string, () => Promise<ActionModule>> = {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function main(): Promise<void> {
|
||||
let values: { file?: string; action?: string; page?: string; output?: string; help?: boolean };
|
||||
let values: { file?: string; action?: string; page?: string; output?: string; help?: boolean; spec?: string; base?: string; strict?: boolean; prune?: boolean; "dry-run"?: boolean; fail?: string; views?: string; kind?: string; property?: string[]; from?: string; to?: string };
|
||||
try {
|
||||
({ values } = parseArgs({
|
||||
args: process.argv.slice(2),
|
||||
@@ -62,6 +72,17 @@ async function main(): Promise<void> {
|
||||
action: { type: "string", short: "a" },
|
||||
page: { type: "string", short: "p" },
|
||||
output: { type: "string", short: "o" },
|
||||
spec: { type: "string" },
|
||||
base: { type: "string" },
|
||||
strict: { type: "boolean" },
|
||||
prune: { type: "boolean" },
|
||||
"dry-run": { type: "boolean" },
|
||||
fail: { type: "string" },
|
||||
views: { type: "string" },
|
||||
kind: { type: "string" },
|
||||
property: { type: "string", multiple: true },
|
||||
from: { type: "string" },
|
||||
to: { type: "string" },
|
||||
help: { type: "boolean", short: "h" },
|
||||
},
|
||||
strict: true,
|
||||
@@ -74,11 +95,25 @@ async function main(): Promise<void> {
|
||||
if (values.help) {
|
||||
console.log(`drawio-tools --file <path> --action <action> [--page <index>] [--output <path>]
|
||||
|
||||
Lifecycle options:
|
||||
--spec <path> Edit batch, policy list, or incoming sync model
|
||||
--base <path> Previous generated model for three-way sync
|
||||
--strict Treat policy warnings as failures
|
||||
--prune Remove identities absent from incoming sync model
|
||||
--dry-run Return edit/sync preview without writing
|
||||
--fail <node-id> Failed node for what-if or story overlay
|
||||
--views <csv> executive,system,deployment,dataflow,security
|
||||
--kind <kind> Query node kind
|
||||
--property k=v Repeatable exact property query
|
||||
--from <node-id> Directed path start (use with --to)
|
||||
--to <node-id> Directed path destination (use with --from)
|
||||
|
||||
Doctor does not require --file.
|
||||
Actions: ${Object.keys(ACTIONS).join(", ")}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!values.file) {
|
||||
if (!values.file && values.action !== "doctor") {
|
||||
printError("Missing required argument: --file");
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -88,7 +123,7 @@ Actions: ${Object.keys(ACTIONS).join(", ")}`);
|
||||
}
|
||||
|
||||
const actionName = values.action;
|
||||
const filePath = values.file;
|
||||
const filePath = values.file ?? "";
|
||||
|
||||
// Parse optional --page argument (0-based index, default 0)
|
||||
let pageIndex = 0;
|
||||
@@ -113,7 +148,11 @@ Actions: ${Object.keys(ACTIONS).join(", ")}`);
|
||||
|
||||
try {
|
||||
const mod = await ACTIONS[actionName]();
|
||||
const result = mod.run(filePath, pageIndex, values.output);
|
||||
const result = mod.run(filePath, pageIndex, values.output, {
|
||||
spec: values.spec, base: values.base, strict: values.strict, prune: values.prune,
|
||||
dryRun: values["dry-run"], fail: values.fail, views: values.views, kind: values.kind,
|
||||
property: values.property, from: values.from, to: values.to,
|
||||
});
|
||||
process.stdout.write(
|
||||
yaml.dump(result, { noRefs: true, sortKeys: false, lineWidth: 120 })
|
||||
);
|
||||
@@ -121,6 +160,7 @@ Actions: ${Object.keys(ACTIONS).join(", ")}`);
|
||||
if (actionName === "validate" && summary && typeof summary === "object" && (summary as Record<string, unknown>).valid === false) {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
if (result.failed === true) process.exitCode = 1;
|
||||
} catch (err) {
|
||||
const errorOutput = {
|
||||
error: true,
|
||||
|
||||
Reference in New Issue
Block a user