@sideid/id-profanity-filter 1.1.0 → 1.9.4

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.
@@ -1,129 +1,129 @@
1
- import { FilterOptions, FilterResult, ProfanityWord } from '../types';
2
- import { findProfanity, findProfanityWithMetadata } from './matcher';
3
-
4
- /**
5
- * Menyensor kata kotor dalam teks
6
- *
7
- * @param text Teks yang akan disensor
8
- * @param options Opsi untuk filter
9
- * @returns FilterResult dengan hasil filter
10
- */
11
- export function filter(
12
- text: string,
13
- options: FilterOptions = {},
14
- ): FilterResult {
15
- const {
16
- replaceWith = '*',
17
- fullWordCensor = true,
18
- detectLeetSpeak = true,
19
- whitelist = [],
20
- checkSubstring = false,
21
- } = options;
22
-
23
- const matches = findProfanity(text, {
24
- ...options,
25
- detectLeetSpeak,
26
- whitelist,
27
- checkSubstring,
28
- });
29
-
30
- const matchDetails = findProfanityWithMetadata(text, options);
31
-
32
- if (matches.length === 0) {
33
- return {
34
- filtered: text,
35
- censored: 0,
36
- replacements: [],
37
- };
38
- }
39
-
40
- let filteredText = text;
41
-
42
- const replacements: Array<{
43
- original: string;
44
- censored: string;
45
- metadata?: ProfanityWord;
46
- }> = [];
47
-
48
- matches.forEach((word) => {
49
- const metadata = matchDetails.find(
50
- (m) =>
51
- m.word.toLowerCase() === word.toLowerCase() ||
52
- (m.aliases &&
53
- m.aliases.some(
54
- (alias) => alias.toLowerCase() === word.toLowerCase(),
55
- )),
56
- );
57
-
58
- const regex = new RegExp(`\\b${escapeRegExp(word)}\\b`, 'gi');
59
-
60
- let match;
61
- while ((match = regex.exec(filteredText)) !== null) {
62
- const originalWord = match[0];
63
-
64
- if (whitelist.includes(originalWord.toLowerCase())) continue;
65
-
66
- const censoredWord = fullWordCensor
67
- ? replaceWith.repeat(originalWord.length)
68
- : censorPartialWord(originalWord, replaceWith);
69
-
70
- replacements.push({
71
- original: originalWord,
72
- censored: censoredWord,
73
- metadata,
74
- });
75
-
76
- const replaceRegex = new RegExp(
77
- `\\b${escapeRegExp(originalWord)}\\b`,
78
- 'g',
79
- );
80
- filteredText = filteredText.replace(replaceRegex, censoredWord);
81
- }
82
- });
83
-
84
- // if (detectLeetSpeak) {
85
- // }
86
-
87
- return {
88
- filtered: filteredText,
89
- censored: replacements.length,
90
- replacements,
91
- };
92
- }
93
-
94
- /**
95
- * Memeriksa apakah teks mengandung kata kotor
96
- *
97
- * @param text Teks yang akan diperiksa
98
- * @param options Opsi untuk pemeriksaan
99
- * @returns Boolean apakah teks mengandung kata kotor
100
- */
101
- export function isProfane(text: string, options: FilterOptions = {}): boolean {
102
- const matches = findProfanity(text, options);
103
- return matches.length > 0;
104
- }
105
-
106
- /**
107
- * Escape karakter khusus regex
108
- *
109
- * @param string String untuk di-escape
110
- * @returns String yang telah di-escape
111
- */
112
- function escapeRegExp(string: string): string {
113
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
114
- }
115
-
116
- /**
117
- * Menyensor sebagian kata
118
- * @param word Kata yang akan disensor
119
- * @param replaceChar Karakter pengganti
120
- * @returns Kata yang sudah disensor sebagian
121
- */
122
- function censorPartialWord(word: string, replaceChar: string): string {
123
- if (word.length <= 2) {
124
- return replaceChar.repeat(word.length);
125
- }
126
-
127
- // Simpan huruf pertama dan terakhir, sensor yang lain
128
- return word[0] + replaceChar.repeat(word.length - 2) + word[word.length - 1];
129
- }
1
+ import { FilterOptions, FilterResult, ProfanityWord } from "../types";
2
+ import { findProfanity, findProfanityWithMetadata } from "./matcher";
3
+ import { censorWord, escapeRegExp, normalizeText } from "../utils/stringUtils";
4
+ import { createWordRegex } from "../utils/regexUtils";
5
+ import {
6
+ DEFAULT_OPTIONS,
7
+ makeRandomGrawlixString,
8
+ getRandomGrawlix,
9
+ } from "../config/options";
10
+
11
+ /**
12
+ * Menyensor kata kotor dalam teks
13
+ *
14
+ * @param text Teks yang akan disensor
15
+ * @param options Opsi untuk filter
16
+ * @returns FilterResult dengan hasil filter
17
+ */
18
+ export function filter(
19
+ text: string,
20
+ options: FilterOptions = {},
21
+ ): FilterResult {
22
+ const {
23
+ replaceWith = "*",
24
+ fullWordCensor = true,
25
+ detectLeetSpeak = true,
26
+ whitelist = [],
27
+ checkSubstring = false,
28
+ useRandomGrawlix = false,
29
+ keepFirstAndLast = false,
30
+ indonesianVariation = false,
31
+ } = { ...DEFAULT_OPTIONS, ...options };
32
+
33
+ const matches = findProfanity(text, {
34
+ ...options,
35
+ detectLeetSpeak,
36
+ whitelist,
37
+ checkSubstring,
38
+ indonesianVariation,
39
+ });
40
+
41
+ const matchDetails = findProfanityWithMetadata(text, options);
42
+
43
+ if (matches.length === 0) {
44
+ return {
45
+ filtered: text,
46
+ censored: 0,
47
+ replacements: [],
48
+ };
49
+ }
50
+
51
+ let filteredText = text;
52
+
53
+ const replacements: Array<{
54
+ original: string;
55
+ censored: string;
56
+ metadata?: ProfanityWord;
57
+ }> = [];
58
+
59
+ matches.forEach((word) => {
60
+ const metadata = matchDetails.find(
61
+ (m) =>
62
+ m.word.toLowerCase() === word.toLowerCase() ||
63
+ (m.aliases &&
64
+ m.aliases.some(
65
+ (alias) => alias.toLowerCase() === word.toLowerCase(),
66
+ )),
67
+ );
68
+
69
+ const regex = createWordRegex(word, {
70
+ wholeWord: true,
71
+ caseSensitive: false,
72
+ leetSpeak: false,
73
+ detectSplit: false,
74
+ indonesianVariation: false,
75
+ });
76
+
77
+ let match;
78
+ const textToSearch = filteredText;
79
+
80
+ regex.lastIndex = 0;
81
+
82
+ while ((match = regex.exec(textToSearch)) !== null) {
83
+ const originalWord = match[0];
84
+
85
+ if (whitelist.includes(originalWord.toLowerCase())) continue;
86
+
87
+ let censoredWord;
88
+ if (useRandomGrawlix) {
89
+ censoredWord = makeRandomGrawlixString(originalWord.length);
90
+ } else {
91
+ censoredWord = censorWord(
92
+ originalWord,
93
+ replaceWith,
94
+ !fullWordCensor && keepFirstAndLast,
95
+ );
96
+ }
97
+
98
+ replacements.push({
99
+ original: originalWord,
100
+ censored: censoredWord,
101
+ metadata,
102
+ });
103
+
104
+ const replaceRegex = new RegExp(
105
+ `\\b${escapeRegExp(originalWord)}\\b`,
106
+ "g",
107
+ );
108
+ filteredText = filteredText.replace(replaceRegex, censoredWord);
109
+ }
110
+ });
111
+
112
+ return {
113
+ filtered: filteredText,
114
+ censored: replacements.length,
115
+ replacements,
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Memeriksa apakah teks mengandung kata kotor
121
+ *
122
+ * @param text Teks yang akan diperiksa
123
+ * @param options Opsi untuk pemeriksaan
124
+ * @returns Boolean apakah teks mengandung kata kotor
125
+ */
126
+ export function isProfane(text: string, options: FilterOptions = {}): boolean {
127
+ const matches = findProfanity(text, options);
128
+ return matches.length > 0;
129
+ }