(pkg: NpmSearchResult, text: string, scope: SearchScope)
| 209 | |
| 210 | // Filter predicates |
| 211 | function matchesTextFilter(pkg: NpmSearchResult, text: string, scope: SearchScope): boolean { |
| 212 | if (!text) return true |
| 213 | |
| 214 | const pkgName = pkg.package.name.toLowerCase() |
| 215 | const pkgDescription = (pkg.package.description ?? '').toLowerCase() |
| 216 | const pkgKeywords = (pkg.package.keywords ?? []).map(k => k.toLowerCase()) |
| 217 | |
| 218 | // When scope is 'all', parse and handle operators |
| 219 | if (scope === 'all') { |
| 220 | const parsed = parseSearchOperators(text) |
| 221 | |
| 222 | // If operators are present, use structured matching |
| 223 | if (hasSearchOperators(parsed)) { |
| 224 | // All specified operators must match (AND logic between operator types) |
| 225 | // Within each operator, any value can match (OR logic within operator) |
| 226 | |
| 227 | if (parsed.name?.length) { |
| 228 | const nameMatches = parsed.name.some(n => pkgName.includes(n.toLowerCase())) |
| 229 | if (!nameMatches) return false |
| 230 | } |
| 231 | |
| 232 | if (parsed.description?.length) { |
| 233 | const descMatches = parsed.description.some(d => pkgDescription.includes(d.toLowerCase())) |
| 234 | if (!descMatches) return false |
| 235 | } |
| 236 | |
| 237 | if (parsed.keywords?.length) { |
| 238 | const kwMatches = parsed.keywords.some(kw => |
| 239 | pkgKeywords.some(pk => pk.includes(kw.toLowerCase())), |
| 240 | ) |
| 241 | if (!kwMatches) return false |
| 242 | } |
| 243 | |
| 244 | // If there's remaining text, it must match somewhere |
| 245 | if (parsed.text) { |
| 246 | const textLower = parsed.text.toLowerCase() |
| 247 | const textMatches = |
| 248 | pkgName.includes(textLower) || |
| 249 | pkgDescription.includes(textLower) || |
| 250 | pkgKeywords.some(k => k.includes(textLower)) |
| 251 | if (!textMatches) return false |
| 252 | } |
| 253 | |
| 254 | return true |
| 255 | } |
| 256 | |
| 257 | // No operators - fall through to standard 'all' search |
| 258 | const lower = text.toLowerCase() |
| 259 | return ( |
| 260 | pkgName.includes(lower) || |
| 261 | pkgDescription.includes(lower) || |
| 262 | pkgKeywords.some(k => k.includes(lower)) |
| 263 | ) |
| 264 | } |
| 265 | |
| 266 | // Non-'all' scopes - simple matching |
| 267 | const lower = text.toLowerCase() |
| 268 | switch (scope) { |
no test coverage detected