search target fix
This commit is contained in:
+34
-16
@@ -206,28 +206,46 @@ export function extractMatchedTextFromSnippet(
|
|||||||
const firstStart = first.index ?? 0;
|
const firstStart = first.index ?? 0;
|
||||||
const lastEnd = (last.index ?? 0) + last[0].length;
|
const lastEnd = (last.index ?? 0) + last[0].length;
|
||||||
|
|
||||||
const span = snippetHtml.slice(firstStart, lastEnd);
|
// Marked-span text — just the tokens Typesense highlighted.
|
||||||
const plain = normalizeQuotes(
|
const markedSpan = snippetHtml.slice(firstStart, lastEnd);
|
||||||
decodeSnippetEntities(span.replace(/<[^>]*>/g, ""))
|
const markedPlain = normalizeQuotes(
|
||||||
|
decodeSnippetEntities(markedSpan.replace(/<[^>]*>/g, ""))
|
||||||
.replace(/\s+/g, " ")
|
.replace(/\s+/g, " ")
|
||||||
.trim(),
|
.trim(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!plain) return null;
|
// Full-snippet text — includes Typesense's surrounding context. Typesense
|
||||||
|
// snippets are direct slices of the source field, so the surrounding text
|
||||||
|
// exists verbatim in the destination page. Using it as the prefix makes
|
||||||
|
// single-token matches (e.g. `<mark>Therefore</mark> material senses...`)
|
||||||
|
// land on the *correct* occurrence on the destination page rather than the
|
||||||
|
// first instance of that token alphabetically.
|
||||||
|
const fullPlain = normalizeQuotes(
|
||||||
|
decodeSnippetEntities(snippetHtml.replace(/<[^>]*>/g, ""))
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
// strip leading/trailing ellipsis Typesense sometimes adds
|
||||||
|
.replace(/^(?:…|\.{3,})\s*/, "")
|
||||||
|
.replace(/\s*(?:…|\.{3,})$/, "")
|
||||||
|
.trim(),
|
||||||
|
);
|
||||||
|
|
||||||
// If the span between first and last mark is unreasonably long
|
// Pick the best candidate:
|
||||||
// (e.g. snippet has marks at far ends of a long passage), fall back to
|
// - if the marked span alone is already ≥6 words, it's a multi-token phrase
|
||||||
// just the first marked term — that's still a real match in the doc.
|
// and is specific enough — use it.
|
||||||
if (plain.length > 200) {
|
// - otherwise prefer the full snippet (more context = more uniquely placed),
|
||||||
const firstPlain = normalizeQuotes(
|
// capped at 200 chars to keep URLs sane.
|
||||||
decodeSnippetEntities(first[1].replace(/<[^>]*>/g, ""))
|
// - fall back to marked span if the full snippet is empty / unusable.
|
||||||
.replace(/\s+/g, " ")
|
const markedWordCount = markedPlain
|
||||||
.trim(),
|
? markedPlain.split(/\s+/).filter(Boolean).length
|
||||||
);
|
: 0;
|
||||||
return firstPlain || null;
|
|
||||||
|
if (markedWordCount >= 6) {
|
||||||
|
return markedPlain || null;
|
||||||
}
|
}
|
||||||
|
if (fullPlain && fullPlain.length <= 200) {
|
||||||
return plain;
|
return fullPlain;
|
||||||
|
}
|
||||||
|
return markedPlain || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode the HTML entities Typesense commonly emits in match snippets.
|
// Decode the HTML entities Typesense commonly emits in match snippets.
|
||||||
|
|||||||
Reference in New Issue
Block a user