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 0504557..fe5e205 100644 --- a/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts +++ b/understand-anything-plugin/packages/core/src/__tests__/schema.test.ts @@ -662,3 +662,61 @@ describe("permissive validation", () => { expect(result.errors).toContain('edges[0]: target "non-existent-node" does not exist in nodes — removed'); }); }); + +describe("Extended node/edge types", () => { + it("validates nodes with new types: config, document, service, table, endpoint, pipeline, schema, resource", () => { + const newTypes = ["config", "document", "service", "table", "endpoint", "pipeline", "schema", "resource"]; + for (const type of newTypes) { + const graph = structuredClone(validGraph); + (graph.nodes[0] as any).type = type; + const result = validateGraph(graph); + expect(result.success).toBe(true); + expect(result.data!.nodes[0].type).toBe(type); + } + }); + + it("validates edges with new types: deploys, serves, migrates, documents, provisions, routes, defines_schema, triggers", () => { + const newTypes = ["deploys", "serves", "migrates", "documents", "provisions", "routes", "defines_schema", "triggers"]; + for (const type of newTypes) { + const graph = structuredClone(validGraph); + (graph.edges[0] as any).type = type; + const result = validateGraph(graph); + expect(result.success).toBe(true); + expect(result.data!.edges[0].type).toBe(type); + } + }); + + it("auto-fixes new node type aliases: container->service, doc->document, workflow->pipeline, etc.", () => { + const aliases: Record = { + container: "service", + doc: "document", + workflow: "pipeline", + route: "endpoint", + setting: "config", + infra: "resource", + migration: "table", + }; + for (const [alias, canonical] of Object.entries(aliases)) { + const graph = structuredClone(validGraph); + (graph.nodes[0] as any).type = alias; + const result = validateGraph(graph); + expect(result.success).toBe(true); + expect(result.data!.nodes[0].type).toBe(canonical); + } + }); + + it("auto-fixes new edge type aliases: describes->documents, creates->provisions, exposes->serves", () => { + const aliases: Record = { + describes: "documents", + creates: "provisions", + exposes: "serves", + }; + for (const [alias, canonical] of Object.entries(aliases)) { + const graph = structuredClone(validGraph); + (graph.edges[0] as any).type = alias; + const result = validateGraph(graph); + expect(result.success).toBe(true); + expect(result.data!.edges[0].type).toBe(canonical); + } + }); +}); diff --git a/understand-anything-plugin/packages/core/src/schema.ts b/understand-anything-plugin/packages/core/src/schema.ts index 18ccbb6..f661c28 100644 --- a/understand-anything-plugin/packages/core/src/schema.ts +++ b/understand-anything-plugin/packages/core/src/schema.ts @@ -1,12 +1,14 @@ import { z } from "zod"; -// Edge types (18 values across 5 categories) +// Edge types (26 values across 6 categories) export const EdgeTypeSchema = z.enum([ "imports", "exports", "contains", "inherits", "implements", // Structural "calls", "subscribes", "publishes", "middleware", // Behavioral "reads_from", "writes_to", "transforms", "validates", // Data flow "depends_on", "tested_by", "configures", // Dependencies "related", "similar_to", // Semantic + "deploys", "serves", "migrates", "documents", // Infrastructure + "provisions", "routes", "defines_schema", "triggers", // Infrastructure ]); // Aliases that LLMs commonly generate instead of canonical node types @@ -19,6 +21,35 @@ export const NODE_TYPE_ALIASES: Record = { mod: "module", pkg: "module", package: "module", + // Non-code aliases + container: "service", + deployment: "service", + pod: "service", + doc: "document", + readme: "document", + docs: "document", + workflow: "pipeline", + job: "pipeline", + ci: "pipeline", + action: "pipeline", + route: "endpoint", + api: "endpoint", + query: "endpoint", + mutation: "endpoint", + setting: "config", + env: "config", + configuration: "config", + infra: "resource", + infrastructure: "resource", + terraform: "resource", + migration: "table", + database: "table", + db: "table", + view: "table", + proto: "schema", + protobuf: "schema", + definition: "schema", + typedef: "schema", }; // Aliases that LLMs commonly generate instead of canonical edge types @@ -36,6 +67,18 @@ export const EDGE_TYPE_ALIASES: Record = { contain: "contains", publish: "publishes", subscribe: "subscribes", + // Non-code aliases + describes: "documents", + documented_by: "documents", + creates: "provisions", + exposes: "serves", + listens: "serves", + deploys_to: "deploys", + migrates_to: "migrates", + routes_to: "routes", + triggers_on: "triggers", + fires: "triggers", + defines: "defines_schema", }; // Aliases for complexity values LLMs commonly generate @@ -266,7 +309,11 @@ export function autoFixGraph(data: Record): { export const GraphNodeSchema = z.object({ id: z.string(), - type: z.enum(["file", "function", "class", "module", "concept"]), + type: z.enum([ + "file", "function", "class", "module", "concept", + "config", "document", "service", "table", "endpoint", + "pipeline", "schema", "resource", + ]), name: z.string(), filePath: z.string().optional(), lineRange: z.tuple([z.number(), z.number()]).optional(),