(caller: Node, at: { line?: number; column?: number }, callee?: string)
| 461 | const callAt = (caller: Node, site: { line?: number; column?: number; callee?: string }) => calls.callSite(caller, site); |
| 462 | /** A hop's position with its call's span and enclosing call, read from the tree; the bare position when unreadable. */ |
| 463 | const hopAt = async (caller: Node, at: { line?: number; column?: number }, callee?: string): Promise<HopSite> => { |
| 464 | const line = at.line ?? caller.startLine; |
| 465 | const column = at.column ?? 0; |
| 466 | const read = at.line ? await callAt(caller, { ...at, ...(callee ? { callee } : {}) }) : null; |
| 467 | // The read must be THIS call. An inline handler's edges carry the ROUTE's |
| 468 | // line (`router.post('/users/login', async (req, res) => {`), where the |
| 469 | // only call is the registration itself — and taking its span would make |
| 470 | // every call in the handler read as written inside it, and so as running |
| 471 | // first. A miss is a bare position: no span to nest by, no `within`. |
| 472 | const last = (n: string) => n.replace(/\([^()]*\)/g, '').split(/[.:]/).pop() ?? n; |
| 473 | const usable = read !== null && (!callee || last(read.callee) === last(callee)); |
| 474 | if (!usable) return { file: caller.filePath, line, column, end: { line, column }, within: null }; |
| 475 | return { |
| 476 | file: caller.filePath, |
| 477 | line: read.span?.start.line ?? line, |
| 478 | column: read.span?.start.column ?? column, |
| 479 | end: read.span?.end ?? { line, column }, |
| 480 | within: read.within ?? null, |
| 481 | }; |
| 482 | }; |
| 483 | const pointHop = (caller: Node, at: { line?: number; column?: number }): HopSite => { |
| 484 | const line = at.line ?? caller.startLine; |
| 485 | const column = at.column ?? 0; |
no test coverage detected