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.
- package/dist/bin/sverklo.js +38 -5
- package/dist/bin/sverklo.js.map +1 -1
- package/dist/src/server/tools/impact.d.ts +4 -0
- package/dist/src/server/tools/impact.js +77 -1
- package/dist/src/server/tools/impact.js.map +1 -1
- package/dist/src/workspace/cli.d.ts +17 -0
- package/dist/src/workspace/cli.js +205 -0
- package/dist/src/workspace/cli.js.map +1 -0
- package/dist/src/workspace/cross-db.d.ts +49 -0
- package/dist/src/workspace/cross-db.js +192 -0
- package/dist/src/workspace/cross-db.js.map +1 -0
- package/dist/src/workspace/cross-indexer.d.ts +16 -0
- package/dist/src/workspace/cross-indexer.js +288 -0
- package/dist/src/workspace/cross-indexer.js.map +1 -0
- package/dist/src/workspace/graphql-consumer.d.ts +13 -0
- package/dist/src/workspace/graphql-consumer.js +293 -0
- package/dist/src/workspace/graphql-consumer.js.map +1 -0
- package/dist/src/workspace/graphql-extractor.d.ts +13 -0
- package/dist/src/workspace/graphql-extractor.js +172 -0
- package/dist/src/workspace/graphql-extractor.js.map +1 -0
- package/dist/src/workspace/workspace-config.d.ts +32 -0
- package/dist/src/workspace/workspace-config.js +91 -0
- package/dist/src/workspace/workspace-config.js.map +1 -0
- package/package.json +1 -1
|
@@ -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[];
|