/**
* Pure text-matching helpers shared by the keyword/name triggers.
*
* Whole-word, case-insensitive matching is used identically to fire lore
* entries (by key), activate NPCs (by name) and detect first mentions. Sharing
* it keeps `world`, `characters` and `disclosure` decoupled from one another.
*/
/** Escape a string for safe literal use inside a RegExp. */
export function escapeRegExp(s: string): string {
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/**
* Whole-word, case-insensitive test for `term` in `text` (supports phrases).
* A blank term never matches; a term that can't be compiled never matches
* (returns false rather than throwing).
*/
export function wholeWordMatch(text: string, term: string): boolean {
const t = term.trim();
if (!t) return false;
try {
return new RegExp(`\\b${escapeRegExp(t)}\\b`, "i").test(text);
} catch {
return false;
}
}