(
ce: IComputeEngine,
arg1:
| string
| {
[id: string]: Type | TypeString | Partial<SymbolDefinition>;
},
arg2?: Type | TypeString | Partial<SymbolDefinition>,
scope?: Scope
)
| 144 | return op.evaluate || op.collection ? 'function' : 'opaque'; |
| 145 | } |
| 146 | if (isValueDef(def)) return def.value.isConstant ? 'constant' : 'variable'; |
| 147 | return undefined; |
| 148 | } |
| 149 | |
| 150 | /** The description line(s) of a definition, as a list of searchable strings. */ |
| 151 | function descriptionLines(def: BoxedDefinition): string[] { |
| 152 | const d = isOperatorDef(def) |
| 153 | ? def.operator.description |
| 154 | : isValueDef(def) |
| 155 | ? def.value.description |
| 156 | : undefined; |
| 157 | if (!d) return []; |
| 158 | return typeof d === 'string' ? [d] : d; |
| 159 | } |
| 160 | |
| 161 | /** The curated search keywords of a definition, as a list of searchable |
| 162 | * strings. */ |
| 163 | function keywordsOf(def: BoxedDefinition): string[] { |
| 164 | const k = isOperatorDef(def) |
| 165 | ? def.operator.keywords |
| 166 | : isValueDef(def) |
| 167 | ? def.value.keywords |
| 168 | : undefined; |
| 169 | return k ?? []; |
| 170 | } |
| 171 | |
| 172 | /** |
| 173 | * Reverse library search: map a plain-text concept query to a ranked list of |
| 174 | * matching identifiers. See `ComputeEngine.searchDefinitions`. |
| 175 | */ |
| 176 | export function searchDefinitions( |
| 177 | ce: IComputeEngine, |
| 178 | query: string | string[], |
| 179 | options?: { limit?: number } |
| 180 | ): DefinitionSearchResult[] { |
| 181 | // Normalize into a list of phrases (one per array element, or the whole |
| 182 | // string), then a deduplicated bag of tokens. Matching is an OR over |
| 183 | // tokens; ranking rewards matching more of them. |
| 184 | const phrases = (typeof query === 'string' ? [query] : query) |
| 185 | .map((q) => q.trim().toLowerCase().replace(/\s+/g, ' ')) |
| 186 | .filter((q) => q.length > 0); |
| 187 | if (phrases.length === 0) return []; |
| 188 | |
| 189 | const tokens = [...new Set(phrases.flatMap((p) => p.split(' ')))]; |
| 190 | |
| 191 | // Multi-word phrases also participate in tier scoring so an exact keyword |
| 192 | // like "inverse cosine" ranks above token-level description matches. |
| 193 | const probes = [ |
| 194 | ...new Set([...tokens, ...phrases.filter((p) => p.includes(' '))]), |
| 195 | ]; |
| 196 | |
| 197 | // Clamp limit to [1, 100], default 10. |
| 198 | let limit = options?.limit ?? 10; |
| 199 | if (!Number.isFinite(limit)) limit = 10; |
| 200 | limit = Math.max(1, Math.min(100, Math.floor(limit))); |
| 201 | |
| 202 | // Trigger axis: name -> triggers. Degrades gracefully (no triggers) when no |
| 203 | // LaTeX syntax is available or it doesn't implement `getNamedTriggers`. This |
nothing calls this directly
no test coverage detected