@abhinav2203/codeflow-core 1.0.0 → 1.0.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.
@@ -1,4 +1,4 @@
1
1
  export { buildBlueprintGraph } from "./build.js";
2
2
  export { analyzeTypeScriptRepo } from "./repo.js";
3
3
  export { analyzeRepo } from "./repo-multi.js";
4
- export type { AnalyzeRepoOptions } from "./repo-multi.js";
4
+ export type { AnalyzeRepoOptions, RepoAnalysisResult, SourceSpanEntry, CallSiteEntry } from "./repo-multi.js";
@@ -1,6 +1,25 @@
1
1
  type RepoGraphPart = Omit<import("../schema/index.js").BlueprintGraph, "projectName" | "mode" | "generatedAt">;
2
+ export interface SourceSpanEntry {
3
+ nodeId: string;
4
+ filePath: string;
5
+ startLine: number;
6
+ endLine: number;
7
+ symbol?: string;
8
+ }
9
+ export interface CallSiteEntry {
10
+ edgeKey: string;
11
+ fromNodeId: string;
12
+ toNodeId: string;
13
+ filePath: string;
14
+ lineNumbers: number[];
15
+ expressions: string[];
16
+ }
17
+ export interface RepoAnalysisResult extends RepoGraphPart {
18
+ sourceSpans: Record<string, SourceSpanEntry>;
19
+ callSites: Record<string, CallSiteEntry>;
20
+ }
2
21
  export interface AnalyzeRepoOptions {
3
22
  excludePatterns?: string[];
4
23
  }
5
- export declare const analyzeRepo: (repoPath: string, options?: AnalyzeRepoOptions) => Promise<RepoGraphPart>;
24
+ export declare const analyzeRepo: (repoPath: string, options?: AnalyzeRepoOptions) => Promise<RepoAnalysisResult>;
6
25
  export {};
@@ -70,6 +70,16 @@ export const analyzeRepo = async (repoPath, options) => {
70
70
  allImportEdges.push(...result.importEdges);
71
71
  allInheritEdges.push(...result.inheritEdges);
72
72
  }
73
+ const sourceSpans = {};
74
+ for (const n of allNodes) {
75
+ sourceSpans[n.nodeId] = {
76
+ nodeId: n.nodeId,
77
+ filePath: n.path,
78
+ startLine: n.startLine,
79
+ endLine: n.endLine,
80
+ symbol: n.sourceRefs.find(r => r.symbol)?.symbol
81
+ };
82
+ }
73
83
  const nodeMap = new Map();
74
84
  for (const n of allNodes) {
75
85
  nodeMap.set(n.nodeId, createNode({
@@ -237,10 +247,42 @@ export const analyzeRepo = async (repoPath, options) => {
237
247
  }
238
248
  });
239
249
  }
250
+ // Build callSites from resolved call edges
251
+ const callSites = {};
252
+ const callSiteGroups = new Map();
253
+ for (const call of allCallEdges) {
254
+ const targetId = [...allSymbolIndex.entries()].find(([key]) => key.endsWith(`::${call.toName}`))?.[1];
255
+ if (!targetId || targetId === call.fromId)
256
+ continue;
257
+ const edgeKey = `calls:${call.fromId}:${targetId}`;
258
+ const callerNode = nodeMap.get(call.fromId);
259
+ const filePath = callerNode?.path ?? "";
260
+ if (!filePath)
261
+ continue;
262
+ let group = callSiteGroups.get(edgeKey);
263
+ if (!group) {
264
+ group = { fromId: call.fromId, toId: targetId, lines: [], texts: [] };
265
+ callSiteGroups.set(edgeKey, group);
266
+ }
267
+ group.lines.push(call.callLine);
268
+ group.texts.push(call.callText);
269
+ }
270
+ for (const [edgeKey, group] of callSiteGroups) {
271
+ callSites[edgeKey] = {
272
+ edgeKey,
273
+ fromNodeId: group.fromId,
274
+ toNodeId: group.toId,
275
+ filePath: nodeMap.get(group.fromId)?.path ?? "",
276
+ lineNumbers: [...new Set(group.lines)].sort((a, b) => a - b),
277
+ expressions: [...new Set(group.texts)]
278
+ };
279
+ }
240
280
  return {
241
281
  nodes: [...nodeMap.values()],
242
282
  edges: dedupeEdges(edges),
243
283
  workflows: [],
244
- warnings
284
+ warnings,
285
+ sourceSpans,
286
+ callSites
245
287
  };
246
288
  };
@@ -12,6 +12,8 @@ interface ExtractedNode {
12
12
  symbol?: string;
13
13
  }>;
14
14
  ownerId?: string;
15
+ startLine: number;
16
+ endLine: number;
15
17
  }
