demotivator
Version:
A TypeScript library containing 500+ hand-curated insults organized into themed packs, along with utilities to generate, search, and transform them.
137 lines • 5.21 kB
JavaScript
/**
* @license
* Copyright 2024, PorkyProductions, and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { insultPacks } from './insults';
const profanityWords = [
'bullshit',
'fucking',
'asshole',
'bitch',
'damn',
'fuck',
'shit',
'ass'
];
const assertInsult = (insult) => {
if (typeof insult !== 'string')
throw new TypeError('Insult must be a string');
if (insult.trim().length === 0)
throw new Error('Insult cannot be empty');
};
const assertPositiveInteger = (value, label) => {
if (!Number.isInteger(value))
throw new TypeError(`${label} must be an integer`);
if (value < 1)
throw new RangeError(`${label} must be greater than 0`);
};
const getPackInfoFromInsult = (insult) => {
const packKeys = Object.keys(insultPacks);
for (const packKey of packKeys) {
const pack = insultPacks[packKey];
const position = pack.insults.indexOf(insult);
if (position >= 0) {
return {
insult,
packKey,
packTitle: pack.title,
explicit: pack.explicit,
position: position + 1
};
}
}
throw new Error('Insult not found in any built-in pack');
};
const buildMask = (length, symbol) => {
const repeatCount = Math.ceil(length / symbol.length);
return symbol.repeat(repeatCount).slice(0, length);
};
const profaneWordRegex = new RegExp(`\\b(${profanityWords.join('|')})\\b`, 'gi');
/**
* Masks profane words in an insult using a caller-selected symbol.
* @param insult The insult string to purify.
* @param symbol Replacement symbol. Defaults to `*`.
* @returns The purified insult.
* @since 15.0.0
*/
export const purify = (insult, symbol = '*') => {
assertInsult(insult);
if (typeof symbol !== 'string' || symbol.length === 0)
throw new TypeError('Symbol must be a non-empty string');
return insult.replace(profaneWordRegex, (word) => buildMask(word.length, symbol));
};
export function packInfo(input, array) {
if (typeof input === 'string') {
assertInsult(input);
return getPackInfoFromInsult(input);
}
if (typeof input === 'number') {
assertPositiveInteger(input, 'Position');
const sourceArray = array ?? insultPacks.original.insults;
if (input > sourceArray.length)
throw new RangeError(`Position must be between 1 and ${sourceArray.length}`);
const insult = sourceArray[input - 1];
if (!insult)
throw new Error('No insults available');
return getPackInfoFromInsult(insult);
}
if (typeof input === 'object' && input !== null) {
assertPositiveInteger(input.position, 'Position');
assertInsult(input.insult);
if (!array) {
return getPackInfoFromInsult(input.insult);
}
if (input.position > array.length)
throw new RangeError(`Position must be between 1 and ${array.length}`);
const insultAtPosition = array[input.position - 1];
if (!insultAtPosition)
throw new Error('No insults available');
if (insultAtPosition !== input.insult)
throw new Error('Search result does not match insult at the provided position in the supplied array');
return getPackInfoFromInsult(insultAtPosition);
}
throw new TypeError('Invalid packInfo input');
}
/**
* Inserts "Porky" into random positions in an insult.
* @param insult The insult string to modify.
* @param amount Number of times to insert "Porky". Defaults to `1`.
* @returns The porkified insult.
* @since 15.0.0
*/
export const porkify = (insult, amount = 1) => {
assertInsult(insult);
assertPositiveInteger(amount, 'Amount');
const tokens = insult.trim().split(/\s+/);
for (let i = 0; i < amount; i++) {
const insertPosition = Math.floor(Math.random() * (tokens.length + 1));
tokens.splice(insertPosition, 0, 'Porky');
}
return tokens.join(' ');
};
/**
* Uppercases an insult, removes ending punctuation, and appends exclamation marks.
* @param insult The insult string to transform.
* @param exclamationCount Number of trailing exclamation marks. Defaults to `3`.
* @returns The angry version of the insult.
* @since 15.0.0
*/
export const makeAngry = (insult, exclamationCount = 3) => {
assertInsult(insult);
assertPositiveInteger(exclamationCount, 'Exclamation count');
const withoutTrailingPunctuation = insult.trimEnd().replace(/[\p{P}\p{S}]+$/gu, '');
return `${withoutTrailingPunctuation.toUpperCase()}${'!'.repeat(exclamationCount)}`;
};
//# sourceMappingURL=texttools.js.map