diff --git a/understand-anything-plugin/packages/core/src/__tests__/domain-types.test.ts b/understand-anything-plugin/packages/core/src/__tests__/domain-types.test.ts new file mode 100644 index 0000000..b0a1051 --- /dev/null +++ b/understand-anything-plugin/packages/core/src/__tests__/domain-types.test.ts @@ -0,0 +1,141 @@ +import { describe, it, expect } from "vitest"; +import { validateGraph } from "../schema.js"; +import type { KnowledgeGraph } from "../types.js"; + +const domainGraph: KnowledgeGraph = { + version: "1.0.0", + project: { + name: "test-project", + languages: ["typescript"], + frameworks: [], + description: "A test project", + analyzedAt: "2026-04-01T00:00:00.000Z", + gitCommitHash: "abc123", + }, + nodes: [ + { + id: "domain:order-management", + type: "domain", + name: "Order Management", + summary: "Handles order lifecycle", + tags: ["core"], + complexity: "complex", + }, + { + id: "flow:create-order", + type: "flow", + name: "Create Order", + summary: "Customer submits a new order", + tags: ["write-path"], + complexity: "moderate", + domainMeta: { + entryPoint: "POST /api/orders", + entryType: "http", + }, + }, + { + id: "step:create-order:validate", + type: "step", + name: "Validate Input", + summary: "Checks request body", + tags: ["validation"], + complexity: "simple", + filePath: "src/validators/order.ts", + lineRange: [10, 30], + }, + ], + edges: [ + { + source: "domain:order-management", + target: "flow:create-order", + type: "contains_flow", + direction: "forward", + weight: 1.0, + }, + { + source: "flow:create-order", + target: "step:create-order:validate", + type: "flow_step", + direction: "forward", + weight: 0.1, + }, + ], + layers: [], + tour: [], +}; + +describe("domain graph types", () => { + it("validates a domain graph with domain/flow/step node types", () => { + const result = validateGraph(domainGraph); + expect(result.success).toBe(true); + expect(result.data).toBeDefined(); + expect(result.data!.nodes).toHaveLength(3); + expect(result.data!.edges).toHaveLength(2); + }); + + it("validates contains_flow edge type", () => { + const result = validateGraph(domainGraph); + expect(result.success).toBe(true); + expect(result.data!.edges[0].type).toBe("contains_flow"); + }); + + it("validates flow_step edge type", () => { + const result = validateGraph(domainGraph); + expect(result.success).toBe(true); + expect(result.data!.edges[1].type).toBe("flow_step"); + }); + + it("validates cross_domain edge type", () => { + const graph = structuredClone(domainGraph); + graph.nodes.push({ + id: "domain:logistics", + type: "domain", + name: "Logistics", + summary: "Handles shipping", + tags: [], + complexity: "moderate", + }); + graph.edges.push({ + source: "domain:order-management", + target: "domain:logistics", + type: "cross_domain", + direction: "forward", + description: "Triggers on order confirmed", + weight: 0.6, + }); + const result = validateGraph(graph); + expect(result.success).toBe(true); + }); + + it("normalizes domain type aliases", () => { + const graph = structuredClone(domainGraph); + (graph.nodes[0] as any).type = "business_domain"; + (graph.nodes[1] as any).type = "workflow"; + (graph.nodes[2] as any).type = "action"; + const result = validateGraph(graph); + expect(result.success).toBe(true); + expect(result.data!.nodes[0].type).toBe("domain"); + expect(result.data!.nodes[1].type).toBe("flow"); + expect(result.data!.nodes[2].type).toBe("step"); + }); + + it("normalizes domain edge type aliases", () => { + const graph = structuredClone(domainGraph); + (graph.edges[0] as any).type = "has_flow"; + (graph.edges[1] as any).type = "next_step"; + const result = validateGraph(graph); + expect(result.success).toBe(true); + expect(result.data!.edges[0].type).toBe("contains_flow"); + expect(result.data!.edges[1].type).toBe("flow_step"); + }); + + it("preserves domainMeta on nodes through validation", () => { + const result = validateGraph(domainGraph); + expect(result.success).toBe(true); + const flowNode = result.data!.nodes.find((n) => n.id === "flow:create-order"); + expect((flowNode as any).domainMeta).toEqual({ + entryPoint: "POST /api/orders", + entryType: "http", + }); + }); +}); diff --git a/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts b/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts index 2ea911a..7b3c440 100644 --- a/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts +++ b/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts @@ -686,11 +686,11 @@ describe("Extended node/edge types", () => { } }); - it("auto-fixes new node type aliases: container->service, doc->document, workflow->pipeline, etc.", () => { + it("auto-fixes new node type aliases: container->service, doc->document, workflow->flow, etc.", () => { const aliases: Record = { container: "service", doc: "document", - workflow: "pipeline", + workflow: "flow", route: "endpoint", setting: "config", infra: "resource", diff --git a/understand-anything-plugin/packages/core/src/schema.ts b/understand-anything-plugin/packages/core/src/schema.ts index 5b9ad1a..8839d33 100644 --- a/understand-anything-plugin/packages/core/src/schema.ts +++ b/understand-anything-plugin/packages/core/src/schema.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -// Edge types (26 values across 6 categories) +// Edge types (29 values across 7 categories) export const EdgeTypeSchema = z.enum([ "imports", "exports", "contains", "inherits", "implements", // Structural "calls", "subscribes", "publishes", "middleware", // Behavioral @@ -9,6 +9,7 @@ export const EdgeTypeSchema = z.enum([ "related", "similar_to", // Semantic "deploys", "serves", "provisions", "triggers", // Infrastructure "migrates", "documents", "routes", "defines_schema", // Schema/Data + "contains_flow", "flow_step", "cross_domain", // Domain ]); // Aliases that LLMs commonly generate instead of canonical node types @@ -28,10 +29,8 @@ export const NODE_TYPE_ALIASES: Record = { doc: "document", readme: "document", docs: "document", - workflow: "pipeline", job: "pipeline", ci: "pipeline", - action: "pipeline", route: "endpoint", api: "endpoint", query: "endpoint", @@ -50,6 +49,12 @@ export const NODE_TYPE_ALIASES: Record = { protobuf: "schema", definition: "schema", typedef: "schema", + // Domain aliases + business_domain: "domain", + process: "flow", + workflow: "flow", + action: "step", + task: "step", }; // Aliases that LLMs commonly generate instead of canonical edge types @@ -79,6 +84,11 @@ export const EDGE_TYPE_ALIASES: Record = { triggers_on: "triggers", fires: "triggers", defines: "defines_schema", + // Domain aliases + has_flow: "contains_flow", + next_step: "flow_step", + interacts_with: "cross_domain", + implemented_by: "implements", }; // Aliases for complexity values LLMs commonly generate @@ -313,6 +323,7 @@ export const GraphNodeSchema = z.object({ "file", "function", "class", "module", "concept", "config", "document", "service", "table", "endpoint", "pipeline", "schema", "resource", + "domain", "flow", "step", ]), name: z.string(), filePath: z.string().optional(), @@ -321,7 +332,7 @@ export const GraphNodeSchema = z.object({ tags: z.array(z.string()), complexity: z.enum(["simple", "moderate", "complex"]), languageNotes: z.string().optional(), -}); +}).passthrough(); export const GraphEdgeSchema = z.object({ source: z.string(), diff --git a/understand-anything-plugin/packages/core/src/types.ts b/understand-anything-plugin/packages/core/src/types.ts index ab92cd7..106f25e 100644 --- a/understand-anything-plugin/packages/core/src/types.ts +++ b/understand-anything-plugin/packages/core/src/types.ts @@ -1,10 +1,11 @@ -// Node types (13 total: 5 code + 8 non-code) +// Node types (16 total: 5 code + 8 non-code + 3 domain) export type NodeType = | "file" | "function" | "class" | "module" | "concept" | "config" | "document" | "service" | "table" | "endpoint" - | "pipeline" | "schema" | "resource"; + | "pipeline" | "schema" | "resource" + | "domain" | "flow" | "step"; -// Edge types (26 total in 6 categories: Structural, Behavioral, Data flow, Dependencies, Semantic, Infrastructure/Schema) +// Edge types (29 total in 7 categories: Structural, Behavioral, Data flow, Dependencies, Semantic, Infrastructure/Schema, Domain) export type EdgeType = | "imports" | "exports" | "contains" | "inherits" | "implements" // Structural | "calls" | "subscribes" | "publishes" | "middleware" // Behavioral @@ -12,9 +13,19 @@ export type EdgeType = | "depends_on" | "tested_by" | "configures" // Dependencies | "related" | "similar_to" // Semantic | "deploys" | "serves" | "provisions" | "triggers" // Infrastructure - | "migrates" | "documents" | "routes" | "defines_schema"; // Schema/Data + | "migrates" | "documents" | "routes" | "defines_schema" // Schema/Data + | "contains_flow" | "flow_step" | "cross_domain"; // Domain -// GraphNode with 13 types: 5 code + 8 non-code +// Optional domain metadata for domain/flow/step nodes +export interface DomainMeta { + entities?: string[]; + businessRules?: string[]; + crossDomainInteractions?: string[]; + entryPoint?: string; + entryType?: "http" | "cli" | "event" | "cron" | "manual"; +} + +// GraphNode with 16 types: 5 code + 8 non-code + 3 domain export interface GraphNode { id: string; type: NodeType; @@ -25,6 +36,7 @@ export interface GraphNode { tags: string[]; complexity: "simple" | "moderate" | "complex"; languageNotes?: string; + domainMeta?: DomainMeta; } // GraphEdge with rich relationship modeling