16
18
  export declare const extractNodesFromFile: (filePath: string, relativePath: string) => Promise<{
17
19
  nodes: ExtractedNode[];
@@ -21,6 +23,7 @@ export declare const extractNodesFromFile: (filePath: string, relativePath: stri
21
23
  fromId: string;
22
24
  toName: string;
23
25
  callText: string;
26
+ callLine: number;
24
27
  }>;
25
28
  importEdges: Array<{
26
29
  fromModuleId: string;
@@ -147,6 +147,7 @@ export const extractNodesFromFile = async (filePath, relativePath) => {
147
147
  const importEdges = [];
148
148
  const inheritEdges = [];
149
149
  const moduleId = createNodeId("module", relativePath, relativePath);
150
+ const moduleEndLine = root.endPosition.row + 1;
150
151
  nodes.push({
151
152
  nodeId: moduleId,
152
153
  kind: "module",
@@ -154,7 +155,9 @@ export const extractNodesFromFile = async (filePath, relativePath) => {
154
155
  summary: `Source module ${relativePath}.`,
155
156
  path: relativePath,
156
157
  signature: "",
157
- sourceRefs: [{ kind: "repo", path: relativePath }]
158
+ sourceRefs: [{ kind: "repo", path: relativePath }],
159
+ startLine: 1,
160
+ endLine: moduleEndLine
158
161
  });
159
162
  const recordFunc = (funcName, funcNode, paramsNode, returnTypeNode, bodyNode, ownerName, ownerId) => {
160
163
  if (!funcName)
@@ -175,7 +178,9 @@ export const extractNodesFromFile = async (filePath, relativePath) => {
175
178
  path: relativePath,
176
179
  signature,
177
180
  sourceRefs: [{ kind: "repo", path: relativePath, symbol: displayName }],
178
- ownerId: isMethod ? ownerId : (kind === "function" ? moduleId : undefined)
181
+ ownerId: isMethod ? ownerId : (kind === "function" ? moduleId : undefined),
182
+ startLine: funcNode.startPosition.row + 1,
183
+ endLine: funcNode.endPosition.row + 1
179
184
  });
180
185
  // Only store fully-qualified keys for methods to avoid collisions
181
186
  symbolIndex.set(`${relativePath}::${displayName}`, nodeId);
@@ -206,7 +211,12 @@ export const extractNodesFromFile = async (filePath, relativePath) => {
206
211
  }
207
212
  }
208
213
  if (calleeName) {
209
- callEdges.push({ fromId: callerId, toName: calleeName, callText: child.text });
214
+ callEdges.push({
215
+ fromId: callerId,
216
+ toName: calleeName,
217
+ callText: child.text,
218
+ callLine: child.startPosition.row + 1
219
+ });
210
220
  }
211
221
  collectCalls(child, callerId);
212
222
  }
@@ -441,7 +451,9 @@ export const extractNodesFromFile = async (filePath, relativePath) => {
441
451
  path: relativePath,
442
452
  signature: `class ${className}`,
443
453
  sourceRefs: [{ kind: "repo", path: relativePath, symbol: className }],
444
- ownerId: moduleId
454
+ ownerId: moduleId,
455
+ startLine: child.startPosition.row + 1,
456
+ endLine: child.endPosition.row + 1
445
457
  });
446
458
  symbolIndex.set(`${relativePath}::${className}`, classId);
447
459
  if (parentClass)
@@ -473,7 +485,9 @@ export const extractNodesFromFile = async (filePath, relativePath) => {
473
485
  path: relativePath,
474
486
  signature: `class ${className}`,
475
487
  sourceRefs: [{ kind: "repo", path: relativePath, symbol: className }],
476
- ownerId: moduleId
488
+ ownerId: moduleId,
489
+ startLine: child.startPosition.row + 1,
490
+ endLine: child.endPosition.row + 1
477
491
  });
478
492
  symbolIndex.set(`${relativePath}::${className}`, classId);
479
493
  if (parentClass)
@@ -496,7 +510,9 @@ export const extractNodesFromFile = async (filePath, relativePath) => {
496
510
  summary: buildSummary(className, child, null, [], ""),
497
511
  path: relativePath,
498
512
  signature: `type ${className} struct`,
499
- sourceRefs: [{ kind: "repo", path: relativePath, symbol: className }]
513
+ sourceRefs: [{ kind: "repo", path: relativePath, symbol: className }],
514
+ startLine: structType.startPosition.row + 1,
515
+ endLine: structType.endPosition.row + 1
500
516
  });
501
517
  symbolIndex.set(`${relativePath}::${className}`, classId);
502
518
  walkFunctions(child, className, classId);
@@ -519,7 +535,9 @@ export const extractNodesFromFile = async (filePath, relativePath) => {
519
535
  summary: buildSummary(className, child, null, [], ""),
520
536
  path: relativePath,
521
537
  signature: `struct ${className}`,
522
- sourceRefs: [{ kind: "repo", path: relativePath, symbol: className }]
538
+ sourceRefs: [{ kind: "repo", path: relativePath, symbol: className }],
539
+ startLine: child.startPosition.row + 1,
540
+ endLine: child.endPosition.row + 1
523
541
  });
524
542
  symbolIndex.set(`${relativePath}::${className}`, classId);
525
543
  walkFunctions(child, className, classId);
@@ -547,7 +565,9 @@ export const extractNodesFromFile = async (filePath, relativePath) => {
547
565
  summary: buildSummary(className, child, null, [], ""),
548
566
  path: relativePath,
549
567
  signature: `impl ${className}`,
550
- sourceRefs: [{ kind: "repo", path: relativePath, symbol: className }]
568
+ sourceRefs: [{ kind: "repo", path: relativePath, symbol: className }],
569
+ startLine: child.startPosition.row + 1,
570
+ endLine: child.endPosition.row + 1
551
571
  });
552
572
  symbolIndex.set(`${relativePath}::${className}`, classId);
553
573
  walkFunctions(child, className, classId);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@abhinav2203/codeflow-core",
3
3
  "description": "Framework-agnostic CodeFlow analysis core for blueprint generation, repository analysis, exports, and conflict detection.",
4
- "version": "1.0.0",
4
+ "version": "1.0.2",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",