Files
dbx/apps/desktop/src/lib/common/searchPattern.ts
T

54 lines
1.8 KiB
TypeScript

/**
* Parse the conventional `/pattern/flags` spelling used by search inputs.
*
* This legacy parser intentionally preserves ordinary-search behavior: it
* accepts the established flag set and adds `i` when the user omits it.
* Explicit Regex mode uses compileSearchRegex below for runtime-native flags
* and exact explicit-flag semantics.
*/
export function parseSlashDelimitedRegexQuery(query: string): RegExp | null {
if (!query.startsWith("/") || query.length < 2) return null;
const lastSlash = query.lastIndexOf("/");
if (lastSlash <= 0) return null;
const source = query.slice(1, lastSlash);
const flags = query.slice(lastSlash + 1);
if (!/^[dgimsuvy]*$/.test(flags)) return null;
try {
return new RegExp(source, flags.includes("i") ? flags : `${flags}i`);
} catch {
return null;
}
}
export interface CompiledSearchRegex {
regex: RegExp | null;
invalid: boolean;
}
/** Compile a search value when the caller has explicitly enabled Regex mode. */
export function compileSearchRegex(query: string): CompiledSearchRegex {
const value = query.trim();
if (!value) return { regex: null, invalid: false };
// Keep `/pattern/flags` compatible with the existing search syntax. A
// slash at the beginning without a closing slash is an ordinary pattern in
// explicit Regex mode, and therefore goes through the regular constructor.
if (value.startsWith("/")) {
const lastSlash = value.lastIndexOf("/");
if (lastSlash > 0) {
try {
return { regex: new RegExp(value.slice(1, lastSlash), value.slice(lastSlash + 1) || "i"), invalid: false };
} catch {
return { regex: null, invalid: true };
}
}
}
try {
return { regex: new RegExp(value, "i"), invalid: false };
} catch {
return { regex: null, invalid: true };
}
}