refactor(group): extract workspace discovery orchestrator from sync

Move per-ecosystem workspace extractor calls into a single
discoverWorkspaceLinks() orchestrator. Reduces sync.ts from 295
to 264 lines and gives a clean extension point for adding
more ecosystem extractors.
This commit is contained in:
Christian C. Berclaz 2026-05-01 19:49:14 +02:00
parent 187c343d6d
commit 3a7c0fb566
No known key found for this signature in database
2 changed files with 77 additions and 40 deletions

View file

@ -0,0 +1,68 @@
import type { CypherExecutor } from '../contract-extractor.js';
import type { GroupManifestLink } from '../types.js';
import { extractRustWorkspaceLinks } from './rust-workspace-extractor.js';
import { extractNodeWorkspaceLinks } from './node-workspace-extractor.js';
import { extractPythonWorkspaceLinks } from './python-workspace-extractor.js';
import { extractGoWorkspaceLinks } from './go-workspace-extractor.js';
export interface WorkspaceDiscoveryResult {
links: GroupManifestLink[];
stats: WorkspaceExtractorStats[];
}
interface WorkspaceExtractorStats {
ecosystem: string;
linkCount: number;
projectCount: number;
}
export async function discoverWorkspaceLinks(
repos: Record<string, string>,
repoPaths: Map<string, string>,
dbExecutors?: Map<string, CypherExecutor>,
): Promise<WorkspaceDiscoveryResult> {
const links: GroupManifestLink[] = [];
const stats: WorkspaceExtractorStats[] = [];
const rustResult = await extractRustWorkspaceLinks(repos, repoPaths, dbExecutors);
if (rustResult.links.length > 0) {
links.push(...rustResult.links);
stats.push({
ecosystem: 'Rust',
linkCount: rustResult.links.length,
projectCount: rustResult.discoveredCrates.size,
});
}
const nodeResult = await extractNodeWorkspaceLinks(repos, repoPaths, dbExecutors);
if (nodeResult.links.length > 0) {
links.push(...nodeResult.links);
stats.push({
ecosystem: 'Node',
linkCount: nodeResult.links.length,
projectCount: nodeResult.discoveredPackages.size,
});
}
const pyResult = await extractPythonWorkspaceLinks(repos, repoPaths, dbExecutors);
if (pyResult.links.length > 0) {
links.push(...pyResult.links);
stats.push({
ecosystem: 'Python',
linkCount: pyResult.links.length,
projectCount: pyResult.discoveredPackages.size,
});
}
const goResult = await extractGoWorkspaceLinks(repos, repoPaths, dbExecutors);
if (goResult.links.length > 0) {
links.push(...goResult.links);
stats.push({
ecosystem: 'Go',
linkCount: goResult.links.length,
projectCount: goResult.discoveredModules.size,
});
}
return { links, stats };
}

View file

@ -8,10 +8,7 @@ import { HttpRouteExtractor } from './extractors/http-route-extractor.js';
import { GrpcExtractor } from './extractors/grpc-extractor.js';
import { TopicExtractor } from './extractors/topic-extractor.js';
import { ManifestExtractor } from './extractors/manifest-extractor.js';
import { extractRustWorkspaceLinks } from './extractors/rust-workspace-extractor.js';
import { extractNodeWorkspaceLinks } from './extractors/node-workspace-extractor.js';
import { extractPythonWorkspaceLinks } from './extractors/python-workspace-extractor.js';
import { extractGoWorkspaceLinks } from './extractors/go-workspace-extractor.js';
import { discoverWorkspaceLinks } from './extractors/workspace-extractor.js';
import { runExactMatch } from './matching.js';
import { detectServiceBoundaries, assignService } from './service-boundary-detector.js';
import type { CypherExecutor } from './contract-extractor.js';
@ -196,43 +193,15 @@ export async function syncGroup(config: GroupConfig, opts?: SyncOptions): Promis
if (e) repoPaths.set(groupPath, e.path);
}
const rustResult = await extractRustWorkspaceLinks(config.repos, repoPaths, dbExecutors);
if (rustResult.links.length > 0) {
allLinks = [...allLinks, ...rustResult.links];
const wsResult = await discoverWorkspaceLinks(config.repos, repoPaths, dbExecutors);
if (wsResult.links.length > 0) {
allLinks = [...allLinks, ...wsResult.links];
if (opts?.verbose) {
console.log(
` workspace-deps: discovered ${rustResult.links.length} cross-crate links from ${rustResult.discoveredCrates.size} Rust crates`,
);
}
}
const nodeResult = await extractNodeWorkspaceLinks(config.repos, repoPaths, dbExecutors);
if (nodeResult.links.length > 0) {
allLinks = [...allLinks, ...nodeResult.links];
if (opts?.verbose) {
console.log(
` workspace-deps: discovered ${nodeResult.links.length} cross-package links from ${nodeResult.discoveredPackages.size} Node packages`,
);
}
}
const pyResult = await extractPythonWorkspaceLinks(config.repos, repoPaths, dbExecutors);
if (pyResult.links.length > 0) {
allLinks = [...allLinks, ...pyResult.links];
if (opts?.verbose) {
console.log(
` workspace-deps: discovered ${pyResult.links.length} cross-package links from ${pyResult.discoveredPackages.size} Python packages`,
);
}
}
const goResult = await extractGoWorkspaceLinks(config.repos, repoPaths, dbExecutors);
if (goResult.links.length > 0) {
allLinks = [...allLinks, ...goResult.links];
if (opts?.verbose) {
console.log(
` workspace-deps: discovered ${goResult.links.length} cross-module links from ${goResult.discoveredModules.size} Go modules`,
);
for (const s of wsResult.stats) {
console.log(
` workspace-deps: discovered ${s.linkCount} cross-${s.ecosystem.toLowerCase()} links from ${s.projectCount} ${s.ecosystem} projects`,
);
}
}
}
}