{
  "sha": "d6681989d460fe5513bbd9695b4329bce0c4916c",
  "redacted": false,
  "message": "fix(search): match mixed Latin and CJK queries (#397)\n\nSplit mixed-script search terms and allow CJK phrase matches across indexed spaces.",
  "author": {
    "login": "nnneeeooo-nnneeeooo",
    "name": "neo",
    "email": "125815713+nnneeeooo-nnneeeooo@users.noreply.github.com"
  },
  "committer": {
    "login": "web-flow",
    "name": "GitHub",
    "email": "noreply@github.com"
  },
  "created_at": "2026-10-25T19:09:10Z",
  "files": [
    {
      "filename": "static/search.js",
      "previous_filename": "",
      "status": "modified",
      "additions": 16,
      "deletions": 1,
      "changes": 17
    },
    {
      "filename": "tests/test_search.py",
      "previous_filename": "",
      "status": "modified",
      "additions": 31,
      "deletions": 0,
      "changes": 31
    }
  ],
  "diff": "diff --git a/static/search.js b/static/search.js\\nindex e266e355e..afc712963 100644\\n--- a/static/search.js\\n+++ b/static/search.js\\n@@ -12,10 +12,24 @@\\n       .trim();\\n   }\\n \\n+  function queryTerms(value) {\\n+    var normalized = normalize(value);\\n+    return normalized.match(\\n+      /[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]+|[^\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}\\s]+/gu\\n+    ) || [];\\n+  }\\n+\\n   function termMatches(haystack, term) {\\n     if (/^[a-z0-9]{1,3}$/.test(term)) {\\n       return haystack.split(/\\s+/).indexOf(term) !== -1;\\n     }\\n+    if (/[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]/u.test(term)) {\\n+      var compactCjk = haystack.replace(\\n+        /([\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}])\\s+(?=[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}])/gu,\\n+        \"$1\"\\n+      );\\n+      return compactCjk.indexOf(term) !== -1;\\n+    }\\n     return haystack.indexOf(term) !== -1;\\n   }\\n \\n@@ -149,7 +163,7 @@\\n     var modelQuery = parseModelQuery(records, textQuery.normalize(\"NFKC\"));\\n     if (modelQuery) textQuery = modelQuery.remainder;\\n     var normalizedQuery = normalize(textQuery);\\n-    var terms = normalizedQuery.split(/\\s+/).filter(Boolean);\\n+    var terms = queryTerms(textQuery);\\n     var criteria = {\\n       normalizedQuery: normalizedQuery,\\n       terms: terms,\\n@@ -184,6 +198,7 @@\\n   if (typeof module !== \"undefined\" && module.exports) {\\n     module.exports = {\\n       normalize: normalize,\\n+      queryTerms: queryTerms,\\n       termMatches: termMatches,\\n       parseAirlineCodeQuery: parseAirlineCodeQuery,\\n       searchRecords: searchRecords\\ndiff --git a/tests/test_search.py b/tests/test_search.py\\nindex 683b38edf..2d95ddc5a 100644\\n--- a/tests/test_search.py\\n+++ b/tests/test_search.py\\n@@ -3,6 +3,7 @@ from __future__ import annotations\\n \\n import json\\n import re\\n+import subprocess\\n import sys\\n import tempfile\\n import unicodedata\\n@@ -164,6 +165,36 @@ def main() -> None:\\n     assert payload[\"airlineCodes\"][\"icao\"][\"ASV\"] == \"ASV\"\\n     assert \"9S\" not in payload[\"airlineCodes\"][\"iata\"]\\n     items_by_id = {row[\"id\"]: row for row in payload[\"items\"]}\\n+    client_search = subprocess.run(\\n+        [\\n+            \"node\",\\n+            \"-e\",\\n+            r\"\"\"\\n+const assert = require(\"assert\").strict;\\n+const search = require(\"./static/search.js\");\\n+const index = require(\"./site/search-index.json\");\\n+const result = search.searchRecords(\\n+  index.items,\\n+  \"SAS SK916折返紐瓦克\",\\n+  index.airlineCodes,\\n+  \"zh\"\\n+);\\n+assert.ok(\\n+  result.matches.some(({record}) => record.id === \"a-sas-sk916-jfk-turnback-20261025\"),\\n+  JSON.stringify({\\n+    queryTerms: search.queryTerms(\"SAS SK916折返紐瓦克\"),\\n+    matchIds: result.matches.map(({record}) => record.id)\\n+  })\\n+);\\n+\"\"\",\\n+        ],\\n+        cwd=ROOT,\\n+        capture_output=True,\\n+        text=True,\\n+        check=False,\\n+    )\\n+    assert client_search.returncode == 0, (\\n+        client_search.stdout + client_search.stderr)\\n     live_condor = items_by_id[\\n         \"a-20260915-0811-simple-flying-reports-condor-a320-missed\"]\\n     beyond_borders = items_by_id["
}
