fix(providers): handle space-separated search queries via matchesAnyToken (#8660)

Consolidates PR #8660 (matchesAnyToken with full-match priority over
token-level OR fallback) with the existing Turkish search normalization
shipped on release/v3.8.49.

The PR adds a new matchesAnyToken helper used by the providers search
to allow space-separated queries (e.g. 'pollinations sambanova') to
match when any of the tokens is present. Full query match takes
priority so that an exact 'pollinations sambanova' query still hits
even if a partial token would have been ambiguous.

The unit test file gains 12 PR-side matchesAnyToken tests on top of
the 6 release-side Turkish-normalization tests covering the same
function, totaling 27 tests.

Co-authored-by: maxmad64bis <maxmad64bis@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
Dizzle
2026-07-27 22:24:04 +02:00
committed by GitHub
parent 10115000d8
commit 4f3971f7ac
2 changed files with 46 additions and 4 deletions

View File

@@ -50,6 +50,7 @@ export function matchesSearch(
/**
* Checks if `text` matches any whitespace-separated token in `query`.
* Returns `true` if `query` is empty or if any token is found in `text`.
* Full query match takes priority over token-level OR fallback.
*/
export function matchesAnyToken(
text: string | null | undefined,
@@ -57,10 +58,9 @@ export function matchesAnyToken(
): boolean {
const q = normalizeForSearch(query);
if (!q) return true;
const tokens = q.split(/\s+/).filter(Boolean);
if (tokens.length === 0) return true;
const normText = normalizeForSearch(text);
return tokens.some((token) => normText.includes(token));
const normalizedText = normalizeForSearch(text);
if (normalizedText.includes(q)) return true;
return q.split(/\s+/).filter(Boolean).some((token) => normalizedText.includes(token));
}
const trCollator = new Intl.Collator("tr", {

View File

@@ -75,6 +75,10 @@ test("compareTr: null/undefined argümanları güvenli (?? '' guard)", () => {
assert.equal(compareTr(null, undefined), 0);
});
// ---------------------------------------------------------------------------
// matchesAnyToken — Türkçe bölümü (release tarafı)
// ---------------------------------------------------------------------------
test("matchesAnyToken: tek token eşleşmesi", () => {
assert.equal(matchesAnyToken("pollinations", "pollinations sambanova"), true);
});
@@ -100,3 +104,41 @@ test("matchesAnyToken: null/undefined text/query güvenli", () => {
assert.equal(matchesAnyToken(null, "test"), false);
assert.equal(matchesAnyToken("test", null), true);
});
// ---------------------------------------------------------------------------
// matchesAnyToken — PR #8660 bölümü (space-separated query)
// ---------------------------------------------------------------------------
test("matchesAnyToken: single token behaves like matchesSearch", () => {
assert.equal(matchesAnyToken("İstanbul", "istanbul"), true);
assert.equal(matchesAnyToken("OpenAI", "anthropic"), false);
});
test("matchesAnyToken: multi-token query matches any token (OR fallback)", () => {
assert.equal(matchesAnyToken("pollinations", "pollinations sambanova"), true);
assert.equal(matchesAnyToken("sambanova", "pollinations sambanova"), true);
assert.equal(matchesAnyToken("huggingface", "pollinations sambanova"), false);
assert.equal(matchesAnyToken("testorg", "testorg github"), true);
assert.equal(matchesAnyToken("github", "testorg github"), true);
});
test("matchesAnyToken: full query match takes priority before OR split", () => {
assert.equal(matchesAnyToken("pollinations sambanova", "pollinations sambanova"), true);
});
test("matchesAnyToken: Turkish normalization works across tokens", () => {
assert.equal(matchesAnyToken("Şarj", "sarj istanbul"), true);
assert.equal(matchesAnyToken("İstanbul", "istanbul sarj"), true);
});
test("matchesAnyToken: empty or whitespace query matches all", () => {
assert.equal(matchesAnyToken("anything", ""), true);
assert.equal(matchesAnyToken("anything", " "), true);
});
test("matchesAnyToken: null/undefined guard mirrors matchesSearch", () => {
assert.equal(matchesAnyToken(null, "query"), false);
assert.equal(matchesAnyToken("text", null), true);
assert.equal(matchesAnyToken(undefined, "query"), false);
assert.equal(matchesAnyToken("text", undefined), true);
});