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:
@@ -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,
|
||||
|
||||
@@ -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 } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user