diff --git a/src/shared/utils/turkishText.ts b/src/shared/utils/turkishText.ts index af55400ed6..930bf733ed 100644 --- a/src/shared/utils/turkishText.ts +++ b/src/shared/utils/turkishText.ts @@ -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", { diff --git a/tests/unit/turkishText.test.ts b/tests/unit/turkishText.test.ts index 9d42db99cf..cc8d4583f6 100644 --- a/tests/unit/turkishText.test.ts +++ b/tests/unit/turkishText.test.ts @@ -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); +});