feat(core): add knowledge graph type system and validation tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lum1104
2026-03-14 17:25:49 +08:00
Unverified
parent 7fb8c5cbb8
commit 35d0545100
6 changed files with 253 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
{
"name": "@understand-anything/core",
"version": "0.1.0",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"test": "vitest run"
},
"devDependencies": {
"typescript": "^5.7.0",
"vitest": "^3.1.0"
}
}
+1
View File
@@ -0,0 +1 @@
export * from "./types.js";
+117
View File
@@ -0,0 +1,117 @@
import { describe, it, expect } from "vitest";
import type { KnowledgeGraph, GraphNode, GraphEdge } from "./types.js";
describe("KnowledgeGraph types", () => {
it("should create a valid empty KnowledgeGraph", () => {
const graph: KnowledgeGraph = {
version: "1.0.0",
project: {
name: "test-project",
languages: [],
frameworks: [],
description: "A test project",
analyzedAt: new Date().toISOString(),
gitCommitHash: "abc123",
},
nodes: [],
edges: [],
layers: [],
tour: [],
};
expect(graph.version).toBe("1.0.0");
expect(graph.project.name).toBe("test-project");
expect(graph.nodes).toHaveLength(0);
expect(graph.edges).toHaveLength(0);
expect(graph.layers).toHaveLength(0);
expect(graph.tour).toHaveLength(0);
});
it("should create valid GraphNodes with all fields", () => {
const fileNode: GraphNode = {
id: "node-1",
type: "file",
name: "index.ts",
filePath: "src/index.ts",
lineRange: [1, 50],
summary: "Entry point of the application",
tags: ["entry", "typescript"],
complexity: "simple",
languageNotes: "Uses ES module syntax",
};
expect(fileNode.id).toBe("node-1");
expect(fileNode.type).toBe("file");
expect(fileNode.filePath).toBe("src/index.ts");
expect(fileNode.lineRange).toEqual([1, 50]);
expect(fileNode.tags).toContain("entry");
expect(fileNode.complexity).toBe("simple");
const functionNode: GraphNode = {
id: "node-2",
type: "function",
name: "processData",
filePath: "src/utils.ts",
lineRange: [10, 25],
summary: "Processes raw data into structured format",
tags: ["utility", "data"],
complexity: "moderate",
};
expect(functionNode.type).toBe("function");
expect(functionNode.complexity).toBe("moderate");
expect(functionNode.languageNotes).toBeUndefined();
const classNode: GraphNode = {
id: "node-3",
type: "class",
name: "DataStore",
summary: "Manages application state",
tags: ["state", "core"],
complexity: "complex",
};
expect(classNode.type).toBe("class");
expect(classNode.filePath).toBeUndefined();
expect(classNode.lineRange).toBeUndefined();
});
it("should create valid GraphEdges with weight bounds", () => {
const edge: GraphEdge = {
source: "node-1",
target: "node-2",
type: "imports",
direction: "forward",
description: "index.ts imports processData from utils.ts",
weight: 0.8,
};
expect(edge.source).toBe("node-1");
expect(edge.target).toBe("node-2");
expect(edge.type).toBe("imports");
expect(edge.direction).toBe("forward");
expect(edge.weight).toBeGreaterThanOrEqual(0);
expect(edge.weight).toBeLessThanOrEqual(1);
const minWeightEdge: GraphEdge = {
source: "node-1",
target: "node-3",
type: "related",
direction: "bidirectional",
weight: 0,
};
expect(minWeightEdge.weight).toBe(0);
expect(minWeightEdge.description).toBeUndefined();
const maxWeightEdge: GraphEdge = {
source: "node-2",
target: "node-3",
type: "calls",
direction: "forward",
weight: 1,
};
expect(maxWeightEdge.weight).toBe(1);
});
});
+103
View File
@@ -0,0 +1,103 @@
// Edge types (17 total in 5 categories: Structural, Behavioral, Data flow, Dependencies, Semantic)
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
// GraphNode with 5 types: file, function, class, module, concept
export interface GraphNode {
id: string;
type: "file" | "function" | "class" | "module" | "concept";
name: string;
filePath?: string;
lineRange?: [number, number];
summary: string;
tags: string[];
complexity: "simple" | "moderate" | "complex";
languageNotes?: string;
}
// GraphEdge with rich relationship modeling
export interface GraphEdge {
source: string;
target: string;
type: EdgeType;
direction: "forward" | "backward" | "bidirectional";
description?: string;
weight: number; // 0-1
}
// Layer (logical grouping)
export interface Layer {
id: string;
name: string;
description: string;
nodeIds: string[];
}
// TourStep (for learn mode)
export interface TourStep {
order: number;
title: string;
description: string;
nodeIds: string[];
languageLesson?: string;
}
// ProjectMeta
export interface ProjectMeta {
name: string;
languages: string[];
frameworks: string[];
description: string;
analyzedAt: string;
gitCommitHash: string;
}
// Root KnowledgeGraph
export interface KnowledgeGraph {
version: string;
project: ProjectMeta;
nodes: GraphNode[];
edges: GraphEdge[];
layers: Layer[];
tour: TourStep[];
}
// AnalysisMeta (for persistence)
export interface AnalysisMeta {
lastAnalyzedAt: string;
gitCommitHash: string;
version: string;
analyzedFiles: 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 }>;
}
export interface ImportResolution {
source: string;
resolvedPath: string;
specifiers: string[];
}
export interface CallGraphEntry {
caller: string;
callee: string;
lineNumber: number;
}
export interface AnalyzerPlugin {
name: string;
languages: string[];
analyzeFile(filePath: string, content: string): StructuralAnalysis;
resolveImports(filePath: string, content: string): ImportResolution[];
extractCallGraph?(filePath: string, content: string): CallGraphEntry[];
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
+9
View File
@@ -15,6 +15,15 @@ importers:
specifier: ^3.1.0
version: 3.2.4
packages/core:
devDependencies:
typescript:
specifier: ^5.7.0
version: 5.9.3
vitest:
specifier: ^3.1.0
version: 3.2.4
packages:
'@esbuild/aix-ppc64@0.27.4':