UNPKG

sanity-plugin-mux-input

Version:

An input component that integrates Sanity Studio with Mux video encoding/hosting service.

77 lines (65 loc) 2.82 kB
// Adaptation of Sanity's createSearchQuery for our limited use case: // https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/core/search/weighted/createSearchQuery.ts import {compact, toLower, trim, uniq, words} from 'lodash' const SPECIAL_CHARS = /([^!@#$%^&*(),\\/?";:{}|[\]+<>\s-])+/g const STRIP_EDGE_CHARS = /(^[.]+)|([.]+$)/ function tokenize(string: string): string[] { return (string.match(SPECIAL_CHARS) || []).map((token) => token.replace(STRIP_EDGE_CHARS, '')) } function toGroqParams(terms: string[]): Record<string, string> { const params: Record<string, string> = {} return terms.reduce((acc, term, i) => { acc[`t${i}`] = `*${term}*` // "t" is short for term return acc }, params) } /** * Convert a string into an array of tokenized terms. * * Any (multi word) text wrapped in double quotes will be treated as "phrases", or separate tokens that * will not have its special characters removed. * E.g.`"the" "fantastic mr" fox fox book` =\> ["the", `"fantastic mr"`, "fox", "book"] * * Phrases wrapped in quotes are assigned relevance scoring differently from regular words. * * @internal */ function extractTermsFromQuery(query: string): string[] { const quotedQueries = [] as string[] const unquotedQuery = query.replace(/("[^"]*")/g, (match) => { if (words(match).length > 1) { quotedQueries.push(match) return '' } return match }) // Lowercase and trim quoted queries const quotedTerms = quotedQueries.map((str) => trim(toLower(str))) /** * Convert (remaining) search query into an array of deduped, sanitized tokens. * All white space and special characters are removed. * e.g. "The saint of Saint-Germain-des-Prés" =\> ['the', 'saint', 'of', 'germain', 'des', 'pres'] */ const remainingTerms = uniq(compact(tokenize(toLower(unquotedQuery)))) return [...quotedTerms, ...remainingTerms] } /** * Create GROQ constraints, given search terms and the full spec of available document types and fields. * Essentially a large list of all possible fields (joined by logical OR) to match our search terms against. */ function createConstraints(terms: string[], includeAssetId: boolean) { const searchPaths = includeAssetId ? ['filename', 'assetId'] : ['filename'] const constraints = terms .map((_term, i) => searchPaths.map((joinedPath) => `${joinedPath} match $t${i}`)) .filter((constraint) => constraint.length > 0) return constraints.map((constraint) => `(${constraint.join(' || ')})`) } export function createSearchFilter(query: string) { const terms = extractTermsFromQuery(query) return { filter: createConstraints(terms, query.length >= 8), // if the search is big enough, include the assetId (mux id) in the results params: { ...toGroqParams(terms), }, } }