(
ce: IComputeEngine,
arg1: string | { [id: string]: AssignValue },
arg2?: AssignValue
)
| 249 | if (idLower === s) return 0; |
| 250 | if (idLower.startsWith(s)) return 1; |
| 251 | if (triggersLower.some((t) => t === s)) return 2; |
| 252 | if (keywordsLower.some((k) => k === s)) return 2; |
| 253 | if (idLower.includes(s)) return 3; |
| 254 | if (triggersLower.some((t) => t.includes(s))) return 4; |
| 255 | if (searchable.some((x) => x.includes(s))) return 5; |
| 256 | return undefined; |
| 257 | }; |
| 258 | |
| 259 | // Gate: at least one token must match (OR semantics). Ranking then |
| 260 | // rewards matching more tokens, and matching them more exactly. |
| 261 | const matched = tokens.filter((tok) => tierOf(tok) !== undefined).length; |
| 262 | if (matched === 0) continue; |
| 263 | |
| 264 | let tier = Infinity; |
| 265 | for (const probe of probes) { |
| 266 | const t = tierOf(probe); |
| 267 | if (t !== undefined && t < tier) tier = t; |
| 268 | } |
| 269 | |
| 270 | results.push({ id: name, kind, matched, tier }); |
| 271 | } |
| 272 | scope = scope.parent; |
| 273 | } |
| 274 | |
| 275 | // Deterministic ordering: most tokens matched, then tier, then shorter id, |
| 276 | // then alphabetical. |
| 277 | results.sort((a, b) => { |
| 278 | if (a.matched !== b.matched) return b.matched - a.matched; |
| 279 | if (a.tier !== b.tier) return a.tier - b.tier; |
| 280 | if (a.id.length !== b.id.length) return a.id.length - b.id.length; |
| 281 | return a.id < b.id ? -1 : a.id > b.id ? 1 : 0; |
| 282 | }); |
| 283 | |
| 284 | return results.slice(0, limit).map(({ id, kind }) => ({ id, kind })); |
| 285 | } |
| 286 | |
| 287 | // Per-engine cache of the operator-name pool, invalidated when the definition |
| 288 | // generation changes. |
| 289 | const operatorPoolCache = new WeakMap< |
| 290 | IComputeEngine, |
| 291 | { generation: number; names: string[] } |
| 292 | >(); |
| 293 | |
| 294 | /** |
| 295 | * The names of all operator (function) definitions visible in the current |
| 296 | * scope chain — the candidate pool for `suggestOperatorName`. Nearest scope |
| 297 | * wins for duplicate names. Cached per engine, invalidated by generation. |
| 298 | */ |
| 299 | function operatorNamePool(ce: IComputeEngine): string[] { |
| 300 | const cached = operatorPoolCache.get(ce); |
| 301 | if (cached && cached.generation === ce._anyVersion) return cached.names; |
| 302 | |
| 303 | const names: string[] = []; |
| 304 | const seen = new Set<string>(); |
| 305 | let scope: Scope | null = ce.context.lexicalScope; |
| 306 | while (scope) { |
| 307 | for (const [name, def] of scope.bindings) { |
| 308 | if (seen.has(name)) continue; |
nothing calls this directly
no test coverage detected