Restructure to skill-manager conventions
- Move the TypeScript project under scripts/ (src, tsconfig, package.json, pnpm lockfile/workspace, canonical .gitignore); drop the npm package-lock - Add scripts/Taskfile.yml aggregator plus .scripts modules (loggers, base, cli) with build, run, and validate tasks - Move the six SKILL-*.md docs into references/ with kebab names and extract the connector-routing sections from SKILL.md into references/routing-best-practices.md (SKILL.md 666 -> ~310 lines) - Add license/metadata/compatibility frontmatter, an Available scripts section, and update all CLI paths in README and references skill-manager validate: 13/13 passed, 0 warnings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* drawio-tools CLI dispatcher
|
||||
*
|
||||
* Usage:
|
||||
* drawio-tools --file <path-to-drawio> --action <action-name> [--page <index>]
|
||||
*
|
||||
* Actions:
|
||||
* summary — inventory of all shapes and edges for every page in the file
|
||||
* page-summary — inventory of shapes and edges for a single page (use --page, default 0)
|
||||
* page-hierarchy — containment tree of shapes (layers → subsystems → components)
|
||||
* page-connectors-summary — summary of all connectors with type, labels, waypoints
|
||||
* page-connectors-validation — detect connector-shape overlaps and connector crossings
|
||||
* page-labels-validation — detect empty, duplicate, or overly long shape labels
|
||||
* page-shape-bbox-validation — detect non-containment bounding box overlaps between shapes
|
||||
* page-orphans — find isolated shapes and dangling connectors
|
||||
* page-recommendations — bounding box analysis and page size recommendation
|
||||
* page-negative-space-summary — free horizontal corridors (negative space) per nesting level
|
||||
*
|
||||
* Output is always YAML to stdout. Exit 0 on success, 1 on error.
|
||||
*/
|
||||
|
||||
import { parseArgs } from "node:util";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Action registry
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type ActionModule = {
|
||||
run: (filePath: string, pageIndex?: number) => Record<string, unknown>;
|
||||
};
|
||||
|
||||
const ACTIONS: Record<string, () => Promise<ActionModule>> = {
|
||||
"summary": () => import("../actions/summary/action.js"),
|
||||
"page-summary": () => import("../actions/page-summary/action.js"),
|
||||
"page-hierarchy": () => import("../actions/page-hierarchy/action.js"),
|
||||
"page-connectors-summary": () => import("../actions/page-connectors-summary/action.js"),
|
||||
"page-connectors-validation": () => import("../actions/page-connectors-validation/action.js"),
|
||||
"page-labels-validation": () => import("../actions/page-labels-validation/action.js"),
|
||||
"page-shape-bbox-validation": () => import("../actions/page-shape-bbox-validation/action.js"),
|
||||
"page-orphans": () => import("../actions/page-orphans/action.js"),
|
||||
"page-recommendations": () => import("../actions/page-recommendations/action.js"),
|
||||
"page-hierarchy-full": () => import("../actions/page-hierarchy-full/action.js"),
|
||||
"page-negative-space-summary":() => import("../actions/page-negative-space-summary/action.js"),
|
||||
"validate": () => import("../actions/validate/action.js"),
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// CLI
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function main(): Promise<void> {
|
||||
let values: { file?: string; action?: string; page?: string; help?: boolean };
|
||||
try {
|
||||
({ values } = parseArgs({
|
||||
args: process.argv.slice(2),
|
||||
options: {
|
||||
file: { type: "string", short: "f" },
|
||||
action: { type: "string", short: "a" },
|
||||
page: { type: "string", short: "p" },
|
||||
help: { type: "boolean", short: "h" },
|
||||
},
|
||||
strict: true,
|
||||
}));
|
||||
} catch (err) {
|
||||
printError(String(err));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (values.help) {
|
||||
console.log(`drawio-tools --file <path> --action <action> [--page <index>]
|
||||
|
||||
Actions: ${Object.keys(ACTIONS).join(", ")}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!values.file) {
|
||||
printError("Missing required argument: --file");
|
||||
process.exit(1);
|
||||
}
|
||||
if (!values.action) {
|
||||
printError("Missing required argument: --action");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const actionName = values.action;
|
||||
const filePath = values.file;
|
||||
|
||||
// Parse optional --page argument (0-based index, default 0)
|
||||
let pageIndex = 0;
|
||||
if (values.page !== undefined) {
|
||||
pageIndex = parseInt(values.page, 10);
|
||||
if (isNaN(pageIndex) || pageIndex < 0) {
|
||||
printError(`--page must be a non-negative integer, got: ${values.page}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ACTIONS[actionName]) {
|
||||
printError(
|
||||
`Unknown action '${actionName}'. Available: ${Object.keys(ACTIONS).join(", ")}`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
const mod = await ACTIONS[actionName]();
|
||||
const result = mod.run(filePath, pageIndex);
|
||||
process.stdout.write(
|
||||
yaml.dump(result, { noRefs: true, sortKeys: false, lineWidth: 120 })
|
||||
);
|
||||
} catch (err) {
|
||||
const errorOutput = {
|
||||
error: true,
|
||||
action: actionName,
|
||||
file: filePath,
|
||||
message: err instanceof Error ? err.message : String(err),
|
||||
stack: err instanceof Error ? err.stack : undefined,
|
||||
};
|
||||
process.stdout.write(yaml.dump(errorOutput, { noRefs: true, sortKeys: false }));
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function printError(msg: string): void {
|
||||
process.stderr.write(`Error: ${msg}\n`);
|
||||
process.stderr.write(
|
||||
`Usage: drawio-tools --file <path> --action <${Object.keys(ACTIONS).join("|")}> [--page <index>]\n`
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user