MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / ginMiddlewareChainEdges

Function ginMiddlewareChainEdges

src/resolution/callback-synthesizer.ts:1935–1997  ·  view source on GitHub ↗
(queries: QueryBuilder, ctx: ResolutionContext, onYield: MaybeYield)

Source from the content-addressed store, hash-verified

1933}
1934
1935async function ginMiddlewareChainEdges(queries: QueryBuilder, ctx: ResolutionContext, onYield: MaybeYield): Promise<Edge[]> {
1936 let scanned255 = 0;
1937 let scannedFiles = 0;
1938 // 1. Find the chain dispatcher(s): a Go method that invokes a `handlers` slice by index.
1939 const dispatchers: Node[] = [];
1940 for (const n of queries.iterateNodesByKind('method')) {
1941 if ((++scanned255 & 63) === 0) await onYield();
1942 if (n.language !== 'go') continue;
1943 const content = ctx.readFile(n.filePath);
1944 const src = content && sliceLines(content, n.startLine, n.endLine);
1945 if (src && GIN_DISPATCH_RE.test(src)) dispatchers.push(n);
1946 }
1947 if (dispatchers.length === 0) return []; // not a gin repo — bail
1948
1949 // 2. Collect handler identifiers registered via gin registration calls
1950 // (.Use / .GET / … / .Handle). String args (paths/methods) and inline
1951 // closures are dropped by goHandlerIdent; the rest are HandlerFuncs.
1952 const registered = new Map<string, string>(); // name → registeredAt (file:line)
1953 for (const file of ctx.getAllFiles()) {
1954 if ((++scannedFiles & 15) === 0) await onYield();
1955 if (!file.endsWith('.go')) continue;
1956 const content = ctx.readFile(file);
1957 if (!content || (!content.includes('.Use(') && !/\.(?:GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD|Any|Handle)\(/.test(content))) continue;
1958 const safe = stripCommentsForRegex(content, 'go');
1959 GIN_REG_RE.lastIndex = 0;
1960 let m: RegExpExecArray | null;
1961 while ((m = GIN_REG_RE.exec(safe))) {
1962 const parenIdx = m.index + m[0].length - 1;
1963 const argStr = goBalancedArgs(safe, parenIdx);
1964 if (!argStr) continue;
1965 const line = safe.slice(0, m.index).split('\n').length;
1966 for (const arg of goSplitArgs(argStr)) {
1967 const name = goHandlerIdent(arg);
1968 if (name && !registered.has(name)) registered.set(name, `${file}:${line}`);
1969 }
1970 }
1971 }
1972 if (registered.size === 0) return [];
1973
1974 // 3. Link each dispatcher → each registered handler node (dedup, capped).
1975 const edges: Edge[] = [];
1976 const seen = new Set<string>();
1977 for (const disp of dispatchers) {
1978 let added = 0;
1979 for (const [name, registeredAt] of registered) {
1980 if (added >= MAX_CALLBACKS_PER_CHANNEL) break;
1981 const handler = ctx.getNodesByName(name).find(
1982 (n) => (n.kind === 'function' || n.kind === 'method') && n.language === 'go'
1983 );
1984 if (!handler || handler.id === disp.id) continue;
1985 const key = `${disp.id}>${handler.id}`;
1986 if (seen.has(key)) continue;
1987 seen.add(key);
1988 edges.push({
1989 source: disp.id, target: handler.id, kind: 'calls', line: disp.startLine,
1990 provenance: 'heuristic',
1991 metadata: { synthesizedBy: 'gin-middleware-chain', via: name, registeredAt },
1992 });

Callers 1

Calls 12

stripCommentsForRegexFunction · 0.90
sliceLinesFunction · 0.85
goBalancedArgsFunction · 0.85
goSplitArgsFunction · 0.85
goHandlerIdentFunction · 0.85
readFileMethod · 0.80
hasMethod · 0.80
iterateNodesByKindMethod · 0.65
getAllFilesMethod · 0.65
execMethod · 0.65
getNodesByNameMethod · 0.65
setMethod · 0.45

Tested by

no test coverage detected