@useverse/profanity-guard 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,1302 @@
1
+ # Profanity Guard 🚫
2
+
3
+ A flexible, production-ready TypeScript library for content moderation and profanity filtering with React hooks support.
4
+
5
+ [![npm version](https://badge.fury.io/js/@useverse/profanity-guard.svg)](https://www.npmjs.com/package/@useverse/profanity-guard)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue.svg)](https://www.typescriptlang.org/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![React](https://img.shields.io/badge/React-Hooks-61DAFB.svg)](https://reactjs.org/)
9
+
10
+ ## ✨ Features
11
+
12
+ - 🎯 **Multiple Severity Levels** - MILD, MODERATE, SEVERE, and WTF classifications
13
+ - 🔧 **Flexible Moderation Modes** - OFF, RELAXED, MODERATE, and STRICT
14
+ - 🕵️ **Obfuscation Detection** - Catches common character substitutions (e.g., `@` for `a`, `3` for `e`)
15
+ - 📚 **Expandable Library** - Easily add, remove, or import custom word lists
16
+ - 🔄 **Smart Alternatives** - Replace profanity with appropriate alternatives
17
+ - 📊 **Detailed Results** - Get comprehensive information about detected words
18
+ - 💪 **TypeScript First** - Full type safety and IntelliSense support
19
+ - ⚡ **Performance Optimized** - Efficient pattern matching and caching
20
+
21
+ ## 📦 Installation
22
+
23
+ ```bash
24
+ npm install @useverse/profanity-guard
25
+ ```
26
+
27
+ ```bash
28
+ yarn add @useverse/profanity-guard
29
+ ```
30
+
31
+ ```bash
32
+ pnpm add @useverse/profanity-guard
33
+ ```
34
+
35
+ ## 🚀 Quick Start
36
+
37
+ ### Basic Usage
38
+
39
+ ```typescript
40
+ import { ProfanityGuard, ModerationLevel } from '@useverse/profanity-guard';
41
+
42
+ // Create a moderator instance
43
+ const moderator = new ProfanityGuard(ModerationLevel.MODERATE);
44
+
45
+ // Check if content is clean
46
+ const isClean = moderator.isClean("Hello world!"); // true
47
+
48
+ // Get sanitized content
49
+ const sanitized = moderator.sanitize("This is some shit text");
50
+ // Output: "This is some **** text"
51
+
52
+ // Get detailed moderation results
53
+ const result = moderator.moderate("This shit text has ass in it");
54
+ console.log(result);
55
+ // {
56
+ // isClean: false,
57
+ // foundWords: ['shit', 'ass'],
58
+ // severity: 'moderate',
59
+ // isWTF: false,
60
+ // sanitized: 'This **** text has *** in it',
61
+ // matches: [
62
+ // { word: 'shit', severity: 'moderate', position: 5 },
63
+ // { word: 'ass', severity: 'moderate', position: 19 }
64
+ // ]
65
+ // }
66
+ ```
67
+
68
+ ### React Hooks (Quick Start)
69
+
70
+ ```tsx
71
+ import { useProfanityGuard, ModerationLevel } from '@useverse/profanity-guard';
72
+
73
+ function CommentForm() {
74
+ const [comment, setComment] = useState('');
75
+ const { moderate, sanitize } = useProfanityGuard({
76
+ level: ModerationLevel.MODERATE
77
+ });
78
+
79
+ const result = moderate(comment);
80
+
81
+ return (
82
+ <div>
83
+ <textarea
84
+ value={comment}
85
+ onChange={e => setComment(e.target.value)}
86
+ placeholder="Enter your comment..."
87
+ />
88
+ {!result.isClean && (
89
+ <p className="error">
90
+ ⚠️ Contains inappropriate content: {result.foundWords.join(', ')}
91
+ </p>
92
+ )}
93
+ <p>Preview: {sanitize(comment)}</p>
94
+ </div>
95
+ );
96
+ }
97
+ ```
98
+
99
+ ## 📚 Table of Contents
100
+
101
+ - [Installation](#-installation)
102
+ - [Quick Start](#-quick-start)
103
+ - [Core Concepts](#-core-concepts)
104
+ - [Usage Guide](#-usage-guide)
105
+ - [Creating a Moderator](#creating-a-moderator)
106
+ - [Moderation Levels](#moderation-levels)
107
+ - [Basic Operations](#basic-operations)
108
+ - [Custom Word Library](#custom-word-library)
109
+ - [React Hooks](#-react-hooks)
110
+ - [useProfanityGuard](#useprofanityguard)
111
+ - [useModeratedInput](#usemoderatedinput)
112
+ - [useBatchModeration](#usebatchmoderation)
113
+ - [useProfanityValidation](#useprofanityvalidation)
114
+ - [useLiveSanitizer](#uselivesanitizer)
115
+ - [useProfanityStats](#useprofanitystats)
116
+ - [useContentReplacement](#usecontentreplacement)
117
+ - [Advanced Features](#-advanced-features)
118
+ - [Real-World Use Cases](#-real-world-use-cases)
119
+ - [API Reference](#-api-reference)
120
+ - [Performance](#-performance)
121
+ - [Contributing](#-contributing)
122
+
123
+ ## 🎓 Core Concepts
124
+
125
+ ### Word Severity Levels
126
+
127
+ Profanity Guard classifies words into four severity levels:
128
+
129
+ | Severity | Description | Examples | Use Case |
130
+ |----------|-------------|----------|----------|
131
+ | **MILD** | Minor profanity, generally acceptable in casual contexts | damn, hell, crap | Family-friendly apps with some tolerance |
132
+ | **MODERATE** | Common profanity, inappropriate in most public contexts | shit, ass, bitch | Standard content moderation |
133
+ | **SEVERE** | Strong profanity and slurs, offensive in virtually all contexts | fuck, and various slurs | Strict professional environments |
134
+ | **WTF** | Extreme profanity, hate speech, always blocked | Extreme content | Zero-tolerance policies |
135
+
136
+ ### Moderation Modes
137
+
138
+ | Mode | Blocks | Best For |
139
+ |------|--------|----------|
140
+ | **OFF** | Nothing | Testing, admin panels |
141
+ | **RELAXED** | SEVERE + WTF | Adult-oriented platforms |
142
+ | **MODERATE** | MODERATE + SEVERE + WTF | General social media, forums |
143
+ | **STRICT** | ALL levels | Children's apps, professional platforms |
144
+
145
+ ## 📖 Usage Guide
146
+
147
+ ### Creating a Moderator
148
+
149
+ ```typescript
150
+ import { ProfanityGuard, ModerationLevel } from '@useverse/profanity-guard';
151
+
152
+ // Default settings (MODERATE level, '*' censor)
153
+ const moderator = new ProfanityGuard();
154
+
155
+ // Custom moderation level
156
+ const strictModerator = new ProfanityGuard(ModerationLevel.STRICT);
157
+
158
+ // Custom censor character
159
+ const hashModerator = new ProfanityGuard(ModerationLevel.MODERATE, '#');
160
+
161
+ // Relaxed for adult content
162
+ const relaxedModerator = new ProfanityGuard(ModerationLevel.RELAXED);
163
+
164
+ // Turn off moderation (for admin/testing)
165
+ const offModerator = new ProfanityGuard(ModerationLevel.OFF);
166
+ ```
167
+
168
+ ### Moderation Levels
169
+
170
+ | Level | Description | Blocks |
171
+ |-------|-------------|--------|
172
+ | `OFF` | No moderation | Nothing |
173
+ | `RELAXED` | Minimal filtering | SEVERE, WTF |
174
+ | `MODERATE` | Standard filtering (default) | MODERATE, SEVERE, WTF |
175
+ | `STRICT` | Maximum filtering | MILD, MODERATE, SEVERE, WTF |
176
+
177
+ ### Basic Operations
178
+
179
+ ```typescript
180
+ // Quick clean check
181
+ if (moderator.isClean(userInput)) {
182
+ console.log("Content is safe!");
183
+ }
184
+
185
+ // Sanitize content
186
+ const clean = moderator.sanitize("This damn thing is shit");
187
+ // Output: "This **** thing is ****"
188
+
189
+ // Get detailed results
190
+ const result = moderator.moderate(userInput);
191
+ if (!result.isClean) {
192
+ console.log(`Found ${result.foundWords.length} profane words`);
193
+ console.log(`Severity: ${result.severity}`);
194
+ }
195
+ ```
196
+
197
+ ### Using Alternatives
198
+
199
+ Replace profanity with appropriate alternatives instead of censoring:
200
+
201
+ ```typescript
202
+ const result = moderator.moderateSentence(
203
+ "This damn thing is awesome",
204
+ true // preserveStructure
205
+ );
206
+
207
+ console.log(result.sanitized);
208
+ // Output: "This darn thing is awesome"
209
+ ```
210
+
211
+ ### Custom Word Library
212
+
213
+ ```typescript
214
+ import { WordSeverity } from '@useverse/profanity-guard';
215
+
216
+ // Add individual words
217
+ moderator.addWord('badword', WordSeverity.MODERATE, ['goodword']);
218
+
219
+ // Add multiple words
220
+ moderator.addWords([
221
+ { word: 'word1', severity: WordSeverity.MILD, alternatives: ['alt1'] },
222
+ { word: 'word2', severity: WordSeverity.SEVERE }
223
+ ]);
224
+
225
+ // Remove a word
226
+ moderator.removeWord('damn');
227
+
228
+ // Import from JSON
229
+ import customWords from './my-words.json';
230
+ moderator.importLibrary(customWords);
231
+
232
+ // Export current library
233
+ const myLibrary = moderator.exportLibrary();
234
+ ```
235
+
236
+ ### Using Pre-filtered Libraries
237
+
238
+ ```typescript
239
+ import {
240
+ all_bad_words,
241
+ mild_bad_words,
242
+ moderate_bad_words,
243
+ severe_bad_words
244
+ } from 'nobadword/core/library';
245
+
246
+ // Import only severe words
247
+ const moderator = new NoBadWord();
248
+ moderator.clearLibrary(); // Remove defaults
249
+ moderator.importLibrary(severe_bad_words);
250
+ ```
251
+
252
+ ### Library Statistics
253
+
254
+ ```typescript
255
+ const stats = moderator.getStats();
256
+ console.log(`Total: ${stats.total}`);
257
+ console.log(`Mild: ${stats.mild}`);
258
+ console.log(`Moderate: ${stats.moderate}`);
259
+ console.log(`Severe: ${stats.severe}`);
260
+ ```
261
+
262
+ ### Quick Moderate (One-off Use)
263
+
264
+ ```typescript
265
+ import { quickModerate, ModerationLevel } from 'nobadword';
266
+
267
+ const result = quickModerate("Some text", ModerationLevel.STRICT);
268
+ ```
269
+
270
+ ## 🎯 Advanced Features
271
+
272
+ ### Obfuscation Detection
273
+
274
+ NoBadWord automatically detects common character substitutions:
275
+
276
+ ```typescript
277
+ moderator.isClean("sh!t"); // false - detects ! as i
278
+ moderator.isClean("d@mn"); // false - detects @ as a
279
+ moderator.isClean("f**k"); // false - detects asterisks
280
+ moderator.isClean("b-a-d"); // false - detects spacing
281
+ ```
282
+
283
+ Supported substitutions:
284
+ - `a` → `@`, `4`
285
+ - `e` → `3`
286
+ - `i` → `1`, `!`, `|`
287
+ - `o` → `0`
288
+ - `s` → `$`, `5`
289
+ - And more...
290
+
291
+ ### Content Analysis Utilities
292
+
293
+ #### Profanity Scoring
294
+ ```typescript
295
+ const score = moderator.getProfanityScore("This damn text");
296
+ // Returns 0-100 based on severity and frequency
297
+
298
+ const isAcceptable = moderator.isWithinThreshold(content, 20);
299
+ // Check if score is within acceptable range
300
+ ```
301
+
302
+ #### Detailed Analysis
303
+ ```typescript
304
+ const report = moderator.getDetailedReport("This damn shit is bad");
305
+ console.log(report);
306
+ // {
307
+ // isClean: false,
308
+ // totalWords: 5,
309
+ // profaneWords: 2,
310
+ // profanityPercentage: 40,
311
+ // score: 35,
312
+ // highestSeverity: 'moderate',
313
+ // severityCounts: { mild: 1, moderate: 1, severe: 0, wtf: 0 },
314
+ // flaggedWords: ['damn', 'shit'],
315
+ // details: [...]
316
+ // }
317
+ ```
318
+
319
+ #### Content Validation
320
+ ```typescript
321
+ const validation = moderator.validate("Content to check", {
322
+ maxProfanityScore: 20,
323
+ maxSeverity: WordSeverity.MILD,
324
+ maxProfaneWords: 1
325
+ });
326
+
327
+ if (!validation.isValid) {
328
+ console.log(validation.reasons); // Why validation failed
329
+ }
330
+ ```
331
+
332
+ ### Content Manipulation Utilities
333
+
334
+ #### Highlighting
335
+ ```typescript
336
+ const highlighted = moderator.highlight("This damn text is shit");
337
+ // Output: "This <mark>damn</mark> text is <mark>shit</mark>"
338
+
339
+ // Custom tags
340
+ const custom = moderator.highlight(
341
+ content,
342
+ '<span class="flagged">',
343
+ '</span>'
344
+ );
345
+ ```
346
+
347
+ #### Alternative Replacements
348
+ ```typescript
349
+ const replaced = moderator.replaceWithAlternatives("This damn thing");
350
+ // Output: "This darn thing" or "This dang thing" (random from alternatives)
351
+ ```
352
+
353
+ #### Extract Clean Content
354
+ ```typescript
355
+ const text = "Hello world. This is damn bad. Nice day.";
356
+ const clean = moderator.getCleanSentences(text);
357
+ // Output: ["Hello world", "Nice day"]
358
+ ```
359
+
360
+ ### Batch Processing
361
+
362
+ ```typescript
363
+ // Process multiple items
364
+ const results = moderator.moderateBatch([
365
+ "Hello world",
366
+ "This is damn bad",
367
+ "Nice day"
368
+ ]);
369
+
370
+ // Filter arrays
371
+ const cleanOnly = moderator.filterClean(allComments);
372
+ const profaneOnly = moderator.filterProfane(allComments);
373
+ ```
374
+
375
+ ### Library Inspection
376
+
377
+ ```typescript
378
+ // Check if word exists
379
+ if (moderator.hasWord('damn')) {
380
+ const info = moderator.getWordInfo('damn');
381
+ console.log(info.severity); // 'mild'
382
+ console.log(info.alternatives); // ['darn', 'dang']
383
+ }
384
+
385
+ // Get suggestions
386
+ const suggestions = moderator.getSuggestions('damn');
387
+ // Output: ['darn', 'dang']
388
+
389
+ // Get words by severity
390
+ const mildWords = moderator.getWordsBySeverity(WordSeverity.MILD);
391
+ ```
392
+
393
+ ### Quick Utilities (No Instance Required)
394
+
395
+ For one-off operations without creating a moderator instance:
396
+
397
+ ```typescript
398
+ import {
399
+ quickCheck,
400
+ quickSanitize,
401
+ quickScore,
402
+ quickValidate
403
+ } from 'nobadword';
404
+
405
+ // Quick checks
406
+ if (quickCheck("Hello world")) {
407
+ console.log("Clean!");
408
+ }
409
+
410
+ // Quick sanitization
411
+ const clean = quickSanitize("This damn text");
412
+
413
+ // Quick scoring
414
+ const score = quickScore("This is bad");
415
+
416
+ // Quick validation
417
+ const isValid = quickValidate(content, {
418
+ maxProfanityScore: 20,
419
+ maxSeverity: WordSeverity.MILD
420
+ });
421
+ ```
422
+
423
+ > **Note:** Quick utilities are convenient but less efficient for repeated use. For better performance with multiple operations, create a NoBadWord instance and reuse it.
424
+
425
+ ### Match Details
426
+
427
+ Get precise information about each detected word:
428
+
429
+ ```typescript
430
+ const result = moderator.moderate("This damn text has shit");
431
+
432
+ result.matches.forEach(match => {
433
+ console.log(`Word: "${match.word}"`);
434
+ console.log(`Severity: ${match.severity}`);
435
+ console.log(`Position: ${match.position}`);
436
+ });
437
+ ```
438
+
439
+ ### Dynamic Moderation Level
440
+
441
+ ```typescript
442
+ // Start with relaxed moderation
443
+ moderator.setModerationLevel(ModerationLevel.RELAXED);
444
+
445
+ // Switch to strict for sensitive content
446
+ moderator.setModerationLevel(ModerationLevel.STRICT);
447
+
448
+ // Check current level
449
+ const level = moderator.getModerationLevel();
450
+ ```
451
+
452
+ ## 🔧 TypeScript Support
453
+
454
+ Full TypeScript support with comprehensive type definitions:
455
+
456
+ ```typescript
457
+ import {
458
+ NoBadWord,
459
+ ModerationLevel,
460
+ WordSeverity,
461
+ ModerationResult,
462
+ WordEntry,
463
+ Match
464
+ } from 'nobadword';
465
+
466
+ const moderator: NoBadWord = new NoBadWord();
467
+ const result: ModerationResult = moderator.moderate("text");
468
+ const entry: WordEntry = {
469
+ word: "example",
470
+ severity: WordSeverity.MODERATE,
471
+ alternatives: ["alt"]
472
+ };
473
+ ```
474
+
475
+ ## 📚 API Reference
476
+
477
+ ### NoBadWord Class
478
+
479
+ #### Constructor
480
+ ```typescript
481
+ new NoBadWord(moderationLevel?: ModerationLevel, censorChar?: string)
482
+ ```
483
+
484
+ #### Core Methods
485
+
486
+ | Method | Description | Returns |
487
+ |--------|-------------|---------|
488
+ | `moderate(content)` | Full moderation with details | `ModerationResult` |
489
+ | `isClean(content)` | Quick clean check | `boolean` |
490
+ | `sanitize(content)` | Get censored content | `string` |
491
+ | `moderateSentence(sentence, preserveStructure?)` | Moderate with alternatives | `ModerationResult` |
492
+
493
+ #### Analysis Methods
494
+
495
+ | Method | Description | Returns |
496
+ |--------|-------------|---------|
497
+ | `getProfanityScore(content)` | Calculate profanity score (0-100) | `number` |
498
+ | `isWithinThreshold(content, threshold)` | Check if score within limit | `boolean` |
499
+ | `countBySeverity(content)` | Count words by severity | `Object` |
500
+ | `getDetailedReport(content)` | Comprehensive analysis report | `Object` |
501
+ | `validate(content, options)` | Validate against criteria | `Object` |
502
+
503
+ #### Manipulation Methods
504
+
505
+ | Method | Description | Returns |
506
+ |--------|-------------|---------|
507
+ | `highlight(content, openTag?, closeTag?)` | Wrap profanity in tags | `string` |
508
+ | `replaceWithAlternatives(content)` | Replace with random alternatives | `string` |
509
+ | `getCleanSentences(content, delimiter?)` | Extract clean sentences | `string[]` |
510
+
511
+ #### Batch Methods
512
+
513
+ | Method | Description | Returns |
514
+ |--------|-------------|---------|
515
+ | `moderateBatch(contents)` | Moderate multiple items | `ModerationResult[]` |
516
+ | `filterClean(contents)` | Filter to clean items only | `string[]` |
517
+ | `filterProfane(contents)` | Filter to profane items only | `string[]` |
518
+
519
+ #### Library Methods
520
+
521
+ | Method | Description | Returns |
522
+ |--------|-------------|---------|
523
+ | `addWord(word, severity, alternatives?)` | Add single word | `void` |
524
+ | `addWords(entries)` | Add multiple words | `void` |
525
+ | `removeWord(word)` | Remove a word | `boolean` |
526
+ | `hasWord(word)` | Check if word exists | `boolean` |
527
+ | `getWordInfo(word)` | Get word details | `WordEntry \| null` |
528
+ | `getSuggestions(word)` | Get alternatives for word | `string[]` |
529
+ | `getWordsBySeverity(severity)` | Get all words by severity | `WordEntry[]` |
530
+ | `importLibrary(jsonData)` | Import word list | `void` |
531
+ | `exportLibrary()` | Export word list | `WordEntry[]` |
532
+ | `clearLibrary()` | Clear all words | `void` |
533
+ | `setModerationLevel(level)` | Change moderation level | `void` |
534
+ | `getModerationLevel()` | Get current level | `ModerationLevel` |
535
+ | `getStats()` | Get library statistics | `LibraryStats` |
536
+
537
+ ### Quick Utility Functions
538
+
539
+ | Function | Description | Returns |
540
+ |----------|-------------|---------|
541
+ | `quickModerate(content, level?)` | One-off moderation | `ModerationResult` |
542
+ | `quickCheck(content, level?)` | Quick clean check | `boolean` |
543
+ | `quickSanitize(content, level?, char?)` | Quick sanitization | `string` |
544
+ | `quickScore(content, level?)` | Quick profanity score | `number` |
545
+ | `quickValidate(content, options)` | Quick validation | `boolean` |
546
+
547
+ ### Types
548
+
549
+ #### ModerationResult
550
+ ```typescript
551
+ {
552
+ isClean: boolean;
553
+ foundWords: string[];
554
+ severity: WordSeverity | null;
555
+ sanitized: string;
556
+ matches: Match[];
557
+ }
558
+ ```
559
+
560
+ #### WordEntry
561
+ ```typescript
562
+ {
563
+ word: string;
564
+ severity: WordSeverity;
565
+ alternatives?: string[];
566
+ }
567
+ ```
568
+
569
+ #### Match
570
+ ```typescript
571
+ {
572
+ word: string;
573
+ severity: WordSeverity;
574
+ position: number;
575
+ }
576
+ ```
577
+
578
+ ## 🎨 Use Cases
579
+
580
+ ### Comment Moderation
581
+ ```typescript
582
+ function moderateComment(comment: string): string {
583
+ const moderator = new NoBadWord(ModerationLevel.MODERATE);
584
+ const result = moderator.moderate(comment);
585
+
586
+ if (!result.isClean) {
587
+ logModerationEvent(result);
588
+ }
589
+
590
+ return result.sanitized;
591
+ }
592
+ ```
593
+
594
+ ### Chat Filter
595
+ ```typescript
596
+ function filterChatMessage(message: string): { allowed: boolean; filtered: string } {
597
+ const moderator = new NoBadWord(ModerationLevel.STRICT);
598
+ const result = moderator.moderateSentence(message, true);
599
+
600
+ return {
601
+ allowed: result.severity !== 'severe',
602
+ filtered: result.sanitized
603
+ };
604
+ }
605
+ ```
606
+
607
+ ### User-Generated Content
608
+ ```typescript
609
+ function validateUsername(username: string): { valid: boolean; reason?: string } {
610
+ const moderator = new NoBadWord(ModerationLevel.STRICT);
611
+
612
+ if (!moderator.isClean(username)) {
613
+ return { valid: false, reason: 'Username contains inappropriate language' };
614
+ }
615
+
616
+ return { valid: true };
617
+ }
618
+ ```
619
+
620
+ ## ⚛️ React Hooks
621
+
622
+ Profanity Guard provides a comprehensive set of React hooks for seamless integration into React applications.
623
+
624
+ ### useProfanityGuard
625
+
626
+ Main hook for content moderation with full access to all moderation features.
627
+
628
+ ```tsx
629
+ import { useProfanityGuard, ModerationLevel } from '@useverse/profanity-guard';
630
+
631
+ function CommentSection() {
632
+ const [comment, setComment] = useState('');
633
+ const { moderate, sanitize, isClean, addWord } = useProfanityGuard({
634
+ level: ModerationLevel.MODERATE,
635
+ censorChar: '*'
636
+ });
637
+
638
+ const result = moderate(comment);
639
+
640
+ const handleSubmit = () => {
641
+ if (result.isClean) {
642
+ // Submit comment
643
+ submitComment(comment);
644
+ } else {
645
+ alert(`Please remove: ${result.foundWords.join(', ')}`);
646
+ }
647
+ };
648
+
649
+ return (
650
+ <div>
651
+ <textarea value={comment} onChange={e => setComment(e.target.value)} />
652
+ <div className={result.isClean ? 'clean' : 'flagged'}>
653
+ {result.isClean ? '✓ Clean' : `⚠️ Found: ${result.foundWords.join(', ')}`}
654
+ </div>
655
+ <button onClick={handleSubmit} disabled={!result.isClean}>
656
+ Post Comment
657
+ </button>
658
+ </div>
659
+ );
660
+ }
661
+ ```
662
+
663
+ ### useModeratedInput
664
+
665
+ Real-time input moderation with built-in state management.
666
+
667
+ ```tsx
668
+ import { useModeratedInput, ModerationLevel } from '@useverse/profanity-guard';
669
+
670
+ function ChatInput() {
671
+ const {
672
+ content,
673
+ setContent,
674
+ result,
675
+ sanitizedContent,
676
+ isClean,
677
+ foundWords,
678
+ severity
679
+ } = useModeratedInput('', {
680
+ level: ModerationLevel.STRICT
681
+ });
682
+
683
+ return (
684
+ <div className="chat-input">
685
+ <input
686
+ value={content}
687
+ onChange={e => setContent(e.target.value)}
688
+ placeholder="Type your message..."
689
+ className={isClean ? '' : 'has-profanity'}
690
+ />
691
+
692
+ {!isClean && (
693
+ <div className="warning">
694
+ <span>⚠️ Contains: {foundWords.join(', ')}</span>
695
+ <span className="severity-badge">{severity}</span>
696
+ </div>
697
+ )}
698
+
699
+ <div className="preview">
700
+ Preview: {sanitizedContent}
701
+ </div>
702
+
703
+ <button disabled={!isClean}>Send</button>
704
+ </div>
705
+ );
706
+ }
707
+ ```
708
+
709
+ ### useBatchModeration
710
+
711
+ Batch processing for lists of content.
712
+
713
+ ```tsx
714
+ import { useBatchModeration } from '@useverse/profanity-guard';
715
+
716
+ function CommentList({ comments }) {
717
+ const { moderateBatch, filterClean, filterProfane } = useBatchModeration({
718
+ level: ModerationLevel.MODERATE
719
+ });
720
+
721
+ const results = moderateBatch(comments);
722
+ const cleanComments = filterClean(comments);
723
+ const flaggedComments = filterProfane(comments);
724
+
725
+ return (
726
+ <div>
727
+ <h3>Clean Comments ({cleanComments.length})</h3>
728
+ {cleanComments.map((comment, i) => (
729
+ <div key={i} className="comment clean">{comment}</div>
730
+ ))}
731
+
732
+ <h3>Flagged Comments ({flaggedComments.length})</h3>
733
+ {flaggedComments.map((comment, i) => (
734
+ <div key={i} className="comment flagged">
735
+ {results[comments.indexOf(comment)].sanitized}
736
+ </div>
737
+ ))}
738
+ </div>
739
+ );
740
+ }
741
+ ```
742
+
743
+ ### useProfanityValidation
744
+
745
+ Form validation with profanity checking.
746
+
747
+ ```tsx
748
+ import { useProfanityValidation } from '@useverse/profanity-guard';
749
+
750
+ function SignupForm() {
751
+ const [formData, setFormData] = useState({ username: '', bio: '' });
752
+ const { validateField, errors, hasErrors, clearError } = useProfanityValidation({
753
+ level: ModerationLevel.STRICT
754
+ });
755
+
756
+ const handleSubmit = (e) => {
757
+ e.preventDefault();
758
+
759
+ const usernameValid = validateField('username', formData.username);
760
+ const bioValid = validateField('bio', formData.bio);
761
+
762
+ if (usernameValid && bioValid) {
763
+ // Submit form
764
+ console.log('Form is valid!');
765
+ }
766
+ };
767
+
768
+ return (
769
+ <form onSubmit={handleSubmit}>
770
+ <div>
771
+ <label>Username</label>
772
+ <input
773
+ value={formData.username}
774
+ onChange={e => {
775
+ setFormData({...formData, username: e.target.value});
776
+ clearError('username');
777
+ }}
778
+ />
779
+ {errors.username && <span className="error">{errors.username}</span>}
780
+ </div>
781
+
782
+ <div>
783
+ <label>Bio</label>
784
+ <textarea
785
+ value={formData.bio}
786
+ onChange={e => {
787
+ setFormData({...formData, bio: e.target.value});
788
+ clearError('bio');
789
+ }}
790
+ />
791
+ {errors.bio && <span className="error">{errors.bio}</span>}
792
+ </div>
793
+
794
+ <button type="submit" disabled={hasErrors}>
795
+ Sign Up
796
+ </button>
797
+ </form>
798
+ );
799
+ }
800
+ ```
801
+
802
+ ### useLiveSanitizer
803
+
804
+ Debounced live sanitization for performance.
805
+
806
+ ```tsx
807
+ import { useLiveSanitizer } from '@useverse/profanity-guard';
808
+
809
+ function LiveEditor() {
810
+ const { content, setContent, sanitized, isProcessing } = useLiveSanitizer(300, {
811
+ level: ModerationLevel.MODERATE
812
+ });
813
+
814
+ return (
815
+ <div className="editor">
816
+ <div className="input-section">
817
+ <label>Your Content</label>
818
+ <textarea
819
+ value={content}
820
+ onChange={e => setContent(e.target.value)}
821
+ placeholder="Type here..."
822
+ />
823
+ {isProcessing && <span className="processing">Processing...</span>}
824
+ </div>
825
+
826
+ <div className="preview-section">
827
+ <label>Sanitized Preview</label>
828
+ <div className="preview">{sanitized}</div>
829
+ </div>
830
+ </div>
831
+ );
832
+ }
833
+ ```
834
+
835
+ ### useProfanityStats
836
+
837
+ Analytics and statistics tracking.
838
+
839
+ ```tsx
840
+ import { useProfanityStats } from '@useverse/profanity-guard';
841
+
842
+ function ModerationDashboard() {
843
+ const { stats, analyzeContent, history, clearHistory } = useProfanityStats({
844
+ level: ModerationLevel.MODERATE
845
+ });
846
+
847
+ return (
848
+ <div className="dashboard">
849
+ <h2>Moderation Statistics</h2>
850
+
851
+ <div className="stats-grid">
852
+ <div className="stat-card">
853
+ <h3>Total Analyzed</h3>
854
+ <p className="stat-number">{stats.analyzed.total}</p>
855
+ </div>
856
+
857
+ <div className="stat-card">
858
+ <h3>Flagged Content</h3>
859
+ <p className="stat-number">{stats.analyzed.flagged}</p>
860
+ <p className="stat-percent">{stats.analyzed.flaggedPercentage.toFixed(1)}%</p>
861
+ </div>
862
+
863
+ <div className="stat-card">
864
+ <h3>Clean Content</h3>
865
+ <p className="stat-number">{stats.analyzed.clean}</p>
866
+ </div>
867
+ </div>
868
+
869
+ <div className="library-stats">
870
+ <h3>Word Library</h3>
871
+ <ul>
872
+ <li>Total Words: {stats.library.total}</li>
873
+ <li>Mild: {stats.library.mild}</li>
874
+ <li>Moderate: {stats.library.moderate}</li>
875
+ <li>Severe: {stats.library.severe}</li>
876
+ <li>WTF: {stats.library.wtf}</li>
877
+ </ul>
878
+ </div>
879
+
880
+ <button onClick={clearHistory}>Clear History</button>
881
+ </div>
882
+ );
883
+ }
884
+ ```
885
+
886
+ ### useContentReplacement
887
+
888
+ Smart word replacement with alternatives.
889
+
890
+ ```tsx
891
+ import { useContentReplacement } from '@useverse/profanity-guard';
892
+
893
+ function SmartEditor() {
894
+ const [text, setText] = useState('');
895
+ const { replaceWithAlternatives, getSuggestions, getWordInfo } = useContentReplacement({
896
+ level: ModerationLevel.MODERATE
897
+ });
898
+
899
+ const handleAutoFix = () => {
900
+ const cleaned = replaceWithAlternatives(text);
901
+ setText(cleaned);
902
+ };
903
+
904
+ const handleWordClick = (word) => {
905
+ const suggestions = getSuggestions(word);
906
+ const info = getWordInfo(word);
907
+
908
+ if (suggestions.length > 0) {
909
+ // Show suggestions modal
910
+ showSuggestionsModal(word, suggestions, info);
911
+ }
912
+ };
913
+
914
+ return (
915
+ <div>
916
+ <textarea value={text} onChange={e => setText(e.target.value)} />
917
+ <button onClick={handleAutoFix}>Auto-Fix Profanity</button>
918
+ </div>
919
+ );
920
+ }
921
+ ```
922
+
923
+ ## 🌍 Real-World Use Cases
924
+
925
+ ### 1. Social Media Platform
926
+
927
+ ```tsx
928
+ // Complete comment moderation system
929
+ import { useProfanityGuard, useModeratedInput } from '@useverse/profanity-guard';
930
+
931
+ function SocialMediaPost() {
932
+ const {
933
+ content,
934
+ setContent,
935
+ result,
936
+ sanitizedContent,
937
+ isClean
938
+ } = useModeratedInput('', {
939
+ level: ModerationLevel.MODERATE
940
+ });
941
+
942
+ const [showWarning, setShowWarning] = useState(false);
943
+
944
+ const handlePost = async () => {
945
+ if (!isClean) {
946
+ setShowWarning(true);
947
+ return;
948
+ }
949
+
950
+ await api.createPost({ content });
951
+ setContent('');
952
+ };
953
+
954
+ return (
955
+ <div className="post-creator">
956
+ <textarea
957
+ value={content}
958
+ onChange={e => setContent(e.target.value)}
959
+ placeholder="What's on your mind?"
960
+ maxLength={280}
961
+ />
962
+
963
+ {showWarning && !isClean && (
964
+ <div className="warning-banner">
965
+ <p>Your post contains inappropriate language: {result.foundWords.join(', ')}</p>
966
+ <p>Sanitized version: {sanitizedContent}</p>
967
+ <button onClick={() => setContent(sanitizedContent)}>
968
+ Use Sanitized Version
969
+ </button>
970
+ </div>
971
+ )}
972
+
973
+ <div className="post-footer">
974
+ <span className={isClean ? 'status-ok' : 'status-warning'}>
975
+ {isClean ? '✓ Ready to post' : '⚠️ Contains profanity'}
976
+ </span>
977
+ <button onClick={handlePost} disabled={!isClean}>
978
+ Post
979
+ </button>
980
+ </div>
981
+ </div>
982
+ );
983
+ }
984
+ ```
985
+
986
+ ### 2. Live Chat Application
987
+
988
+ ```tsx
989
+ // Real-time chat with moderation
990
+ import { useModeratedInput, useBatchModeration } from '@useverse/profanity-guard';
991
+
992
+ function ChatRoom({ messages }) {
993
+ const { content, setContent, isClean, sanitizedContent } = useModeratedInput('', {
994
+ level: ModerationLevel.STRICT
995
+ });
996
+
997
+ const { filterClean } = useBatchModeration({
998
+ level: ModerationLevel.STRICT
999
+ });
1000
+
1001
+ const [chatHistory, setChatHistory] = useState(messages);
1002
+
1003
+ const sendMessage = () => {
1004
+ if (isClean) {
1005
+ const newMessage = { text: content, user: currentUser, timestamp: Date.now() };
1006
+ setChatHistory([...chatHistory, newMessage]);
1007
+ setContent('');
1008
+ } else {
1009
+ // Auto-sanitize and send
1010
+ const newMessage = { text: sanitizedContent, user: currentUser, timestamp: Date.now() };
1011
+ setChatHistory([...chatHistory, newMessage]);
1012
+ setContent('');
1013
+ }
1014
+ };
1015
+
1016
+ return (
1017
+ <div className="chat-room">
1018
+ <div className="messages">
1019
+ {chatHistory.map((msg, i) => (
1020
+ <div key={i} className="message">
1021
+ <strong>{msg.user}:</strong> {msg.text}
1022
+ </div>
1023
+ ))}
1024
+ </div>
1025
+
1026
+ <div className="input-area">
1027
+ <input
1028
+ value={content}
1029
+ onChange={e => setContent(e.target.value)}
1030
+ onKeyPress={e => e.key === 'Enter' && sendMessage()}
1031
+ placeholder="Type a message..."
1032
+ />
1033
+ <button onClick={sendMessage}>Send</button>
1034
+ </div>
1035
+ </div>
1036
+ );
1037
+ }
1038
+ ```
1039
+
1040
+ ### 3. User Profile Management
1041
+
1042
+ ```tsx
1043
+ // Profile creation with validation
1044
+ import { useProfanityValidation } from '@useverse/profanity-guard';
1045
+
1046
+ function ProfileEditor({ initialProfile }) {
1047
+ const [profile, setProfile] = useState(initialProfile);
1048
+ const { validateField, errors, hasErrors } = useProfanityValidation({
1049
+ level: ModerationLevel.STRICT
1050
+ });
1051
+
1052
+ const handleSave = async () => {
1053
+ const fields = ['username', 'displayName', 'bio', 'location'];
1054
+ const validations = fields.map(field => validateField(field, profile[field]));
1055
+
1056
+ if (validations.every(v => v)) {
1057
+ await api.updateProfile(profile);
1058
+ toast.success('Profile updated successfully!');
1059
+ } else {
1060
+ toast.error('Please fix the errors before saving');
1061
+ }
1062
+ };
1063
+
1064
+ return (
1065
+ <div className="profile-editor">
1066
+ <h2>Edit Profile</h2>
1067
+
1068
+ <div className="form-group">
1069
+ <label>Username</label>
1070
+ <input
1071
+ value={profile.username}
1072
+ onChange={e => setProfile({...profile, username: e.target.value})}
1073
+ onBlur={() => validateField('username', profile.username)}
1074
+ />
1075
+ {errors.username && <span className="error">{errors.username}</span>}
1076
+ </div>
1077
+
1078
+ <div className="form-group">
1079
+ <label>Display Name</label>
1080
+ <input
1081
+ value={profile.displayName}
1082
+ onChange={e => setProfile({...profile, displayName: e.target.value})}
1083
+ onBlur={() => validateField('displayName', profile.displayName)}
1084
+ />
1085
+ {errors.displayName && <span className="error">{errors.displayName}</span>}
1086
+ </div>
1087
+
1088
+ <div className="form-group">
1089
+ <label>Bio</label>
1090
+ <textarea
1091
+ value={profile.bio}
1092
+ onChange={e => setProfile({...profile, bio: e.target.value})}
1093
+ onBlur={() => validateField('bio', profile.bio)}
1094
+ maxLength={500}
1095
+ />
1096
+ {errors.bio && <span className="error">{errors.bio}</span>}
1097
+ </div>
1098
+
1099
+ <button onClick={handleSave} disabled={hasErrors}>
1100
+ Save Profile
1101
+ </button>
1102
+ </div>
1103
+ );
1104
+ }
1105
+ ```
1106
+
1107
+ ### 4. Content Moderation Dashboard
1108
+
1109
+ ```tsx
1110
+ // Admin moderation dashboard
1111
+ import { useProfanityStats, useBatchModeration } from '@useverse/profanity-guard';
1112
+
1113
+ function ModerationPanel({ reportedContent }) {
1114
+ const { stats, analyzeContent } = useProfanityStats({
1115
+ level: ModerationLevel.MODERATE
1116
+ });
1117
+
1118
+ const { moderateBatch } = useBatchModeration({
1119
+ level: ModerationLevel.MODERATE
1120
+ });
1121
+
1122
+ const [selectedLevel, setSelectedLevel] = useState(ModerationLevel.MODERATE);
1123
+ const results = moderateBatch(reportedContent.map(r => r.content));
1124
+
1125
+ const handleBulkAction = (action) => {
1126
+ const flaggedItems = results
1127
+ .map((result, index) => ({ result, item: reportedContent[index] }))
1128
+ .filter(({ result }) => !result.isClean);
1129
+
1130
+ if (action === 'approve') {
1131
+ flaggedItems.forEach(({ item }) => approveContent(item.id));
1132
+ } else if (action === 'reject') {
1133
+ flaggedItems.forEach(({ item }) => rejectContent(item.id));
1134
+ }
1135
+ };
1136
+
1137
+ return (
1138
+ <div className="moderation-panel">
1139
+ <div className="stats-header">
1140
+ <h2>Moderation Dashboard</h2>
1141
+ <div className="stats-summary">
1142
+ <div>Total Analyzed: {stats.analyzed.total}</div>
1143
+ <div>Flagged: {stats.analyzed.flagged} ({stats.analyzed.flaggedPercentage.toFixed(1)}%)</div>
1144
+ <div>Clean: {stats.analyzed.clean}</div>
1145
+ </div>
1146
+ </div>
1147
+
1148
+ <div className="controls">
1149
+ <select value={selectedLevel} onChange={e => setSelectedLevel(e.target.value)}>
1150
+ <option value={ModerationLevel.RELAXED}>Relaxed</option>
1151
+ <option value={ModerationLevel.MODERATE}>Moderate</option>
1152
+ <option value={ModerationLevel.STRICT}>Strict</option>
1153
+ </select>
1154
+
1155
+ <button onClick={() => handleBulkAction('approve')}>Approve All Clean</button>
1156
+ <button onClick={() => handleBulkAction('reject')}>Reject All Flagged</button>
1157
+ </div>
1158
+
1159
+ <div className="content-list">
1160
+ {results.map((result, index) => (
1161
+ <div key={index} className={`content-item ${result.isClean ? 'clean' : 'flagged'}`}>
1162
+ <div className="content-text">{reportedContent[index].content}</div>
1163
+ <div className="content-meta">
1164
+ <span className="status">{result.isClean ? '✓ Clean' : '⚠️ Flagged'}</span>
1165
+ {!result.isClean && (
1166
+ <>
1167
+ <span className="severity">{result.severity}</span>
1168
+ <span className="words">Found: {result.foundWords.join(', ')}</span>
1169
+ </>
1170
+ )}
1171
+ </div>
1172
+ <div className="sanitized">Sanitized: {result.sanitized}</div>
1173
+ </div>
1174
+ ))}
1175
+ </div>
1176
+ </div>
1177
+ );
1178
+ }
1179
+ ```
1180
+
1181
+ ### 5. E-commerce Product Reviews
1182
+
1183
+ ```tsx
1184
+ // Product review submission with moderation
1185
+ import { useModeratedInput, useProfanityGuard } from '@useverse/profanity-guard';
1186
+
1187
+ function ProductReview({ productId }) {
1188
+ const {
1189
+ content: reviewText,
1190
+ setContent: setReviewText,
1191
+ isClean,
1192
+ sanitizedContent,
1193
+ severity
1194
+ } = useModeratedInput('', {
1195
+ level: ModerationLevel.MODERATE
1196
+ });
1197
+
1198
+ const [rating, setRating] = useState(5);
1199
+ const [submitted, setSubmitted] = useState(false);
1200
+
1201
+ const handleSubmit = async () => {
1202
+ if (!isClean && severity === 'severe') {
1203
+ alert('Your review contains inappropriate language and cannot be submitted.');
1204
+ return;
1205
+ }
1206
+
1207
+ const finalReview = isClean ? reviewText : sanitizedContent;
1208
+
1209
+ await api.submitReview({
1210
+ productId,
1211
+ rating,
1212
+ text: finalReview,
1213
+ flagged: !isClean
1214
+ });
1215
+
1216
+ setSubmitted(true);
1217
+ };
1218
+
1219
+ return (
1220
+ <div className="review-form">
1221
+ <h3>Write a Review</h3>
1222
+
1223
+ <div className="rating-selector">
1224
+ <label>Rating:</label>
1225
+ {[1, 2, 3, 4, 5].map(star => (
1226
+ <button
1227
+ key={star}
1228
+ onClick={() => setRating(star)}
1229
+ className={rating >= star ? 'star-filled' : 'star-empty'}
1230
+ >
1231
+
1232
+ </button>
1233
+ ))}
1234
+ </div>
1235
+
1236
+ <div className="review-input">
1237
+ <label>Your Review:</label>
1238
+ <textarea
1239
+ value={reviewText}
1240
+ onChange={e => setReviewText(e.target.value)}
1241
+ placeholder="Share your experience..."
1242
+ rows={6}
1243
+ />
1244
+
1245
+ {!isClean && (
1246
+ <div className="moderation-notice">
1247
+ <p className="warning">
1248
+ ⚠️ Your review contains language that may be inappropriate.
1249
+ </p>
1250
+ {severity !== 'severe' && (
1251
+ <p className="info">
1252
+ We'll sanitize it automatically: "{sanitizedContent}"
1253
+ </p>
1254
+ )}
1255
+ </div>
1256
+ )}
1257
+ </div>
1258
+
1259
+ <button
1260
+ onClick={handleSubmit}
1261
+ disabled={!reviewText || (severity === 'severe')}
1262
+ >
1263
+ Submit Review
1264
+ </button>
1265
+
1266
+ {submitted && (
1267
+ <div className="success-message">
1268
+ ✓ Thank you for your review!
1269
+ {!isClean && ' (Your review was moderated for appropriate language)'}
1270
+ </div>
1271
+ )}
1272
+ </div>
1273
+ );
1274
+ }
1275
+ ```
1276
+
1277
+ ## 🤝 Contributing
1278
+
1279
+ Contributions are welcome! Please feel free to submit a Pull Request.
1280
+
1281
+ ## 📄 License
1282
+
1283
+ MIT © [Your Name]
1284
+
1285
+ ## 🔗 Links
1286
+
1287
+ - [Documentation](https://github.com/yourusername/nobadword#readme)
1288
+ - [NPM Package](https://www.npmjs.com/package/nobadword)
1289
+ - [Issue Tracker](https://github.com/yourusername/nobadword/issues)
1290
+
1291
+ ## ⚠️ Disclaimer
1292
+
1293
+ This library provides content moderation capabilities but should not be the only line of defense in production applications. Always combine automated moderation with:
1294
+ - Human review for borderline cases
1295
+ - Context-aware moderation logic
1296
+ - Regular library updates
1297
+ - User reporting systems
1298
+ - Community guidelines
1299
+
1300
+ ## 🌟 Support
1301
+
1302
+ If you find this library helpful, please consider giving it a star on GitHub!