glin-profanity 2.0.0 → 2.1.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 +160 -46
- package/lib/cjs/filters/Filter.d.ts +8 -2
- package/lib/cjs/filters/Filter.js +46 -21
- package/lib/cjs/filters/Filter.js.map +1 -1
- package/lib/cjs/hooks/useProfanityChecker.d.ts +18 -4
- package/lib/cjs/hooks/useProfanityChecker.js +23 -13
- package/lib/cjs/hooks/useProfanityChecker.js.map +1 -1
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +3 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/types/types.d.ts +10 -3
- package/lib/esm/filters/Filter.d.ts +8 -2
- package/lib/esm/filters/Filter.js +46 -21
- package/lib/esm/filters/Filter.js.map +1 -1
- package/lib/esm/hooks/useProfanityChecker.d.ts +18 -4
- package/lib/esm/hooks/useProfanityChecker.js +23 -13
- package/lib/esm/hooks/useProfanityChecker.js.map +1 -1
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/types/types.d.ts +10 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,100 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://www.glincker.com/tools/glin-profanity" target="_blank">
|
|
3
|
+
<img src="../../assets/glinr-logo.png" alt="Glin Profanity" width="40" />
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<h1 align="center">GLIN PROFANITY</h1>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<strong>A multilingual profanity detection and filtering engine for modern applications — by <a href="https://glincker.com">GLINCKER</a></strong>
|
|
11
|
+
</p>
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://www.glincker.com/tools/glin-profanity">
|
|
14
|
+
<img src="https://img.shields.io/badge/🚀%20Try%20Live%20Demo-online-blue" alt="Try Live Demo" />
|
|
15
|
+
</a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="https://www.npmjs.com/package/glin-profanity">
|
|
20
|
+
<img src="https://img.shields.io/npm/v/glin-profanity" alt="NPM Version" />
|
|
21
|
+
</a>
|
|
22
|
+
<a href="https://github.com/GLINCKER/glin-profanity/blob/main/LICENSE">
|
|
23
|
+
<img src="https://img.shields.io/badge/license-MIT-green" alt="MIT License" />
|
|
24
|
+
</a>
|
|
25
|
+
<a href="https://github.com/GLINCKER/glin-profanity/actions">
|
|
26
|
+
<img src="https://img.shields.io/github/actions/workflow/status/GLINCKER/glin-profanity/ci.yml" alt="CI Status" />
|
|
27
|
+
</a>
|
|
28
|
+
<a href="https://www.npmjs.com/package/glin-profanity">
|
|
29
|
+
<img src="https://img.shields.io/npm/dw/glin-profanity" alt="Weekly Downloads" />
|
|
30
|
+
</a>
|
|
31
|
+
<a href="https://github.com/GLINCKER/glin-profanity/issues">
|
|
32
|
+
<img src="https://img.shields.io/github/issues/GLINCKER/glin-profanity" alt="Open Issues" />
|
|
33
|
+
</a>
|
|
34
|
+
<a href="https://github.com/GLINCKER/glin-profanity/pulls">
|
|
35
|
+
<img src="https://img.shields.io/github/issues-pr/GLINCKER/glin-profanity" alt="Open PRs" />
|
|
36
|
+
</a>
|
|
37
|
+
<a href="https://github.com/GLINCKER/glin-profanity/commits/main">
|
|
38
|
+
<img src="https://img.shields.io/github/last-commit/GLINCKER/glin-profanity" alt="Last Commit" />
|
|
39
|
+
</a>
|
|
40
|
+
<a href="https://github.com/GLINCKER/glin-profanity/stargazers">
|
|
41
|
+
<img src="https://img.shields.io/github/stars/GLINCKER/glin-profanity" alt="GitHub Stars" />
|
|
42
|
+
</a>
|
|
43
|
+
<a href="https://github.com/GLINCKER/glin-profanity/network/members">
|
|
44
|
+
<img src="https://img.shields.io/github/forks/GLINCKER/glin-profanity" alt="GitHub Forks" />
|
|
45
|
+
</a>
|
|
46
|
+
<a href="https://github.com/GLINCKER/glin-profanity/graphs/contributors">
|
|
47
|
+
<img src="https://img.shields.io/github/contributors/GLINCKER/glin-profanity" alt="Contributors" />
|
|
48
|
+
</a>
|
|
49
|
+
<a href="#-table-of-contents">
|
|
50
|
+
<img src="https://img.shields.io/badge/-Table%20of%20Contents-blue" alt="Table Of Contents" />
|
|
51
|
+
</a>
|
|
52
|
+
</p>
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
> A multilingual profanity detection and filtering engine for modern applications — by [GLINCKER](https://glincker.com)
|
|
58
|
+
|
|
59
|
+
[](https://www.glincker.com/tools/glin-profanity)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## ✨ Overview
|
|
64
|
+
|
|
65
|
+
**Glin-Profanity** is a high-performance JavaScript/TypeScript library built to detect, filter, and sanitize profane or harmful language in user-generated content. With support for over 20+ languages, configurable severity levels, obfuscation detection, and real-time React integration, it’s designed for developers who care about building safe, inclusive platforms.
|
|
66
|
+
|
|
67
|
+
Whether you're moderating chat messages, community forums, or content input forms, Glin-Profanity empowers you to:
|
|
68
|
+
|
|
69
|
+
- 🧼 Filter text with real-time or batch processing
|
|
70
|
+
- 🗣️ Detect offensive terms in **20+ human languages**
|
|
71
|
+
- 💬 Catch obfuscated profanity like `sh1t`, `f*ck`, `a$$hole`
|
|
72
|
+
- 🎚️ Adjust severity thresholds (`Exact`, `Fuzzy`, `Merged`)
|
|
73
|
+
- 🔁 Replace bad words with symbols or emojis
|
|
74
|
+
- 🧩 Seamlessly integrate into **React apps** via `useProfanityChecker`
|
|
75
|
+
- 🛡️ Add custom word lists or ignore specific terms
|
|
76
|
+
|
|
77
|
+
## 📚 Table of Contents
|
|
78
|
+
|
|
79
|
+
- [🚀 Features](#-features)
|
|
80
|
+
- [📦 Installation](#installation)
|
|
81
|
+
- [🌍 Supported Languages](#supported-languages)
|
|
82
|
+
- [⚙️ Usage](#usage)
|
|
83
|
+
- [Basic Usage](#basic-usage)
|
|
84
|
+
- [🧠 API](#api)
|
|
85
|
+
- [Filter Class](#filter-class)
|
|
86
|
+
- [Constructor](#constructor)
|
|
87
|
+
- [FilterConfig Options](#filterconfig-options)
|
|
88
|
+
- [Methods](#methods)
|
|
89
|
+
- [isProfane](#isprofane)
|
|
90
|
+
- [checkProfanity](#checkprofanity)
|
|
91
|
+
- [useProfanityChecker Hook](#useprofanitychecker-hook)
|
|
92
|
+
- [Parameters](#parameters)
|
|
93
|
+
- [Return Value](#return-value)
|
|
94
|
+
- [⚠️ Note](#note)
|
|
95
|
+
- [🛠 Use Cases](#-use-cases)
|
|
96
|
+
- [📄 License](#license)
|
|
97
|
+
- [MIT License](#mit-license)
|
|
4
98
|
|
|
5
99
|
## Installation
|
|
6
100
|
|
|
@@ -14,61 +108,60 @@ OR
|
|
|
14
108
|
```bash
|
|
15
109
|
yarn add glin-profanity
|
|
16
110
|
```
|
|
111
|
+
|
|
112
|
+
### Supported Languages
|
|
113
|
+
|
|
114
|
+
Arabic, Chinese, Czech, Danish, English, Esperanto, Finnish, French, German, Hindi, Hungarian, Italian, Japanese, Korean, Norwegian, Persian, Polish, Portuguese, Russian, Turkish, Swedish, Thai
|
|
115
|
+
|
|
17
116
|
## Usage
|
|
18
117
|
|
|
19
118
|
### Basic Usage
|
|
20
119
|
|
|
21
120
|
Here's a simple example of how to use Glin-Profanity in a React application:
|
|
22
121
|
|
|
23
|
-
```
|
|
122
|
+
```tsx
|
|
24
123
|
import React, { useState } from 'react';
|
|
25
|
-
import { useProfanityChecker, Language } from 'glin-profanity';
|
|
124
|
+
import { useProfanityChecker, SeverityLevel, Language } from 'glin-profanity';
|
|
26
125
|
|
|
27
|
-
const App
|
|
126
|
+
const App = () => {
|
|
28
127
|
const [text, setText] = useState('');
|
|
29
|
-
const [
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
128
|
+
const [autoReplace, setAutoReplace] = useState(true);
|
|
129
|
+
const [replaceWith, setReplaceWith] = useState('***');
|
|
130
|
+
const [minSeverity, setMinSeverity] = useState(SeverityLevel.Exact);
|
|
131
|
+
|
|
132
|
+
const { result, checkText } = useProfanityChecker({
|
|
133
|
+
allLanguages: true,
|
|
134
|
+
severityLevels: true,
|
|
135
|
+
autoReplace,
|
|
136
|
+
replaceWith,
|
|
137
|
+
minSeverity,
|
|
138
|
+
customActions: (res) => {
|
|
139
|
+
console.log('[Detected]', res.profaneWords);
|
|
140
|
+
},
|
|
141
|
+
});
|
|
41
142
|
|
|
42
143
|
return (
|
|
43
144
|
<div>
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
<div>
|
|
48
|
-
<label>
|
|
49
|
-
<input
|
|
50
|
-
type="checkbox"
|
|
51
|
-
checked={checkAllLanguages}
|
|
52
|
-
onChange={(e) => setCheckAllLanguages(e.target.checked)}
|
|
53
|
-
/>
|
|
54
|
-
Check All Languages
|
|
55
|
-
</label>
|
|
56
|
-
</div>
|
|
145
|
+
<input value={text} onChange={(e) => setText(e.target.value)} />
|
|
146
|
+
<button onClick={() => checkText(text)}>Scan</button>
|
|
147
|
+
|
|
57
148
|
{result && (
|
|
58
|
-
|
|
149
|
+
<>
|
|
59
150
|
<p>Contains Profanity: {result.containsProfanity ? 'Yes' : 'No'}</p>
|
|
60
151
|
{result.containsProfanity && (
|
|
61
|
-
|
|
152
|
+
<>
|
|
153
|
+
<p>Detected: {result.profaneWords.join(', ')}</p>
|
|
154
|
+
<p>Replaced: {result.processedText}</p>
|
|
155
|
+
</>
|
|
62
156
|
)}
|
|
63
|
-
|
|
157
|
+
</>
|
|
64
158
|
)}
|
|
65
159
|
</div>
|
|
66
160
|
);
|
|
67
161
|
};
|
|
68
|
-
|
|
69
|
-
export default App;
|
|
70
162
|
```
|
|
71
163
|
|
|
164
|
+
|
|
72
165
|
## API
|
|
73
166
|
|
|
74
167
|
### `Filter` Class
|
|
@@ -89,16 +182,26 @@ new Filter(config?: {
|
|
|
89
182
|
});
|
|
90
183
|
```
|
|
91
184
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
185
|
+
#### FilterConfig Options:
|
|
186
|
+
|
|
187
|
+
| Option | Type | Description |
|
|
188
|
+
|-------------------------|--------------------|-------------|
|
|
189
|
+
| `languages` | `Language[]` | Languages to include |
|
|
190
|
+
| `allLanguages` | `boolean` | If true, scan all available languages |
|
|
191
|
+
| `caseSensitive` | `boolean` | Match case exactly |
|
|
192
|
+
| `wordBoundaries` | `boolean` | Only match full words (turn off for substring matching) |
|
|
193
|
+
| `customWords` | `string[]` | Add your own words |
|
|
194
|
+
| `replaceWith` | `string` | Replace matched words with this string |
|
|
195
|
+
| `severityLevels` | `boolean` | Enable severity mapping (Exact, Fuzzy, Merged) |
|
|
196
|
+
| `ignoreWords` | `string[]` | Words to skip even if found |
|
|
197
|
+
| `logProfanity` | `boolean` | Log results via console |
|
|
198
|
+
| `allowObfuscatedMatch` | `boolean` | Enable fuzzy pattern matching like `f*ck` |
|
|
199
|
+
| `fuzzyToleranceLevel` | `number (0–1)` | Adjust how tolerant fuzzy matching is |
|
|
200
|
+
| `autoReplace` | `boolean` | Whether to auto-replace flagged words |
|
|
201
|
+
| `minSeverity` | `SeverityLevel` | Minimum severity to include in final list |
|
|
202
|
+
| `customActions` | `(result) => void` | Custom logging/callback support |
|
|
203
|
+
|
|
204
|
+
---
|
|
102
205
|
|
|
103
206
|
#### Methods
|
|
104
207
|
|
|
@@ -156,6 +259,17 @@ A custom React hook for using the profanity checker.
|
|
|
156
259
|
const { result, checkText, checkTextAsync } = useProfanityChecker(config);
|
|
157
260
|
```
|
|
158
261
|
|
|
262
|
+
## Note
|
|
263
|
+
⚠️ Glin-Profanity is a best-effort tool. Language evolves, and no filter is perfect. Always supplement with human moderation for high-risk platforms.
|
|
264
|
+
|
|
265
|
+
## 🛠 Use Cases
|
|
266
|
+
|
|
267
|
+
- 🔐 Chat moderation in messaging apps
|
|
268
|
+
- 🧼 Comment sanitization for blogs or forums
|
|
269
|
+
- 🕹️ Game lobbies & multiplayer chats
|
|
270
|
+
- 🤖 AI content filters before processing input
|
|
271
|
+
|
|
272
|
+
|
|
159
273
|
## License
|
|
160
274
|
|
|
161
275
|
This software is also available under the GLINCKER LLC proprietary license. The proprietary license allows for use, modification, and distribution of the software with certain restrictions and conditions as set forth by GLINCKER LLC.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Language, CheckProfanityResult } from '../types/types';
|
|
2
|
-
interface FilterConfig {
|
|
1
|
+
import { Language, CheckProfanityResult, SeverityLevel } from '../types/types';
|
|
2
|
+
export interface FilterConfig {
|
|
3
3
|
languages?: Language[];
|
|
4
4
|
allLanguages?: boolean;
|
|
5
5
|
caseSensitive?: boolean;
|
|
@@ -23,11 +23,17 @@ declare class Filter {
|
|
|
23
23
|
private allowObfuscatedMatch;
|
|
24
24
|
private fuzzyToleranceLevel;
|
|
25
25
|
constructor(config?: FilterConfig);
|
|
26
|
+
private debugLog;
|
|
26
27
|
private normalizeObfuscated;
|
|
27
28
|
private getRegex;
|
|
28
29
|
private isFuzzyToleranceMatch;
|
|
29
30
|
private evaluateSeverity;
|
|
30
31
|
isProfane(value: string): boolean;
|
|
32
|
+
matches(word: string): boolean;
|
|
31
33
|
checkProfanity(text: string): CheckProfanityResult;
|
|
34
|
+
checkProfanityWithMinSeverity(text: string, minSeverity?: SeverityLevel): {
|
|
35
|
+
filteredWords: string[];
|
|
36
|
+
result: CheckProfanityResult;
|
|
37
|
+
};
|
|
32
38
|
}
|
|
33
39
|
export { Filter };
|
|
@@ -5,13 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Filter = void 0;
|
|
7
7
|
const dictionary_1 = __importDefault(require("../data/dictionary"));
|
|
8
|
+
const types_1 = require("../types/types");
|
|
8
9
|
class Filter {
|
|
9
10
|
constructor(config) {
|
|
10
11
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
11
12
|
let words = [];
|
|
12
13
|
this.caseSensitive = (_a = config === null || config === void 0 ? void 0 : config.caseSensitive) !== null && _a !== void 0 ? _a : false;
|
|
13
14
|
this.allowObfuscatedMatch = (_b = config === null || config === void 0 ? void 0 : config.allowObfuscatedMatch) !== null && _b !== void 0 ? _b : false;
|
|
14
|
-
this.wordBoundaries = (_c = config === null || config === void 0 ? void 0 : config.wordBoundaries) !== null && _c !== void 0 ? _c : !this.allowObfuscatedMatch;
|
|
15
|
+
this.wordBoundaries = (_c = config === null || config === void 0 ? void 0 : config.wordBoundaries) !== null && _c !== void 0 ? _c : !this.allowObfuscatedMatch;
|
|
15
16
|
this.replaceWith = config === null || config === void 0 ? void 0 : config.replaceWith;
|
|
16
17
|
this.severityLevels = (_d = config === null || config === void 0 ? void 0 : config.severityLevels) !== null && _d !== void 0 ? _d : false;
|
|
17
18
|
this.ignoreWords = new Set(((_e = config === null || config === void 0 ? void 0 : config.ignoreWords) === null || _e === void 0 ? void 0 : _e.map((word) => word.toLowerCase())) || []);
|
|
@@ -27,19 +28,22 @@ class Filter {
|
|
|
27
28
|
else {
|
|
28
29
|
const languages = (config === null || config === void 0 ? void 0 : config.languages) || ['english'];
|
|
29
30
|
const languagesChecks = new Set(languages);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
});
|
|
34
|
-
}
|
|
31
|
+
languagesChecks.forEach((lang) => {
|
|
32
|
+
words = [...words, ...dictionary_1.default[lang]];
|
|
33
|
+
});
|
|
35
34
|
}
|
|
36
35
|
if (config === null || config === void 0 ? void 0 : config.customWords) {
|
|
37
36
|
words = [...words, ...config.customWords];
|
|
38
37
|
}
|
|
39
38
|
this.words = new Map(words.map((word) => [word.toLowerCase(), 1]));
|
|
40
39
|
}
|
|
40
|
+
debugLog(...args) {
|
|
41
|
+
if (this.logProfanity) {
|
|
42
|
+
console.log('[glin-profanity]', ...args);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
41
45
|
normalizeObfuscated(text) {
|
|
42
|
-
let normalized = text.replace(/([a-zA-Z])\1{1,}/g, '$1$1');
|
|
46
|
+
let normalized = text.replace(/([a-zA-Z])\1{1,}/g, '$1$1');
|
|
43
47
|
const charMap = {
|
|
44
48
|
'@': 'a',
|
|
45
49
|
$: 's',
|
|
@@ -73,20 +77,19 @@ class Filter {
|
|
|
73
77
|
return score >= this.fuzzyToleranceLevel;
|
|
74
78
|
}
|
|
75
79
|
evaluateSeverity(word, text) {
|
|
76
|
-
if (this.wordBoundaries) {
|
|
77
|
-
return
|
|
80
|
+
if (this.wordBoundaries && this.getRegex(word).test(text)) {
|
|
81
|
+
return types_1.SeverityLevel.Exact;
|
|
78
82
|
}
|
|
79
83
|
if (this.getRegex(word).test(text))
|
|
80
|
-
return
|
|
84
|
+
return types_1.SeverityLevel.Exact;
|
|
81
85
|
if (this.isFuzzyToleranceMatch(word, text))
|
|
82
|
-
return
|
|
86
|
+
return types_1.SeverityLevel.Fuzzy;
|
|
83
87
|
return undefined;
|
|
84
88
|
}
|
|
85
89
|
isProfane(value) {
|
|
86
|
-
let input =
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
+
let input = this.allowObfuscatedMatch
|
|
91
|
+
? this.normalizeObfuscated(value)
|
|
92
|
+
: value;
|
|
90
93
|
for (const word of this.words.keys()) {
|
|
91
94
|
if (!this.ignoreWords.has(word.toLowerCase()) &&
|
|
92
95
|
this.evaluateSeverity(word, input) !== undefined) {
|
|
@@ -95,11 +98,14 @@ class Filter {
|
|
|
95
98
|
}
|
|
96
99
|
return false;
|
|
97
100
|
}
|
|
101
|
+
matches(word) {
|
|
102
|
+
return this.isProfane(word);
|
|
103
|
+
}
|
|
98
104
|
checkProfanity(text) {
|
|
99
|
-
let input =
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
let input = this.allowObfuscatedMatch
|
|
106
|
+
? this.normalizeObfuscated(text)
|
|
107
|
+
: text;
|
|
108
|
+
input = input.toLowerCase();
|
|
103
109
|
const profaneWords = [];
|
|
104
110
|
const severityMap = {};
|
|
105
111
|
for (const dictWord of this.words.keys()) {
|
|
@@ -111,16 +117,24 @@ class Filter {
|
|
|
111
117
|
let match;
|
|
112
118
|
while ((match = regex.exec(input)) !== null) {
|
|
113
119
|
profaneWords.push(match[0]);
|
|
114
|
-
severityMap[match[0]]
|
|
120
|
+
if (severityMap[match[0]] === undefined) {
|
|
121
|
+
severityMap[match[0]] = severity;
|
|
122
|
+
}
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
}
|
|
126
|
+
if (profaneWords.length > 0) {
|
|
127
|
+
this.debugLog('Detected:', profaneWords);
|
|
128
|
+
}
|
|
118
129
|
let processedText = text;
|
|
119
130
|
if (this.replaceWith && profaneWords.length > 0) {
|
|
120
131
|
const uniqueWords = Array.from(new Set(profaneWords));
|
|
121
132
|
for (const word of uniqueWords) {
|
|
122
133
|
const escaped = word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
123
|
-
|
|
134
|
+
const replacementRegex = this.wordBoundaries
|
|
135
|
+
? new RegExp(`\\b${escaped}\\b`, 'gi')
|
|
136
|
+
: new RegExp(escaped, 'gi');
|
|
137
|
+
processedText = processedText.replace(replacementRegex, this.replaceWith);
|
|
124
138
|
}
|
|
125
139
|
}
|
|
126
140
|
return {
|
|
@@ -132,6 +146,17 @@ class Filter {
|
|
|
132
146
|
: undefined,
|
|
133
147
|
};
|
|
134
148
|
}
|
|
149
|
+
checkProfanityWithMinSeverity(text, minSeverity = types_1.SeverityLevel.Exact) {
|
|
150
|
+
const result = this.checkProfanity(text);
|
|
151
|
+
const filteredWords = result.severityMap && result.profaneWords.length > 0
|
|
152
|
+
? result.profaneWords.filter((word) => {
|
|
153
|
+
var _a;
|
|
154
|
+
const severity = (_a = result.severityMap) === null || _a === void 0 ? void 0 : _a[word];
|
|
155
|
+
return typeof severity === 'number' && severity >= minSeverity;
|
|
156
|
+
})
|
|
157
|
+
: [];
|
|
158
|
+
return { filteredWords, result };
|
|
159
|
+
}
|
|
135
160
|
}
|
|
136
161
|
exports.Filter = Filter;
|
|
137
162
|
//# sourceMappingURL=Filter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Filter.js","sourceRoot":"","sources":["../../../src/filters/Filter.ts"],"names":[],"mappings":";;;;;;AAAA,oEAA4C;
|
|
1
|
+
{"version":3,"file":"Filter.js","sourceRoot":"","sources":["../../../src/filters/Filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CheckProfanityResult, Language } from '../types/types';
|
|
2
|
-
interface ProfanityCheckerConfig {
|
|
1
|
+
import { CheckProfanityResult, Language, SeverityLevel } from '../types/types';
|
|
2
|
+
export interface ProfanityCheckerConfig {
|
|
3
3
|
languages?: Language[];
|
|
4
4
|
allLanguages?: boolean;
|
|
5
5
|
caseSensitive?: boolean;
|
|
@@ -9,12 +9,26 @@ interface ProfanityCheckerConfig {
|
|
|
9
9
|
severityLevels?: boolean;
|
|
10
10
|
allowObfuscatedMatch?: boolean;
|
|
11
11
|
fuzzyToleranceLevel?: number;
|
|
12
|
+
minSeverity?: SeverityLevel;
|
|
13
|
+
autoReplace?: boolean;
|
|
12
14
|
customActions?: (result: CheckProfanityResult) => void;
|
|
13
15
|
}
|
|
14
16
|
export declare const useProfanityChecker: (config?: ProfanityCheckerConfig) => {
|
|
15
17
|
result: CheckProfanityResult;
|
|
16
|
-
checkText: (text: string) =>
|
|
18
|
+
checkText: (text: string) => {
|
|
19
|
+
filteredWords: string[];
|
|
20
|
+
autoReplaced: string;
|
|
21
|
+
containsProfanity: boolean;
|
|
22
|
+
profaneWords: string[];
|
|
23
|
+
processedText?: string;
|
|
24
|
+
severityMap?: Record<string, SeverityLevel>;
|
|
25
|
+
matchContexts?: {
|
|
26
|
+
word: string;
|
|
27
|
+
context: string;
|
|
28
|
+
}[];
|
|
29
|
+
};
|
|
17
30
|
checkTextAsync: (text: string) => Promise<CheckProfanityResult>;
|
|
18
31
|
reset: () => void;
|
|
32
|
+
isDirty: boolean;
|
|
33
|
+
isWordProfane: (word: string) => boolean;
|
|
19
34
|
};
|
|
20
|
-
export {};
|
|
@@ -17,41 +17,51 @@ const react_1 = require("react");
|
|
|
17
17
|
const Filter_1 = require("../filters/Filter");
|
|
18
18
|
const globalWhitelist_json_1 = __importDefault(require("../data/globalWhitelist.json"));
|
|
19
19
|
const useProfanityChecker = (config) => {
|
|
20
|
+
var _a;
|
|
20
21
|
const [result, setResult] = (0, react_1.useState)(null);
|
|
21
22
|
const filterConfig = (0, react_1.useMemo)(() => {
|
|
22
23
|
var _a;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
if (effectiveConfig.allowObfuscatedMatch &&
|
|
26
|
-
effectiveConfig.wordBoundaries) {
|
|
24
|
+
const effective = Object.assign(Object.assign({}, (config !== null && config !== void 0 ? config : {})), { ignoreWords: globalWhitelist_json_1.default.whitelist, fuzzyToleranceLevel: (_a = config === null || config === void 0 ? void 0 : config.fuzzyToleranceLevel) !== null && _a !== void 0 ? _a : 0.8 });
|
|
25
|
+
if (effective.allowObfuscatedMatch && effective.wordBoundaries) {
|
|
27
26
|
console.warn('[Glin-Profanity] Obfuscated match enabled → wordBoundaries will be ignored internally.');
|
|
28
27
|
}
|
|
29
|
-
return
|
|
28
|
+
return effective;
|
|
30
29
|
}, [config]);
|
|
31
30
|
const filter = (0, react_1.useMemo)(() => new Filter_1.Filter(filterConfig), [filterConfig]);
|
|
32
31
|
const checkText = (text) => {
|
|
32
|
+
var _a;
|
|
33
33
|
const checkResult = filter.checkProfanity(text);
|
|
34
|
+
// Filter based on minSeverity (if provided)
|
|
35
|
+
const filteredWords = (config === null || config === void 0 ? void 0 : config.minSeverity) && checkResult.severityMap
|
|
36
|
+
? checkResult.profaneWords.filter((word) => checkResult.severityMap &&
|
|
37
|
+
checkResult.severityMap[word] >= config.minSeverity)
|
|
38
|
+
: checkResult.profaneWords;
|
|
39
|
+
// Optional auto-replace
|
|
40
|
+
const autoReplaced = (config === null || config === void 0 ? void 0 : config.autoReplace) && checkResult.processedText
|
|
41
|
+
? checkResult.processedText
|
|
42
|
+
: text;
|
|
34
43
|
setResult(checkResult);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
(_a = config === null || config === void 0 ? void 0 : config.customActions) === null || _a === void 0 ? void 0 : _a.call(config, checkResult);
|
|
45
|
+
return Object.assign(Object.assign({}, checkResult), { filteredWords,
|
|
46
|
+
autoReplaced });
|
|
38
47
|
};
|
|
39
48
|
const checkTextAsync = (text) => __awaiter(void 0, void 0, void 0, function* () {
|
|
40
49
|
return new Promise((resolve) => {
|
|
41
|
-
const checkResult =
|
|
42
|
-
setResult(checkResult);
|
|
43
|
-
if (config === null || config === void 0 ? void 0 : config.customActions) {
|
|
44
|
-
config.customActions(checkResult);
|
|
45
|
-
}
|
|
50
|
+
const checkResult = checkText(text); // sync call
|
|
46
51
|
resolve(checkResult);
|
|
47
52
|
});
|
|
48
53
|
});
|
|
54
|
+
const isWordProfane = (word) => {
|
|
55
|
+
return filter.checkProfanity(word).containsProfanity;
|
|
56
|
+
};
|
|
49
57
|
const reset = () => setResult(null);
|
|
50
58
|
return {
|
|
51
59
|
result,
|
|
52
60
|
checkText,
|
|
53
61
|
checkTextAsync,
|
|
54
62
|
reset,
|
|
63
|
+
isDirty: (_a = result === null || result === void 0 ? void 0 : result.containsProfanity) !== null && _a !== void 0 ? _a : false,
|
|
64
|
+
isWordProfane,
|
|
55
65
|
};
|
|
56
66
|
};
|
|
57
67
|
exports.useProfanityChecker = useProfanityChecker;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useProfanityChecker.js","sourceRoot":"","sources":["../../../src/hooks/useProfanityChecker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,iCAA0C;AAC1C,
|
|
1
|
+
{"version":3,"file":"useProfanityChecker.js","sourceRoot":"","sources":["../../../src/hooks/useProfanityChecker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,iCAA0C;AAC1C,8CAAyD;AAEzD,wFAA+D;AAiBxD,MAAM,mBAAmB,GAAG,CAAC,MAA+B,EAAE,EAAE;;IACrE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAA,gBAAQ,EAA8B,IAAI,CAAC,CAAC;IAExE,MAAM,YAAY,GAAiB,IAAA,eAAO,EAAC,GAAG,EAAE;;QAC9C,MAAM,SAAS,mCACV,CAAC,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,EAAE,CAAC,KACjB,WAAW,EAAE,8BAAmB,CAAC,SAAS,EAC1C,mBAAmB,EAAE,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,mBAAmB,mCAAI,GAAG,GACxD,CAAC;QAEF,IAAI,SAAS,CAAC,oBAAoB,IAAI,SAAS,CAAC,cAAc,EAAE,CAAC;YAC/D,OAAO,CAAC,IAAI,CACV,wFAAwF,CACzF,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,MAAM,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE,CAAC,IAAI,eAAM,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAEvE,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE;;QACjC,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAEhD,4CAA4C;QAC5C,MAAM,aAAa,GACjB,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,WAAW,KAAI,WAAW,CAAC,WAAW;YAC5C,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,CAC7B,CAAC,IAAI,EAAE,EAAE,CACP,WAAW,CAAC,WAAW;gBACvB,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,WAAY,CACvD;YACH,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC;QAE/B,wBAAwB;QACxB,MAAM,YAAY,GAChB,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,WAAW,KAAI,WAAW,CAAC,aAAa;YAC9C,CAAC,CAAC,WAAW,CAAC,aAAa;YAC3B,CAAC,CAAC,IAAI,CAAC;QAEX,SAAS,CAAC,WAAW,CAAC,CAAC;QACvB,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,aAAa,uDAAG,WAAW,CAAC,CAAC;QAErC,uCACK,WAAW,KACd,aAAa;YACb,YAAY,IACZ;IACJ,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,CAAO,IAAY,EAAE,EAAE;QAC5C,OAAO,IAAI,OAAO,CAAuB,CAAC,OAAO,EAAE,EAAE;YACnD,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY;YACjD,OAAO,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC,CAAA,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE;QACrC,OAAO,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC;IACvD,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEpC,OAAO;QACL,MAAM;QACN,SAAS;QACT,cAAc;QACd,KAAK;QACL,OAAO,EAAE,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,iBAAiB,mCAAI,KAAK;QAC3C,aAAa;KACd,CAAC;AACJ,CAAC,CAAC;AAvEW,QAAA,mBAAmB,uBAuE9B"}
|
package/lib/cjs/index.d.ts
CHANGED
package/lib/cjs/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useProfanityChecker = exports.Filter = void 0;
|
|
3
|
+
exports.SeverityLevel = exports.useProfanityChecker = exports.Filter = void 0;
|
|
4
4
|
var Filter_1 = require("./filters/Filter");
|
|
5
5
|
Object.defineProperty(exports, "Filter", { enumerable: true, get: function () { return Filter_1.Filter; } });
|
|
6
6
|
var useProfanityChecker_1 = require("./hooks/useProfanityChecker");
|
|
7
7
|
Object.defineProperty(exports, "useProfanityChecker", { enumerable: true, get: function () { return useProfanityChecker_1.useProfanityChecker; } });
|
|
8
|
+
var types_1 = require("./types/types");
|
|
9
|
+
Object.defineProperty(exports, "SeverityLevel", { enumerable: true, get: function () { return types_1.SeverityLevel; } });
|
|
8
10
|
//# sourceMappingURL=index.js.map
|
package/lib/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAA0C;AAAjC,gGAAA,MAAM,OAAA;AACf,mEAAkE;AAAzD,0HAAA,mBAAmB,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAA0C;AAAjC,gGAAA,MAAM,OAAA;AACf,mEAAkE;AAAzD,0HAAA,mBAAmB,OAAA;AAC5B,uCAA8C;AAArC,sGAAA,aAAa,OAAA"}
|
package/lib/cjs/types/types.d.ts
CHANGED
|
@@ -3,12 +3,19 @@ export declare enum SeverityLevel {
|
|
|
3
3
|
Fuzzy = 2,
|
|
4
4
|
Merged = 3
|
|
5
5
|
}
|
|
6
|
+
export type SeverityLabel = keyof typeof SeverityLevel;
|
|
7
|
+
export interface FilteredProfanityResult {
|
|
8
|
+
result: CheckProfanityResult;
|
|
9
|
+
filteredWords: string[];
|
|
10
|
+
}
|
|
6
11
|
export interface CheckProfanityResult {
|
|
7
12
|
containsProfanity: boolean;
|
|
8
13
|
profaneWords: string[];
|
|
9
14
|
processedText?: string;
|
|
10
|
-
severityMap?:
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
severityMap?: Record<string, SeverityLevel>;
|
|
16
|
+
matchContexts?: {
|
|
17
|
+
word: string;
|
|
18
|
+
context: string;
|
|
19
|
+
}[];
|
|
13
20
|
}
|
|
14
21
|
export type Language = 'arabic' | 'chinese' | 'czech' | 'danish' | 'english' | 'esperanto' | 'finnish' | 'french' | 'german' | 'hindi' | 'hungarian' | 'italian' | 'japanese' | 'korean' | 'norwegian' | 'persian' | 'polish' | 'portuguese' | 'russian' | 'turkish' | 'swedish' | 'thai';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Language, CheckProfanityResult } from '../types/types';
|
|
2
|
-
interface FilterConfig {
|
|
1
|
+
import { Language, CheckProfanityResult, SeverityLevel } from '../types/types';
|
|
2
|
+
export interface FilterConfig {
|
|
3
3
|
languages?: Language[];
|
|
4
4
|
allLanguages?: boolean;
|
|
5
5
|
caseSensitive?: boolean;
|
|
@@ -23,11 +23,17 @@ declare class Filter {
|
|
|
23
23
|
private allowObfuscatedMatch;
|
|
24
24
|
private fuzzyToleranceLevel;
|
|
25
25
|
constructor(config?: FilterConfig);
|
|
26
|
+
private debugLog;
|
|
26
27
|
private normalizeObfuscated;
|
|
27
28
|
private getRegex;
|
|
28
29
|
private isFuzzyToleranceMatch;
|
|
29
30
|
private evaluateSeverity;
|
|
30
31
|
isProfane(value: string): boolean;
|
|
32
|
+
matches(word: string): boolean;
|
|
31
33
|
checkProfanity(text: string): CheckProfanityResult;
|
|
34
|
+
checkProfanityWithMinSeverity(text: string, minSeverity?: SeverityLevel): {
|
|
35
|
+
filteredWords: string[];
|
|
36
|
+
result: CheckProfanityResult;
|
|
37
|
+
};
|
|
32
38
|
}
|
|
33
39
|
export { Filter };
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import dictionary from '../data/dictionary';
|
|
2
|
+
import { SeverityLevel } from '../types/types';
|
|
2
3
|
class Filter {
|
|
3
4
|
constructor(config) {
|
|
4
5
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
5
6
|
let words = [];
|
|
6
7
|
this.caseSensitive = (_a = config === null || config === void 0 ? void 0 : config.caseSensitive) !== null && _a !== void 0 ? _a : false;
|
|
7
8
|
this.allowObfuscatedMatch = (_b = config === null || config === void 0 ? void 0 : config.allowObfuscatedMatch) !== null && _b !== void 0 ? _b : false;
|
|
8
|
-
this.wordBoundaries = (_c = config === null || config === void 0 ? void 0 : config.wordBoundaries) !== null && _c !== void 0 ? _c : !this.allowObfuscatedMatch;
|
|
9
|
+
this.wordBoundaries = (_c = config === null || config === void 0 ? void 0 : config.wordBoundaries) !== null && _c !== void 0 ? _c : !this.allowObfuscatedMatch;
|
|
9
10
|
this.replaceWith = config === null || config === void 0 ? void 0 : config.replaceWith;
|
|
10
11
|
this.severityLevels = (_d = config === null || config === void 0 ? void 0 : config.severityLevels) !== null && _d !== void 0 ? _d : false;
|
|
11
12
|
this.ignoreWords = new Set(((_e = config === null || config === void 0 ? void 0 : config.ignoreWords) === null || _e === void 0 ? void 0 : _e.map((word) => word.toLowerCase())) || []);
|
|
@@ -21,19 +22,22 @@ class Filter {
|
|
|
21
22
|
else {
|
|
22
23
|
const languages = (config === null || config === void 0 ? void 0 : config.languages) || ['english'];
|
|
23
24
|
const languagesChecks = new Set(languages);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
});
|
|
28
|
-
}
|
|
25
|
+
languagesChecks.forEach((lang) => {
|
|
26
|
+
words = [...words, ...dictionary[lang]];
|
|
27
|
+
});
|
|
29
28
|
}
|
|
30
29
|
if (config === null || config === void 0 ? void 0 : config.customWords) {
|
|
31
30
|
words = [...words, ...config.customWords];
|
|
32
31
|
}
|
|
33
32
|
this.words = new Map(words.map((word) => [word.toLowerCase(), 1]));
|
|
34
33
|
}
|
|
34
|
+
debugLog(...args) {
|
|
35
|
+
if (this.logProfanity) {
|
|
36
|
+
console.log('[glin-profanity]', ...args);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
35
39
|
normalizeObfuscated(text) {
|
|
36
|
-
let normalized = text.replace(/([a-zA-Z])\1{1,}/g, '$1$1');
|
|
40
|
+
let normalized = text.replace(/([a-zA-Z])\1{1,}/g, '$1$1');
|
|
37
41
|
const charMap = {
|
|
38
42
|
'@': 'a',
|
|
39
43
|
$: 's',
|
|
@@ -67,20 +71,19 @@ class Filter {
|
|
|
67
71
|
return score >= this.fuzzyToleranceLevel;
|
|
68
72
|
}
|
|
69
73
|
evaluateSeverity(word, text) {
|
|
70
|
-
if (this.wordBoundaries) {
|
|
71
|
-
return
|
|
74
|
+
if (this.wordBoundaries && this.getRegex(word).test(text)) {
|
|
75
|
+
return SeverityLevel.Exact;
|
|
72
76
|
}
|
|
73
77
|
if (this.getRegex(word).test(text))
|
|
74
|
-
return
|
|
78
|
+
return SeverityLevel.Exact;
|
|
75
79
|
if (this.isFuzzyToleranceMatch(word, text))
|
|
76
|
-
return
|
|
80
|
+
return SeverityLevel.Fuzzy;
|
|
77
81
|
return undefined;
|
|
78
82
|
}
|
|
79
83
|
isProfane(value) {
|
|
80
|
-
let input =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
+
let input = this.allowObfuscatedMatch
|
|
85
|
+
? this.normalizeObfuscated(value)
|
|
86
|
+
: value;
|
|
84
87
|
for (const word of this.words.keys()) {
|
|
85
88
|
if (!this.ignoreWords.has(word.toLowerCase()) &&
|
|
86
89
|
this.evaluateSeverity(word, input) !== undefined) {
|
|
@@ -89,11 +92,14 @@ class Filter {
|
|
|
89
92
|
}
|
|
90
93
|
return false;
|
|
91
94
|
}
|
|
95
|
+
matches(word) {
|
|
96
|
+
return this.isProfane(word);
|
|
97
|
+
}
|
|
92
98
|
checkProfanity(text) {
|
|
93
|
-
let input =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
let input = this.allowObfuscatedMatch
|
|
100
|
+
? this.normalizeObfuscated(text)
|
|
101
|
+
: text;
|
|
102
|
+
input = input.toLowerCase();
|
|
97
103
|
const profaneWords = [];
|
|
98
104
|
const severityMap = {};
|
|
99
105
|
for (const dictWord of this.words.keys()) {
|
|
@@ -105,16 +111,24 @@ class Filter {
|
|
|
105
111
|
let match;
|
|
106
112
|
while ((match = regex.exec(input)) !== null) {
|
|
107
113
|
profaneWords.push(match[0]);
|
|
108
|
-
severityMap[match[0]]
|
|
114
|
+
if (severityMap[match[0]] === undefined) {
|
|
115
|
+
severityMap[match[0]] = severity;
|
|
116
|
+
}
|
|
109
117
|
}
|
|
110
118
|
}
|
|
111
119
|
}
|
|
120
|
+
if (profaneWords.length > 0) {
|
|
121
|
+
this.debugLog('Detected:', profaneWords);
|
|
122
|
+
}
|
|
112
123
|
let processedText = text;
|
|
113
124
|
if (this.replaceWith && profaneWords.length > 0) {
|
|
114
125
|
const uniqueWords = Array.from(new Set(profaneWords));
|
|
115
126
|
for (const word of uniqueWords) {
|
|
116
127
|
const escaped = word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
117
|
-
|
|
128
|
+
const replacementRegex = this.wordBoundaries
|
|
129
|
+
? new RegExp(`\\b${escaped}\\b`, 'gi')
|
|
130
|
+
: new RegExp(escaped, 'gi');
|
|
131
|
+
processedText = processedText.replace(replacementRegex, this.replaceWith);
|
|
118
132
|
}
|
|
119
133
|
}
|
|
120
134
|
return {
|
|
@@ -126,6 +140,17 @@ class Filter {
|
|
|
126
140
|
: undefined,
|
|
127
141
|
};
|
|
128
142
|
}
|
|
143
|
+
checkProfanityWithMinSeverity(text, minSeverity = SeverityLevel.Exact) {
|
|
144
|
+
const result = this.checkProfanity(text);
|
|
145
|
+
const filteredWords = result.severityMap && result.profaneWords.length > 0
|
|
146
|
+
? result.profaneWords.filter((word) => {
|
|
147
|
+
var _a;
|
|
148
|
+
const severity = (_a = result.severityMap) === null || _a === void 0 ? void 0 : _a[word];
|
|
149
|
+
return typeof severity === 'number' && severity >= minSeverity;
|
|
150
|
+
})
|
|
151
|
+
: [];
|
|
152
|
+
return { filteredWords, result };
|
|
153
|
+
}
|
|
129
154
|
}
|
|
130
155
|
export { Filter };
|
|
131
156
|
//# sourceMappingURL=Filter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Filter.js","sourceRoot":"","sources":["../../../src/filters/Filter.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"Filter.js","sourceRoot":"","sources":["../../../src/filters/Filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CheckProfanityResult, Language } from '../types/types';
|
|
2
|
-
interface ProfanityCheckerConfig {
|
|
1
|
+
import { CheckProfanityResult, Language, SeverityLevel } from '../types/types';
|
|
2
|
+
export interface ProfanityCheckerConfig {
|
|
3
3
|
languages?: Language[];
|
|
4
4
|
allLanguages?: boolean;
|
|
5
5
|
caseSensitive?: boolean;
|
|
@@ -9,12 +9,26 @@ interface ProfanityCheckerConfig {
|
|
|
9
9
|
severityLevels?: boolean;
|
|
10
10
|
allowObfuscatedMatch?: boolean;
|
|
11
11
|
fuzzyToleranceLevel?: number;
|
|
12
|
+
minSeverity?: SeverityLevel;
|
|
13
|
+
autoReplace?: boolean;
|
|
12
14
|
customActions?: (result: CheckProfanityResult) => void;
|
|
13
15
|
}
|
|
14
16
|
export declare const useProfanityChecker: (config?: ProfanityCheckerConfig) => {
|
|
15
17
|
result: CheckProfanityResult;
|
|
16
|
-
checkText: (text: string) =>
|
|
18
|
+
checkText: (text: string) => {
|
|
19
|
+
filteredWords: string[];
|
|
20
|
+
autoReplaced: string;
|
|
21
|
+
containsProfanity: boolean;
|
|
22
|
+
profaneWords: string[];
|
|
23
|
+
processedText?: string;
|
|
24
|
+
severityMap?: Record<string, SeverityLevel>;
|
|
25
|
+
matchContexts?: {
|
|
26
|
+
word: string;
|
|
27
|
+
context: string;
|
|
28
|
+
}[];
|
|
29
|
+
};
|
|
17
30
|
checkTextAsync: (text: string) => Promise<CheckProfanityResult>;
|
|
18
31
|
reset: () => void;
|
|
32
|
+
isDirty: boolean;
|
|
33
|
+
isWordProfane: (word: string) => boolean;
|
|
19
34
|
};
|
|
20
|
-
export {};
|
|
@@ -11,41 +11,51 @@ import { useMemo, useState } from 'react';
|
|
|
11
11
|
import { Filter } from '../filters/Filter';
|
|
12
12
|
import globalWhitelistData from '../data/globalWhitelist.json';
|
|
13
13
|
export const useProfanityChecker = (config) => {
|
|
14
|
+
var _a;
|
|
14
15
|
const [result, setResult] = useState(null);
|
|
15
16
|
const filterConfig = useMemo(() => {
|
|
16
17
|
var _a;
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
if (effectiveConfig.allowObfuscatedMatch &&
|
|
20
|
-
effectiveConfig.wordBoundaries) {
|
|
18
|
+
const effective = Object.assign(Object.assign({}, (config !== null && config !== void 0 ? config : {})), { ignoreWords: globalWhitelistData.whitelist, fuzzyToleranceLevel: (_a = config === null || config === void 0 ? void 0 : config.fuzzyToleranceLevel) !== null && _a !== void 0 ? _a : 0.8 });
|
|
19
|
+
if (effective.allowObfuscatedMatch && effective.wordBoundaries) {
|
|
21
20
|
console.warn('[Glin-Profanity] Obfuscated match enabled → wordBoundaries will be ignored internally.');
|
|
22
21
|
}
|
|
23
|
-
return
|
|
22
|
+
return effective;
|
|
24
23
|
}, [config]);
|
|
25
24
|
const filter = useMemo(() => new Filter(filterConfig), [filterConfig]);
|
|
26
25
|
const checkText = (text) => {
|
|
26
|
+
var _a;
|
|
27
27
|
const checkResult = filter.checkProfanity(text);
|
|
28
|
+
// Filter based on minSeverity (if provided)
|
|
29
|
+
const filteredWords = (config === null || config === void 0 ? void 0 : config.minSeverity) && checkResult.severityMap
|
|
30
|
+
? checkResult.profaneWords.filter((word) => checkResult.severityMap &&
|
|
31
|
+
checkResult.severityMap[word] >= config.minSeverity)
|
|
32
|
+
: checkResult.profaneWords;
|
|
33
|
+
// Optional auto-replace
|
|
34
|
+
const autoReplaced = (config === null || config === void 0 ? void 0 : config.autoReplace) && checkResult.processedText
|
|
35
|
+
? checkResult.processedText
|
|
36
|
+
: text;
|
|
28
37
|
setResult(checkResult);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
(_a = config === null || config === void 0 ? void 0 : config.customActions) === null || _a === void 0 ? void 0 : _a.call(config, checkResult);
|
|
39
|
+
return Object.assign(Object.assign({}, checkResult), { filteredWords,
|
|
40
|
+
autoReplaced });
|
|
32
41
|
};
|
|
33
42
|
const checkTextAsync = (text) => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
43
|
return new Promise((resolve) => {
|
|
35
|
-
const checkResult =
|
|
36
|
-
setResult(checkResult);
|
|
37
|
-
if (config === null || config === void 0 ? void 0 : config.customActions) {
|
|
38
|
-
config.customActions(checkResult);
|
|
39
|
-
}
|
|
44
|
+
const checkResult = checkText(text); // sync call
|
|
40
45
|
resolve(checkResult);
|
|
41
46
|
});
|
|
42
47
|
});
|
|
48
|
+
const isWordProfane = (word) => {
|
|
49
|
+
return filter.checkProfanity(word).containsProfanity;
|
|
50
|
+
};
|
|
43
51
|
const reset = () => setResult(null);
|
|
44
52
|
return {
|
|
45
53
|
result,
|
|
46
54
|
checkText,
|
|
47
55
|
checkTextAsync,
|
|
48
56
|
reset,
|
|
57
|
+
isDirty: (_a = result === null || result === void 0 ? void 0 : result.containsProfanity) !== null && _a !== void 0 ? _a : false,
|
|
58
|
+
isWordProfane,
|
|
49
59
|
};
|
|
50
60
|
};
|
|
51
61
|
//# sourceMappingURL=useProfanityChecker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useProfanityChecker.js","sourceRoot":"","sources":["../../../src/hooks/useProfanityChecker.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"useProfanityChecker.js","sourceRoot":"","sources":["../../../src/hooks/useProfanityChecker.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAgB,MAAM,mBAAmB,CAAC;AAEzD,OAAO,mBAAmB,MAAM,8BAA8B,CAAC;AAiB/D,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,MAA+B,EAAE,EAAE;;IACrE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA8B,IAAI,CAAC,CAAC;IAExE,MAAM,YAAY,GAAiB,OAAO,CAAC,GAAG,EAAE;;QAC9C,MAAM,SAAS,mCACV,CAAC,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,EAAE,CAAC,KACjB,WAAW,EAAE,mBAAmB,CAAC,SAAS,EAC1C,mBAAmB,EAAE,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,mBAAmB,mCAAI,GAAG,GACxD,CAAC;QAEF,IAAI,SAAS,CAAC,oBAAoB,IAAI,SAAS,CAAC,cAAc,EAAE,CAAC;YAC/D,OAAO,CAAC,IAAI,CACV,wFAAwF,CACzF,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAEvE,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE;;QACjC,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAEhD,4CAA4C;QAC5C,MAAM,aAAa,GACjB,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,WAAW,KAAI,WAAW,CAAC,WAAW;YAC5C,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,CAC7B,CAAC,IAAI,EAAE,EAAE,CACP,WAAW,CAAC,WAAW;gBACvB,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,WAAY,CACvD;YACH,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC;QAE/B,wBAAwB;QACxB,MAAM,YAAY,GAChB,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,WAAW,KAAI,WAAW,CAAC,aAAa;YAC9C,CAAC,CAAC,WAAW,CAAC,aAAa;YAC3B,CAAC,CAAC,IAAI,CAAC;QAEX,SAAS,CAAC,WAAW,CAAC,CAAC;QACvB,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,aAAa,uDAAG,WAAW,CAAC,CAAC;QAErC,uCACK,WAAW,KACd,aAAa;YACb,YAAY,IACZ;IACJ,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,CAAO,IAAY,EAAE,EAAE;QAC5C,OAAO,IAAI,OAAO,CAAuB,CAAC,OAAO,EAAE,EAAE;YACnD,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY;YACjD,OAAO,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC,CAAA,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE;QACrC,OAAO,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC;IACvD,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEpC,OAAO;QACL,MAAM;QACN,SAAS;QACT,cAAc;QACd,KAAK;QACL,OAAO,EAAE,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,iBAAiB,mCAAI,KAAK;QAC3C,aAAa;KACd,CAAC;AACJ,CAAC,CAAC"}
|
package/lib/esm/index.d.ts
CHANGED
package/lib/esm/index.js
CHANGED
package/lib/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
|
package/lib/esm/types/types.d.ts
CHANGED
|
@@ -3,12 +3,19 @@ export declare enum SeverityLevel {
|
|
|
3
3
|
Fuzzy = 2,
|
|
4
4
|
Merged = 3
|
|
5
5
|
}
|
|
6
|
+
export type SeverityLabel = keyof typeof SeverityLevel;
|
|
7
|
+
export interface FilteredProfanityResult {
|
|
8
|
+
result: CheckProfanityResult;
|
|
9
|
+
filteredWords: string[];
|
|
10
|
+
}
|
|
6
11
|
export interface CheckProfanityResult {
|
|
7
12
|
containsProfanity: boolean;
|
|
8
13
|
profaneWords: string[];
|
|
9
14
|
processedText?: string;
|
|
10
|
-
severityMap?:
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
severityMap?: Record<string, SeverityLevel>;
|
|
16
|
+
matchContexts?: {
|
|
17
|
+
word: string;
|
|
18
|
+
context: string;
|
|
19
|
+
}[];
|
|
13
20
|
}
|
|
14
21
|
export type Language = 'arabic' | 'chinese' | 'czech' | 'danish' | 'english' | 'esperanto' | 'finnish' | 'french' | 'german' | 'hindi' | 'hungarian' | 'italian' | 'japanese' | 'korean' | 'norwegian' | 'persian' | 'polish' | 'portuguese' | 'russian' | 'turkish' | 'swedish' | 'thai';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glin-profanity",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Glin-Profanity is a lightweight and efficient npm package designed to detect and filter profane language in text inputs across multiple languages. Whether you’re building a chat application, a comment section, or any platform where user-generated content is involved, Glin-Profanity helps you maintain a clean and respectful environment.",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/esm/index.js",
|