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

Function objectRegistryEdges

src/resolution/callback-synthesizer.ts:2228–2307  ·  view source on GitHub ↗
(ctx: ResolutionContext, onYield: MaybeYield)

Source from the content-addressed store, hash-verified

2226}
2227
2228async function objectRegistryEdges(ctx: ResolutionContext, onYield: MaybeYield): Promise<Edge[]> {
2229 let scannedFiles = 0;
2230 const edges: Edge[] = [];
2231 const seen = new Set<string>();
2232 let scanned = 0;
2233 for (const file of ctx.getAllFiles()) {
2234 if ((++scannedFiles & 15) === 0) await onYield();
2235 if ((++scanned & 255) === 0) await onYield(); // #1091: yield mid-scan on huge graphs
2236 if (!REGISTRY_JS_EXT.test(file)) continue;
2237 const content = ctx.readFile(file);
2238 // Cheap pre-filter: a computed member access BY NAME (`ident[ident`) — the dispatch shape.
2239 if (!content || !/[\w$]\s*\[\s*[A-Za-z_$]/.test(content)) continue;
2240 // Skip minified/generated bundles (draco, three.min, base64…): their pervasive `h[x](...)`
2241 // calls + single-letter `{a:b}` literals are a false-positive minefield. Average line
2242 // length is the reliable tell — real source ~30–80, minified in the hundreds/thousands.
2243 const newlines = (content.match(/\n/g)?.length ?? 0) + 1;
2244 if (content.length / newlines > 200) continue;
2245 const safe = stripCommentsForRegex(content, /\.(?:jsx?|mjs|cjs)$/.test(file) ? 'javascript' : 'typescript');
2246
2247 // 1. Dispatch sites: `(new )?<ref>[<ident-key>]` followed by a call or a chained method.
2248 // A quoted-string key (`['save']`) does NOT match — that's a static access, not dispatch.
2249 REGISTRY_DISPATCH_RE.lastIndex = 0;
2250 const dispatches: Array<{ ref: string; line: number; chained: string | null }> = [];
2251 let dm: RegExpExecArray | null;
2252 while ((dm = REGISTRY_DISPATCH_RE.exec(safe))) {
2253 const win = safe.slice(dm.index, dm.index + 160);
2254 const cm = /\]\s*\([^)]*\)\s*\.\s*([A-Za-z_$][\w$]*)/.exec(win) || /\]\s*\.\s*([A-Za-z_$][\w$]*)/.exec(win);
2255 dispatches.push({ ref: dm[1]!, line: safe.slice(0, dm.index).split('\n').length, chained: cm ? cm[1]! : null });
2256 }
2257 if (!dispatches.length) continue;
2258 // Normalize a leading `this.` so a class FIELD-INITIALIZER registry (`commands = {…}`)
2259 // matches a `this.commands[k]` dispatch, not just the constructor form `this.commands = {…}`.
2260 const norm = (r: string) => r.replace(/^this\./, '');
2261 const refs = new Set(dispatches.map((d) => norm(d.ref)));
2262
2263 // 2. Registries: an object literal assigned to a dispatched ref, ≥2 entries resolving to callables.
2264 REGISTRY_ASSIGN_RE.lastIndex = 0;
2265 const registries = new Map<string, { names: string[]; line: number }>();
2266 let am: RegExpExecArray | null;
2267 while ((am = REGISTRY_ASSIGN_RE.exec(safe))) {
2268 const lhs = norm(am[1] ?? am[2]!);
2269 if (!refs.has(lhs) || registries.has(lhs)) continue;
2270 const body = braceBody(safe, am.index + am[0].length - 1);
2271 if (!body) continue;
2272 const names = registryEntryNames(body); // depth-0 `key: Identifier` entries only
2273 if (names.length >= REGISTRY_MIN_ENTRIES) {
2274 registries.set(lhs, { names, line: safe.slice(0, am.index).split('\n').length });
2275 }
2276 }
2277 if (!registries.size) continue;
2278
2279 // 3. Link each dispatcher → each registered handler's callable entry.
2280 const nodesInFile = ctx.getNodesInFile(file);
2281 for (const d of dispatches) {
2282 const reg = registries.get(norm(d.ref));
2283 if (!reg) continue;
2284 const disp = enclosingFn(nodesInFile, d.line);
2285 if (!disp) continue;

Callers 1

Calls 13

stripCommentsForRegexFunction · 0.90
braceBodyFunction · 0.85
registryEntryNamesFunction · 0.85
enclosingFnFunction · 0.85
resolveRegistryHandlerFunction · 0.85
readFileMethod · 0.80
hasMethod · 0.80
normFunction · 0.70
getAllFilesMethod · 0.65
execMethod · 0.65
getNodesInFileMethod · 0.65
getMethod · 0.65

Tested by

no test coverage detected