sverklo 0.3.0 → 0.4.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.
@@ -0,0 +1,192 @@
1
+ import Database from "better-sqlite3";
2
+ import { mkdirSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ const SCHEMA = `
5
+ CREATE TABLE IF NOT EXISTS projects (
6
+ id TEXT PRIMARY KEY,
7
+ path TEXT NOT NULL UNIQUE,
8
+ name TEXT NOT NULL,
9
+ role TEXT NOT NULL DEFAULT 'both',
10
+ last_indexed_at INTEGER,
11
+ git_sha TEXT
12
+ );
13
+
14
+ CREATE TABLE IF NOT EXISTS interface_contracts (
15
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
16
+ project_id TEXT NOT NULL REFERENCES projects(id),
17
+ interface_type TEXT NOT NULL,
18
+ source_file TEXT NOT NULL,
19
+ symbol_name TEXT NOT NULL,
20
+ symbol_kind TEXT NOT NULL,
21
+ signature TEXT,
22
+ file_line INTEGER,
23
+ content_hash TEXT NOT NULL,
24
+ UNIQUE(project_id, interface_type, symbol_name, symbol_kind)
25
+ );
26
+
27
+ CREATE INDEX IF NOT EXISTS idx_contracts_symbol ON interface_contracts(symbol_name);
28
+ CREATE INDEX IF NOT EXISTS idx_contracts_project ON interface_contracts(project_id);
29
+
30
+ CREATE TABLE IF NOT EXISTS cross_edges (
31
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
32
+ consumer_project_id TEXT NOT NULL REFERENCES projects(id),
33
+ consumer_file TEXT NOT NULL,
34
+ consumer_symbol TEXT NOT NULL,
35
+ consumer_line INTEGER,
36
+ contract_id INTEGER NOT NULL REFERENCES interface_contracts(id),
37
+ edge_type TEXT NOT NULL,
38
+ confidence REAL DEFAULT 1.0,
39
+ UNIQUE(consumer_project_id, consumer_symbol, contract_id)
40
+ );
41
+
42
+ CREATE INDEX IF NOT EXISTS idx_cross_edges_contract ON cross_edges(contract_id);
43
+ CREATE INDEX IF NOT EXISTS idx_cross_edges_consumer ON cross_edges(consumer_project_id);
44
+ `;
45
+ export class CrossRepoDb {
46
+ db;
47
+ constructor(dbPath) {
48
+ mkdirSync(dirname(dbPath), { recursive: true });
49
+ this.db = new Database(dbPath);
50
+ this.db.pragma("journal_mode = WAL");
51
+ this.db.pragma("foreign_keys = ON");
52
+ this.db.pragma("synchronous = NORMAL");
53
+ this.db.exec(SCHEMA);
54
+ }
55
+ // --- Projects ---
56
+ upsertProject(id, path, name, role, gitSha) {
57
+ this.db
58
+ .prepare(`INSERT INTO projects (id, path, name, role, last_indexed_at, git_sha)
59
+ VALUES (?, ?, ?, ?, ?, ?)
60
+ ON CONFLICT(id) DO UPDATE SET
61
+ path = excluded.path,
62
+ name = excluded.name,
63
+ role = excluded.role,
64
+ last_indexed_at = excluded.last_indexed_at,
65
+ git_sha = excluded.git_sha`)
66
+ .run(id, path, name, role, Date.now(), gitSha);
67
+ }
68
+ getProject(id) {
69
+ const row = this.db
70
+ .prepare("SELECT id, path, name, role, last_indexed_at, git_sha FROM projects WHERE id = ?")
71
+ .get(id);
72
+ return row ? this.mapProject(row) : null;
73
+ }
74
+ listProjects() {
75
+ const rows = this.db
76
+ .prepare("SELECT id, path, name, role, last_indexed_at, git_sha FROM projects")
77
+ .all();
78
+ return rows.map((r) => this.mapProject(r));
79
+ }
80
+ // --- Interface contracts ---
81
+ upsertContract(contract) {
82
+ this.db
83
+ .prepare(`INSERT INTO interface_contracts (project_id, interface_type, source_file, symbol_name, symbol_kind, signature, file_line, content_hash)
84
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
85
+ ON CONFLICT(project_id, interface_type, symbol_name, symbol_kind) DO UPDATE SET
86
+ source_file = excluded.source_file,
87
+ signature = excluded.signature,
88
+ file_line = excluded.file_line,
89
+ content_hash = excluded.content_hash`)
90
+ .run(contract.projectId, contract.interfaceType, contract.sourceFile, contract.symbolName, contract.symbolKind, contract.signature ?? null, contract.fileLine ?? null, contract.contentHash);
91
+ }
92
+ getContractsForProject(projectId) {
93
+ const rows = this.db
94
+ .prepare("SELECT id, project_id, interface_type, source_file, symbol_name, symbol_kind, signature, file_line, content_hash FROM interface_contracts WHERE project_id = ?")
95
+ .all(projectId);
96
+ return rows.map((r) => this.mapContract(r));
97
+ }
98
+ getContractBySymbol(symbolName, interfaceType) {
99
+ if (interfaceType) {
100
+ const rows = this.db
101
+ .prepare("SELECT id, project_id, interface_type, source_file, symbol_name, symbol_kind, signature, file_line, content_hash FROM interface_contracts WHERE symbol_name = ? AND interface_type = ?")
102
+ .all(symbolName, interfaceType);
103
+ return rows.map((r) => this.mapContract(r));
104
+ }
105
+ const rows = this.db
106
+ .prepare("SELECT id, project_id, interface_type, source_file, symbol_name, symbol_kind, signature, file_line, content_hash FROM interface_contracts WHERE symbol_name = ?")
107
+ .all(symbolName);
108
+ return rows.map((r) => this.mapContract(r));
109
+ }
110
+ deleteContractsForProject(projectId) {
111
+ // Delete edges that reference these contracts first (FK constraint)
112
+ this.db
113
+ .prepare("DELETE FROM cross_edges WHERE contract_id IN (SELECT id FROM interface_contracts WHERE project_id = ?)")
114
+ .run(projectId);
115
+ this.db.prepare("DELETE FROM interface_contracts WHERE project_id = ?").run(projectId);
116
+ }
117
+ // --- Cross-repo edges ---
118
+ upsertCrossEdge(edge) {
119
+ this.db
120
+ .prepare(`INSERT INTO cross_edges (consumer_project_id, consumer_file, consumer_symbol, consumer_line, contract_id, edge_type, confidence)
121
+ VALUES (?, ?, ?, ?, ?, ?, ?)
122
+ ON CONFLICT(consumer_project_id, consumer_symbol, contract_id) DO UPDATE SET
123
+ consumer_file = excluded.consumer_file,
124
+ consumer_line = excluded.consumer_line,
125
+ edge_type = excluded.edge_type,
126
+ confidence = excluded.confidence`)
127
+ .run(edge.consumerProjectId, edge.consumerFile, edge.consumerSymbol, edge.consumerLine ?? null, edge.contractId, edge.edgeType, edge.confidence);
128
+ }
129
+ getCrossEdgesForContract(contractId) {
130
+ const rows = this.db
131
+ .prepare("SELECT id, consumer_project_id, consumer_file, consumer_symbol, consumer_line, contract_id, edge_type, confidence FROM cross_edges WHERE contract_id = ?")
132
+ .all(contractId);
133
+ return rows.map((r) => this.mapEdge(r));
134
+ }
135
+ getCrossEdgesForProject(projectId) {
136
+ const rows = this.db
137
+ .prepare("SELECT id, consumer_project_id, consumer_file, consumer_symbol, consumer_line, contract_id, edge_type, confidence FROM cross_edges WHERE consumer_project_id = ?")
138
+ .all(projectId);
139
+ return rows.map((r) => this.mapEdge(r));
140
+ }
141
+ deleteCrossEdgesForProject(projectId) {
142
+ this.db.prepare("DELETE FROM cross_edges WHERE consumer_project_id = ?").run(projectId);
143
+ }
144
+ // --- Staleness ---
145
+ isProjectStale(projectId, currentSha) {
146
+ const project = this.getProject(projectId);
147
+ if (!project)
148
+ return true;
149
+ return project.gitSha !== currentSha;
150
+ }
151
+ // --- Lifecycle ---
152
+ close() {
153
+ this.db.close();
154
+ }
155
+ // --- Private mappers ---
156
+ mapProject(row) {
157
+ return {
158
+ id: row.id,
159
+ path: row.path,
160
+ name: row.name,
161
+ role: row.role,
162
+ lastIndexedAt: row.last_indexed_at,
163
+ gitSha: row.git_sha,
164
+ };
165
+ }
166
+ mapContract(row) {
167
+ return {
168
+ id: row.id,
169
+ projectId: row.project_id,
170
+ interfaceType: row.interface_type,
171
+ sourceFile: row.source_file,
172
+ symbolName: row.symbol_name,
173
+ symbolKind: row.symbol_kind,
174
+ signature: row.signature ?? undefined,
175
+ fileLine: row.file_line ?? undefined,
176
+ contentHash: row.content_hash,
177
+ };
178
+ }
179
+ mapEdge(row) {
180
+ return {
181
+ id: row.id,
182
+ consumerProjectId: row.consumer_project_id,
183
+ consumerFile: row.consumer_file,
184
+ consumerSymbol: row.consumer_symbol,
185
+ consumerLine: row.consumer_line ?? undefined,
186
+ contractId: row.contract_id,
187
+ edgeType: row.edge_type,
188
+ confidence: row.confidence,
189
+ };
190
+ }
191
+ }
192
+ //# sourceMappingURL=cross-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-db.js","sourceRoot":"","sources":["../../../src/workspace/cross-db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { CrossRepoDb } from "./cross-db.js";
2
+ import type { WorkspaceConfig } from "./workspace-config.js";
3
+ export interface CrossIndexResult {
4
+ contractsFound: number;
5
+ edgesFound: number;
6
+ staleProjects: string[];
7
+ errors: string[];
8
+ }
9
+ /**
10
+ * Index all cross-repo relationships in a workspace.
11
+ *
12
+ * 1. For each provider project, extract interface contracts (GraphQL schemas)
13
+ * 2. For each consumer project, detect references to those contracts
14
+ * 3. Populate cross_edges in the workspace DB
15
+ */
16
+ export declare function crossIndex(config: WorkspaceConfig, db: CrossRepoDb): Promise<CrossIndexResult>;
@@ -0,0 +1,288 @@
1
+ import { readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { join, relative } from "node:path";
3
+ import { execSync } from "node:child_process";
4
+ import ignore from "ignore";
5
+ import picomatch from "picomatch";
6
+ import { extractGraphQLContracts } from "./graphql-extractor.js";
7
+ import { detectGraphQLConsumers } from "./graphql-consumer.js";
8
+ const MAX_FILE_SIZE = 1_000_000; // 1 MB
9
+ const CONSUMER_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx"]);
10
+ /**
11
+ * Index all cross-repo relationships in a workspace.
12
+ *
13
+ * 1. For each provider project, extract interface contracts (GraphQL schemas)
14
+ * 2. For each consumer project, detect references to those contracts
15
+ * 3. Populate cross_edges in the workspace DB
16
+ */
17
+ export async function crossIndex(config, db) {
18
+ const result = {
19
+ contractsFound: 0,
20
+ edgesFound: 0,
21
+ staleProjects: [],
22
+ errors: [],
23
+ };
24
+ // Phase 1: Index providers — extract contracts from GraphQL schema files
25
+ for (const project of config.projects) {
26
+ if (project.role !== "provider" && project.role !== "both")
27
+ continue;
28
+ const projectId = projectKey(project);
29
+ try {
30
+ const currentSha = getGitSha(project.path);
31
+ // Upsert the project record so foreign keys are satisfied
32
+ db.upsertProject(projectId, project.path, projectId, project.role, currentSha ?? "");
33
+ // Check staleness
34
+ if (currentSha && !db.isProjectStale(projectId, currentSha)) {
35
+ // Not stale — count existing contracts
36
+ result.contractsFound += db.getContractsForProject(projectId).length;
37
+ continue;
38
+ }
39
+ if (currentSha) {
40
+ result.staleProjects.push(projectId);
41
+ }
42
+ // Collect GraphQL schema globs from the interfaces config
43
+ const schemaGlobs = getGraphQLGlobs(project);
44
+ // Find GraphQL schema files matching the interface globs
45
+ const schemaFiles = findSchemaFiles(project.path, schemaGlobs);
46
+ // Delete old contracts for this project, then insert new ones
47
+ db.deleteContractsForProject(projectId);
48
+ for (const absPath of schemaFiles) {
49
+ try {
50
+ const content = readFileSync(absPath, "utf-8");
51
+ const relPath = relative(project.path, absPath);
52
+ const { contracts } = extractGraphQLContracts(relPath, content);
53
+ for (const contract of contracts) {
54
+ db.upsertContract({
55
+ projectId: projectId,
56
+ ...contract,
57
+ });
58
+ result.contractsFound++;
59
+ }
60
+ }
61
+ catch (err) {
62
+ result.errors.push(`Failed to extract contracts from ${absPath}: ${err instanceof Error ? err.message : String(err)}`);
63
+ }
64
+ }
65
+ // Update stored SHA
66
+ if (currentSha) {
67
+ db.upsertProject(projectId, project.path, projectId, project.role, currentSha);
68
+ }
69
+ }
70
+ catch (err) {
71
+ result.errors.push(`Failed to index provider ${projectId}: ${err instanceof Error ? err.message : String(err)}`);
72
+ }
73
+ }
74
+ // Phase 2: Index consumers — detect references to known contracts
75
+ // Gather all contracts across all provider projects
76
+ const allContracts = [];
77
+ for (const project of config.projects) {
78
+ if (project.role !== "provider" && project.role !== "both")
79
+ continue;
80
+ const pid = projectKey(project);
81
+ allContracts.push(...db.getContractsForProject(pid));
82
+ }
83
+ if (allContracts.length === 0)
84
+ return result;
85
+ for (const project of config.projects) {
86
+ if (project.role !== "consumer" && project.role !== "both")
87
+ continue;
88
+ const projectId = projectKey(project);
89
+ try {
90
+ const currentSha = getGitSha(project.path);
91
+ // Upsert the project record
92
+ db.upsertProject(projectId, project.path, projectId, project.role, currentSha ?? "");
93
+ // Check staleness
94
+ if (currentSha && !db.isProjectStale(projectId, currentSha)) {
95
+ result.edgesFound += db.getCrossEdgesForProject(projectId).length;
96
+ continue;
97
+ }
98
+ // Delete old edges for this consumer
99
+ db.deleteCrossEdgesForProject(projectId);
100
+ // Build ignore filter for the project
101
+ const ig = buildIgnoreFilter(project.path);
102
+ // Walk project files for consumer code
103
+ const consumerFiles = discoverConsumerFiles(project.path, ig);
104
+ for (const absPath of consumerFiles) {
105
+ try {
106
+ const content = readFileSync(absPath, "utf-8");
107
+ const matches = detectGraphQLConsumers(absPath, content, allContracts);
108
+ for (const match of matches) {
109
+ // For each referenced field, find the matching contract and create an edge
110
+ for (const fieldRef of match.referencedFields) {
111
+ const matchingContracts = db.getContractBySymbol(fieldRef, "graphql");
112
+ if (matchingContracts.length === 0)
113
+ continue;
114
+ const contract = matchingContracts[0];
115
+ const confidence = computeFieldConfidence(fieldRef, allContracts);
116
+ db.upsertCrossEdge({
117
+ consumerProjectId: projectId,
118
+ consumerFile: relative(project.path, match.file),
119
+ consumerSymbol: match.symbol,
120
+ consumerLine: match.line,
121
+ contractId: contract.id,
122
+ edgeType: match.edgeType,
123
+ confidence,
124
+ });
125
+ result.edgesFound++;
126
+ }
127
+ }
128
+ }
129
+ catch (err) {
130
+ result.errors.push(`Failed to scan consumer file ${absPath}: ${err instanceof Error ? err.message : String(err)}`);
131
+ }
132
+ }
133
+ // Update stored SHA
134
+ if (currentSha) {
135
+ db.upsertProject(projectId, project.path, projectId, project.role, currentSha);
136
+ }
137
+ }
138
+ catch (err) {
139
+ result.errors.push(`Failed to index consumer ${projectId}: ${err instanceof Error ? err.message : String(err)}`);
140
+ }
141
+ }
142
+ return result;
143
+ }
144
+ // ---------------------------------------------------------------------------
145
+ // Project identity
146
+ // ---------------------------------------------------------------------------
147
+ /** Derive a stable project ID from its path (last path segment). */
148
+ function projectKey(project) {
149
+ return project.path.split("/").filter(Boolean).pop() ?? project.path;
150
+ }
151
+ // ---------------------------------------------------------------------------
152
+ // GraphQL glob extraction from workspace config
153
+ // ---------------------------------------------------------------------------
154
+ function getGraphQLGlobs(project) {
155
+ if (!project.interfaces || project.interfaces.length === 0) {
156
+ // Default: look for .graphql files anywhere in the project
157
+ return ["**/*.graphql"];
158
+ }
159
+ const globs = [];
160
+ for (const iface of project.interfaces) {
161
+ if (iface.type === "graphql") {
162
+ globs.push(iface.schema ?? "**/*.graphql");
163
+ }
164
+ }
165
+ return globs.length > 0 ? globs : ["**/*.graphql"];
166
+ }
167
+ // ---------------------------------------------------------------------------
168
+ // Git helpers
169
+ // ---------------------------------------------------------------------------
170
+ function getGitSha(rootPath) {
171
+ try {
172
+ execSync("git rev-parse --verify HEAD", {
173
+ cwd: rootPath,
174
+ stdio: ["ignore", "ignore", "ignore"],
175
+ timeout: 5000,
176
+ });
177
+ }
178
+ catch {
179
+ return null;
180
+ }
181
+ try {
182
+ return execSync("git rev-parse HEAD", {
183
+ cwd: rootPath,
184
+ encoding: "utf-8",
185
+ stdio: ["ignore", "pipe", "ignore"],
186
+ timeout: 5000,
187
+ }).trim();
188
+ }
189
+ catch {
190
+ return null;
191
+ }
192
+ }
193
+ // ---------------------------------------------------------------------------
194
+ // Schema file discovery
195
+ // ---------------------------------------------------------------------------
196
+ function findSchemaFiles(rootPath, globs) {
197
+ const matchers = globs.map((g) => picomatch(g));
198
+ const files = [];
199
+ function walk(dir) {
200
+ let entries;
201
+ try {
202
+ entries = readdirSync(dir, { withFileTypes: true });
203
+ }
204
+ catch {
205
+ return;
206
+ }
207
+ for (const entry of entries) {
208
+ const absPath = join(dir, entry.name);
209
+ const relPath = relative(rootPath, absPath);
210
+ if (entry.isDirectory()) {
211
+ if (entry.name === "node_modules" || entry.name === ".git")
212
+ continue;
213
+ walk(absPath);
214
+ }
215
+ else if (entry.isFile()) {
216
+ if (matchers.some((m) => m(relPath))) {
217
+ files.push(absPath);
218
+ }
219
+ }
220
+ }
221
+ }
222
+ walk(rootPath);
223
+ return files;
224
+ }
225
+ // ---------------------------------------------------------------------------
226
+ // Consumer file discovery
227
+ // ---------------------------------------------------------------------------
228
+ function buildIgnoreFilter(rootPath) {
229
+ const ig = ignore();
230
+ ig.add(["node_modules", ".git", "dist", "build", "out", "__pycache__"]);
231
+ const gitignorePath = join(rootPath, ".gitignore");
232
+ try {
233
+ ig.add(readFileSync(gitignorePath, "utf-8"));
234
+ }
235
+ catch {
236
+ // No .gitignore — fine
237
+ }
238
+ return ig;
239
+ }
240
+ function discoverConsumerFiles(rootPath, ig) {
241
+ const files = [];
242
+ function walk(dir) {
243
+ let entries;
244
+ try {
245
+ entries = readdirSync(dir, { withFileTypes: true });
246
+ }
247
+ catch {
248
+ return;
249
+ }
250
+ for (const entry of entries) {
251
+ const absPath = join(dir, entry.name);
252
+ const relPath = relative(rootPath, absPath);
253
+ if (ig.ignores(relPath))
254
+ continue;
255
+ if (entry.isDirectory()) {
256
+ if (!ig.ignores(relPath + "/")) {
257
+ walk(absPath);
258
+ }
259
+ }
260
+ else if (entry.isFile()) {
261
+ const ext = "." + entry.name.split(".").pop()?.toLowerCase();
262
+ if (!CONSUMER_EXTENSIONS.has(ext))
263
+ continue;
264
+ try {
265
+ const stat = statSync(absPath);
266
+ if (stat.size > MAX_FILE_SIZE)
267
+ continue;
268
+ }
269
+ catch {
270
+ continue;
271
+ }
272
+ files.push(absPath);
273
+ }
274
+ }
275
+ }
276
+ walk(rootPath);
277
+ return files;
278
+ }
279
+ // ---------------------------------------------------------------------------
280
+ // Confidence scoring
281
+ // ---------------------------------------------------------------------------
282
+ function computeFieldConfidence(fieldRef, allContracts) {
283
+ // Exact match against a known contract symbol -> 1.0
284
+ // Inferred (guessed parent type) -> 0.8
285
+ const isExact = allContracts.some((c) => c.symbolName === fieldRef);
286
+ return isExact ? 1.0 : 0.8;
287
+ }
288
+ //# sourceMappingURL=cross-indexer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-indexer.js","sourceRoot":"","sources":["../../../src/workspace/cross-indexer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,SAAS,MAAM,WAAW,CAAC;AAGlC,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAS/D,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,OAAO;AACxC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAuB,EACvB,EAAe;IAEf,MAAM,MAAM,GAAqB;QAC/B,cAAc,EAAE,CAAC;QACjB,UAAU,EAAE,CAAC;QACb,aAAa,EAAE,EAAE;QACjB,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,yEAAyE;IACzE,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QAErE,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAEtC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAE3C,0DAA0D;YAC1D,EAAE,CAAC,aAAa,CACd,SAAS,EACT,OAAO,CAAC,IAAI,EACZ,SAAS,EACT,OAAO,CAAC,IAAI,EACZ,UAAU,IAAI,EAAE,CACjB,CAAC;YAEF,kBAAkB;YAClB,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC;gBAC5D,uCAAuC;gBACvC,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;gBACrE,SAAS;YACX,CAAC;YAED,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvC,CAAC;YAED,0DAA0D;YAC1D,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;YAE7C,yDAAyD;YACzD,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YAE/D,8DAA8D;YAC9D,EAAE,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAC;YAExC,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;gBAClC,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;oBAChD,MAAM,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBAEhE,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;wBACjC,EAAE,CAAC,cAAc,CAAC;4BAChB,SAAS,EAAE,SAAS;4BACpB,GAAG,QAAQ;yBACZ,CAAC,CAAC;wBACH,MAAM,CAAC,cAAc,EAAE,CAAC;oBAC1B,CAAC;gBACH,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,MAAM,CAAC,IAAI,CAChB,oCAAoC,OAAO,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACnG,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,oBAAoB;YACpB,IAAI,UAAU,EAAE,CAAC;gBACf,EAAE,CAAC,aAAa,CACd,SAAS,EACT,OAAO,CAAC,IAAI,EACZ,SAAS,EACT,OAAO,CAAC,IAAI,EACZ,UAAU,CACX,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,MAAM,CAAC,IAAI,CAChB,4BAA4B,SAAS,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC7F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,oDAAoD;IACpD,MAAM,YAAY,GAAwB,EAAE,CAAC;IAC7C,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QACrE,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAChC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAE7C,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QAErE,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAEtC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAE3C,4BAA4B;YAC5B,EAAE,CAAC,aAAa,CACd,SAAS,EACT,OAAO,CAAC,IAAI,EACZ,SAAS,EACT,OAAO,CAAC,IAAI,EACZ,UAAU,IAAI,EAAE,CACjB,CAAC;YAEF,kBAAkB;YAClB,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC;gBAC5D,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;gBAClE,SAAS;YACX,CAAC;YAED,qCAAqC;YACrC,EAAE,CAAC,0BAA0B,CAAC,SAAS,CAAC,CAAC;YAEzC,sCAAsC;YACtC,MAAM,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAE3C,uCAAuC;YACvC,MAAM,aAAa,GAAG,qBAAqB,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAE9D,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;gBACpC,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBAC/C,MAAM,OAAO,GAAG,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;oBAEvE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;wBAC5B,2EAA2E;wBAC3E,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC;4BAC9C,MAAM,iBAAiB,GAAG,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;4BACtE,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;gCAAE,SAAS;4BAE7C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;4BACtC,MAAM,UAAU,GAAG,sBAAsB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;4BAElE,EAAE,CAAC,eAAe,CAAC;gCACjB,iBAAiB,EAAE,SAAS;gCAC5B,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC;gCAChD,cAAc,EAAE,KAAK,CAAC,MAAM;gCAC5B,YAAY,EAAE,KAAK,CAAC,IAAI;gCACxB,UAAU,EAAE,QAAQ,CAAC,EAAG;gCACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gCACxB,UAAU;6BACX,CAAC,CAAC;4BACH,MAAM,CAAC,UAAU,EAAE,CAAC;wBACtB,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,MAAM,CAAC,IAAI,CAChB,gCAAgC,OAAO,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC/F,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,oBAAoB;YACpB,IAAI,UAAU,EAAE,CAAC;gBACf,EAAE,CAAC,aAAa,CACd,SAAS,EACT,OAAO,CAAC,IAAI,EACZ,SAAS,EACT,OAAO,CAAC,IAAI,EACZ,UAAU,CACX,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,MAAM,CAAC,IAAI,CAChB,4BAA4B,SAAS,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC7F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,oEAAoE;AACpE,SAAS,UAAU,CAAC,OAAyB;IAC3C,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;AACvE,CAAC;AAED,8EAA8E;AAC9E,gDAAgD;AAChD,8EAA8E;AAE9E,SAAS,eAAe,CAAC,OAAyB;IAChD,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,2DAA2D;QAC3D,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;AACrD,CAAC;AAED,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,SAAS,SAAS,CAAC,QAAgB;IACjC,IAAI,CAAC;QACH,QAAQ,CAAC,6BAA6B,EAAE;YACtC,GAAG,EAAE,QAAQ;YACb,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACrC,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,oBAAoB,EAAE;YACpC,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YACnC,OAAO,EAAE,IAAI;SACd,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,SAAS,eAAe,CAAC,QAAgB,EAAE,KAAe;IACxD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,SAAS,IAAI,CAAC,GAAW;QACvB,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAE5C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;oBAAE,SAAS;gBACrE,IAAI,CAAC,OAAO,CAAC,CAAC;YAChB,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;oBACrC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,CAAC;IACf,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,0BAA0B;AAC1B,8EAA8E;AAE9E,SAAS,iBAAiB,CAAC,QAAgB;IACzC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,EAAE,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC;IAExE,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC;QACH,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,qBAAqB,CAC5B,QAAgB,EAChB,EAA6B;IAE7B,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,SAAS,IAAI,CAAC,GAAW;QACvB,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAE5C,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;gBAAE,SAAS;YAElC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC,EAAE,CAAC;oBAC/B,IAAI,CAAC,OAAO,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,MAAM,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;gBAC7D,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAE5C,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;oBAC/B,IAAI,IAAI,CAAC,IAAI,GAAG,aAAa;wBAAE,SAAS;gBAC1C,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;gBAED,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,CAAC;IACf,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,SAAS,sBAAsB,CAC7B,QAAgB,EAChB,YAAiC;IAEjC,qDAAqD;IACrD,wCAAwC;IACxC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC;IACpE,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { InterfaceContract } from "./cross-db.js";
2
+ export interface ConsumerMatch {
3
+ file: string;
4
+ symbol: string;
5
+ line: number;
6
+ referencedFields: string[];
7
+ edgeType: "query" | "mutation" | "subscription";
8
+ }
9
+ /**
10
+ * Scan a TypeScript/JavaScript file for GraphQL operations (gql tagged templates,
11
+ * graphql() calls, .graphql imports) and resolve field references against known contracts.
12
+ */
13
+ export declare function detectGraphQLConsumers(filePath: string, content: string, knownContracts: InterfaceContract[]): ConsumerMatch[];