@aroman22/codegraph-vba 1.3.3 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -240,6 +240,51 @@ export declare class QueryBuilder {
240
240
  * Get incoming edges to a node
241
241
  */
242
242
  getIncomingEdges(targetId: string, kinds?: EdgeKind[]): Edge[];
243
+ /**
244
+ * Find VBA call-stub candidate nodes for `resolveVbaCallStubs` (vba-graph-
245
+ * connectivity-fixes, #12).
246
+ *
247
+ * Design deviation note: the design's `getVbaCallStubs()` was specified as
248
+ * `SELECT * FROM nodes WHERE ... metadata LIKE '%"stub":true%'`, mirroring
249
+ * the JSON-in-JS convention used elsewhere (F2). That assumes a
250
+ * `nodes.metadata` column — but `nodes` has NO `metadata` column (only
251
+ * `edges` does; see schema.sql). `Node.metadata` is genuinely never
252
+ * persisted anywhere in this codebase today (the pre-existing
253
+ * `DoCmd.OpenForm` stub's `metadata:{stub:true}` on its `form-layout`
254
+ * node has the same characteristic — decorative at extraction time only).
255
+ * Adding a nodes-wide schema column is out of scope for this targeted fix.
256
+ *
257
+ * Equivalent-semantics fix: a VBA call-stub node is, BY DEFINITION,
258
+ * exactly a node that is the TARGET of a `calls` edge whose OWN metadata
259
+ * (which DOES persist) carries `stub: true`. So this queries via a JOIN
260
+ * against `edges.metadata` instead of a `nodes.metadata` column — same
261
+ * LIKE-prefilter-then-correctness-check shape as the JSON-in-JS
262
+ * convention, just anchored on the table that actually stores metadata
263
+ * for this row type.
264
+ */
265
+ getVbaCallStubs(): Node[];
266
+ /**
267
+ * Repoint an edge's `target` + `metadata` in place, leaving all other
268
+ * columns (source, kind, line, col, provenance) untouched. Used by
269
+ * `resolveVbaCallStubs` to redirect a stub `calls` edge to its resolved
270
+ * real node (#12). `metadataJson` is the caller's already-serialized JSON
271
+ * text (or null to clear it) — mirrors `insertEdge`'s convention of
272
+ * storing edge metadata as TEXT.
273
+ */
274
+ repointEdgeTarget(edgeId: number, newTargetId: string, metadataJson: string | null): void;
275
+ /**
276
+ * Delete a single edge row by its AUTOINCREMENT id. Used by
277
+ * `resolveVbaCallStubs` to collapse a duplicate `(source,target,kind)`
278
+ * edge onto an already-repointed one (F1) instead of leaving two
279
+ * identical rows.
280
+ */
281
+ deleteEdgeById(id: number): void;
282
+ /**
283
+ * True iff a `(source, target, kind)` edge row already exists. Used by
284
+ * `resolveVbaCallStubs` to detect a would-be duplicate before repointing
285
+ * a second stub edge onto the same real target (F1 duplicate-collapse).
286
+ */
287
+ edgeExists(source: string, target: string, kind: EdgeKind): boolean;
243
288
  /**
244
289
  * Find all edges where both source and target are in the given node set.
245
290
  * Useful for recovering inter-node connectivity after BFS.
@@ -57,6 +57,8 @@ export declare class VbaExtractor {
57
57
  private createModuleOrClassNode;
58
58
  /** Sub/Function/Property regex — captures visibility prefix, kind, and name. */
59
59
  private static readonly PROC_RE;
60
+ /** `[visibility] Declare [PtrSafe] Sub|Function <Name> ...` DLL/API declaration. */
61
+ private static readonly DLL_DECLARE_RE;
60
62
  /**
61
63
  * Walk the (uncommented, line-joined) source and emit one `function` node
62
64
  * per `Sub` / `Function` / `Property` declaration. Also records the proc
@@ -112,13 +114,6 @@ export declare class VbaExtractor {
112
114
  private static readonly ENUM_MEMBER_RE;
113
115
  /** `[visibility] Const <decls>` — captures visibility (1) and the rest (2). */
114
116
  private static readonly CONST_DECL_RE;
115
- /**
116
- * One declared name inside a `Const` body. A name sits at a declaration
117
- * boundary (start-of-body or after a comma), optionally followed by
118
- * `As <Type>`, then `=`. Run with /g over the CONST_DECL_RE group 2 so
119
- * multi-name lines (`Const A = 1, B = 2`) emit one node per name.
120
- */
121
- private static readonly CONST_NAME_RE;
122
117
  /**
123
118
  * Fold a VBA visibility keyword to the canonical lowercase enum, matching
124
119
  * the procedure convention: `Private` → 'private'; `Public`, `Global`,
@@ -164,16 +159,15 @@ export declare class VbaExtractor {
164
159
  /**
165
160
  * `DoCmd.OpenForm "<FormName>"` modelling regex — B4 (hueco 6).
166
161
  *
167
- * Real VBA idiom (matches both forms):
162
+ * Real VBA idiom (matches literal and bare-identifier forms):
168
163
  * `DoCmd.OpenForm "MyForm"`
164
+ * `DoCmd.OpenForm FORM_MY_FORM`
169
165
  * `DoCmd.OpenForm "MyForm", acNormal, , , acFormEdit`
170
166
  *
171
- * Captures the form NAME (group 1) so the extractor can synthesize an
172
- * `opens-form` heuristic edge from the calling Sub to a stub for the
173
- * target form. The trailing positional args (`acNormal`, `acFormEdit`,
174
- * etc.) are intentionally NOT captured — the orchestrator's scope decision
175
- * was to cover ONLY `OpenForm` for this commit; `OpenReport`, `OpenQuery`,
176
- * `OpenTable`, … are flagged in the commit body as follow-up work.
167
+ * Captures the first argument (group 1). String literals are unwrapped;
168
+ * bare identifiers resolve against local Const declarations, falling back
169
+ * to the identifier name when unknown. The trailing positional args
170
+ * (`acNormal`, `acFormEdit`, etc.) are intentionally NOT captured.
177
171
  *
178
172
  * Why a separate dispatch: `DoCmd` is in `RUNTIME_RECEIVER_BLACKLIST`
179
173
  * (R4 invariant), so `DoCmd.OpenForm` is intentionally SKIPPED by the
@@ -182,7 +176,7 @@ export declare class VbaExtractor {
182
176
  * matches BEFORE the call-site scan and uses its own dispatch to emit
183
177
  * the `opens-form` edge instead — sharing no logic with CALL_RE.
184
178
  */
185
- private static readonly OPEN_FORM_RE;
179
+ private static readonly OPEN_FORM_ARG_RE;
186
180
  /** SQL assigned to a local variable, e.g. `m_SQL = "SELECT ..." & ...`. */
187
181
  private static readonly SQL_VAR_ASSIGN_RE;
188
182
  /** SQL wrapper called with a variable, e.g. `getdb().Execute m_SQL`. */
@@ -245,6 +239,19 @@ export declare class VbaExtractor {
245
239
  * return false so runtime/DAO calls are suppressed.
246
240
  */
247
241
  private isLocalProjectClassVar;
242
+ /**
243
+ * #12a: resolve the "receiver type" used to build a qualified call-stub's
244
+ * name/qualifiedName. When `receiverName` is a file-local variable typed
245
+ * as a candidate project class (`isLocalProjectClassVar`), returns the
246
+ * RESOLVED CLASS NAME from `localVarTypeMap` (e.g. `m_NCOp` typed
247
+ * `As NCOperaciones` → `'NCOperaciones'`) so the stub's qualifiedName
248
+ * matches the real `.cls` method's `${className}.${proc}` shape and the
249
+ * post-extraction resolver (#12b) can find it via an exact qualifiedName
250
+ * match. Otherwise returns `receiverName` unchanged — this is the case
251
+ * for `.bas`-qualified module calls (`modUtils.Foo`), where the receiver
252
+ * IS already the target module's name and no resolution is needed.
253
+ */
254
+ private resolveReceiverType;
248
255
  private sweepCallsAndSql;
249
256
  private scanCallSites;
250
257
  /** Cache so we don't re-emit the same proc function node per call site. */
@@ -348,11 +355,9 @@ export declare class VbaExtractor {
348
355
  * flagged this as acceptable for B4 — only `OpenForm` is in scope.
349
356
  * `OpenReport`, `OpenQuery`, `OpenTable`, … are follow-up work.
350
357
  *
351
- * Scope note: this regex matches ONLY the literal-string form
352
- * `DoCmd.OpenForm "X"`. Variable-form calls like
353
- * `DoCmd.OpenForm m_FormName` are intentionally NOT captured here
354
- * because resolving the variable to a concrete form name would
355
- * require data-flow analysis that is out of scope.
358
+ * Scope note: this regex matches literal-string and bare-identifier forms.
359
+ * Bare identifiers are resolved only through local `Const` declarations;
360
+ * arbitrary variable data-flow remains intentionally out of scope.
356
361
  */
357
362
  private scanOpenFormCalls;
358
363
  /**
@@ -374,6 +379,19 @@ export declare class VbaExtractor {
374
379
  */
375
380
  private emitOpensFormEdge;
376
381
  private scanSqlInLine;
382
+ /**
383
+ * #13 fix: `sql = sql & "..."` (self-referential concatenation) must
384
+ * ACCUMULATE the new fragment onto whatever was already tracked for
385
+ * `varName`, not overwrite it. Overwriting silently dropped earlier
386
+ * fragments' tables — typically the initial `FROM <table>` in
387
+ * `sql = "SELECT * FROM tblA"` followed by `sql = sql & " WHERE x=1"`.
388
+ *
389
+ * Detection: the RHS (`m[2]`, trimmed) starts with `<varName> &`,
390
+ * case-insensitively — matching VBA's case-insensitive identifiers (`Sql`
391
+ * and `sql` are the same variable). A genuine fresh assignment (RHS does
392
+ * NOT start with the self-reference) still RESETS tracking — that
393
+ * behavior is unchanged.
394
+ */
377
395
  private trackSqlVariableAssignment;
378
396
  private collectStringLiteralText;
379
397
  private emitSqlTableReferences;
@@ -390,5 +408,7 @@ export declare class VbaExtractor {
390
408
  * typed as a SIMPLE (non-qualified, non-primitive) identifier emit edges.
391
409
  */
392
410
  private localVarTypeMap;
411
+ /** Local constant name (lowercase) → simple literal value for OpenForm resolution. */
412
+ private localConstants;
393
413
  }
394
414
  //# sourceMappingURL=vba-extractor.d.ts.map
@@ -16,7 +16,11 @@
16
16
  * Both are STRIPPED only when outside double-quoted strings. We walk
17
17
  * character-by-character so a `'` inside `"..."` is preserved.
18
18
  *
19
- * 3. extractStringLiterals(src)
19
+ * 3. preprocessConditionalCompilation(src)
20
+ * Blanks inactive VBA conditional-compilation branches (`#If`, `#ElseIf`,
21
+ * `#Else`, `#End If`) while preserving line count.
22
+ *
23
+ * 4. extractStringLiterals(src)
20
24
  * Used by SQL-variable tracking to read literal fragments from assignments
21
25
  * such as `m_SQL = "SELECT ..." & ...`. It returns every `"..."` span
22
26
  * with its 1-based line and 0-based column. VBA doubles `"` inside literals
@@ -62,6 +66,18 @@ export declare function joinLineContinuations(src: string): string;
62
66
  * Source is treated as read-only.
63
67
  */
64
68
  export declare function stripVbaComments(src: string): string;
69
+ /**
70
+ * Evaluate VBA conditional-compilation directives for the modern Windows
71
+ * Access/VBA target this extractor is designed around:
72
+ * - VBA7 = true
73
+ * - Win64 = true
74
+ * - Mac = false
75
+ *
76
+ * Directives and inactive branch lines are replaced with empty strings so
77
+ * downstream extraction keeps source-line parity. Unsupported/unsafe
78
+ * expressions evaluate to false rather than throwing.
79
+ */
80
+ export declare function preprocessConditionalCompilation(src: string): string;
65
81
  export interface StringLiteralSpan {
66
82
  /** The literal content (no surrounding quotes; `""` collapsed to `"`). */
67
83
  text: string;
@@ -173,6 +173,44 @@ export declare class ReferenceResolver {
173
173
  * of newly-created edges.
174
174
  */
175
175
  resolveDeferredThisMemberRefs(): number;
176
+ /**
177
+ * VBA #12b — post-extraction resolver pass (vba-graph-connectivity-fixes,
178
+ * issue #12). Repoints qualified call-stub `calls` edges (tagged
179
+ * `metadata.stub === true` by the extractor's #12a stub-tagging) to their
180
+ * REAL cross-file target node when uniquely resolvable:
181
+ * - **Class-typed**: exact `qualifiedName` match. #12a already renamed
182
+ * the stub's name/qualifiedName to `${resolvedClassType}.${member}`
183
+ * (via `localVarTypeMap`), matching a real `.cls` method's own
184
+ * `${className}.${proc}` qualifiedName shape exactly.
185
+ * - **`.bas`-qualified fallback**: when the exact match finds nothing
186
+ * (the common case for `modUtils.Foo` — real `.bas` function
187
+ * qualifiedNames are bare, no module prefix), narrow bare-member
188
+ * candidates in `.bas` files to the ones whose containing module's
189
+ * identity equals the stub's receiver text (case-insensitive).
190
+ * Zero or ambiguous (2+) candidates at either step DECLINE — the stub
191
+ * (and its edges, whose `metadata.stub` stays `true`) is left untouched;
192
+ * never a crash.
193
+ *
194
+ * Duplicate `(source,target,'calls')` rows — e.g. two call sites in one
195
+ * Sub targeting the same real method — are collapsed to ONE surviving
196
+ * edge (F1): `edges` has an AUTOINCREMENT PK and no unique constraint, so
197
+ * blindly repointing every incoming edge would leave duplicate rows that
198
+ * make `codegraph_node`/explore double-count the caller.
199
+ *
200
+ * Invoked at the `resolveChainedCallsViaConformance()` lifecycle slot in
201
+ * both `indexAll()` and `sync()` (src/index.ts). Idempotent: a stub that
202
+ * was already resolved in a prior pass no longer exists (its node was
203
+ * deleted), so `getVbaCallStubs()` won't return it again; re-running with
204
+ * no new stubs is a no-op.
205
+ */
206
+ resolveVbaCallStubs(): number;
207
+ /**
208
+ * Resolve a single VBA call-stub node to its real target, or `null` when
209
+ * unresolvable/ambiguous. See `resolveVbaCallStubs` for the two-step
210
+ * strategy (exact qualifiedName match, then `.bas` module-scoped
211
+ * fallback).
212
+ */
213
+ private resolveVbaCallStubTarget;
176
214
  private gateLanguage;
177
215
  /**
178
216
  * Drop a FRAMEWORK-strategy resolution that crosses two *known* language
package/dist/types.d.ts CHANGED
@@ -87,6 +87,15 @@ export interface Node {
87
87
  * An edge representing a relationship between two nodes
88
88
  */
89
89
  export interface Edge {
90
+ /**
91
+ * Database row id (AUTOINCREMENT PK on the `edges` table). Only populated
92
+ * when the edge was read back from the DB (e.g. via `getIncomingEdges`);
93
+ * undefined for edges constructed in-memory by an extractor/resolver
94
+ * before insertion. Needed by `resolveVbaCallStubs` to target a specific
95
+ * row for `repointEdgeTarget`/`deleteEdgeById` (vba-graph-connectivity-
96
+ * fixes, #12) since `edges` has no natural unique key.
97
+ */
98
+ id?: number;
90
99
  /** Source node ID */
91
100
  source: string;
92
101
  /** Target node ID */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aroman22/codegraph-vba",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "Local-first code intelligence for AI agents (MCP). Self-contained — bundles its own runtime.",
5
5
  "bin": {
6
6
  "codegraph-vba": "npm-shim.js"
@@ -15,12 +15,12 @@
15
15
  "./package.json": "./package.json"
16
16
  },
17
17
  "optionalDependencies": {
18
- "@aroman22/codegraph-vba-darwin-arm64": "1.3.3",
19
- "@aroman22/codegraph-vba-darwin-x64": "1.3.3",
20
- "@aroman22/codegraph-vba-linux-arm64": "1.3.3",
21
- "@aroman22/codegraph-vba-linux-x64": "1.3.3",
22
- "@aroman22/codegraph-vba-win32-arm64": "1.3.3",
23
- "@aroman22/codegraph-vba-win32-x64": "1.3.3"
18
+ "@aroman22/codegraph-vba-darwin-arm64": "1.3.4",
19
+ "@aroman22/codegraph-vba-darwin-x64": "1.3.4",
20
+ "@aroman22/codegraph-vba-linux-arm64": "1.3.4",
21
+ "@aroman22/codegraph-vba-linux-x64": "1.3.4",
22
+ "@aroman22/codegraph-vba-win32-arm64": "1.3.4",
23
+ "@aroman22/codegraph-vba-win32-x64": "1.3.4"
24
24
  },
25
25
  "files": [
26
26
  "npm-shim.js",