Skip to content

feat(vba): parameter nodes, and table fields from the Access ERD export #257

Description

@ardelperal

Summary

Two additions that finish the symbol layer, both using node kinds that already exist in NODE_KINDS — no new kinds, no schema migration:

  • A. parameter nodes for VBA procedure parameters (4,747 in the corpus).
  • B. Real table nodes with their fields, parsed from the Access structure export (ERD/*.md) — 81 tables, 451 fields, and 15 linked tables pointing at 6 external backends.

They are independent. Land them as two PRs.

Half A — parameter nodes

Source of truth

#250's metadata.params. That issue already parses the signature — name, type, ByRef, Optional, isArray, hasDefault — after line-continuation joining, which matters: the corpus has 7,753 line continuations and multi-line signatures are common.

This half is emission only. Do not write a second signature parser. Land #250 first.

Shape

id            generateNodeId(filePath, 'parameter', `${procName}.${paramName}`, declLine)
kind          'parameter'
name          the parameter name
qualifiedName '<ModuleOrClass>.<Procedure>.<param>'
filePath      the .bas / .cls
startLine     the procedure's declaration line (parameters have no line of their own)
metadata      { position, byRef, optional, isArray, hasDefault, declaredType }

Edges:

Edge Source Target Kind
procedure owns its parameter function parameter contains
parameter has a project type parameter the type's node type_of

type_of fires only when the declared type is a project class, using the existing Dim … As Foo resolution machinery in vba/dims.ts. Primitives (Long, String, Variant, …) emit nothing — PRIMITIVE_TYPES is already the gate.

Budget

Procedures 4,815
…with at least one parameter 2,561
Total parameters 4,747
Largest signature 11 parameters

So ~4,700 nodes and ~4,700 contains edges, plus type_of only for project-typed parameters.

Exclusions

  • Do not add 'parameter' to HIGH_VALUE_NODE_KINDS (src/context/index.ts) — it is the default node filter for context results, and 4,700 parameters would flood every response.
  • Do not add it to CONTAINER_NODE_KINDS (src/mcp/tools.ts).

Half B — table structure from the Access ERD export

The input, and why this is declaration rather than inference

Table references in the graph today are synthetic class placeholders created from SQL text: a name, nothing else. There is no column information anywhere, and inferring columns from SELECT lists would be incomplete by construction.

But there is an authoritative export. 00_GESTION_RIESGOS/ERD/Estructura_Datos.md is a generated structure dump of the backend:

# Estructura de Datos: Gestion_Riesgos_Datos.accdb

## Tabla: TbAnexos
| Campo | Tipo | Longitud |
| :--- | :--- | :--- |
| IDAnexo | 4 | 4 |
| Titulo | 10 | 255 |

## Tabla: TbAplicaciones
> (LINKED) **Tabla Vinculada**
> *Origen:* TbAplicaciones
> *Conexión:* MS Access;PWD=***;DATABASE=\\datoste\...\0Lanzadera\Lanzadera_Datos.accdb

| Campo | Tipo | Longitud |
...

Contents of that one file: 81 tables, 451 fields, 15 linked tables resolving to 6 distinct external backends — Lanzadera, EXPEDIENTES, AGEDO, AGEDYS, No Conformidades and the project's own datos file. That is the cross-application data topology of this estate, and none of it is in the graph.

Only 1 of the 3 corpus projects has this file. The extractor must treat it as optional and degrade silently when absent — no warning, no error, no empty node.

Shape

New extractor src/extraction/access-erd-extractor.ts, routed on a path match for ERD/*.md plus a content-shape gate (# Estructura de Datos: on the first non-empty line). Gate on both, exactly as the .sql route gates on a sibling queries.json — an ordinary ERD folder in a non-Access repo must never be picked up.

Emitted Kind Notes
One node per table class Same kind the SQL placeholders already use — see the convergence note below
One node per field type_member contains from its table; metadata: { accessType, length, position }
Linked-table origin references edge synthesizedBy: 'vba-linked-table', metadata: { originTable, backendPath }

The convergence problem — read this before writing code

vba-sql-table (in vba/sql-wrapper.ts) and sql-query-table (in sql-query-extractor.ts) already create class placeholder nodes for table names, keyed on generateNodeId(filePath, 'class', tableName, 0)keyed on the referencing file. The ERD extractor keys on the ERD file.

Left alone, TbAnexos from the ERD and TbAnexos from a SELECT in a .cls are two unrelated nodes, and the whole feature buys nothing: fields on one node, references on the other.

Decided strategy: resolve it in src/resolution/, reusing the mechanism that already repoints VBA call stubs (resolveVbaCallStubs in src/resolution/index.ts).

  • The ERD extractor emits table nodes exactly like any other extractor — per-file ids, no special id scheme. Do not invent a global key; that would break the per-file node identity every other extractor relies on.
  • A post-extraction pass promotes the ERD table node to canonical when one exists for that name, and repoints the SQL placeholders' references onto it, stamping the outcome the way repointDecision already does for call stubs.
  • When two ERD files declare the same table name (two backends, same table), that is declined-ambiguous — repoint nothing and leave both. Do not guess which backend a SELECT meant.
  • When no ERD exists, the pass is a no-op and today's placeholder behaviour is unchanged.

This reuses a proven mechanism, keeps extraction ignorant of resolution, and degrades correctly on the two corpus projects that ship no ERD.

Budget

81 table nodes, 451 field nodes, ~530 contains edges, 15 references edges — on the one project that ships an ERD. Negligible.

Secondary win

The linked-table origins give the cross-backend edge that the SQL-scanner issue (#256) calls out as missing for the IN "other.accdb" clause. The two should agree on how an external backend file is represented; whichever lands second adopts the first one's shape.

Acceptance criteria

Half A

  • One parameter node per parameter, qualifiedName scoped to the procedure
  • contains edge from the owning function node
  • type_of edge only for project-typed parameters; primitives emit nothing
  • A continued signature (_ line continuation) produces the same nodes as the one-line form
  • ParamArray and Optional … = default carry the right metadata
  • 'parameter' absent from HIGH_VALUE_NODE_KINDS and CONTAINER_NODE_KINDS, asserted by test
  • Corpus yields ~4,747 parameter nodes; exact figure in the PR body
  • No other node kind's count changes

Half B

  • ERD/Estructura_Datos.md yields 81 table nodes and 451 field nodes
  • The 15 linked tables emit references edges carrying their backend path
  • A project with no ERD/ directory extracts exactly as before — no warning, no empty node
  • A markdown file under an ERD/ folder that is not an Access structure export is ignored (content-shape gate)
  • Table-node convergence: after resolution, a SELECT * FROM TbAnexos in a .cls and the ERD's TbAnexos resolve to one node that has both the fields and the reference
  • Two ERD files declaring the same table name repoint nothing (ambiguous), and both nodes survive

Context

Task T16 of docs/vba-node-discovery-plan.md. Half A depends on #250. Half B is independent of everything else in the roadmap and coordinates with #256 on how an external backend file is represented.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:vbaVBA/Access-specific work (parent codegraph product)status:approvedApproved for implementationtype:featureNew feature

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions