feat: move buildTypeEdges to src/analysis/type-compat.ts as standalone function

Relocate buildTypeEdges from construction.ts to type-compat.ts per architecture spec.
construction.ts re-exports it for backward compatibility. Add 10 unit tests for
buildTypeEdges covering compatible edges, incompatible edges with mismatches,
unknown schema passthrough, incremental construction, and edge deduplication.
This commit is contained in:
2026-05-21 22:06:26 +00:00
parent 3b52998f20
commit fa2223b90b
5 changed files with 144 additions and 26 deletions

View File

@@ -4,8 +4,7 @@ export {
defaultEdgeType,
resolveDefaultNodeAttrs,
} from "./defaults.js";
export { typeCompat, type TypeCompatResult, type TypeMismatch } from "./type-compat.js";
export { buildTypeEdges } from "../graph/construction.js";
export { typeCompat, buildTypeEdges, type TypeCompatResult, type TypeMismatch } from "./type-compat.js";
export {
validateSchema,
validateGraph,

View File

@@ -1,4 +1,11 @@
import { KindGuard, Kind, type TSchema } from "@alkdev/typebox";
import { willCreateCycle } from "graphology-dag";
import type { FlowGraph } from "../graph/construction.js";
import {
OperationNodeAttrs as OperationNodeAttrsSchema,
OperationEdgeAttrs as OperationEdgeAttrsSchema,
} from "../schema/index.js";
import type { OperationNodeAttrs } from "../schema/index.js";
export interface TypeMismatch {
path: string;
@@ -275,4 +282,25 @@ export function typeCompat(outputSchema: TSchema, inputSchema: TSchema): TypeCom
}
return { compatible: false, mismatches };
}
export function buildTypeEdges(graph: FlowGraph<typeof OperationNodeAttrsSchema, typeof OperationEdgeAttrsSchema>): void {
const nodeKeys = graph.nodes();
for (const source of nodeKeys) {
for (const target of nodeKeys) {
if (source === target) continue;
const sourceAttrs = graph.getNodeAttributes(source as never) as unknown as OperationNodeAttrs;
const targetAttrs = graph.getNodeAttributes(target as never) as unknown as OperationNodeAttrs;
const result = typeCompat(sourceAttrs.outputSchema as TSchema, targetAttrs.inputSchema as TSchema);
if (result === undefined) continue;
if (graph.hasEdge(source, target)) continue;
if (willCreateCycle(graph.graph, source, target)) continue;
const detail = result.detail ?? `${sourceAttrs.namespace}.${sourceAttrs.name}.output → ${targetAttrs.namespace}.${targetAttrs.name}.input`;
graph.addTypedEdge(source, target, {
compatible: result.compatible,
detail,
...(result.mismatches !== undefined ? { mismatches: result.mismatches } : {}),
});
}
}
}

View File

@@ -21,8 +21,10 @@ import {
OperationGraphSerialized,
CallGraphSerialized,
} from "../schema/index.js";
import type { OperationNodeAttrs, FlowGraphSerialized } from "../schema/index.js";
import { typeCompat, type TypeCompatResult } from "../analysis/type-compat.js";
import type { FlowGraphSerialized } from "../schema/index.js";
import { buildTypeEdges, type TypeCompatResult } from "../analysis/type-compat.js";
export { buildTypeEdges } from "../analysis/type-compat.js";
export interface FlowGraphOptions {
type?: "directed";
@@ -455,25 +457,4 @@ export class FlowGraph<
}
return [];
}
}
export function buildTypeEdges(graph: OperationGraph): void {
const nodeKeys = graph.nodes();
for (const source of nodeKeys) {
for (const target of nodeKeys) {
if (source === target) continue;
const sourceAttrs = graph.getNodeAttributes(source as never) as unknown as OperationNodeAttrs;
const targetAttrs = graph.getNodeAttributes(target as never) as unknown as OperationNodeAttrs;
const result = typeCompat(sourceAttrs.outputSchema as TSchema, targetAttrs.inputSchema as TSchema);
if (result === undefined) continue;
if (graph.hasEdge(source, target)) continue;
if (willCreateCycle(graph.graph, source, target)) continue;
const detail = result.detail ?? `${sourceAttrs.namespace}.${sourceAttrs.name}.output → ${targetAttrs.namespace}.${targetAttrs.name}.input`;
graph.addTypedEdge(source, target, {
compatible: result.compatible,
detail,
...(result.mismatches !== undefined ? { mismatches: result.mismatches } : {}),
});
}
}
}

View File

@@ -1,6 +1,7 @@
export * from "./error/index.js";
export { FlowGraph, buildTypeEdges, type FlowGraphOptions, type OperationSpec } from "./graph/index.js";
export { typeCompat, type TypeCompatResult, type TypeMismatch } from "./analysis/type-compat.js";
export {
validateSchema,
validateGraph,