mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-08-29 05:57:32 +00:00
51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import { diacritics } from 'normalize-diacritics/diacritics'
|
|
|
|
export type SearchTextValue =
|
|
string | number | boolean | bigint | null | undefined
|
|
|
|
const NON_ASCII = /[^\x00-\x7F]/
|
|
const SEPARATORS = /[^\p{L}\p{N}]+/u
|
|
|
|
export function normalizeSearchText(value: SearchTextValue): string {
|
|
const text = String(value ?? '')
|
|
|
|
// Nothing in the table matches ASCII, so skip normaliation
|
|
if (!NON_ASCII.test(text)) return text.toLocaleLowerCase()
|
|
|
|
const normalized = diacritics.reduce((text, replacement) => {
|
|
return text.replace(replacement.diacritics, replacement.letter)
|
|
}, text)
|
|
|
|
return normalized.toLocaleLowerCase()
|
|
}
|
|
|
|
export function matchesSearchText(
|
|
value: SearchTextValue,
|
|
searchText: SearchTextValue
|
|
): boolean {
|
|
const query = normalizeSearchText(searchText)
|
|
const terms = query.split(SEPARATORS).filter(Boolean)
|
|
|
|
// Empty or punctuation-only query, nothing to split into terms
|
|
if (terms.length === 0) {
|
|
return normalizeSearchText(value).includes(query.trim())
|
|
}
|
|
|
|
const words = normalizeSearchText(value).split(SEPARATORS).filter(Boolean)
|
|
const claimed = new Array<boolean>(words.length).fill(false)
|
|
|
|
// Each term takes a word of its own, longest first, so that "another tag th"
|
|
// doesn't match "Another Tag" by finding the "th" inside "another"
|
|
return terms
|
|
.sort((a, b) => b.length - a.length)
|
|
.every((term) => {
|
|
for (let i = 0; i < words.length; i++) {
|
|
if (!claimed[i] && words[i].includes(term)) {
|
|
claimed[i] = true
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
})
|
|
}
|