Skip to content

refactor(vba): declarative rule table for the 5 classifiers (VbaExtractionRule shape) #153

Description

@ardelperal

Problem

VbaExtractor (after Issue #83) is a "thin orchestrator" that owns 5 create*Classifier() factory functions in src/extraction/vba/:

  • createEventsTypesDeclaresClassifier()declarations.ts
  • createImplementsClassifier()implements.ts
  • createDimsClassifier()dims.ts
  • createEnumsConstsClassifier()enums-consts.ts
  • createCallsAndSqlClassifier(lines)call-sweep.ts

Each is a function that returns a VbaClassifier object (defined in src/extraction/vba/context.ts) with a classifyLine(line, index, ctx) method. The actual rule definitions (regexes, gating conditions, emit logic) are scattered as private functions and consts inside the respective files.

Adding a new rule (e.g., for a new VBA construct) currently requires: edit a *Classifier file, add a regex constant, add a check inside classifyLine, add a count++ somewhere. The discipline is implicit — there's no central registry of "what does this extractor actually look for".

The JSDoc in src/extraction/vba-extractor.ts:21-31 even hints at the direction:

"This class is now a THIN ORCHESTRATOR that owns a SINGLE per-line walk. Preprocessed source is split into a readonly string[] ONCE…"

…and a 2026-06-28 design doc in openspec/changes/archive/2026-06-28-vba-extractor/design.md:79-87 lists 9 rules (R1-R9) in a clean table format. That table never made it into code as a structure — it stayed as documentation.

Goal

Promote the implicit rules table to an explicit one. Each rule lives as a typed object with a stable id, pattern(s), and an emit callback. The orchestrator drives the table; the rule bodies are testable in isolation.

Why now

  • The codebase is at a clean state (FORMS-1..7 done, god-file split done, single-walk done). The next refactor is the rule table.
  • The existing 5 classifiers stay; this is a structural change that fits inside them.
  • Adding a new rule becomes: write one rule object, drop it in the table. No more "which classifier should I edit?".
  • The compliance bar for new VBA features (e.g., With block member calls, Set x = New, RaiseEvent, etc.) is much lower.

Approach

Define VbaExtractionRule<T> in a new src/extraction/vba/rules.ts:

interface VbaExtractionRule<T = unknown> {
  readonly id: string;                // 'procedure', 'dim', 'implements', 'sql-in-strings', ...
  readonly description: string;
  readonly pattern: RegExp | RegExp[];
  readonly requires?: 'class' | 'module' | 'inside-procedure' | string;
  readonly scan?: 'masked' | 'unmasked' | 'both';  // masked = callScanLine, unmasked = original
  readonly emit: (match: RegExpMatchArray, ctx: VbaExtractorContext, line: string, lineNum: number) => T | null;
  readonly count?: (result: T) => number;  // how many symbols this rule emitted (for hasAnySymbols)
}

Then src/extraction/vba/procedures.ts (and the other 4 files) export a RULES: VbaExtractionRule[] constant. The orchestrator iterates the table, dispatches each line to each rule, and the rule's emit returns the node/edge/unresolved-ref to be appended.

Compatibility shim: the existing VbaClassifier interface stays (it's used by createCallsAndSqlClassifier which carries inter-line state — procedure stack, with stack, sqlVariables). The 5 classifier files become "rule + inter-line state container" — the rules they own are exposed as a RULES array, and the classifier's classifyLine orchestrates the in-rule dispatches.

Acceptance criteria

  • New src/extraction/vba/rules.ts with the VbaExtractionRule interface
  • Each of the 5 classifier files exports a RULES: VbaExtractionRule[] constant (rules extracted from inline code)
  • The orchestrator (vba-extractor.ts) imports each classifier's RULES and validates the table is non-empty
  • Adding a new test rule (emitWithNewKind returning a property node for Property Set Foo) requires touching 1 file: the new rule's *.ts and a 1-line addition to the classifier's RULES array
  • All existing tests pass (no behavior change — this is structural)
  • New test __tests__/extraction-vba-rule-table.test.ts validates the table shape (every rule has a unique id, a non-empty pattern, an emit function)
  • Documentation in the rule file: a comment per rule describing what it matches and what it emits (the 2026-06-28 design doc table comes back as JSDoc)

Out of scope

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:vbaVBA/Access-specific work (parent codegraph product)refactorCode refactor, no behavior change

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions