UNPKG

demotivator

Version:

A TypeScript library containing 500+ hand-curated insults organized into themed packs, along with utilities to generate, search, and transform them.

78 lines 2.75 kB
import { insults } from './insults'; import s from 'lodash/sample'; /** * Scores how relevant an insult is to a given (pre-lowercased) search term. * * | Score | Condition | * |-------|-----------| * | 4 | Exact match (case-insensitive) | * | 3 | Insult starts with the term | * | 2 | Term appears as a whole word inside the insult | * | 1 | Term appears anywhere as a substring | * | 0 | No match | * * @internal */ const scoreInsult = (insult, normalizedTerm, wordBoundaryRegex) => { const normalizedInsult = insult.toLowerCase(); if (normalizedInsult === normalizedTerm) return 4; if (normalizedInsult.startsWith(normalizedTerm)) return 3; if (wordBoundaryRegex.test(insult)) return 2; if (normalizedInsult.includes(normalizedTerm)) return 1; return 0; }; /** * @returns a pseudorandom insult from the insult array. */ export default (array = insults) => { const result = s(array); if (!result) throw new Error('No insults available'); return result; }; /** * Get a specific insult from a point and array that you specify * * @param {Insult[]} [array=insults] The array to select from. Default is original only * @param {number} position The position in the array to select. Starts indexing at 1, not 0. * @returns {Insult} */ export const insultAt = (position, array = insults) => { if (!Number.isInteger(position)) throw new TypeError('Position must be an integer'); if (position < 1 || position > array.length) throw new RangeError(`Position must be between 1 and ${array.length}`); const result = array[position - 1]; if (!result) throw new Error('No insults available'); return result; }; export function searchInsults(term, array = insults, withPosition = false) { if (array.length === 0) throw new Error('No insults available'); const normalizedTerm = term.toLowerCase(); const escapedTerm = normalizedTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const wordBoundaryRegex = new RegExp(`\\b${escapedTerm}\\b`, 'i'); let bestMatch; let bestIndex = -1; let bestScore = 0; for (let i = 0; i < array.length; i++) { const insult = array[i]; const score = scoreInsult(insult, normalizedTerm, wordBoundaryRegex); if (score > bestScore) { bestScore = score; bestMatch = insult; bestIndex = i; } if (bestScore === 4) break; // exact match — can't do better } if (!bestMatch) throw new Error(`No insults found matching "${term}"`); return withPosition ? { insult: bestMatch, position: bestIndex + 1 } : bestMatch; } //# sourceMappingURL=generateinsult.js.map