UNPKG

@coffeeandfun/google-profanity-words

Version:

Real profanity words banned by Google, extracted from their hidden API before shutdown. Now available as an easy-to-use Node.js library for content filtering.

535 lines (367 loc) โ€ข 13.4 kB
![alt text](.github/readme.png 'Logo Title Text 1') # โ˜• Google Profanity Words > A fun and developer-friendly profanity detection library brought to you by [Coffee & Fun LLC](https://coffeeandfun.com) โ˜•๐ŸŽ‰ > Built and maintained with love by [Robert James Gabriel](https://github.com/robertgabriel) ๐Ÿ’ปโœจ [![npm version](https://img.shields.io/npm/v/@coffeeandfun/google-profanity-words.svg)](https://www.npmjs.com/package/@coffeeandfun/google-profanity-words) [![Stars](https://img.shields.io/github/stars/coffee-and-fun/google-profanity-words?style=social)](https://github.com/coffee-and-fun/google-profanity-words) --- ## ๐Ÿš€ What's This? **Google Profanity Words** is a Node.js library that helps you detect and filter out naughty language (in multiple languages!) from your apps or content. Whether you're building a chat app, a comment section, a game, or a comment moderator โ€” this one's your profanity-slaying sidekick. Made by devs for devs. Maintained by Robert at Coffee & Fun โ˜•โค๏ธ --- ## โœจ Features - ๐ŸŒ **Multilingual** โ€” English, Spanish, French, Irish, Arabic, and Chinese out of the box - โšก **Fast & tiny** โ€” zero runtime dependencies, O(1) lookups with `Set` - ๐Ÿงช **Battle-tested** โ€” 200+ Jest tests across every language - ๐Ÿ”’ **Secure by default** โ€” no polynomial regex, ships with provenance - ๐Ÿ“ **TypeScript ready** โ€” types included, no `@types` install needed - ๐ŸŽฏ **Framework-friendly** โ€” works with Express, Fastify, Koa, Next.js, Discord.js, you name it --- ## ๐Ÿ“ฆ Install Me ```bash npm install @coffeeandfun/google-profanity-words ``` Requires **Node.js 16+**. --- ## โšก Quickstart Guide ```js import { ProfanityEngine } from '@coffeeandfun/google-profanity-words'; // Default is English const profanity = new ProfanityEngine(); // Espaรฑol? You got it. const profanityES = new ProfanityEngine({ language: 'es' }); // Check a single word const isBad = await profanity.search('hell'); // Or check a full sentence const hasCurses = await profanity.hasCurseWords('This is a test sentence'); // Or grab the actual bad words const found = await profanity.getCurseWords('oh hell and damn'); console.log(isBad, hasCurses, found); // โ†’ true, false, ['hell', 'damn'] ``` That's the whole idea. Everything below is detail. โœจ --- ## ๐Ÿง  What a Returned Object Looks Like Every check method is **async** and returns a Promise. Here's what you'll actually see back: ```js await profanity.hasCurseWords('oh hell no'); // โ†’ true await profanity.hasCurseWords('have a lovely day'); // โ†’ false await profanity.getCurseWords('hell, damn, and hell again'); // โ†’ ['hell', 'damn'] // unique, lowercase await profanity.getCurseWords('a perfectly fine sentence'); // โ†’ [] // empty array, never null await profanity.search('HELL'); // โ†’ true // case-insensitive await profanity.search('hello'); // โ†’ false await profanity.all(); // โ†’ ['2 girls 1 cup', '2g1c', '4r5e', /* โ€ฆ962 total */] ``` --- ## ๐Ÿ” API Reference ### ๐Ÿ› ๏ธ `new ProfanityEngine(options?)` Create a new profanity detector engine! ```js const profanity = new ProfanityEngine(); // Defaults to English const spanishProfanity = new ProfanityEngine({ language: 'es' }); ``` #### Options | Option | Type | Default | What it does | | ---------- | --------- | ------- | ---------------------------------------------------------------- | | `language` | `string` | `'en'` | ISO code matching a file in `data/`. Falls back to English. | | `testMode` | `boolean` | `false` | When `true`, suppresses `console.warn` output (great in tests). | --- ### ๐Ÿ”Ž `search(word)` Check a single word to see if it's naughty. ```js await profanity.search('heck'); // โ†’ false await profanity.search('hell'); // โ†’ true await profanity.search('HELL'); // โ†’ true (case-insensitive) await profanity.search(' hell '); // โ†’ true (trimmed for you) await profanity.search(''); // โ†’ false await profanity.search(null); // โ†’ false (handles bad input) ``` --- ### ๐Ÿ’ฌ `hasCurseWords(sentence)` Check a full sentence or phrase for profanity. ```js await profanity.hasCurseWords('You silly goose'); // โ†’ false await profanity.hasCurseWords('oh hell no'); // โ†’ true await profanity.hasCurseWords('(hell)!'); // โ†’ true (punctuation is handled) await profanity.hasCurseWords('This is hellhole land'); // โ†’ false (whole-word match) ``` --- ### ๐Ÿ“‹ `getCurseWords(sentence)` Get the actual bad words that showed up (unique, lowercase). ```js await profanity.getCurseWords('hell and damn and hell again'); // โ†’ ['hell', 'damn'] await profanity.getCurseWords('a clean message'); // โ†’ [] ``` Great for logging moderation events or showing users exactly what tripped the filter. --- ### ๐Ÿ“œ `all()` Get the full list of bad words in the current language. ```js const badWords = await profanity.all(); console.log(badWords.length); // โ†’ 962 (for English) console.log(badWords[0]); // โ†’ '2 girls 1 cup' ``` The returned array is a **copy** โ€” mutating it won't affect the engine. --- ### ๐Ÿ”„ `reset()` Clears the in-memory cache. Next call re-reads the data file. Useful in tests or if you hot-swap the data file. ```js profanity.reset(); ``` --- ## ๐ŸŒ Supported Languages | Code | Language | Entries (approx.) | | ---- | --------------------- | ----------------- | | `en` | English ๐Ÿ‡ฌ๐Ÿ‡ง (default) | 962 | | `es` | Spanish ๐Ÿ‡ช๐Ÿ‡ธ | 564 | | `fr` | French ๐Ÿ‡ซ๐Ÿ‡ท | 23 | | `ga` | Irish ๐Ÿ‡ฎ๐Ÿ‡ช | 15 | | `ar` | Arabic | 23 | | `zh` | Chinese ๐Ÿ‡จ๐Ÿ‡ณ | 30 | > If you pass a language code that doesn't exist, the engine gracefully falls back to English and prints a warning (unless `testMode: true`). --- ## ๐Ÿ’ก Real Talk: Edge Cases - Empty strings? We gotchu. Returns `false` / `[]`. ๐Ÿ‘Œ - `null`, `undefined`, numbers, objects? No crashes โ€” returns `false` / `[]`. - **Case-insensitive** by default (`Hell`, `HELL`, `hell` all match). - Handles punctuation: `hell!`, `(hell)`, `"hell"`, `hell.` โ€” all detected. - **Whole-word matching**: `hellhole` does **not** trigger on `hell`. - Works with Unicode (Spanish `ยฟ`/`ยก`, Chinese characters, Arabic, etc.) thanks to `Intl.Segmenter`. --- ## ๐Ÿงช Testing with Jest We've got testing covered like whipped cream on a latte โ˜•๐ŸŽ‚ ```bash # Run the full suite npm test # Run a single language's tests npm run en npm run es npm run engine # Or use Jest directly npx jest --watch npx jest --coverage npx jest path/to/file.test.js ``` Tests live in `__tests__/` and run against the **real** word-list files โ€” no mocking, no surprises. ๐ŸŽฏ --- ## ๐Ÿ”€ Example Use Cases ### โœ… Filter User Input ```js import { ProfanityEngine } from '@coffeeandfun/google-profanity-words'; const profanity = new ProfanityEngine(); async function cleanInput(input) { if (await profanity.hasCurseWords(input)) { return 'โš ๏ธ Whoa there! Language, please.'; } return input; } ``` --- ### ๐ŸŒ Multi-Language Setup ```js const en = new ProfanityEngine({ language: 'en' }); const es = new ProfanityEngine({ language: 'es' }); const [englishHit, spanishHit] = await Promise.all([ en.hasCurseWords('oh hell no'), es.hasCurseWords('ยกquรฉ mierda!'), ]); console.log(englishHit, spanishHit); // โ†’ true, true ``` --- ### ๐Ÿšฆ Express Middleware Block profane comments at the API boundary. ```js import express from 'express'; import { ProfanityEngine } from '@coffeeandfun/google-profanity-words'; const app = express(); const profanity = new ProfanityEngine(); app.use(express.json()); app.post('/comments', async (req, res) => { const text = req.body?.text ?? ''; if (await profanity.hasCurseWords(text)) { return res.status(400).json({ error: 'Please keep it friendly ๐Ÿ’›', }); } res.json({ ok: true, comment: text }); }); app.listen(3000); ``` --- ### โšก Fastify ```js import Fastify from 'fastify'; import { ProfanityEngine } from '@coffeeandfun/google-profanity-words'; const app = Fastify(); const profanity = new ProfanityEngine(); app.post('/chat', async (request, reply) => { const { message } = request.body; if (await profanity.hasCurseWords(message)) { reply.code(400); return { error: 'Please watch your language ๐Ÿ˜…' }; } return { ok: true, message }; }); await app.listen({ port: 3000 }); ``` --- ### ๐Ÿงญ Koa ```js import Koa from 'koa'; import bodyParser from 'koa-bodyparser'; import { ProfanityEngine } from '@coffeeandfun/google-profanity-words'; const app = new Koa(); const profanity = new ProfanityEngine(); app.use(bodyParser()); app.use(async (ctx) => { const { text = '' } = ctx.request.body || {}; if (await profanity.hasCurseWords(text)) { ctx.status = 400; ctx.body = { error: 'Language, please ๐Ÿ™ˆ' }; return; } ctx.body = { ok: true }; }); app.listen(3000); ``` --- ### ๐Ÿ”บ Next.js API Route (App Router) `app/api/moderate/route.js`: ```js import { NextResponse } from 'next/server'; import { ProfanityEngine } from '@coffeeandfun/google-profanity-words'; const profanity = new ProfanityEngine(); export async function POST(request) { const { text } = await request.json(); const hasBadWords = await profanity.hasCurseWords(text); return NextResponse.json({ clean: !hasBadWords }); } ``` --- ### ๐ŸŽฎ Discord.js Bot Delete messages with profanity and warn the user. ```js import { Client, GatewayIntentBits } from 'discord.js'; import { ProfanityEngine } from '@coffeeandfun/google-profanity-words'; const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, ], }); const profanity = new ProfanityEngine(); client.on('messageCreate', async (message) => { if (message.author.bot) return; if (await profanity.hasCurseWords(message.content)) { await message.delete(); await message.channel.send( `${message.author}, please keep the channel friendly ๐Ÿ’›` ); } }); client.login(process.env.DISCORD_TOKEN); ``` --- ### ๐ŸŽญ Replace / Censor Matched Words Swap found words with asterisks. ```js async function censor(text) { const bad = await profanity.getCurseWords(text); let result = text; for (const word of bad) { const mask = '*'.repeat(word.length); result = result.replaceAll(new RegExp(`\\b${word}\\b`, 'gi'), mask); } return result; } await censor('what the hell, damn it'); // โ†’ 'what the ****, **** it' ``` --- ### ๐Ÿ“Š Count Profanity ```js async function countBad(text) { const words = await profanity.getCurseWords(text); return { count: words.length, words, hasProfanity: words.length > 0, }; } await countBad('hell and damn and hell again'); // โ†’ { count: 2, words: ['hell', 'damn'], hasProfanity: true } ``` --- ### ๐Ÿ“ฆ Batch Processing Check a whole array of strings in parallel. ```js const messages = [ 'hello world', 'oh hell no', 'have a great day', 'damn it', ]; const results = await Promise.all( messages.map(async (msg) => ({ message: msg, clean: !(await profanity.hasCurseWords(msg)), })) ); console.log(results); // [ // { message: 'hello world', clean: true }, // { message: 'oh hell no', clean: false }, // { message: 'have a great day', clean: true }, // { message: 'damn it', clean: false }, // ] ``` --- ### ๐Ÿงฉ TypeScript Types ship with the package โ€” just import. ```ts import { ProfanityEngine, ProfanityEngineOptions, } from '@coffeeandfun/google-profanity-words'; const options: ProfanityEngineOptions = { language: 'en', testMode: true }; const profanity = new ProfanityEngine(options); const hit: boolean = await profanity.hasCurseWords('oh hell no'); const words: string[] = await profanity.getCurseWords('oh hell no'); ``` --- ## ๐ŸŒ Want to Contribute? We love open source buddies ๐Ÿ’› ### Add a New Language 1. Fork it ๐Ÿด 2. Add a file to `/data/` named like `de.txt` for German (ISO 639-1 code) 3. Fill it with one profane word per line, **lowercase** 4. Add a test file under `__tests__/` following `spanish.test.js` as a template 5. Push & open a pull request! ๐Ÿš€ --- ## ๐Ÿ™Œ Who Made This? Built by [Robert James Gabriel](https://github.com/robertgabriel) and the good people at **Coffee & Fun LLC**. We make dev tools with accessibility, coffee, and good vibes in mind. > Wanna support? Send a coffee our way or just spread the word! โ˜•๐Ÿš€ --- ## ๐Ÿ” Security Found a vulnerability? Please report it privately โ€” see [SECURITY.md](SECURITY.md). ๐Ÿ™ --- ## ๐Ÿงก License [MIT](LICENSE) โ€“ because sharing is caring. --- ## ๐Ÿ’ฌ Support & Community - ๐Ÿ› [Report Bugs](https://github.com/coffee-and-fun/google-profanity-words/issues) - ๐Ÿ’ก [Join Discussions](https://github.com/coffee-and-fun/google-profanity-words/discussions) - ๐Ÿ“ฌ Email: [hello@coffeeandfun.com](mailto:hello@coffeeandfun.com) --- Made with โ˜•, code, and a sprinkle of magic at Coffee & Fun LLC ๐Ÿ’– ## ๐Ÿค– AI Usage Claude AI was used to help with this README and with adding extra Jest tests.