universal-ast-mapper 0.5.2

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/README.md ADDED
@@ -0,0 +1,465 @@
1
+ # AST-MCP — Universal Code Skeleton & Dependency Graph
2
+
3
+ An **MCP server + CLI tool** that turns source code into structured, machine-readable skeletons and symbol-level dependency graphs — so AI agents can reason about large codebases without reading every file.
4
+
5
+ Built on [tree-sitter](https://tree-sitter.github.io/) WASM grammars. Zero regex guessing — real AST parsing.
6
+
7
+ **Supported languages:** TypeScript · TSX · JavaScript (ESM/CJS) · Python · Go
8
+
9
+ ---
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ npm install && npm run build
15
+
16
+ # CLI
17
+ ast-map --help
18
+ ast-map langs
19
+ ast-map dead src/
20
+ ast-map validate src/
21
+
22
+ # Or without installing globally
23
+ node dist/cli.js dead src/
24
+ ```
25
+
26
+ ---
27
+
28
+ ## Two Ways to Use
29
+
30
+ | Mode | Entry Point | When to Use |
31
+ |------|-------------|-------------|
32
+ | **CLI** (`ast-map`) | `dist/cli.js` | Terminal, CI scripts, quick checks |
33
+ | **MCP Server** | `dist/index.js` | AI agents (Claude, Cursor, etc.) |
34
+
35
+ ---
36
+
37
+ ## MCP Setup — Claude Desktop
38
+
39
+ **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
40
+ **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
41
+
42
+ ```json
43
+ {
44
+ "mcpServers": {
45
+ "ast-mapper": {
46
+ "command": "node",
47
+ "args": ["C:\\path\\to\\AST-MCP\\dist\\index.js"],
48
+ "env": {
49
+ "AST_MAP_ROOT": "C:\\path\\to\\your\\project"
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ > `AST_MAP_ROOT` is the security boundary — the server only reads files inside this path.
57
+
58
+ ---
59
+
60
+ ## CLI Reference
61
+
62
+ All commands default to `cwd` as root. Override with `AST_MAP_ROOT=/path/to/project ast-map <cmd>`.
63
+ Add `--json` to any command for machine-readable output.
64
+
65
+ ```
66
+ ast-map langs
67
+ ast-map skeleton <path> [-d outline|full] [--html] [--combine] [-o dir]
68
+ ast-map symbol <file> <name> [-k kind] [--related]
69
+ ast-map imports <file>
70
+ ast-map graph <dir> [-o graph.json]
71
+ ast-map validate <path> [--max-lines N] [--max-imports N] [--max-exports N]
72
+ ast-map dead <dir>
73
+ ast-map cycles <dir>
74
+ ast-map search <pattern> [dir] [-m contains|exact|regex] [-k kind] [-e]
75
+ ast-map deps <file> [--scan <dir>]
76
+ ast-map top <dir> [-n 10]
77
+ ast-map impact <file> <symbol> [--scan <dir>]
78
+ ast-map calls <file> <fn> [--scan <dir>]
79
+ ```
80
+
81
+ ### Examples
82
+
83
+ ```bash
84
+ # What does this file export?
85
+ ast-map skeleton src/lib/auth.ts
86
+
87
+ # Show source of validateSession + related types
88
+ ast-map symbol src/lib/auth.ts validateSession --related
89
+
90
+ # Find unused exports
91
+ ast-map dead src/
92
+
93
+ # Detect circular imports
94
+ ast-map cycles src/
95
+
96
+ # Check architecture + structural health
97
+ ast-map validate src/
98
+ ast-map validate src/ --max-lines 300 --max-imports 20
99
+
100
+ # Find all symbols named like "handler" across the project
101
+ ast-map search handler src/ --exported
102
+
103
+ # What does this file import / what imports it?
104
+ ast-map deps src/lib/auth.ts --scan src/
105
+
106
+ # Top 10 most-imported symbols (God Node detector)
107
+ ast-map top src/
108
+
109
+ # Blast radius of changing sanitize()
110
+ ast-map impact src/utils.ts sanitize --scan src/
111
+
112
+ # Full call graph for a function
113
+ ast-map calls src/graph.ts buildSymbolGraph --scan src/
114
+
115
+ # Build symbol graph, write to file (large projects)
116
+ ast-map graph src/ -o graph.json
117
+
118
+ # Machine-readable output
119
+ ast-map dead src/ --json | jq '.deadExports[] | select(.kind == "function")'
120
+ ```
121
+
122
+ ---
123
+
124
+ ## MCP Tools Reference
125
+
126
+ ### `list_supported_languages`
127
+ Returns all supported languages and their file extensions.
128
+
129
+ ---
130
+
131
+ ### `get_skeleton_json`
132
+ Parse a single source file → return normalized JSON skeleton (no HTML written).
133
+ Use when the AI needs file structure only.
134
+
135
+ ```json
136
+ {
137
+ "schemaVersion": "1.1",
138
+ "file": "src/lib/auth.ts",
139
+ "language": "typescript",
140
+ "directives": ["use server"],
141
+ "imports": [
142
+ { "symbol": "prisma", "from": "./prisma", "isDefault": true }
143
+ ],
144
+ "symbols": [
145
+ { "name": "validateSession", "kind": "function", "exported": true,
146
+ "range": { "startLine": 12, "endLine": 34 } }
147
+ ]
148
+ }
149
+ ```
150
+
151
+ **Params:** `path`, `detail` (`"outline"` | `"full"`)
152
+
153
+ ---
154
+
155
+ ### `generate_skeleton`
156
+ Map a file **or directory** → compact JSON + self-contained HTML views.
157
+
158
+ **Params:** `path`, `detail`, `emitHtml` (default `true`), `combineHtml` (single `index.html` with sidebar + search), `outputDir`
159
+
160
+ ---
161
+
162
+ ### `get_symbol_context`
163
+ Extract exact source lines of a named symbol. Token-efficient: a 300-line file → ~40 lines.
164
+ Use `includeRelated: true` to also pull related types referenced in the signature.
165
+
166
+ **Params:** `path`, `symbol`, `kind` (optional), `includeRelated`
167
+
168
+ ---
169
+
170
+ ### `resolve_imports`
171
+ Resolve every import in a file to its target symbol with kind, signature, and params.
172
+
173
+ ```json
174
+ {
175
+ "resolved": [
176
+ {
177
+ "symbol": "validateSession", "from": "../../lib/auth",
178
+ "resolvedRel": "src/lib/auth.ts", "kind": "function",
179
+ "signature": "async function validateSession(token: string): Promise<Session>",
180
+ "params": "(token: string)",
181
+ "found": true, "importKind": "relative"
182
+ }
183
+ ]
184
+ }
185
+ ```
186
+
187
+ **Params:** `path`
188
+
189
+ ---
190
+
191
+ ### `build_symbol_graph`
192
+ Scan a directory → build a two-layer dependency graph.
193
+
194
+ - **Nodes:** `"file"` (one per source file) and `"symbol"` (one per function/class/type/const)
195
+ - **Edges:** `"contains"` (structural hierarchy) and `"imports"` (cross-file dependency)
196
+
197
+ ```json
198
+ {
199
+ "stats": { "fileCount": 42, "symbolNodeCount": 380, "edgeCount": 712 },
200
+ "edges": [
201
+ { "from": "src/app/route.ts", "to": "src/lib/auth.ts::validateSession", "edgeType": "imports" }
202
+ ]
203
+ }
204
+ ```
205
+
206
+ Use `outputFile` to write the graph to disk for large projects.
207
+
208
+ **Params:** `path`, `detail`, `outputFile`
209
+
210
+ ---
211
+
212
+ ### `find_dead_code`
213
+ Scan a directory → find exported symbols with zero incoming import edges.
214
+
215
+ Returns two confidence tiers:
216
+ - `"high"` — functions, classes, consts (very likely unused)
217
+ - `"low"` — interfaces, types, enums (may be used as type annotations only)
218
+
219
+ > Note: framework entry-points (Next.js pages, route handlers) are technically "dead" inside the graph — review before deleting.
220
+
221
+ **Params:** `path`, `detail`
222
+
223
+ ---
224
+
225
+ ### `find_circular_deps`
226
+ Detect circular import chains (A → B → C → A) using DFS.
227
+ Each cycle is canonicalised to avoid duplicates.
228
+
229
+ ```json
230
+ {
231
+ "cycles": [
232
+ { "cycle": ["src/a.ts", "src/b.ts", "src/c.ts", "src/a.ts"], "length": 3 }
233
+ ]
234
+ }
235
+ ```
236
+
237
+ **Params:** `path`
238
+
239
+ ---
240
+
241
+ ### `get_change_impact`
242
+ Given a file + symbol, reverse-traverse the import graph to compute **blast radius**.
243
+
244
+ ```json
245
+ {
246
+ "targetNodeId": "src/lib/auth.ts::validateSession",
247
+ "direct": [{ "file": "src/app/login/page.tsx", "symbol": "validateSession" }],
248
+ "transitive": [{ "file": "src/middleware.ts" }],
249
+ "totalFiles": 5
250
+ }
251
+ ```
252
+
253
+ **Params:** `path`, `symbol`, `scanDir`
254
+
255
+ ---
256
+
257
+ ### `get_call_graph`
258
+ Parse a function body → extract every call expression, resolve callees via the import map, find reverse importers.
259
+
260
+ ```json
261
+ {
262
+ "calls": [
263
+ { "callee": "prisma.session.findUnique", "line": 15, "calleeFileRel": "src/lib/prisma.ts" },
264
+ { "callee": "jwt.verify", "line": 20, "isExternal": true, "calleeFileRel": "jsonwebtoken" }
265
+ ],
266
+ "calledBy": [
267
+ { "file": "src/app/api/auth/route.ts" }
268
+ ]
269
+ }
270
+ ```
271
+
272
+ Supports TypeScript, JavaScript, Python, Go.
273
+ Handles destructured aliases: `const { sign } = jwt` → `sign` correctly resolves to `jsonwebtoken`.
274
+
275
+ **Params:** `path`, `function`, `scanDir`
276
+
277
+ ---
278
+
279
+ ### `search_symbol`
280
+ Find symbols by name across all source files in a directory.
281
+
282
+ **Params:** `path`, `name`, `matchType` (`"contains"` | `"exact"` | `"regex"`), `kind`, `exportedOnly`
283
+
284
+ ---
285
+
286
+ ### `get_file_deps`
287
+ For a single file, show what it imports and what imports it (with symbol names).
288
+ More focused than `build_symbol_graph` — use for quick dependency lookup.
289
+
290
+ **Params:** `path`, `scanDir`
291
+
292
+ ---
293
+
294
+ ### `validate_architecture`
295
+ Scan for architecture violations across two rule sets.
296
+
297
+ **Next.js App Router rules:**
298
+ - `client-server-boundary` — `"use client"` file importing a server-only module *(error)*
299
+ - `api-missing-try-catch` — API route handler with no try/catch *(warning)*
300
+
301
+ **General structural rules (any project):**
302
+ - `large-file` — file exceeds `maxLines` (default 500) *(warning)*
303
+ - `too-many-imports` — file has more than `maxImports` imports (default 15) *(warning)*
304
+ - `god-export` — file exports more than `maxExports` symbols (default 10) *(warning)*
305
+
306
+ Thresholds can be set per-call or in `.ast-map.config.json`.
307
+
308
+ **Params:** `path`, `maxLines`, `maxImports`, `maxExports`
309
+
310
+ ---
311
+
312
+ ### `get_top_symbols`
313
+ Return the N most-imported symbols — your codebase's "God Nodes" where a breaking change has maximum blast radius.
314
+
315
+ **Params:** `path`, `limit` (default 10)
316
+
317
+ ---
318
+
319
+ ## Project Config — `.ast-map.config.json`
320
+
321
+ Place in your project root. All fields optional.
322
+
323
+ ```json
324
+ {
325
+ "ignore": ["dist", "coverage", ".turbo"],
326
+ "maxFileBytes": 500000,
327
+ "outputDir": ".ast-map",
328
+ "rules": {
329
+ "large-file": { "maxLines": 400 },
330
+ "too-many-imports": { "maxImports": 20 },
331
+ "god-export": { "maxExports": 15 }
332
+ }
333
+ }
334
+ ```
335
+
336
+ The config is read live — changes take effect on the next call without restarting the MCP server.
337
+
338
+ ---
339
+
340
+ ## Power Prompts
341
+
342
+ ### Full Architecture Audit
343
+ ```
344
+ Use build_symbol_graph on src/, then:
345
+ 1. get_top_symbols — find the 5 God Nodes
346
+ 2. find_circular_deps — any cycles?
347
+ 3. validate_architecture — architecture violations + structural warnings
348
+ 4. For the worst issue, show source with get_symbol_context
349
+ ```
350
+
351
+ ### Safe Refactor Checklist
352
+ ```
353
+ Before refactoring [functionName] in [file]:
354
+ 1. get_change_impact — who depends on it?
355
+ 2. get_call_graph — what does it call?
356
+ 3. get_symbol_context with includeRelated=true — show me the full signature + types
357
+ 4. Summarise what needs to change alongside the refactor
358
+ ```
359
+
360
+ ### Dead Code Cleanup
361
+ ```
362
+ Run find_dead_code on src/.
363
+ Show high-confidence results grouped by file.
364
+ For each candidate, use get_change_impact to confirm it's truly unreachable,
365
+ then show the source with get_symbol_context so I can verify before deleting.
366
+ ```
367
+
368
+ ---
369
+
370
+ ## Adding a Language
371
+
372
+ 1. Pick a grammar from `tree-sitter-wasms` (~36 bundled grammars).
373
+ 2. Write `src/extractors/<lang>.ts` — export `extract()` and `extractImports()`.
374
+ 3. Add one entry to `src/registry.ts`.
375
+
376
+ No changes to the core pipeline or any MCP tool.
377
+
378
+ ---
379
+
380
+ ## Schema Reference
381
+
382
+ ### `SymbolNode`
383
+ ```typescript
384
+ interface SymbolNode {
385
+ name: string
386
+ kind: "class" | "interface" | "struct" | "function" | "method"
387
+ | "type" | "enum" | "const" | "var" | "field"
388
+ visibility: "public" | "private"
389
+ exported?: boolean
390
+ signature?: string // full detail only
391
+ doc?: string // full detail only
392
+ range: { startLine: number; endLine: number }
393
+ children: SymbolNode[]
394
+ }
395
+ ```
396
+
397
+ ### `ImportRef`
398
+ ```typescript
399
+ interface ImportRef {
400
+ symbol: string // imported name, or "*"
401
+ from: string // module specifier as written in source
402
+ alias?: string // import { Foo as Bar } → "Bar"
403
+ isTypeOnly?: boolean
404
+ isNamespaceImport?: boolean
405
+ isDefault?: boolean
406
+ isSideEffect?: boolean
407
+ }
408
+ ```
409
+
410
+ ### `SkeletonFile` (schema v1.1)
411
+ ```typescript
412
+ interface SkeletonFile {
413
+ schemaVersion: "1.1"
414
+ file: string // relative path, forward-slashed
415
+ language: string
416
+ generatedAt: string
417
+ parser: { engine: "tree-sitter"; grammar: string }
418
+ symbolCount: number
419
+ directives?: string[] // e.g. ["use client"]
420
+ imports?: ImportRef[]
421
+ symbols: SymbolNode[]
422
+ }
423
+ ```
424
+
425
+ ---
426
+
427
+ ## Project Layout
428
+
429
+ ```
430
+ src/
431
+ ├── index.ts — MCP server + all 14 tool registrations
432
+ ├── cli.ts — ast-map CLI (13 commands)
433
+ ├── types.ts — SkeletonFile, SymbolNode, ImportRef
434
+ ├── config.ts — SkeletonOptions, resolveOptions(), loadProjectConfig()
435
+ ├── registry.ts — language detection + extractor registry
436
+ ├── parser.ts — tree-sitter WASM loader + AST node helpers
437
+ ├── skeleton.ts — buildSkeleton(), collectSourceFiles() + parse cache
438
+ ├── resolver.ts — resolveImportPath(), resolveFileImports()
439
+ ├── graph.ts — buildSymbolGraph()
440
+ ├── graph-analysis.ts — findDeadExports(), findCircularDeps(), getChangeImpact(),
441
+ │ getFileDeps(), getTopSymbols()
442
+ ├── callgraph.ts — buildCallGraph() — AST-level call extraction
443
+ ├── analysis.ts — findSymbol(), validate helpers, checkGeneralRules()
444
+ ├── html.ts — renderHtml(), renderCombinedHtml()
445
+ ├── search.ts — searchSymbols()
446
+ └── extractors/
447
+ ├── common.ts — makeSymbol(), toOutline()
448
+ ├── typescript.ts — TS/JS/TSX: symbols + imports + re-exports
449
+ ├── python.ts — Python: symbols + relative import resolution
450
+ └── go.ts — Go: symbols + imports
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Changelog
456
+
457
+ | Version | What changed |
458
+ |---------|--------------|
459
+ | **0.5.2** | Iterative DFS in `findCircularDeps` (eliminates stack overflow on large codebases) · `build_symbol_graph` inline size guard (>2000 nodes → stats + warning) · integration test suite (`test/analysis.mjs`) |
460
+ | **0.5.1** | Re-export tracking (`export { X } from './foo'`, barrel files) · `export const` surfaced as symbols · `const X = class {}` support · Python relative import fix · parser instance cache |
461
+ | **0.5.0** | Call graph destructuring aliases · in-process parse cache · `.ast-map.config.json` · general validation rules (large-file, too-many-imports, god-export) |
462
+ | **0.4.0** | `search_symbol` · `get_file_deps` · `get_top_symbols` · dead code confidence tiers · 3 new CLI commands |
463
+ | **0.3.0** | `ast-map` CLI · `find_dead_code` · `find_circular_deps` · `get_change_impact` · `get_call_graph` |
464
+ | **0.2.0** | Import extraction · `resolve_imports` · `build_symbol_graph` |
465
+ | **0.1.0** | `get_skeleton_json` · `generate_skeleton` · `get_symbol_context` · `validate_architecture` |
@@ -0,0 +1,134 @@
1
+ import path from "node:path";
2
+ // ─── Symbol lookup ────────────────────────────────────────────────────────────
3
+ /** Recursively search for a symbol by name and optional kind. */
4
+ export function findSymbol(symbols, name, kind) {
5
+ for (const sym of symbols) {
6
+ if (sym.name === name && (!kind || sym.kind === kind))
7
+ return sym;
8
+ const found = findSymbol(sym.children, name, kind);
9
+ if (found)
10
+ return found;
11
+ }
12
+ return null;
13
+ }
14
+ /**
15
+ * Given a target symbol with a signature, find related type/interface/enum
16
+ * symbols referenced in that signature and return their source code blocks.
17
+ */
18
+ export function findRelatedSymbols(symbols, target, sourceLines) {
19
+ if (!target.signature)
20
+ return [];
21
+ const seen = new Set([target.name]);
22
+ // PascalCase identifiers in the signature are likely type references
23
+ const typeRefs = [...target.signature.matchAll(/\b([A-Z][a-zA-Z0-9_]*)\b/g)]
24
+ .map((m) => m[1])
25
+ .filter((v) => !seen.has(v) && (seen.add(v), true));
26
+ const related = [];
27
+ for (const typeName of typeRefs) {
28
+ const sym = findSymbol(symbols, typeName);
29
+ if (sym && (sym.kind === "interface" || sym.kind === "type" || sym.kind === "enum")) {
30
+ const code = sourceLines.slice(sym.range.startLine - 1, sym.range.endLine).join("\n");
31
+ related.push({ name: sym.name, kind: sym.kind, range: sym.range, code });
32
+ }
33
+ }
34
+ return related;
35
+ }
36
+ // ─── Architecture validation ──────────────────────────────────────────────────
37
+ /** True if the first 500 chars of source contain the given directive literal. */
38
+ export function hasDirective(source, directive) {
39
+ const head = source.slice(0, 500);
40
+ return head.includes(`"${directive}"`) || head.includes(`'${directive}'`);
41
+ }
42
+ /** Patterns that flag server-only imports in a "use client" file. */
43
+ const SERVER_IMPORT_PATTERNS = [
44
+ { pattern: /from\s+['"]server-only['"]/, label: "server-only" },
45
+ { pattern: /from\s+['"][^'"]*\/prisma['"]/, label: "prisma client" },
46
+ { pattern: /from\s+['"][^'"]*lib\/prisma['"]/, label: "lib/prisma" },
47
+ { pattern: /from\s+['"]next\/headers['"]/, label: "next/headers" },
48
+ { pattern: /from\s+['"]next\/cookies['"]/, label: "next/cookies" },
49
+ { pattern: /from\s+['"][^'"]*lib\/auth['"]/, label: "lib/auth" },
50
+ { pattern: /from\s+['"][^'"]*lib\/auditLog['"]/, label: "lib/auditLog" },
51
+ { pattern: /from\s+['"][^'"]*lib\/apiAuth['"]/, label: "lib/apiAuth" },
52
+ ];
53
+ /** Scan source lines for server-only imports (called on "use client" files). */
54
+ export function findServerImports(source) {
55
+ const lines = source.split("\n");
56
+ const violations = [];
57
+ for (let i = 0; i < lines.length; i++) {
58
+ const line = lines[i];
59
+ for (const { pattern, label } of SERVER_IMPORT_PATTERNS) {
60
+ if (pattern.test(line)) {
61
+ const match = line.match(/from\s+['"]([^'"]+)['"]/);
62
+ violations.push({ module: match ? match[1] : line.trim(), label, line: i + 1 });
63
+ break;
64
+ }
65
+ }
66
+ }
67
+ return violations;
68
+ }
69
+ const HTTP_METHODS = new Set(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]);
70
+ /** True if the relative path looks like a Next.js App Router API route file. */
71
+ export function isApiRoute(relPath) {
72
+ const norm = relPath.split(path.sep).join("/");
73
+ return /app\/api\/.+\/route\.(ts|js|tsx|jsx)$/.test(norm);
74
+ }
75
+ /**
76
+ * Find exported HTTP handler functions that have no try/catch.
77
+ * A simple but effective heuristic: look for the `try {` keyword in the body.
78
+ */
79
+ export function findMissingTryCatch(symbols, sourceLines) {
80
+ const missing = [];
81
+ for (const sym of symbols) {
82
+ if (!HTTP_METHODS.has(sym.name) || sym.exported === false)
83
+ continue;
84
+ const bodyText = sourceLines.slice(sym.range.startLine - 1, sym.range.endLine).join("\n");
85
+ if (!/\btry\s*\{/.test(bodyText))
86
+ missing.push(sym);
87
+ }
88
+ return missing;
89
+ }
90
+ export const GENERAL_RULE_DEFAULTS = {
91
+ largeFileLines: 500,
92
+ tooManyImports: 15,
93
+ godExportCount: 10,
94
+ };
95
+ /**
96
+ * Run general-purpose structural rules against a source file.
97
+ * Returns violations for any threshold exceeded.
98
+ */
99
+ export function checkGeneralRules(fileRel, source, symbols, importCount, thresholds = GENERAL_RULE_DEFAULTS) {
100
+ const violations = [];
101
+ const lineCount = source.split("\n").length;
102
+ if (lineCount > thresholds.largeFileLines) {
103
+ violations.push({
104
+ file: fileRel,
105
+ rule: "large-file",
106
+ severity: "warning",
107
+ message: `File has ${lineCount} lines (threshold: ${thresholds.largeFileLines}) — consider splitting`,
108
+ value: lineCount,
109
+ threshold: thresholds.largeFileLines,
110
+ });
111
+ }
112
+ if (importCount > thresholds.tooManyImports) {
113
+ violations.push({
114
+ file: fileRel,
115
+ rule: "too-many-imports",
116
+ severity: "warning",
117
+ message: `File has ${importCount} imports (threshold: ${thresholds.tooManyImports}) — high coupling`,
118
+ value: importCount,
119
+ threshold: thresholds.tooManyImports,
120
+ });
121
+ }
122
+ const exportedCount = symbols.filter((s) => s.exported).length;
123
+ if (exportedCount > thresholds.godExportCount) {
124
+ violations.push({
125
+ file: fileRel,
126
+ rule: "god-export",
127
+ severity: "warning",
128
+ message: `File exports ${exportedCount} symbols (threshold: ${thresholds.godExportCount}) — potential God File`,
129
+ value: exportedCount,
130
+ threshold: thresholds.godExportCount,
131
+ });
132
+ }
133
+ return violations;
134
+ }