(prompt: string)
| 536 | * is excluded from the member-access form since it's a file reference, not a symbol. |
| 537 | */ |
| 538 | export function extractCodeTokens(prompt: string): string[] { |
| 539 | if (!prompt) return []; |
| 540 | const out = new Set<string>(); |
| 541 | // camelCase / PascalCase-with-inner-cap (getUserId, parseToken, UserService) or |
| 542 | // snake_case (article_publish, get_user) — a whole identifier run that has an |
| 543 | // inner lower→upper transition or an underscore flanked by alphanumerics. |
| 544 | for (const m of prompt.matchAll(/[A-Za-z_$][\w$]*/g)) { |
| 545 | const w = m[0]; |
| 546 | if (/[a-z][A-Z]/.test(w) || /[A-Za-z0-9]_[A-Za-z0-9]/.test(w)) out.add(w); |
| 547 | } |
| 548 | // call form: an identifier directly before '(' — parseToken(, render(). No |
| 549 | // whitespace before '(' so prose like "the function (entry point)" doesn't trip it. |
| 550 | for (const m of prompt.matchAll(/([A-Za-z_$][\w$]*)\(/g)) out.add(m[1]!); |
| 551 | // member access on identifiers (user.login) — but not a doc/data filename. |
| 552 | for (const m of prompt.matchAll(/([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)/g)) { |
| 553 | if (!DOC_DATA_EXT.test(m[0])) { out.add(m[1]!); out.add(m[2]!); } |
| 554 | } |
| 555 | return [...out]; |
| 556 | } |
| 557 | |
| 558 | /** |
| 559 | * Cheap, graph-free candidate gate for the front-load hook: could `prompt` be a |
no outgoing calls
no test coverage detected