(prompt: string)
| 281 | * is excluded from the member-access form since it's a file reference, not a symbol. |
| 282 | */ |
| 283 | export function extractCodeTokens(prompt: string): string[] { |
| 284 | if (!prompt) return []; |
| 285 | const out = new Set<string>(); |
| 286 | // camelCase / PascalCase-with-inner-cap (getUserId, parseToken, UserService) or |
| 287 | // snake_case (article_publish, get_user) — a whole identifier run that has an |
| 288 | // inner lower→upper transition or an underscore flanked by alphanumerics. |
| 289 | for (const m of prompt.matchAll(/[A-Za-z_$][\w$]*/g)) { |
| 290 | const w = m[0]; |
| 291 | if (/[a-z][A-Z]/.test(w) || /[A-Za-z0-9]_[A-Za-z0-9]/.test(w)) out.add(w); |
| 292 | } |
| 293 | // call form: an identifier directly before '(' — parseToken(, render(). No |
| 294 | // whitespace before '(' so prose like "the function (entry point)" doesn't trip it. |
| 295 | for (const m of prompt.matchAll(/([A-Za-z_$][\w$]*)\(/g)) out.add(m[1]!); |
| 296 | // member access on identifiers (user.login) — but not a doc/data filename. |
| 297 | for (const m of prompt.matchAll(/([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)/g)) { |
| 298 | if (!DOC_DATA_EXT.test(m[0])) { out.add(m[1]!); out.add(m[2]!); } |
| 299 | } |
| 300 | return [...out]; |
| 301 | } |
| 302 | |
| 303 | /** |
| 304 | * Cheap, graph-free candidate gate for the front-load hook: could `prompt` be a |
no outgoing calls
no test coverage detected