feat: package Pi extensions as Bun workspaces
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import type { AnalysisSnapshot, AnalyzerFailure } from "./policy.ts";
|
||||
export interface AnalysisRequest { readonly analyzerKey: string; readonly paths: readonly string[] }
|
||||
export interface AnalyzerAdapter { analyze(paths: readonly string[], workspaceRevision: number, signal?: AbortSignal): Promise<AnalysisSnapshot> }
|
||||
export class AnalysisCoordinator {
|
||||
constructor(private readonly adapters: ReadonlyMap<string, AnalyzerAdapter>) {}
|
||||
async run(requests: readonly AnalysisRequest[], revision: number, signal?: AbortSignal): Promise<ReadonlyMap<string, AnalysisSnapshot>> {
|
||||
const grouped = new Map<string, Set<string>>();
|
||||
for (const request of requests) { const paths = grouped.get(request.analyzerKey) ?? new Set<string>(); for (const path of request.paths) paths.add(path); grouped.set(request.analyzerKey, paths); }
|
||||
const entries = await Promise.all([...grouped].sort(([a], [b]) => a.localeCompare(b)).map(async ([key, paths]) => {
|
||||
const adapter = this.adapters.get(key);
|
||||
const sorted = [...paths].sort();
|
||||
if (!adapter) return [key, failed(key, revision, sorted, { kind: "missing", message: `No analyzer registered for ${key}` })] as const;
|
||||
try { return [key, deepFreeze(await adapter.analyze(sorted, revision, signal))] as const; }
|
||||
catch (error) { return [key, failed(key, revision, sorted, { kind: "internal", message: error instanceof Error ? error.message : String(error) })] as const; }
|
||||
}));
|
||||
return readonlyMap(entries);
|
||||
}
|
||||
}
|
||||
function failed(key: string, workspaceRevision: number, paths: readonly string[], failure: AnalyzerFailure): AnalysisSnapshot { return Object.freeze({ analyzerKey: key, workspaceRevision, paths: Object.freeze([...paths]), findings: Object.freeze([]), durationMs: 0, failure: Object.freeze(failure) }); }
|
||||
export function deepFreeze<T>(value: T): T { if (value && typeof value === "object" && !Object.isFrozen(value)) { Object.freeze(value); for (const item of Object.values(value as Record<string, unknown>)) deepFreeze(item); } return value; }
|
||||
export function readonlyMap<K, V>(entries: readonly (readonly [K, V])[]): ReadonlyMap<K, V> { const map = new Map(entries); Object.freeze(map); return new Proxy(map, { get(target, prop) { if (prop === "set" || prop === "delete" || prop === "clear") return undefined; const value = Reflect.get(target, prop, target) as unknown; return typeof value === "function" ? (value as Function).bind(target) : value; } }); }
|
||||
Reference in New Issue
Block a user