feat(core): extend GraphNode/EdgeType/StructuralAnalysis for non-code file types

Add 8 new node types (config, document, service, table, endpoint,
pipeline, schema, resource) and 8 new edge types (deploys, serves,
migrates, documents, provisions, routes, defines_schema, triggers).

Add StructuralAnalysis sub-interfaces: SectionInfo, DefinitionInfo,
ServiceInfo, EndpointInfo, StepInfo, ResourceInfo, ReferenceResolution.

Make resolveImports optional on AnalyzerPlugin and add extractReferences.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lum1104
2026-03-28 18:29:01 +08:00
Unverified
parent fd6235ad24
commit b1f763adac
2 changed files with 137 additions and 6 deletions
@@ -1,5 +1,5 @@
import { describe, it, expect } from "vitest";
import type { KnowledgeGraph, GraphNode, GraphEdge } from "./types.js";
import type { KnowledgeGraph, GraphNode, GraphEdge, EdgeType, StructuralAnalysis, AnalyzerPlugin, ReferenceResolution } from "./types.js";
describe("KnowledgeGraph types", () => {
it("should create a valid empty KnowledgeGraph", () => {
@@ -115,3 +115,78 @@ describe("KnowledgeGraph types", () => {
expect(maxWeightEdge.weight).toBe(1);
});
});
describe("Extended types", () => {
it("accepts all 13 node types", () => {
const nodeTypes: GraphNode["type"][] = [
"file", "function", "class", "module", "concept",
"config", "document", "service", "table", "endpoint",
"pipeline", "schema", "resource",
];
expect(nodeTypes).toHaveLength(13);
});
it("accepts all 26 edge types", () => {
const edgeTypes: EdgeType[] = [
"imports", "exports", "contains", "inherits", "implements",
"calls", "subscribes", "publishes", "middleware",
"reads_from", "writes_to", "transforms", "validates",
"depends_on", "tested_by", "configures",
"related", "similar_to",
"deploys", "serves", "migrates", "documents",
"provisions", "routes", "defines_schema", "triggers",
];
expect(edgeTypes).toHaveLength(26);
});
it("StructuralAnalysis has optional non-code fields", () => {
const analysis: StructuralAnalysis = {
functions: [], classes: [], imports: [], exports: [],
sections: [{ name: "Introduction", level: 1, lineRange: [1, 10] }],
definitions: [{ name: "users", kind: "table", lineRange: [1, 20], fields: ["id", "name"] }],
services: [{ name: "web", image: "node:22", ports: [3000] }],
endpoints: [{ method: "GET", path: "/api/users", lineRange: [5, 15] }],
steps: [{ name: "build", lineRange: [1, 5] }],
resources: [{ name: "aws_s3_bucket.main", kind: "aws_s3_bucket", lineRange: [1, 10] }],
};
expect(analysis.sections).toHaveLength(1);
expect(analysis.definitions).toHaveLength(1);
expect(analysis.services).toHaveLength(1);
expect(analysis.endpoints).toHaveLength(1);
expect(analysis.steps).toHaveLength(1);
expect(analysis.resources).toHaveLength(1);
});
it("StructuralAnalysis is backward compatible (non-code fields are optional)", () => {
const analysis: StructuralAnalysis = {
functions: [], classes: [], imports: [], exports: [],
};
expect(analysis.sections).toBeUndefined();
expect(analysis.definitions).toBeUndefined();
expect(analysis.services).toBeUndefined();
});
it("AnalyzerPlugin allows optional resolveImports", () => {
const plugin: AnalyzerPlugin = {
name: "test-plugin",
languages: ["markdown"],
analyzeFile: () => ({ functions: [], classes: [], imports: [], exports: [] }),
// resolveImports is optional — not provided
};
expect(plugin.resolveImports).toBeUndefined();
expect(plugin.analyzeFile).toBeDefined();
});
it("AnalyzerPlugin supports extractReferences", () => {
const refs: ReferenceResolution[] = [
{ source: "README.md", target: "./docs/guide.md", referenceType: "file", line: 5 },
];
const plugin: AnalyzerPlugin = {
name: "test-plugin",
languages: ["markdown"],
analyzeFile: () => ({ functions: [], classes: [], imports: [], exports: [] }),
extractReferences: () => refs,
};
expect(plugin.extractReferences!("README.md", "")).toEqual(refs);
});
});
@@ -1,15 +1,19 @@
// Edge types (18 total in 5 categories: Structural, Behavioral, Data flow, Dependencies, Semantic)
// Edge types (26 total in 6 categories: Structural, Behavioral, Data flow, Dependencies, Semantic, Infrastructure)
export type EdgeType =
| "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
| "related" | "similar_to" // Semantic
| "deploys" | "serves" | "migrates" | "documents" // Infrastructure
| "provisions" | "routes" | "defines_schema" | "triggers"; // Infrastructure
// GraphNode with 5 types: file, function, class, module, concept
// GraphNode with 13 types: 5 code + 8 non-code
export interface GraphNode {
id: string;
type: "file" | "function" | "class" | "module" | "concept";
type: "file" | "function" | "class" | "module" | "concept"
| "config" | "document" | "service" | "table" | "endpoint"
| "pipeline" | "schema" | "resource";
name: string;
filePath?: string;
lineRange?: [number, number];
@@ -86,12 +90,63 @@ export interface ProjectConfig {
autoUpdate: boolean;
}
// Non-code structural sub-interfaces
export interface SectionInfo {
name: string;
level: number;
lineRange: [number, number];
}
export interface DefinitionInfo {
name: string;
kind: string; // "table", "message", "type", "schema"
lineRange: [number, number];
fields: string[];
}
export interface ServiceInfo {
name: string;
image?: string;
ports: number[];
}
export interface EndpointInfo {
method?: string;
path: string;
lineRange: [number, number];
}
export interface StepInfo {
name: string;
lineRange: [number, number];
}
export interface ResourceInfo {
name: string;
kind: string;
lineRange: [number, number];
}
export interface ReferenceResolution {
source: string;
target: string;
referenceType: string; // "file", "image", "schema", "service"
line?: number;
}
// Plugin interfaces
export interface StructuralAnalysis {
functions: Array<{ name: string; lineRange: [number, number]; params: string[]; returnType?: string }>;
classes: Array<{ name: string; lineRange: [number, number]; methods: string[]; properties: string[] }>;
imports: Array<{ source: string; specifiers: string[]; lineNumber: number }>;
exports: Array<{ name: string; lineNumber: number }>;
// Non-code structural data (all optional for backward compat)
sections?: SectionInfo[];
definitions?: DefinitionInfo[];
services?: ServiceInfo[];
endpoints?: EndpointInfo[];
steps?: StepInfo[];
resources?: ResourceInfo[];
}
export interface ImportResolution {
@@ -110,6 +165,7 @@ export interface AnalyzerPlugin {
name: string;
languages: string[];
analyzeFile(filePath: string, content: string): StructuralAnalysis;
resolveImports(filePath: string, content: string): ImportResolution[];
resolveImports?(filePath: string, content: string): ImportResolution[];
extractCallGraph?(filePath: string, content: string): CallGraphEntry[];
extractReferences?(filePath: string, content: string): ReferenceResolution[];
}