mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-07 02:58:02 +00:00
fix: wire a11y phase into pipeline (extraction was not processed)
jsxElements were extracted by the parse worker but never passed through the rule engine or persisted as A11ySignal nodes. This commit: - adds allJsxElements accumulation in parse-impl and ParseOutput - creates a11y.ts pipeline phase that runs runA11yRules + processA11ySignals - registers a11yPhase in index.ts and pipeline.ts (after orm, before crossFile) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ebc2a715ea
commit
5a596f9c72
5 changed files with 74 additions and 0 deletions
62
gitnexus/src/core/ingestion/pipeline-phases/a11y.ts
Normal file
62
gitnexus/src/core/ingestion/pipeline-phases/a11y.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* Phase: a11y
|
||||
*
|
||||
* Runs WCAG rule engine over JSX elements extracted during parse and
|
||||
* creates A11ySignal nodes + HAS_A11Y_SIGNAL edges in the graph.
|
||||
*
|
||||
* @deps parse
|
||||
* @reads allJsxElements (from parse)
|
||||
* @writes graph (A11ySignal nodes, HAS_A11Y_SIGNAL edges)
|
||||
*/
|
||||
|
||||
import type { PipelinePhase, PipelineContext, PhaseResult } from './types.js';
|
||||
import { getPhaseOutput } from './types.js';
|
||||
import type { ParseOutput } from './parse.js';
|
||||
import { runA11yRules } from '../a11y-rules/index.js';
|
||||
import { processA11ySignals } from '../a11y-processor.js';
|
||||
|
||||
export interface A11yOutput {
|
||||
signalsCreated: number;
|
||||
edgesCreated: number;
|
||||
violations: number;
|
||||
needsReview: number;
|
||||
}
|
||||
|
||||
export const a11yPhase: PipelinePhase<A11yOutput> = {
|
||||
name: 'a11y',
|
||||
deps: ['parse'],
|
||||
|
||||
async execute(
|
||||
ctx: PipelineContext,
|
||||
deps: ReadonlyMap<string, PhaseResult<unknown>>,
|
||||
): Promise<A11yOutput> {
|
||||
const { allJsxElements } = getPhaseOutput<ParseOutput>(deps, 'parse');
|
||||
|
||||
if (allJsxElements.length === 0) {
|
||||
return { signalsCreated: 0, edgesCreated: 0, violations: 0, needsReview: 0 };
|
||||
}
|
||||
|
||||
// Group elements by file so each rule gets the correct filePath context
|
||||
const byFile = new Map<string, typeof allJsxElements[number][]>();
|
||||
for (const el of allJsxElements) {
|
||||
const bucket = byFile.get(el.filePath);
|
||||
if (bucket) {
|
||||
bucket.push(el);
|
||||
} else {
|
||||
byFile.set(el.filePath, [el]);
|
||||
}
|
||||
}
|
||||
|
||||
const allSignals = [];
|
||||
for (const [filePath, elements] of byFile) {
|
||||
const signals = runA11yRules(elements, filePath);
|
||||
for (const s of signals) allSignals.push(s);
|
||||
}
|
||||
|
||||
if (allSignals.length === 0) {
|
||||
return { signalsCreated: 0, edgesCreated: 0, violations: 0, needsReview: 0 };
|
||||
}
|
||||
|
||||
return processA11ySignals(allSignals, ctx.graph);
|
||||
},
|
||||
};
|
||||
|
|
@ -15,6 +15,7 @@ export { parsePhase, type ParseOutput } from './parse.js';
|
|||
export { routesPhase, type RoutesOutput, type RouteEntry } from './routes.js';
|
||||
export { toolsPhase, type ToolsOutput, type ToolDef } from './tools.js';
|
||||
export { ormPhase, type ORMOutput } from './orm.js';
|
||||
export { a11yPhase, type A11yOutput } from './a11y.js';
|
||||
export { crossFilePhase, type CrossFileOutput } from './cross-file.js';
|
||||
export { mroPhase, type MROOutput } from './mro.js';
|
||||
export { communitiesPhase, type CommunitiesOutput } from './communities.js';
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ import type {
|
|||
ExtractedToolDef,
|
||||
FileConstructorBindings,
|
||||
} from '../workers/parse-worker.js';
|
||||
import type { ExtractedJSXElement } from '../a11y-rules/types.js';
|
||||
import type { ExtractedHeritage } from '../model/heritage-map.js';
|
||||
import type { KnowledgeGraph } from '../../graph/types.js';
|
||||
import type { PipelineOptions } from '../pipeline.js';
|
||||
|
|
@ -106,6 +107,7 @@ export async function runChunkedParseAndResolve(
|
|||
allDecoratorRoutes: ExtractedDecoratorRoute[];
|
||||
allToolDefs: ExtractedToolDef[];
|
||||
allORMQueries: ExtractedORMQuery[];
|
||||
allJsxElements: ExtractedJSXElement[];
|
||||
bindingAccumulator: BindingAccumulator;
|
||||
resolutionContext: ReturnType<typeof createResolutionContext>;
|
||||
usedWorkerPool: boolean;
|
||||
|
|
@ -248,6 +250,7 @@ export async function runChunkedParseAndResolve(
|
|||
const allDecoratorRoutes: ExtractedDecoratorRoute[] = [];
|
||||
const allToolDefs: ExtractedToolDef[] = [];
|
||||
const allORMQueries: ExtractedORMQuery[] = [];
|
||||
const allJsxElements: ExtractedJSXElement[] = [];
|
||||
const deferredWorkerCalls: ExtractedCall[] = [];
|
||||
const deferredWorkerHeritage: ExtractedHeritage[] = [];
|
||||
const deferredConstructorBindings: FileConstructorBindings[] = [];
|
||||
|
|
@ -393,6 +396,9 @@ export async function runChunkedParseAndResolve(
|
|||
if (chunkWorkerData.ormQueries?.length) {
|
||||
for (const item of chunkWorkerData.ormQueries) allORMQueries.push(item);
|
||||
}
|
||||
if (chunkWorkerData.jsxElements?.length) {
|
||||
for (const item of chunkWorkerData.jsxElements) allJsxElements.push(item);
|
||||
}
|
||||
} else {
|
||||
await processImports(graph, chunkFiles, astCache, ctx, undefined, repoPath, allPaths);
|
||||
sequentialChunkPaths.push(chunkPaths);
|
||||
|
|
@ -589,6 +595,7 @@ export async function runChunkedParseAndResolve(
|
|||
allDecoratorRoutes,
|
||||
allToolDefs,
|
||||
allORMQueries,
|
||||
allJsxElements,
|
||||
bindingAccumulator,
|
||||
resolutionContext: ctx,
|
||||
// Whether a worker pool was actually live for this run. False means the
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import type {
|
|||
ExtractedToolDef,
|
||||
ExtractedORMQuery,
|
||||
} from '../workers/parse-worker.js';
|
||||
import type { ExtractedJSXElement } from '../a11y-rules/types.js';
|
||||
import type { createResolutionContext } from '../model/resolution-context.js';
|
||||
import { runChunkedParseAndResolve } from './parse-impl.js';
|
||||
|
||||
|
|
@ -47,6 +48,7 @@ export interface ParseOutput {
|
|||
readonly allDecoratorRoutes: readonly ExtractedDecoratorRoute[];
|
||||
readonly allToolDefs: readonly ExtractedToolDef[];
|
||||
readonly allORMQueries: readonly ExtractedORMQuery[];
|
||||
readonly allJsxElements: readonly ExtractedJSXElement[];
|
||||
bindingAccumulator: BindingAccumulator;
|
||||
/** Resolution context from the parse phase — carries importMap, namedImportMap, etc. */
|
||||
resolutionContext: ReturnType<typeof createResolutionContext>;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
routesPhase,
|
||||
toolsPhase,
|
||||
ormPhase,
|
||||
a11yPhase,
|
||||
crossFilePhase,
|
||||
mroPhase,
|
||||
communitiesPhase,
|
||||
|
|
@ -79,6 +80,7 @@ function buildPhaseList(options?: PipelineOptions): PipelinePhase[] {
|
|||
routesPhase,
|
||||
toolsPhase,
|
||||
ormPhase,
|
||||
a11yPhase,
|
||||
crossFilePhase,
|
||||
];
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue