@aroman22/codegraph-vba 1.10.0 → 1.11.0
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.
- package/dist/db/queries.d.ts +37 -0
- package/dist/extraction/frameworks/dysflow-export.d.ts +37 -0
- package/dist/extraction/frameworks/index.d.ts +20 -0
- package/dist/extraction/parse-pool.d.ts +10 -0
- package/dist/extraction/tree-sitter.d.ts +9 -1
- package/dist/extraction/vba/call-sweep.d.ts +43 -0
- package/dist/extraction/vba/context.d.ts +109 -1
- package/dist/extraction/vba/declarations.d.ts +38 -2
- package/dist/extraction/vba/dims.d.ts +35 -1
- package/dist/extraction/vba/enums-consts.d.ts +47 -7
- package/dist/extraction/vba/event-synth.d.ts +3 -0
- package/dist/extraction/vba/implements.d.ts +16 -0
- package/dist/extraction/vba/procedures.d.ts +20 -0
- package/dist/extraction/vba/rules.d.ts +125 -0
- package/dist/extraction/vba-extractor.d.ts +77 -1
- package/dist/extraction/vba-preprocess.d.ts +11 -1
- package/dist/extraction/vba-timing.d.ts +38 -0
- package/dist/project-config.d.ts +31 -0
- package/package.json +7 -7
package/dist/db/queries.d.ts
CHANGED
|
@@ -354,6 +354,43 @@ export declare class QueryBuilder {
|
|
|
354
354
|
* a second stub edge onto the same real target (F1 duplicate-collapse).
|
|
355
355
|
*/
|
|
356
356
|
edgeExists(source: string, target: string, kind: EdgeKind): boolean;
|
|
357
|
+
/**
|
|
358
|
+
* Issue #150 — return every `references` edge whose metadata was
|
|
359
|
+
* stamped by the given `synthesizedBy` key. Used by the
|
|
360
|
+
* event-handler synthesis pass to find every `WithEvents` binding
|
|
361
|
+
* in the project. The `metadata LIKE` filter is a cheap index-free
|
|
362
|
+
* pre-filter (a `synthesizedBy` value can appear as a substring of
|
|
363
|
+
* another); callers must still exact-check the parsed JSON
|
|
364
|
+
* `metadata.synthesizedBy` field.
|
|
365
|
+
*
|
|
366
|
+
* Returns the raw rows (id, source, target, metadata JSON). Callers
|
|
367
|
+
* join against `getNodeById` to materialize the source/target Node
|
|
368
|
+
* values. The `references` edges this returns are the
|
|
369
|
+
* `resolveVbaReferenceStubs`-repointed ones (target is the real
|
|
370
|
+
* class node, not the synthetic stub), so the binding lookup
|
|
371
|
+
* survives the resolver.
|
|
372
|
+
*/
|
|
373
|
+
getReferencesBySynthesizedBy(synthesizedBy: string): Array<{
|
|
374
|
+
id: number;
|
|
375
|
+
source: string;
|
|
376
|
+
target: string;
|
|
377
|
+
metadata: string | null;
|
|
378
|
+
}>;
|
|
379
|
+
/**
|
|
380
|
+
* Issue #150 — return every `raises-event` edge in the DB. Used by
|
|
381
|
+
* the event-handler synthesis pass to walk every `RaiseEvent`
|
|
382
|
+
* statement and connect it to its `m_<var>_<EventName>` handler
|
|
383
|
+
* Sub. Returns the raw rows; callers parse the metadata to pull
|
|
384
|
+
* the `eventName` for downstream edge construction.
|
|
385
|
+
*/
|
|
386
|
+
getRaisesEventEdges(): Array<{
|
|
387
|
+
id: number;
|
|
388
|
+
source: string;
|
|
389
|
+
target: string;
|
|
390
|
+
line: number | null;
|
|
391
|
+
col: number | null;
|
|
392
|
+
metadata: string | null;
|
|
393
|
+
}>;
|
|
357
394
|
/**
|
|
358
395
|
* Find all edges where both source and target are in the given node set.
|
|
359
396
|
* Useful for recovering inter-node connectivity after BFS.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dysflow-export framework resolver (issue #154).
|
|
3
|
+
*
|
|
4
|
+
* The 3 Dysflow-specific extractors ÔÇö form/report SaveAsText UI, test
|
|
5
|
+
* manifests, and test sequences ÔÇö used to be hard-coded into
|
|
6
|
+
* `extractFromSource` as a `detectedLanguage === 'vba' && <isFoo> (filePath)`
|
|
7
|
+
* ladder. They are now lifted into this `FrameworkResolver`-shaped module
|
|
8
|
+
* so they can be:
|
|
9
|
+
* 1. Reached through the standard framework registry (the same path every
|
|
10
|
+
* other framework ÔÇö Express, React, Spring ÔÇö flows through).
|
|
11
|
+
* 2. Opted out at the project level via `codegraph.json`'s
|
|
12
|
+
* `vba.dysflowExport: false` ÔÇö useful for projects that carry legacy
|
|
13
|
+
* `.form.txt`/`.report.txt` files (or test manifests from a different
|
|
14
|
+
* system) and want them tracked as just a `file` node instead of
|
|
15
|
+
* being expanded into the graph.
|
|
16
|
+
*
|
|
17
|
+
* Architecture: the underlying `VbaFormExtractor` / `VbaTestManifestExtractor`
|
|
18
|
+
* / `VbaTestSequenceExtractor` classes are the single source of truth for
|
|
19
|
+
* the per-file extraction logic. This module:
|
|
20
|
+
* - decides WHICH sub-extractor applies to a file (path shape);
|
|
21
|
+
* - delegates the actual `extract()` to that sub-extractor;
|
|
22
|
+
* - exposes the `FrameworkResolver` shape (`detect` / `extract` /
|
|
23
|
+
* `resolve` / `claimsReference`) so the rest of the codebase can treat
|
|
24
|
+
* "Dysflow export" as a regular framework on top of the base VBA
|
|
25
|
+
* language.
|
|
26
|
+
*
|
|
27
|
+
* Behavior contract: with `dysflowExport: true` (the default), the emitted
|
|
28
|
+
* nodes/edges/references are byte-identical to the pre-refactor paths in
|
|
29
|
+
* `tree-sitter.ts`. With `dysflowExport: false`, the framework's `detect()`
|
|
30
|
+
* returns `false` so it's never in the per-project detected list ÔÇö meaning
|
|
31
|
+
* its `extract()` is never called and the form/report/manifest/sequence
|
|
32
|
+
* files fall through to a `file`-only node via the language-specific
|
|
33
|
+
* dispatch in `tree-sitter.ts`.
|
|
34
|
+
*/
|
|
35
|
+
import { FrameworkResolver } from '../../resolution/types';
|
|
36
|
+
export declare const dysflowExportResolver: FrameworkResolver;
|
|
37
|
+
//# sourceMappingURL=dysflow-export.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extraction-side framework resolvers.
|
|
3
|
+
*
|
|
4
|
+
* `src/extraction/frameworks/` is the home for `FrameworkResolver`s whose
|
|
5
|
+
* primary contribution is per-file extraction (nodes + references), as
|
|
6
|
+
* opposed to `src/resolution/frameworks/` whose resolvers are primarily
|
|
7
|
+
* reference resolvers. The two registries are kept separate so a future
|
|
8
|
+
* "extraction-only" framework (e.g. another format-specific generator)
|
|
9
|
+
* doesn't drag in the full resolution pipeline, and so the namespacing
|
|
10
|
+
* matches the layer the resolver actually plugs into.
|
|
11
|
+
*
|
|
12
|
+
* Currently only the Dysflow export resolver lives here ÔÇö the 3
|
|
13
|
+
* Dysflow-specific extractors (form/report, test manifest, test
|
|
14
|
+
* sequence) were lifted out of `tree-sitter.ts` into this `FrameworkResolver`
|
|
15
|
+
* shape so the project can opt out via `codegraph.json`
|
|
16
|
+
* (`vba.dysflowExport: false`, issue #154). New extraction-side frameworks
|
|
17
|
+
* (e.g. a future "terraform state" generator) should be added here.
|
|
18
|
+
*/
|
|
19
|
+
export { dysflowExportResolver } from './dysflow-export';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -48,6 +48,16 @@ export interface ParseTask {
|
|
|
48
48
|
language: Language;
|
|
49
49
|
frameworkNames?: string[];
|
|
50
50
|
vbaTargets?: Record<string, boolean>;
|
|
51
|
+
/** Issue #152: per-file fanout cap for `RaiseEvent` edges (VBA only). */
|
|
52
|
+
maxRaiseFanout?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Issue #154 — gate the 3 Dysflow-specific VBA sub-extractors. `true`
|
|
55
|
+
* (the default) keeps the pre-refactor behavior; `false` opts out so
|
|
56
|
+
* form/report/manifest/sequence files are tracked as just a `file`
|
|
57
|
+
* node. Threaded through the worker so the same flag is honored on
|
|
58
|
+
* either side of the pool boundary.
|
|
59
|
+
*/
|
|
60
|
+
dysflowExport?: boolean;
|
|
51
61
|
}
|
|
52
62
|
/**
|
|
53
63
|
* Resolve the pool size from the `CODEGRAPH_PARSE_WORKERS` override and the
|
|
@@ -701,6 +701,14 @@ export declare class TreeSitterExtractor {
|
|
|
701
701
|
* If `frameworkNames` is provided, framework-specific extractors matching
|
|
702
702
|
* those names and the file's language are run after the tree-sitter pass.
|
|
703
703
|
* Their nodes/references/errors are merged into the returned result.
|
|
704
|
+
*
|
|
705
|
+
* `dysflowExport` (issue #154) gates the 3 Dysflow-specific VBA
|
|
706
|
+
* sub-extractors (form/report SaveAsText, test manifests, test sequences).
|
|
707
|
+
* `true` (the default) preserves the pre-refactor behavior; `false` opts
|
|
708
|
+
* out so `.form.txt`/`.report.txt`/manifest/sequence files are tracked as
|
|
709
|
+
* just a `file` node. Read from `codegraph.json` via
|
|
710
|
+
* `loadDysflowExportConfig(rootDir)` at the call site and threaded in here
|
|
711
|
+
* so this function stays project-config-agnostic.
|
|
704
712
|
*/
|
|
705
|
-
export declare function extractFromSource(filePath: string, source: string, language?: Language, frameworkNames?: string[], vbaTargets?: Record<string, boolean
|
|
713
|
+
export declare function extractFromSource(filePath: string, source: string, language?: Language, frameworkNames?: string[], vbaTargets?: Record<string, boolean>, maxRaiseFanout?: number, dysflowExport?: boolean): ExtractionResult;
|
|
706
714
|
//# sourceMappingURL=tree-sitter.d.ts.map
|
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
import { VbaExtractorContext, VbaClassifier } from './context';
|
|
2
|
+
import { VbaExtractionRule } from './rules';
|
|
3
|
+
/**
|
|
4
|
+
* Issue #153: the declarative rule table for the calls/SQL concern.
|
|
5
|
+
*
|
|
6
|
+
* Of the call-sweep's full machinery, only the per-line *patterns*
|
|
7
|
+
* fit the declarative shape. The procedural scanners
|
|
8
|
+
* (`scanRaiseEvents`, `scanCallSites`, `scanMeControlReferences`,
|
|
9
|
+
* `scanSqlInLine`, `scanDoCmdOpenCalls`, `scanDoCmdOpenQuery`,
|
|
10
|
+
* `scanFormsBang`, `sweepTempVars`, statement/qualified call
|
|
11
|
+
* detection) walk the masked line scanning for call shapes that
|
|
12
|
+
* don't reduce to a single regex — they stay inside the factory's
|
|
13
|
+
* `classifyLine` (acknowledged in the Issue #153 spec: "The
|
|
14
|
+
* inter-line state machines (procedure stack, with stack,
|
|
15
|
+
* sqlVariables) NEED a class, not a pure rule.").
|
|
16
|
+
*
|
|
17
|
+
* Four rules, all driven by the masked line (the call site / Set
|
|
18
|
+
* patterns must not match inside string literals):
|
|
19
|
+
*
|
|
20
|
+
* - `set-new` — `Set <var> = New <Type>[.<Inner>]`; registers the
|
|
21
|
+
* receiver in `localVarTypeMap` and emits a
|
|
22
|
+
* `vba-set-new` `references` edge.
|
|
23
|
+
* - `set-call` — `Set <var> = <Factory>(...)`; types the receiver
|
|
24
|
+
* from a same-file function's project-class return
|
|
25
|
+
* type so a later `x.Method` resolves to the
|
|
26
|
+
* factory's class. Emits a `vba-factory-return`
|
|
27
|
+
* `references` edge.
|
|
28
|
+
* - `with-start` — `With <receiver>`; normalizes the receiver and
|
|
29
|
+
* pushes it onto `ctx.vbaWithStack` (replaces the
|
|
30
|
+
* pre-#153 per-factory closure variable).
|
|
31
|
+
* - `with-end` — `End With`; pops the matching `ctx.vbaWithStack`
|
|
32
|
+
* entry.
|
|
33
|
+
*
|
|
34
|
+
* The `set-new` rule's emit function is a "pure" (match, ctx, line)
|
|
35
|
+
* consumer — it reads/writes only `ctx` and the unmasked/ masked
|
|
36
|
+
* line, with no closure references. Same for the other three.
|
|
37
|
+
*/
|
|
38
|
+
export declare const RULES: readonly VbaExtractionRule<unknown>[];
|
|
2
39
|
/**
|
|
3
40
|
* Issue #83: factory for the calls/SQL classifier. The factory takes the
|
|
4
41
|
* pre-split `lines` array (so `trackSqlVariableAssignment` can do its
|
|
5
42
|
* multi-line look-ahead for `&`-accumulate semantics) and closes over the
|
|
6
43
|
* per-file state the legacy `sweepCallsAndSql` declared locally.
|
|
44
|
+
*
|
|
45
|
+
* Issue #153: the per-line pattern matching has been extracted into
|
|
46
|
+
* the `RULES` table. The factory body is now a thin shell that
|
|
47
|
+
* dispatches `RULES` and runs the procedural scanners (call sites,
|
|
48
|
+
* raise events, SQL, DoCmd, TempVars, etc.) that don't reduce to a
|
|
49
|
+
* single regex.
|
|
7
50
|
*/
|
|
8
51
|
export declare function createCallsAndSqlClassifier(lines: readonly string[]): VbaClassifier;
|
|
9
52
|
/**
|
|
@@ -143,8 +143,58 @@ export declare class VbaExtractorContext {
|
|
|
143
143
|
* of every procedure whose `End` marker the sweep has not yet seen.
|
|
144
144
|
*/
|
|
145
145
|
procStack: number[];
|
|
146
|
+
/**
|
|
147
|
+
* Issue #153: per-extraction state for the events/types/declares
|
|
148
|
+
* classifier's `Type <Name> ... End Type` block tracking. The
|
|
149
|
+
* `currentTypeBlock` is set when a `type-start` rule fires and
|
|
150
|
+
* cleared when the matching `type-end` rule fires. Lives on `ctx`
|
|
151
|
+
* (instead of the factory's closure) so the declarative RULES
|
|
152
|
+
* table's `emit` functions can read/write it without taking a
|
|
153
|
+
* closure-captured mutable reference. `null` means "outside any
|
|
154
|
+
* type block right now". Reset implicitly per-extraction (a fresh
|
|
155
|
+
* `VbaExtractorContext` is constructed every `extract()` call).
|
|
156
|
+
*/
|
|
157
|
+
vbaDeclTypeBlock: {
|
|
158
|
+
id: string;
|
|
159
|
+
name: string;
|
|
160
|
+
} | null;
|
|
161
|
+
/**
|
|
162
|
+
* Issue #153: per-extraction state for the enum/consts classifier's
|
|
163
|
+
* `Enum <Name> ... End Enum` block tracking. Same shape and
|
|
164
|
+
* rationale as `vbaDeclTypeBlock`: lives on `ctx` so the
|
|
165
|
+
* declarative RULES table's `emit` functions can read/write it
|
|
166
|
+
* without taking a closure-captured mutable reference.
|
|
167
|
+
* `null` means "outside any enum block right now".
|
|
168
|
+
*/
|
|
169
|
+
vbaEnumBlock: {
|
|
170
|
+
id: string;
|
|
171
|
+
name: string;
|
|
172
|
+
} | null;
|
|
173
|
+
/**
|
|
174
|
+
* Issue #153: per-extraction state for the calls/SQL classifier's
|
|
175
|
+
* `With <receiver> ... End With` block tracking. The with-receiver
|
|
176
|
+
* stack mirrors the textual nesting of `With` blocks inside a
|
|
177
|
+
* procedure body — the top of the stack is the active receiver
|
|
178
|
+
* for `.Member` and `.Member(args)` statement-form calls. Reset
|
|
179
|
+
* implicitly per-extraction (a fresh `VbaExtractorContext` is
|
|
180
|
+
* constructed every `extract()` call). Replaces the per-factory
|
|
181
|
+
* closure variable that lived in `sweepCallsAndSql` before the
|
|
182
|
+
* Issue #153 RULES-table refactor.
|
|
183
|
+
*/
|
|
184
|
+
vbaWithStack: string[];
|
|
146
185
|
/** Local event name (lowercase) → event node for `RaiseEvent` edge emission. */
|
|
147
186
|
localEvents: Map<string, Node>;
|
|
187
|
+
/**
|
|
188
|
+
* Issue #152: per-event counter for `RaiseEvent <EventName>` sites. Keyed
|
|
189
|
+
* by event node id (so two different events that share a name across
|
|
190
|
+
* files don't collide — the gate is per-file). The count is incremented
|
|
191
|
+
* in `scanRaiseEvents` BEFORE the edge is pushed, so the count equals
|
|
192
|
+
* the number of raise sites regardless of the gate decision downstream.
|
|
193
|
+
* The orchestrator's fanout-gate pass reads this map to decide which
|
|
194
|
+
* event nodes to flag `metadata.highFanout: true` and which `raises-event`
|
|
195
|
+
* edges to drop.
|
|
196
|
+
*/
|
|
197
|
+
raiseEventCounts: Map<string, number>;
|
|
148
198
|
/**
|
|
149
199
|
* Same-file function/property return types, keyed by lowercase proc name →
|
|
150
200
|
* declared return type. ONLY non-primitive (project-class) return types are
|
|
@@ -156,7 +206,34 @@ export declare class VbaExtractorContext {
|
|
|
156
206
|
* time) — that stays the resolver's frontier.
|
|
157
207
|
*/
|
|
158
208
|
functionReturnTypes: Map<string, string>;
|
|
209
|
+
/**
|
|
210
|
+
* Issue #156: per-stage timings, lazily allocated ONLY when
|
|
211
|
+
* `CODEGRAPH_VBA_TIMING=1|2` is set. The default path (env var unset)
|
|
212
|
+
* keeps this `null` so `recordStage` is a single null-check and we
|
|
213
|
+
* pay zero Map-allocation cost in the hot path. Stage names are
|
|
214
|
+
* dot-separated: `preprocess.stripVbaComments`,
|
|
215
|
+
* `preprocess.cc.lexer+parser`, `walk.procedures`, `walk.main`,
|
|
216
|
+
* `classifier.<name>`. Counters are in milliseconds (float).
|
|
217
|
+
*/
|
|
218
|
+
timings: Map<string, number> | null;
|
|
219
|
+
/**
|
|
220
|
+
* Issue #156: how many times each classifier's `classifyLine` was
|
|
221
|
+
* invoked. Only allocated together with `timings` so the default path
|
|
222
|
+
* pays no cost.
|
|
223
|
+
*/
|
|
224
|
+
classifierInvokeCounts: Map<string, number> | null;
|
|
159
225
|
constructor(filePath: string);
|
|
226
|
+
/**
|
|
227
|
+
* Issue #156: ensure the timings Maps exist. Called once per
|
|
228
|
+
* `extract()` by the orchestrator right after it reads the env var.
|
|
229
|
+
* No-op when already allocated.
|
|
230
|
+
*/
|
|
231
|
+
ensureTimings(): void;
|
|
232
|
+
/**
|
|
233
|
+
* Issue #156: add `ms` to the stage named `name`. No-op when
|
|
234
|
+
* `timings` is null (default path).
|
|
235
|
+
*/
|
|
236
|
+
recordStage(name: string, ms: number): void;
|
|
160
237
|
/**
|
|
161
238
|
* Emit a `contains` edge from the (lazily-created) module/class node to
|
|
162
239
|
* `targetId`. Mirrors the pending-source pattern the procedure and
|
|
@@ -193,6 +270,27 @@ export declare class VbaExtractorContext {
|
|
|
193
270
|
resolveReceiverType(receiverName: string): string;
|
|
194
271
|
findOrCreateFunctionNodeId(proc: ProcInfo): string;
|
|
195
272
|
findFunctionNodeByName(name: string): Node | undefined;
|
|
273
|
+
/**
|
|
274
|
+
* Issue #152: apply the per-file `RaiseEvent` fanout gate. For every
|
|
275
|
+
* event whose `raiseEventCounts` value exceeds `maxFanout`:
|
|
276
|
+
* 1. Stamp the event node's `metadata.highFanout = true` and
|
|
277
|
+
* `metadata.raiseCount = <count>` so consumers (codegraph_explore,
|
|
278
|
+
* vba-event-tracer) can recognize a high-fanout event.
|
|
279
|
+
* 2. Drop every `raises-event` edge targeting that event id from
|
|
280
|
+
* `edges`. The event node itself stays — declaration site, handler
|
|
281
|
+
* linkage via `subscribes-event`, and metadata are all preserved.
|
|
282
|
+
*
|
|
283
|
+
* Events with `<= maxFanout` raise sites are untouched (no flag, edges
|
|
284
|
+
* stay). When `maxFanout` is undefined, the gate is disabled and the
|
|
285
|
+
* method is a no-op. Mirrors the upstream `EVENT_FANOUT_CAP` discipline
|
|
286
|
+
* in `src/resolution/callback-synthesizer.ts:43` (this side suppresses
|
|
287
|
+
* the producer side, the upstream side suppresses the synthesized
|
|
288
|
+
* cross-file dispatcher/handler edges).
|
|
289
|
+
*
|
|
290
|
+
* Returns the number of `raises-event` edges dropped (zero when the
|
|
291
|
+
* gate is disabled or no event exceeds the cap — useful for tests).
|
|
292
|
+
*/
|
|
293
|
+
applyRaiseFanoutGate(maxFanout: number | undefined): number;
|
|
196
294
|
/**
|
|
197
295
|
* Emit a `references` edge from the file's module/class node to a synthetic
|
|
198
296
|
* node named `targetName`. Used by Dim, WithEvents, Set-New, and SQL sweeps.
|
|
@@ -206,8 +304,18 @@ export declare class VbaExtractorContext {
|
|
|
206
304
|
* TempVars sweep already emits (`emitTempVarReference`). Omitted for
|
|
207
305
|
* structural references (Dim/WithEvents/Set-New) where the direction is not
|
|
208
306
|
* meaningful.
|
|
307
|
+
*
|
|
308
|
+
* `extras` (optional): additional metadata fields to merge into the
|
|
309
|
+
* emitted edge's `metadata` object. Used by the WithEvents sweep to
|
|
310
|
+
* stamp `variableName` (issue #150) so the post-extraction
|
|
311
|
+
* event-handler synthesis pass can find the `m_<var>_<event>`
|
|
312
|
+
* handler Sub even after `resolveVbaReferenceStubs` CASCADE-deletes
|
|
313
|
+
* the companion `subscribes-event` edge along with the synthetic
|
|
314
|
+
* class stub. Fields here are merged AFTER the standard
|
|
315
|
+
* `{ synthesizedBy [, access] }` shape, so callers can override
|
|
316
|
+
* (rarely useful) but not accidentally drop the stamp.
|
|
209
317
|
*/
|
|
210
|
-
emitReference(targetName: string, lineNum: number, column: number, synthesizedBy: string, access?: 'read' | 'write'): void;
|
|
318
|
+
emitReference(targetName: string, lineNum: number, column: number, synthesizedBy: string, access?: 'read' | 'write', extras?: Record<string, unknown>): void;
|
|
211
319
|
/**
|
|
212
320
|
* Issue #52: shared lookup helper for `scanDoCmdOpenCalls` and
|
|
213
321
|
* `scanDoCmdOpenQuery`. The current scope is the procedure whose
|
|
@@ -1,7 +1,43 @@
|
|
|
1
1
|
import { VbaExtractorContext, VbaClassifier } from './context';
|
|
2
|
+
import { VbaExtractionRule } from './rules';
|
|
2
3
|
/**
|
|
3
|
-
* Issue #
|
|
4
|
-
*
|
|
4
|
+
* Issue #153: the declarative rule table for the events/types/declares
|
|
5
|
+
* concern. Five rules, partitioned by where they fire:
|
|
6
|
+
*
|
|
7
|
+
* - `event-decl` (outside-type-block) — match an `Event <Name>` decl
|
|
8
|
+
* - `type-start` (outside-type-block) — match a `Type <Name>` header;
|
|
9
|
+
* sets `ctx.vbaDeclTypeBlock` on a successful match
|
|
10
|
+
* - `type-end` (inside-type-block) — match `End Type`; clears
|
|
11
|
+
* `ctx.vbaDeclTypeBlock` on a successful match
|
|
12
|
+
* - `type-member` (inside-type-block) — match `<Member> As <Type>`
|
|
13
|
+
* inside an open type block
|
|
14
|
+
* - `dll-declare` (outside-type-block) — match a `[Private|Public]
|
|
15
|
+
* Declare [PtrSafe] Sub|Function <Name> Lib "<dll>"
|
|
16
|
+
* [Alias "<x>"]` Win32 API declaration
|
|
17
|
+
*
|
|
18
|
+
* The `requires` field encodes the type-block precondition. The
|
|
19
|
+
* dispatcher (the factory's `classifyLine`) filters rules whose
|
|
20
|
+
* precondition does not hold, so an `End Type` line never
|
|
21
|
+
* accidentally re-enters the `event-decl` / `dll-declare` paths.
|
|
22
|
+
*
|
|
23
|
+
* Inter-line state lives on `ctx.vbaDeclTypeBlock` (replaces the
|
|
24
|
+
* pre-#153 factory closure variable) so the emit functions can
|
|
25
|
+
* read/write it without taking a mutable closure reference.
|
|
26
|
+
*/
|
|
27
|
+
export declare const RULES: readonly VbaExtractionRule<unknown>[];
|
|
28
|
+
/**
|
|
29
|
+
* Issue #83: factory for the events/types/declares classifier.
|
|
30
|
+
*
|
|
31
|
+
* Inter-line state (`ctx.vbaDeclTypeBlock`) lives on `ctx` — the
|
|
32
|
+
* declarative RULES table's `emit` functions read/write it directly.
|
|
33
|
+
* The dispatcher below honours each rule's `requires` precondition
|
|
34
|
+
* so the per-line dispatch mirrors the legacy cascade exactly:
|
|
35
|
+
*
|
|
36
|
+
* if (currentType) {
|
|
37
|
+
* try type-end, then type-member; return early
|
|
38
|
+
* } else {
|
|
39
|
+
* try event-decl, type-start, dll-declare
|
|
40
|
+
* }
|
|
5
41
|
*/
|
|
6
42
|
export declare function createEventsTypesDeclaresClassifier(): VbaClassifier;
|
|
7
43
|
/**
|
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
import { VbaExtractorContext, VbaClassifier } from './context';
|
|
2
|
+
import { VbaExtractionRule } from './rules';
|
|
2
3
|
/**
|
|
3
|
-
* Issue #
|
|
4
|
+
* Issue #153: the declarative rule table for the Dim / WithEvents
|
|
5
|
+
* concern. Two rules:
|
|
6
|
+
*
|
|
7
|
+
* - `dim-decl` — match a `Dim|Private|Public|Global|Static
|
|
8
|
+
* <var> [As [New] <TypePart>[.<TypePart>]][, …]`
|
|
9
|
+
* declaration; populate `localVarTypeMap` and
|
|
10
|
+
* emit one `references` edge per non-primitive
|
|
11
|
+
* type (or per qualified outer type).
|
|
12
|
+
* - `withevents-decl`— match a `[Dim|Private|Public|Global|Static]
|
|
13
|
+
* WithEvents <var> As <FormType>` declaration;
|
|
14
|
+
* populate `localVarTypeMap` with `withEvents: true`,
|
|
15
|
+
* emit a `references` edge (synthesizedBy:
|
|
16
|
+
* `vba-withevents`) and a `subscribes-event` edge.
|
|
17
|
+
*
|
|
18
|
+
* The two rules are dispatched independently and BOTH can fire on the
|
|
19
|
+
* same line in principle (a `WithEvents` line does NOT match the
|
|
20
|
+
* `Dim|Private|...` prefix because the negative lookahead excludes it).
|
|
21
|
+
* The `dim-decl` rule's `count` hook reports the number of
|
|
22
|
+
* non-primitive `references` edges it emitted, so a multi-variable
|
|
23
|
+
* `Dim a As Foo, b As Bar` line adds 2 to the classifier count, and a
|
|
24
|
+
* bare `Dim x` line adds 0 (the bare-Dim path is a `localVarTypeMap`
|
|
25
|
+
* only side effect, no graph edges).
|
|
26
|
+
*
|
|
27
|
+
* No inter-line state — each rule is self-contained.
|
|
28
|
+
*/
|
|
29
|
+
export declare const RULES: readonly VbaExtractionRule<unknown>[];
|
|
30
|
+
/**
|
|
31
|
+
* Issue #83: factory for the Dim / WithEvents classifier.
|
|
32
|
+
*
|
|
33
|
+
* The body walks the declarative `RULES` table (Issue #153). The two
|
|
34
|
+
* rules are independent: `dim-decl` handles typed declarations
|
|
35
|
+
* (REJECTED if the line is a `WithEvents` because the prefix
|
|
36
|
+
* negative-lookahead excludes `WithEvents`), `withevents-decl`
|
|
37
|
+
* handles WithEvents. No inter-line state.
|
|
4
38
|
*/
|
|
5
39
|
export declare function createDimsClassifier(): VbaClassifier;
|
|
6
40
|
/**
|
|
@@ -1,13 +1,53 @@
|
|
|
1
1
|
import { VbaExtractorContext, VbaClassifier } from './context';
|
|
2
|
+
import { VbaExtractionRule } from './rules';
|
|
2
3
|
/**
|
|
3
|
-
* Issue #
|
|
4
|
-
*
|
|
4
|
+
* Issue #153: the declarative rule table for the enum / const concern.
|
|
5
|
+
* Six rules, partitioned by where they fire:
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* - `proc-start` (outside-enum-block) — match a `Sub` /
|
|
8
|
+
* `Function` / `Property` header; push onto
|
|
9
|
+
* `ctx.procStack` and set `ctx.currentProcKey`
|
|
10
|
+
* so subsequent Const writes land in the
|
|
11
|
+
* per-proc resolution bucket.
|
|
12
|
+
* - `proc-end` (outside-enum-block) — match `End Sub` /
|
|
13
|
+
* `End Function` / `End Property`; pop the
|
|
14
|
+
* matching `procStack` entry.
|
|
15
|
+
* - `enum-start` (outside-enum-block) — match `[visibility]
|
|
16
|
+
* Enum <Name>`; emit an `enum` node + `contains`
|
|
17
|
+
* edge and mark `ctx.vbaEnumBlock`.
|
|
18
|
+
* - `enum-end` (inside-enum-block) — match `End Enum`; clear
|
|
19
|
+
* `ctx.vbaEnumBlock`.
|
|
20
|
+
* - `enum-member` (inside-enum-block) — match `<MemberName>
|
|
21
|
+
* [= <value>]`; emit an `enum_member` node + a
|
|
22
|
+
* `contains` edge from the open enum.
|
|
23
|
+
* - `const-decl` (outside-enum-block) — match `[visibility]
|
|
24
|
+
* Const <decls>`; always write the per-scope
|
|
25
|
+
* resolution bucket, and emit a `constant` node
|
|
26
|
+
* + `contains` edge ONLY when not inside a proc
|
|
27
|
+
* (proc-local Consts are not module symbols).
|
|
28
|
+
*
|
|
29
|
+
* The inter-line `ctx.procStack` / `ctx.currentProcKey` state is
|
|
30
|
+
* SHARED with the calls/SQL classifier (issue #52 protocol). The
|
|
31
|
+
* `ctx.vbaEnumBlock` state is local to this concern and lives on
|
|
32
|
+
* `ctx` for the same RULES-table-friendliness reason as
|
|
33
|
+
* `vbaDeclTypeBlock`.
|
|
34
|
+
*/
|
|
35
|
+
export declare const RULES: readonly VbaExtractionRule<unknown>[];
|
|
36
|
+
/**
|
|
37
|
+
* Issue #83: factory for the enum / const classifier.
|
|
38
|
+
*
|
|
39
|
+
* The body walks the declarative `RULES` table (Issue #153) and
|
|
40
|
+
* honours each rule's `requires` precondition. The inter-line
|
|
41
|
+
* state — `ctx.procStack`, `ctx.currentProcKey`, and
|
|
42
|
+
* `ctx.vbaEnumBlock` — lives on `ctx` so the RULES table's `emit`
|
|
43
|
+
* functions can read/write it without taking a closure reference.
|
|
44
|
+
*
|
|
45
|
+
* Issue #52: the first invocation also resets the shared proc-stack
|
|
46
|
+
* + lookup key so leftover state from a previous `extract()` (only
|
|
47
|
+
* possible in tests that construct a fresh extractor and run twice)
|
|
48
|
+
* never leaks across sweeps. The walk below updates both every
|
|
49
|
+
* iteration; `sweepCallsAndSql` resets again at its own start, so
|
|
50
|
+
* the protocol stays consistent across both classifiers.
|
|
11
51
|
*/
|
|
12
52
|
export declare function createEnumsConstsClassifier(): VbaClassifier;
|
|
13
53
|
/**
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { VbaExtractorContext, VbaClassifier } from './context';
|
|
2
|
+
import { VbaExtractionRule } from './rules';
|
|
3
|
+
/**
|
|
4
|
+
* Issue #153: the declarative rule table for the implements concern.
|
|
5
|
+
* One rule — `implements` — matching a leading `Implements <Name>`
|
|
6
|
+
* declaration. The body has no inter-line state to track, so the
|
|
7
|
+
* orchestrator walks the table and bumps `this.count` on every
|
|
8
|
+
* non-null emit. Keeps the inline `classifyLine` below honest: any
|
|
9
|
+
* branch not represented in this table is dead code.
|
|
10
|
+
*/
|
|
11
|
+
export declare const RULES: readonly VbaExtractionRule<unknown>[];
|
|
2
12
|
/**
|
|
3
13
|
* Issue #83: factory for the `Implements` classifier. Stateless per-line.
|
|
14
|
+
*
|
|
15
|
+
* The body walks the declarative `RULES` table — the inline regex
|
|
16
|
+
* match that lived here before #153 is now a single entry in
|
|
17
|
+
* `RULES`. This is the canonical pattern every classifier will
|
|
18
|
+
* converge on as part of the refactor; the legacy "one giant
|
|
19
|
+
* if/else cascade" is gone.
|
|
4
20
|
*/
|
|
5
21
|
export declare function createImplementsClassifier(): VbaClassifier;
|
|
6
22
|
/**
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import { VbaExtractorContext, ProcInfo, VbaClassifier } from './context';
|
|
2
|
+
import { VbaExtractionRule } from './rules';
|
|
3
|
+
/**
|
|
4
|
+
* Issue #153: the declarative rule table for the procedures concern.
|
|
5
|
+
* One rule — `procedure` — matches a `Sub` / `Function` /
|
|
6
|
+
* `Property Get|Let|Set` declaration and emits the function node,
|
|
7
|
+
* the `localProcs` / `functionNodeByName` / `functionNodeByStartLine`
|
|
8
|
+
* / `functionReturnTypes` registration, and (for form code-behind)
|
|
9
|
+
* the synthesized `event-handler` edge.
|
|
10
|
+
*
|
|
11
|
+
* The emit body is intentionally not split across multiple rules —
|
|
12
|
+
* these are 5+ small operations that all fire on the same declaration
|
|
13
|
+
* line. Splitting them would force the orchestrator to know they
|
|
14
|
+
* always co-occur, which is more coupling than the original cascade
|
|
15
|
+
* had. The pattern is the discriminating surface; everything past
|
|
16
|
+
* `match` is one emit.
|
|
17
|
+
*/
|
|
18
|
+
export declare const RULES: readonly VbaExtractionRule<unknown>[];
|
|
2
19
|
/**
|
|
3
20
|
* Issue #83: factory for the procedures classifier. Closure state: none
|
|
4
21
|
* beyond `count` (the per-concern accumulators live on `ctx`).
|
|
22
|
+
*
|
|
23
|
+
* The body walks the declarative `RULES` table (Issue #153). The
|
|
24
|
+
* inline cascade that used to live here is now one entry in `RULES`.
|
|
5
25
|
*/
|
|
6
26
|
export declare function createProceduresClassifier(): VbaClassifier;
|
|
7
27
|
/**
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VbaExtractionRule — the declarative rule shape every VBA classifier
|
|
3
|
+
* exports as a `RULES: VbaExtractionRule[]` constant. Issue #153.
|
|
4
|
+
*
|
|
5
|
+
* Before this refactor the per-concern sweepers under `src/extraction/vba/`
|
|
6
|
+
* encoded their rules as inline `if (RE.test(line)) { ... }` branches
|
|
7
|
+
* inside `classifyLine`. Each branch was hard to enumerate, impossible
|
|
8
|
+
* to unit-test in isolation, and easy to silently drop when refactoring
|
|
9
|
+
* the body of a sweep. The rule table here promotes the pattern →
|
|
10
|
+
* emit-mapping to a typed object so:
|
|
11
|
+
*
|
|
12
|
+
* 1. Every rule has a stable `id` (used in error messages, logs, and
|
|
13
|
+
* as a stable handle for tools that consume the rule table).
|
|
14
|
+
* 2. The pattern is explicit (single RegExp or RegExp[]) — the
|
|
15
|
+
* dispatcher knows exactly what to test, no "branched control flow
|
|
16
|
+
* around the regex".
|
|
17
|
+
* 3. The emit function is the ONLY side effect for the rule — pure
|
|
18
|
+
* given (match, ctx, line, lineNum) → T | null. That makes the
|
|
19
|
+
* rule trivially testable in isolation.
|
|
20
|
+
* 4. The `count?` hook lets a rule report "N symbols emitted" without
|
|
21
|
+
* sharing an accumulator with the orchestrator (each rule owns
|
|
22
|
+
* its own count semantics).
|
|
23
|
+
*
|
|
24
|
+
* Inter-line state (procedure stack, With stack, SQL variables) STILL
|
|
25
|
+
* lives on `VbaExtractorContext` — the rule table is per-line. The
|
|
26
|
+
* `classifyLine` orchestrator inside each classifier is the "shell"
|
|
27
|
+
* that maintains the state machine and walks the rule table.
|
|
28
|
+
*/
|
|
29
|
+
import type { VbaExtractorContext } from './context';
|
|
30
|
+
/**
|
|
31
|
+
* A single per-line rule the orchestrator dispatches.
|
|
32
|
+
*
|
|
33
|
+
* @typeParam T - The shape `emit` returns. Most rules return
|
|
34
|
+
* `void | null` because they push directly onto `ctx.nodes` /
|
|
35
|
+
* `ctx.edges` (the canonical VBA sweep idiom). Rules that
|
|
36
|
+
* synthesize a specific symbol can narrow `T` to the symbol's
|
|
37
|
+
* shape so `count?` and downstream consumers get a typed handle.
|
|
38
|
+
*
|
|
39
|
+
* Fields:
|
|
40
|
+
*
|
|
41
|
+
* - `id` Stable, human-readable identifier (e.g. `'implements'`,
|
|
42
|
+
* `'procedure'`, `'dim'`, `'sql-in-strings'`). The rule
|
|
43
|
+
* table's primary key — every id within one file must be
|
|
44
|
+
* unique. Used in error messages and in the test suite
|
|
45
|
+
* that pins the table's shape.
|
|
46
|
+
* - `description` One-line plain-English summary. Surfaced in tooling
|
|
47
|
+
* that introspects the table.
|
|
48
|
+
* - `pattern` The regex (or regex alternatives) the dispatcher tests
|
|
49
|
+
* against the per-line source. Either a single `RegExp`
|
|
50
|
+
* or a non-empty `RegExp[]` (a rule is matched when ANY
|
|
51
|
+
* of the alternatives matches). The dispatcher runs
|
|
52
|
+
* `.exec()` for single regexes and iterates for arrays.
|
|
53
|
+
* - `requires?` Optional structural gate. `'class'` means the rule
|
|
54
|
+
* only fires inside a `.cls` file; `'module'` only in
|
|
55
|
+
* `.bas`/`.frm`/`.dsr`; `'inside-procedure'` only when
|
|
56
|
+
* `ctx.procStack.length > 0`. The orchestrator is
|
|
57
|
+
* expected to honour this — keeping the gate declarative
|
|
58
|
+
* lets the rule own its own preconditions instead of
|
|
59
|
+
* scattering `if` checks into the rule body.
|
|
60
|
+
* - `scan?` `'masked'` = run on the string-literal-masked line
|
|
61
|
+
* (so call patterns inside `"..."` are ignored), the
|
|
62
|
+
* default. `'unmasked'` = run on the original line (so
|
|
63
|
+
* SQL patterns inside `"..."` are caught). `'both'` =
|
|
64
|
+
* dispatcher calls the rule twice, once with each line.
|
|
65
|
+
* - `emit` The per-match side effect. Receives the
|
|
66
|
+
* `RegExpExecArray` from the pattern, the shared
|
|
67
|
+
* `VbaExtractorContext`, the original (or masked) line,
|
|
68
|
+
* and the 1-based line number. Returns the symbol it
|
|
69
|
+
* emitted (used by `count?`) or `null` when the match
|
|
70
|
+
* didn't apply (the caller is expected to skip
|
|
71
|
+
* `count?` in that case).
|
|
72
|
+
* - `count?` Optional counter. When the rule emits exactly one
|
|
73
|
+
* symbol per successful match the orchestrator can
|
|
74
|
+
* treat `1` as the implicit count; the hook is for
|
|
75
|
+
* rules whose emit can fan out (e.g. a multi-variable
|
|
76
|
+
* `Dim a As Foo, b As Bar` line that produces two
|
|
77
|
+
* `references` edges from one match).
|
|
78
|
+
*
|
|
79
|
+
* The `count` parameter is typed as `unknown` to keep the
|
|
80
|
+
* `VbaExtractionRule<T>` shape covariant in `T` — narrowing `T`
|
|
81
|
+
* (e.g. to `{ edges: number }` for the dim-decl fan-out rule) does
|
|
82
|
+
* NOT then force `count` to take that narrower type, which would
|
|
83
|
+
* break the `VbaExtractionRule<unknown>[]` aggregate. Rule
|
|
84
|
+
* authors cast inside their `count` body.
|
|
85
|
+
*/
|
|
86
|
+
export interface VbaExtractionRule<T = unknown> {
|
|
87
|
+
readonly id: string;
|
|
88
|
+
readonly description: string;
|
|
89
|
+
readonly pattern: RegExp | RegExp[];
|
|
90
|
+
readonly requires?: 'class' | 'module' | 'inside-procedure' | string;
|
|
91
|
+
readonly scan?: 'masked' | 'unmasked' | 'both';
|
|
92
|
+
readonly emit: (match: RegExpMatchArray, ctx: VbaExtractorContext, line: string, lineNum: number) => T | null;
|
|
93
|
+
readonly count?: (result: unknown) => number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Helper to build a `VbaExtractionRule<T>` with a single RegExp.
|
|
97
|
+
* Most rules are 1-line declarations; this collapses the boilerplate
|
|
98
|
+
* to one place.
|
|
99
|
+
*/
|
|
100
|
+
export declare function defineRule<T = unknown>(spec: Omit<VbaExtractionRule<T>, 'pattern'> & {
|
|
101
|
+
pattern: RegExp;
|
|
102
|
+
}): VbaExtractionRule<T>;
|
|
103
|
+
/**
|
|
104
|
+
* Helper to build a `VbaExtractionRule<T>` whose `pattern` is an array
|
|
105
|
+
* of alternative regexes. The dispatcher treats the rule as matched
|
|
106
|
+
* when ANY alternative matches; it runs the alternatives in order and
|
|
107
|
+
* uses the first match's `RegExpExecArray` for `emit`.
|
|
108
|
+
*/
|
|
109
|
+
export declare function defineRuleAlternatives<T = unknown>(spec: Omit<VbaExtractionRule<T>, 'pattern'> & {
|
|
110
|
+
pattern: RegExp[];
|
|
111
|
+
}): VbaExtractionRule<T>;
|
|
112
|
+
/**
|
|
113
|
+
* Run a single rule's `pattern` against `line` and return the first
|
|
114
|
+
* match's `RegExpMatchArray`, or `null` when no alternative matches.
|
|
115
|
+
* `pattern` is `RegExp | RegExp[]` (an array means "match any of
|
|
116
|
+
* these alternatives"); this helper normalizes both into the same
|
|
117
|
+
* `RegExpMatchArray | null` shape the dispatcher's `emit` expects.
|
|
118
|
+
*
|
|
119
|
+
* Every classifier's `classifyLine` walks the declarative `RULES`
|
|
120
|
+
* table via this helper. Centralizing the RegExp/RegExp[] branching
|
|
121
|
+
* here keeps the per-classifier dispatcher loops trivial and avoids
|
|
122
|
+
* each classifier re-implementing the same boilerplate.
|
|
123
|
+
*/
|
|
124
|
+
export declare function matchRule(pattern: RegExp | RegExp[], line: string): RegExpMatchArray | null;
|
|
125
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -1,11 +1,87 @@
|
|
|
1
1
|
import { ExtractionResult } from '../types';
|
|
2
|
+
import type { VbaExtractionRule } from './vba/rules';
|
|
3
|
+
/**
|
|
4
|
+
* Issue #152: per-file fanout cap for `RaiseEvent <EventName>` edges. An
|
|
5
|
+
* event raised from more than this many sites in a single file is
|
|
6
|
+
* flagged `metadata.highFanout: true` and ALL `raises-event` edges to it
|
|
7
|
+
* are dropped — the gate suppresses graph noise from events with generic
|
|
8
|
+
* names (`Change`, `Click`, `AfterUpdate`, …) that would otherwise
|
|
9
|
+
* produce hundreds of edges per file. Mirrors the upstream
|
|
10
|
+
* `EVENT_FANOUT_CAP` discipline in
|
|
11
|
+
* `src/resolution/callback-synthesizer.ts:43`. Configurable via
|
|
12
|
+
* `codegraph.json` → `vba.maxRaiseFanout`. Pass `Number.POSITIVE_INFINITY`
|
|
13
|
+
* (or any value `>=` the largest expected count) to disable the gate.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_MAX_RAISE_FANOUT = 50;
|
|
16
|
+
/**
|
|
17
|
+
* Issue #153: the orchestrator's aggregated view of every VBA
|
|
18
|
+
* classifier's declarative `RULES` table. Each entry is the
|
|
19
|
+
* `readonly VbaExtractionRule[]` constant exported by the
|
|
20
|
+
* corresponding classifier file. Exposed at module scope so:
|
|
21
|
+
*
|
|
22
|
+
* 1. Tests can pin the table shape and assert that the orchestrator
|
|
23
|
+
* still references each table (a deleted import would
|
|
24
|
+
* accidentally break a whole concern and the test would catch
|
|
25
|
+
* the missing reference).
|
|
26
|
+
* 2. Tooling can introspect every rule the orchestrator
|
|
27
|
+
* dispatches — useful for `codegraph stats` style UIs that
|
|
28
|
+
* show "what kinds of VBA symbols does codegraph know about".
|
|
29
|
+
* 3. The `validateVbaRuleTables` invariant runs on this aggregate
|
|
30
|
+
* so a refactor that empties one concern's `RULES` array
|
|
31
|
+
* (e.g. by deleting the `defineRule` calls during a partial
|
|
32
|
+
* migration) fails loudly at module load instead of silently
|
|
33
|
+
* dropping a whole concern.
|
|
34
|
+
*
|
|
35
|
+
* The keys are the FILE BASENAMES of the classifier modules (no
|
|
36
|
+
* `.ts` extension, kebab-case) — the same naming convention the
|
|
37
|
+
* per-classifier export comments use. Stable identifier for
|
|
38
|
+
* `validateVbaRuleTables` consumers.
|
|
39
|
+
*/
|
|
40
|
+
export declare const VBA_RULE_TABLES: Readonly<Record<string, readonly VbaExtractionRule[]>>;
|
|
41
|
+
/**
|
|
42
|
+
* Issue #153: validate that every per-concern rule table the
|
|
43
|
+
* orchestrator dispatches is non-empty. Called once at module load
|
|
44
|
+
* (see the IIFE at the bottom of this file) so an accidentally-
|
|
45
|
+
* emptied `RULES` array fails loudly when the extractor is first
|
|
46
|
+
* imported, NOT at the first `extract()` call.
|
|
47
|
+
*
|
|
48
|
+
* The result is `{ ok, empty }`:
|
|
49
|
+
* - `ok: true` — every required table has at least one rule.
|
|
50
|
+
* - `ok: false` — at least one table is empty; `empty` lists the
|
|
51
|
+
* concern keys that need attention.
|
|
52
|
+
*
|
|
53
|
+
* The function accepts an optional `tables` argument so the unit
|
|
54
|
+
* test in `__tests__/extraction-vba-rule-table.test.ts` can verify
|
|
55
|
+
* the validator's contract independently of the live data.
|
|
56
|
+
*/
|
|
57
|
+
export declare function validateVbaRuleTables(tables?: Readonly<Record<string, readonly VbaExtractionRule[]>>): {
|
|
58
|
+
ok: boolean;
|
|
59
|
+
empty: string[];
|
|
60
|
+
};
|
|
2
61
|
export declare class VbaExtractor {
|
|
3
62
|
private filePath;
|
|
4
63
|
private source;
|
|
5
64
|
private ctx;
|
|
6
65
|
private vbaTargets?;
|
|
7
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Issue #152: per-file fanout cap for `RaiseEvent <EventName>` edges.
|
|
68
|
+
* When a single event is raised more than this many times in one file,
|
|
69
|
+
* the event node is flagged `metadata.highFanout: true` and ALL
|
|
70
|
+
* `raises-event` edges to it are dropped. Pass `undefined` to disable
|
|
71
|
+
* the gate (the legacy, uncapped behaviour). The 50 default lives in
|
|
72
|
+
* the orchestrator: callers that don't pass a value get the default.
|
|
73
|
+
*/
|
|
74
|
+
private maxRaiseFanout;
|
|
75
|
+
constructor(filePath: string, source: string, vbaTargets?: Record<string, boolean>, maxRaiseFanout?: number);
|
|
8
76
|
extract(): ExtractionResult;
|
|
77
|
+
/**
|
|
78
|
+
* Issue #156: emit the per-file timing block (mode `1` or `2`) and
|
|
79
|
+
* — in mode `2` — append the running aggregate. No-op when
|
|
80
|
+
* `mode === 'off'`. In aggregate mode we flush after every extract()
|
|
81
|
+
* call so the line is visible per-file even without a graceful
|
|
82
|
+
* shutdown (crash-on-file-3 still shows files 1-3 in the aggregate).
|
|
83
|
+
*/
|
|
84
|
+
private maybeEmitTimings;
|
|
9
85
|
private result;
|
|
10
86
|
private isFormOrReportFile;
|
|
11
87
|
private createFileNode;
|
|
@@ -96,7 +96,17 @@ export declare function stripVbaComments(src: string): string;
|
|
|
96
96
|
* downstream extraction keeps source-line parity. Unsupported/unsafe
|
|
97
97
|
* expressions evaluate to false rather than throwing.
|
|
98
98
|
*/
|
|
99
|
-
export declare function preprocessConditionalCompilation(src: string, customTargets?: Record<string, boolean
|
|
99
|
+
export declare function preprocessConditionalCompilation(src: string, customTargets?: Record<string, boolean>,
|
|
100
|
+
/**
|
|
101
|
+
* Issue #156: optional timing sink for the internal lexer+parser.
|
|
102
|
+
* When provided, the wall-clock spent inside `evaluateConditionalExpression`
|
|
103
|
+
* and `evaluateConstRhs` is accumulated under the key
|
|
104
|
+
* `preprocess.cc.lexer+parser` so the orchestrator can break the
|
|
105
|
+
* outer `preprocess.conditionalCompilation` stage into its outer +
|
|
106
|
+
* inner sub-totals. Undefined → no-op, zero cost (just the
|
|
107
|
+
* `if (timings)` null-check on every CC line).
|
|
108
|
+
*/
|
|
109
|
+
timings?: Map<string, number> | null): string;
|
|
100
110
|
export interface StringLiteralSpan {
|
|
101
111
|
/** The literal content (no surrounding quotes; `""` collapsed to `"`). */
|
|
102
112
|
text: string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { VbaExtractorContext, VbaClassifier } from './vba/context';
|
|
2
|
+
export type TimingMode = 'off' | 'per-file' | 'aggregate';
|
|
3
|
+
/**
|
|
4
|
+
* Read the timing mode from the env var. Reads are cached per call —
|
|
5
|
+
* the env var is consulted on every `extract()` but the result is just
|
|
6
|
+
* a number/string compare.
|
|
7
|
+
*/
|
|
8
|
+
export declare function readTimingMode(): TimingMode;
|
|
9
|
+
/**
|
|
10
|
+
* Run `fn`, time the wall-clock, and record into `ctx.timings` under
|
|
11
|
+
* `stageName`. Returns the value `fn` returned. No-op when timings
|
|
12
|
+
* are disabled (the Map is null) — except the `performance.now()` pair,
|
|
13
|
+
* which is the irreducible cost of measuring anything.
|
|
14
|
+
*
|
|
15
|
+
* `performance.now()` is the right primitive here (monotonic, sub-ms
|
|
16
|
+
* resolution on every supported Node version). `Date.now()` would round
|
|
17
|
+
* to whole milliseconds and lose the per-stage signal on small files.
|
|
18
|
+
*/
|
|
19
|
+
export declare function withStage<T>(ctx: VbaExtractorContext, stageName: string, fn: () => T): T;
|
|
20
|
+
/**
|
|
21
|
+
* Time a single `VbaClassifier.classifyLine` invocation. The accumulated
|
|
22
|
+
* time is reported under the bucket `classifier.<name>` so the
|
|
23
|
+
* aggregate stage totals match the per-classifier view.
|
|
24
|
+
*/
|
|
25
|
+
export declare function withClassifier(ctx: VbaExtractorContext, classifier: VbaClassifier, line: string, index: number): void;
|
|
26
|
+
/**
|
|
27
|
+
* Per-file stderr block. Cheap string-build; the per-extract call cost
|
|
28
|
+
* is bounded by the small number of stages (~10).
|
|
29
|
+
*/
|
|
30
|
+
export declare function emitPerFileTimings(ctx: VbaExtractorContext, filePath: string): void;
|
|
31
|
+
export declare function recordAggregateTimings(ctx: VbaExtractorContext, _filePath: string): void;
|
|
32
|
+
export declare function flushAggregate(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Test-only: clear the aggregate between test cases so they do not
|
|
35
|
+
* pollute each other. Not exported in the public API.
|
|
36
|
+
*/
|
|
37
|
+
export declare function _resetAggregateForTests(): void;
|
|
38
|
+
//# sourceMappingURL=vba-timing.d.ts.map
|
package/dist/project-config.d.ts
CHANGED
|
@@ -25,6 +25,27 @@ export interface ProjectConfig {
|
|
|
25
25
|
exclude?: string[];
|
|
26
26
|
vba?: {
|
|
27
27
|
targets?: Record<string, boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* Per-file fanout cap for `RaiseEvent <EventName>` edges (#152). When
|
|
30
|
+
* a single event (by name) is raised from more than this many sites
|
|
31
|
+
* in one file, the event node is flagged `metadata.highFanout: true`
|
|
32
|
+
* and ALL `raises-event` edges to it are dropped — the gate suppresses
|
|
33
|
+
* graph noise from events with generic names (`Change`, `Click`,
|
|
34
|
+
* `AfterUpdate`, …) that would otherwise produce hundreds of edges per
|
|
35
|
+
* file. Defaults to 50 when unset; the event node itself (declaration
|
|
36
|
+
* site, handler linkage via `subscribes-event`) is preserved.
|
|
37
|
+
*/
|
|
38
|
+
maxRaiseFanout?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Run the Dysflow-specific extractors (form/report SaveAsText, test
|
|
41
|
+
* manifests, test sequences) on top of the base VBA extractor. Set to
|
|
42
|
+
* `false` to opt out — useful for projects that carry legacy
|
|
43
|
+
* `.form.txt`/`.report.txt` files (or test-manifest JSON from a
|
|
44
|
+
* different system) and want them tracked as just a `file` node
|
|
45
|
+
* instead of being expanded into the graph (issue #154). Defaults to
|
|
46
|
+
* `true`.
|
|
47
|
+
*/
|
|
48
|
+
dysflowExport?: boolean;
|
|
28
49
|
};
|
|
29
50
|
/**
|
|
30
51
|
* Gitignore-style patterns for first-party source to force INTO the index even
|
|
@@ -43,7 +64,17 @@ export interface ProjectConfig {
|
|
|
43
64
|
}
|
|
44
65
|
export declare function loadVbaConfig(rootDir: string): {
|
|
45
66
|
targets?: Record<string, boolean>;
|
|
67
|
+
maxRaiseFanout?: number;
|
|
68
|
+
dysflowExport?: boolean;
|
|
46
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* Load the validated `vba.dysflowExport` flag for a project, mtime-cached
|
|
72
|
+
* (issue #154). Returns `true` when the flag is absent — the default keeps
|
|
73
|
+
* the legacy Dysflow-specific extractors running so existing users see no
|
|
74
|
+
* behavioral change. `false` opts out, so `.form.txt`/`.report.txt`/test
|
|
75
|
+
* manifest/sequence files are tracked as just a `file` node.
|
|
76
|
+
*/
|
|
77
|
+
export declare function loadDysflowExportConfig(rootDir: string): boolean;
|
|
47
78
|
/**
|
|
48
79
|
* Load the validated extension overrides for a project, mtime-cached.
|
|
49
80
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aroman22/codegraph-vba",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
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.
|
|
19
|
-
"@aroman22/codegraph-vba-darwin-x64": "1.
|
|
20
|
-
"@aroman22/codegraph-vba-linux-arm64": "1.
|
|
21
|
-
"@aroman22/codegraph-vba-linux-x64": "1.
|
|
22
|
-
"@aroman22/codegraph-vba-win32-arm64": "1.
|
|
23
|
-
"@aroman22/codegraph-vba-win32-x64": "1.
|
|
18
|
+
"@aroman22/codegraph-vba-darwin-arm64": "1.11.0",
|
|
19
|
+
"@aroman22/codegraph-vba-darwin-x64": "1.11.0",
|
|
20
|
+
"@aroman22/codegraph-vba-linux-arm64": "1.11.0",
|
|
21
|
+
"@aroman22/codegraph-vba-linux-x64": "1.11.0",
|
|
22
|
+
"@aroman22/codegraph-vba-win32-arm64": "1.11.0",
|
|
23
|
+
"@aroman22/codegraph-vba-win32-x64": "1.11.0"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"npm-shim.js",
|