@sideid/id-profanity-filter 0.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/.eslintrc.js +16 -0
- package/.github/workflows/ci.yml +0 -0
- package/CONTRIBUTING.md +151 -0
- package/LICENSE +21 -0
- package/README.md +285 -0
- package/dist/constants/categories/insult.d.ts +4 -0
- package/dist/constants/categories/sexual.d.ts +4 -0
- package/dist/constants/regions/batak.d.ts +4 -0
- package/dist/constants/regions/betawi.d.ts +4 -0
- package/dist/constants/regions/general.d.ts +4 -0
- package/dist/constants/regions/jawa.d.ts +4 -0
- package/dist/constants/regions/sunda.d.ts +4 -0
- package/dist/constants/wordList.d.ts +34 -0
- package/dist/core/analyzer.d.ts +54 -0
- package/dist/core/filter.d.ts +17 -0
- package/dist/core/matcher.d.ts +31 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.esm.js +1014 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +1031 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +69 -0
- package/examples/basic.ts +52 -0
- package/jest.config.js +10 -0
- package/package.json +51 -0
- package/prettierrc +7 -0
- package/rollup.config.js +35 -0
- package/src/config/options.ts +0 -0
- package/src/constants/categories/blasphemy.ts +0 -0
- package/src/constants/categories/disgusting.ts +0 -0
- package/src/constants/categories/drugs.ts +0 -0
- package/src/constants/categories/index.ts +31 -0
- package/src/constants/categories/insult.ts +114 -0
- package/src/constants/categories/profanity.ts +0 -0
- package/src/constants/categories/sexual.ts +100 -0
- package/src/constants/categories/slur.ts +0 -0
- package/src/constants/regions/aceh.ts +0 -0
- package/src/constants/regions/ambon.ts +0 -0
- package/src/constants/regions/bali.ts +0 -0
- package/src/constants/regions/banjar.ts +0 -0
- package/src/constants/regions/batak.ts +17 -0
- package/src/constants/regions/betawi.ts +39 -0
- package/src/constants/regions/bugis.ts +0 -0
- package/src/constants/regions/general.ts +111 -0
- package/src/constants/regions/index.ts +62 -0
- package/src/constants/regions/jawa.ts +102 -0
- package/src/constants/regions/lampung.ts +0 -0
- package/src/constants/regions/madura.ts +0 -0
- package/src/constants/regions/manado.ts +0 -0
- package/src/constants/regions/minang.ts +0 -0
- package/src/constants/regions/ntb.ts +0 -0
- package/src/constants/regions/ntt.ts +0 -0
- package/src/constants/regions/palembang.ts +0 -0
- package/src/constants/regions/papua.ts +0 -0
- package/src/constants/regions/sunda.ts +35 -0
- package/src/constants/wordList.ts +125 -0
- package/src/core/analyzer.ts +204 -0
- package/src/core/filter.ts +129 -0
- package/src/core/matcher.ts +267 -0
- package/src/index.ts +133 -0
- package/src/types/index.ts +115 -0
- package/src/utils/regexUtils.ts +0 -0
- package/src/utils/stringUtils.ts +0 -0
- package/tsconfig.json +115 -0
|
@@ -0,0 +1,1014 @@
|
|
|
1
|
+
const general = [
|
|
2
|
+
{
|
|
3
|
+
word: 'anjing',
|
|
4
|
+
category: 'profanity',
|
|
5
|
+
region: 'general',
|
|
6
|
+
severity: 0.7,
|
|
7
|
+
aliases: ['anjay', 'anjir', 'anying', 'njing', 'anj'],
|
|
8
|
+
description: 'Mengacu pada hewan anjing, digunakan sebagai umpatan',
|
|
9
|
+
context: 'Umpatan umum untuk menunjukkan kemarahan atau ketidaksetujuan',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
word: 'babi',
|
|
13
|
+
category: 'profanity',
|
|
14
|
+
region: 'general',
|
|
15
|
+
severity: 0.6,
|
|
16
|
+
aliases: ['bab1', 'b4b1'],
|
|
17
|
+
description: 'Mengacu pada hewan babi, digunakan sebagai umpatan',
|
|
18
|
+
context: 'Umpatan umum untuk menunjukkan kemarahan atau ketidaksetujuan',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
word: 'bangsat',
|
|
22
|
+
category: 'insult',
|
|
23
|
+
region: 'general',
|
|
24
|
+
severity: 0.8,
|
|
25
|
+
aliases: ['bangst', 'bngst', 'bgst'],
|
|
26
|
+
description: 'Secara harfiah berarti kutu busuk, digunakan sebagai umpatan untuk menyebut seseorang yang tidak bermoral',
|
|
27
|
+
context: 'Umpatan kasar untuk menyebut orang yang dianggap jahat atau merugikan',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
word: 'kontol',
|
|
31
|
+
category: 'sexual',
|
|
32
|
+
region: 'general',
|
|
33
|
+
severity: 0.9,
|
|
34
|
+
aliases: ['kntl', 'k0ntol', 'k0nt0l'],
|
|
35
|
+
description: 'Kata vulgar yang mengacu pada alat kelamin laki-laki',
|
|
36
|
+
context: 'Umpatan kasar atau istilah vulgar untuk alat kelamin',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
word: 'memek',
|
|
40
|
+
category: 'sexual',
|
|
41
|
+
region: 'general',
|
|
42
|
+
severity: 0.9,
|
|
43
|
+
aliases: ['mmk', 'memk'],
|
|
44
|
+
description: 'Kata vulgar yang mengacu pada alat kelamin perempuan',
|
|
45
|
+
context: 'Umpatan kasar atau istilah vulgar untuk alat kelamin',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
word: 'bego',
|
|
49
|
+
category: 'insult',
|
|
50
|
+
region: 'general',
|
|
51
|
+
severity: 0.5,
|
|
52
|
+
aliases: ['bgo', 'begok'],
|
|
53
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
54
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak pintar',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
word: 'tolol',
|
|
58
|
+
category: 'insult',
|
|
59
|
+
region: 'general',
|
|
60
|
+
severity: 0.6,
|
|
61
|
+
aliases: ['tll', 'tlol'],
|
|
62
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
63
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak pintar',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
word: 'bajingan',
|
|
67
|
+
category: 'insult',
|
|
68
|
+
region: 'general',
|
|
69
|
+
severity: 0.7,
|
|
70
|
+
aliases: ['bajingn', 'bjgn'],
|
|
71
|
+
description: 'Kata yang mengacu pada orang jahat atau tidak bermoral',
|
|
72
|
+
context: 'Hinaan untuk menyebut orang yang dianggap jahat atau tidak bermoral',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
word: 'goblok',
|
|
76
|
+
category: 'insult',
|
|
77
|
+
region: 'general',
|
|
78
|
+
severity: 0.6,
|
|
79
|
+
aliases: ['gblk', 'goblk'],
|
|
80
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
81
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak pintar',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
word: 'keparat',
|
|
85
|
+
category: 'insult',
|
|
86
|
+
region: 'general',
|
|
87
|
+
severity: 0.7,
|
|
88
|
+
aliases: ['kprt', 'keprat'],
|
|
89
|
+
description: 'Kata yang mengacu pada orang jahat atau tidak bermoral',
|
|
90
|
+
context: 'Hinaan untuk menyebut orang yang dianggap jahat atau tidak bermoral',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
word: 'bacot',
|
|
94
|
+
category: 'insult',
|
|
95
|
+
region: 'general',
|
|
96
|
+
severity: 0.5,
|
|
97
|
+
aliases: ['bcot', 'bacot2'],
|
|
98
|
+
description: 'Kata yang mengacu pada orang yang banyak bicara',
|
|
99
|
+
context: 'Hinaan untuk menyebut orang yang banyak bicara atau cerewet',
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
general.map((item) => item.word);
|
|
103
|
+
|
|
104
|
+
const jawa = [
|
|
105
|
+
{
|
|
106
|
+
word: 'asu',
|
|
107
|
+
category: 'profanity',
|
|
108
|
+
region: 'jawa',
|
|
109
|
+
severity: 0.7,
|
|
110
|
+
aliases: ['asyu', 'su'],
|
|
111
|
+
description: 'Secara harfiah berarti anjing dalam Bahasa Jawa',
|
|
112
|
+
context: 'Umpatan umum dalam Bahasa Jawa untuk menunjukkan kemarahan',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
word: 'jancok',
|
|
116
|
+
category: 'sexual',
|
|
117
|
+
region: 'jawa',
|
|
118
|
+
severity: 0.8,
|
|
119
|
+
aliases: ['jancuk', 'jncok', 'jancuk', 'jncuk', 'dancok', 'dancuk'],
|
|
120
|
+
description: 'Kata umpatan kasar dalam Bahasa Jawa',
|
|
121
|
+
context: 'Umpatan kasar yang umum digunakan di Jawa Timur',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
word: 'cuk',
|
|
125
|
+
category: 'sexual',
|
|
126
|
+
region: 'jawa',
|
|
127
|
+
severity: 0.7,
|
|
128
|
+
aliases: ['cok', 'cook'],
|
|
129
|
+
description: 'Singkatan dari jancok/jancuk',
|
|
130
|
+
context: 'Umpatan singkat yang umum digunakan di Jawa Timur',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
word: 'diancok',
|
|
134
|
+
category: 'sexual',
|
|
135
|
+
region: 'jawa',
|
|
136
|
+
severity: 0.8,
|
|
137
|
+
aliases: ['diancuk', 'dancok', 'ancok'],
|
|
138
|
+
description: 'Variasi dari jancok/jancuk',
|
|
139
|
+
context: 'Umpatan kasar yang umum digunakan di Jawa Timur',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
word: 'matamu',
|
|
143
|
+
category: 'insult',
|
|
144
|
+
region: 'jawa',
|
|
145
|
+
severity: 0.5,
|
|
146
|
+
aliases: ['mripat mu', 'matane'],
|
|
147
|
+
description: 'Secara harfiah berarti matamu, digunakan sebagai umpatan ringan',
|
|
148
|
+
context: 'Umpatan ringan untuk menanggapi sesuatu yang dianggap tidak benar',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
word: 'mbokne ancok',
|
|
152
|
+
category: 'insult',
|
|
153
|
+
region: 'jawa',
|
|
154
|
+
severity: 0.8,
|
|
155
|
+
aliases: ['mbokne', 'mbokneancok'],
|
|
156
|
+
description: 'Umpatan yang menyinggung ibu seseorang',
|
|
157
|
+
context: 'Umpatan kasar yang menyinggung orangtua orang lain',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
word: 'pekok',
|
|
161
|
+
category: 'insult',
|
|
162
|
+
region: 'jawa',
|
|
163
|
+
severity: 0.6,
|
|
164
|
+
aliases: ['pekak', 'pekilk'],
|
|
165
|
+
description: 'Kata hinaan yang menunjukkan kebodohan',
|
|
166
|
+
context: 'Hinaan untuk menyebut orang yang dianggap sangat bodoh',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
word: 'sempak',
|
|
170
|
+
category: 'disgusting',
|
|
171
|
+
region: 'jawa',
|
|
172
|
+
severity: 0.5,
|
|
173
|
+
aliases: ['sempok'],
|
|
174
|
+
description: 'Mengacu pada pakaian dalam',
|
|
175
|
+
context: 'Umpatan ringan yang dianggap jorok',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
word: 'taek',
|
|
179
|
+
category: 'disgusting',
|
|
180
|
+
region: 'jawa',
|
|
181
|
+
severity: 0.6,
|
|
182
|
+
aliases: ['tai', 'tahi', 'telek'],
|
|
183
|
+
description: 'Secara harfiah berarti kotoran/tinja',
|
|
184
|
+
context: 'Umpatan untuk menunjukkan sesuatu yang menjijikkan atau buruk',
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
word: 'ndhasmu',
|
|
188
|
+
category: 'insult',
|
|
189
|
+
region: 'jawa',
|
|
190
|
+
severity: 0.5,
|
|
191
|
+
aliases: ['ndas mu', 'dhasmu'],
|
|
192
|
+
description: 'Secara harfiah berarti kepalamu, digunakan sebagai umpatan ringan',
|
|
193
|
+
context: 'Umpatan ringan untuk menanggapi sesuatu yang dianggap tidak benar',
|
|
194
|
+
},
|
|
195
|
+
];
|
|
196
|
+
jawa.map((item) => item.word);
|
|
197
|
+
|
|
198
|
+
const sunda = [
|
|
199
|
+
{
|
|
200
|
+
word: 'bagong',
|
|
201
|
+
category: 'insult',
|
|
202
|
+
region: 'sunda',
|
|
203
|
+
severity: 0.5,
|
|
204
|
+
aliases: ['bagog'],
|
|
205
|
+
description: 'Secara harfiah berarti babi hutan, digunakan sebagai hinaan',
|
|
206
|
+
context: 'Hinaan untuk menyebut orang yang dianggap jorok atau rakus',
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
word: 'belegug',
|
|
210
|
+
category: 'insult',
|
|
211
|
+
region: 'sunda',
|
|
212
|
+
severity: 0.5,
|
|
213
|
+
aliases: ['belecuk', 'beledog'],
|
|
214
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
215
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak pintar',
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
word: 'goblog',
|
|
219
|
+
category: 'insult',
|
|
220
|
+
region: 'sunda',
|
|
221
|
+
severity: 0.6,
|
|
222
|
+
aliases: ['goblok', 'golbok'],
|
|
223
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
224
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak pintar',
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
sunda.map((item) => item.word);
|
|
228
|
+
|
|
229
|
+
const betawi = [
|
|
230
|
+
{
|
|
231
|
+
word: 'jablay',
|
|
232
|
+
category: 'sexual',
|
|
233
|
+
region: 'betawi',
|
|
234
|
+
severity: 0.7,
|
|
235
|
+
aliases: ['jabl4y', 'jalay'],
|
|
236
|
+
description: 'Singkatan dari "jarang dibelai", istilah untuk perempuan yang mudah didekati',
|
|
237
|
+
context: 'Hinaan yang merendahkan untuk wanita',
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
word: 'udik',
|
|
241
|
+
category: 'insult',
|
|
242
|
+
region: 'betawi',
|
|
243
|
+
severity: 0.5,
|
|
244
|
+
aliases: ['kampungan', 'ndeso'],
|
|
245
|
+
description: 'Kata yang mengacu pada seseorang yang dianggap ketinggalan zaman atau tidak modern',
|
|
246
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak modern atau kampungan',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
word: 'perek',
|
|
250
|
+
category: 'sexual',
|
|
251
|
+
region: 'betawi',
|
|
252
|
+
severity: 0.7,
|
|
253
|
+
aliases: ['perempuan eksperimen', 'prk'],
|
|
254
|
+
description: 'Istilah untuk perempuan yang dianggap memiliki moral yang rendah',
|
|
255
|
+
context: 'Hinaan yang merendahkan untuk wanita',
|
|
256
|
+
},
|
|
257
|
+
];
|
|
258
|
+
betawi.map((item) => item.word);
|
|
259
|
+
|
|
260
|
+
const sexual = [
|
|
261
|
+
...general.filter((word) => word.category === 'sexual'),
|
|
262
|
+
...jawa.filter((word) => word.category === 'sexual'),
|
|
263
|
+
...sunda.filter((word) => word.category === 'sexual'),
|
|
264
|
+
...betawi.filter((word) => word.category === 'sexual'),
|
|
265
|
+
{
|
|
266
|
+
word: 'bokep',
|
|
267
|
+
category: 'sexual',
|
|
268
|
+
region: 'general',
|
|
269
|
+
severity: 0.7,
|
|
270
|
+
aliases: ['bkp', 'bokap'],
|
|
271
|
+
description: 'Istilah untuk video atau konten pornografi',
|
|
272
|
+
context: 'Kata yang mengacu pada materi pornografi',
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
word: 'coli',
|
|
276
|
+
category: 'sexual',
|
|
277
|
+
region: 'general',
|
|
278
|
+
severity: 0.8,
|
|
279
|
+
aliases: ['col', 'coly'],
|
|
280
|
+
description: 'Istilah untuk masturbasi laki-laki',
|
|
281
|
+
context: 'Kata vulgar yang merujuk pada aktivitas seksual pribadi',
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
word: 'desah',
|
|
285
|
+
category: 'sexual',
|
|
286
|
+
region: 'general',
|
|
287
|
+
severity: 0.6,
|
|
288
|
+
aliases: ['ds4h', 'dsh'],
|
|
289
|
+
description: 'Istilah untuk suara yang dibuat selama aktivitas seksual',
|
|
290
|
+
context: 'Dapat menjadi vulgar tergantung konteks penggunaan',
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
word: 'seks',
|
|
294
|
+
category: 'sexual',
|
|
295
|
+
region: 'general',
|
|
296
|
+
severity: 0.5,
|
|
297
|
+
aliases: ['sex', 'ML'],
|
|
298
|
+
description: 'Istilah untuk aktivitas seksual',
|
|
299
|
+
context: 'Dapat menjadi vulgar tergantung konteks penggunaan',
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
word: 'itil',
|
|
303
|
+
category: 'sexual',
|
|
304
|
+
region: 'general',
|
|
305
|
+
severity: 0.9,
|
|
306
|
+
aliases: ['itl', 'itul'],
|
|
307
|
+
description: 'Kata vulgar yang mengacu pada bagian dari alat kelamin perempuan',
|
|
308
|
+
context: 'Kata vulgar yang merujuk pada anatomi seksual',
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
word: 'kondom',
|
|
312
|
+
category: 'sexual',
|
|
313
|
+
region: 'general',
|
|
314
|
+
severity: 0.5,
|
|
315
|
+
aliases: ['kndm', 'kondom', 'cd'],
|
|
316
|
+
description: 'Alat kontrasepsi',
|
|
317
|
+
context: 'Dapat menjadi vulgar tergantung konteks penggunaan',
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
word: 'ngewe',
|
|
321
|
+
category: 'sexual',
|
|
322
|
+
region: 'general',
|
|
323
|
+
severity: 0.9,
|
|
324
|
+
aliases: ['ngew', 'we'],
|
|
325
|
+
description: 'Istilah kasar untuk aktivitas seksual',
|
|
326
|
+
context: 'Kata vulgar yang merujuk pada aktivitas seksual',
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
word: 'puki',
|
|
330
|
+
category: 'sexual',
|
|
331
|
+
region: 'general',
|
|
332
|
+
severity: 0.9,
|
|
333
|
+
aliases: ['puk', 'pukih'],
|
|
334
|
+
description: 'Kata vulgar yang mengacu pada alat kelamin perempuan',
|
|
335
|
+
context: 'Kata vulgar yang merujuk pada anatomi seksual',
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
word: 'xxx',
|
|
339
|
+
category: 'sexual',
|
|
340
|
+
region: 'general',
|
|
341
|
+
severity: 0.6,
|
|
342
|
+
aliases: ['xXx', 'triplex'],
|
|
343
|
+
description: 'Simbol yang sering digunakan untuk menandai konten pornografi',
|
|
344
|
+
context: 'Digunakan untuk menandai konten seksual eksplisit',
|
|
345
|
+
},
|
|
346
|
+
];
|
|
347
|
+
sexual.map((item) => item.word);
|
|
348
|
+
|
|
349
|
+
const insult = [
|
|
350
|
+
...general.filter((word) => word.category === 'insult'),
|
|
351
|
+
...jawa.filter((word) => word.category === 'insult'),
|
|
352
|
+
...sunda.filter((word) => word.category === 'insult'),
|
|
353
|
+
...betawi.filter((word) => word.category === 'insult'),
|
|
354
|
+
{
|
|
355
|
+
word: 'idiot',
|
|
356
|
+
category: 'insult',
|
|
357
|
+
region: 'general',
|
|
358
|
+
severity: 0.6,
|
|
359
|
+
aliases: ['idi0t', 'idot'],
|
|
360
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
361
|
+
context: 'Hinaan untuk menyebut orang yang dianggap sangat tidak pintar',
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
word: 'dungu',
|
|
365
|
+
category: 'insult',
|
|
366
|
+
region: 'general',
|
|
367
|
+
severity: 0.5,
|
|
368
|
+
aliases: ['dngu', 'dongu'],
|
|
369
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
370
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak pintar',
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
word: 'sinting',
|
|
374
|
+
category: 'insult',
|
|
375
|
+
region: 'general',
|
|
376
|
+
severity: 0.6,
|
|
377
|
+
aliases: ['sintng', 'senteng'],
|
|
378
|
+
description: 'Kata yang mengacu pada kegilaan atau ketidakwarasan seseorang',
|
|
379
|
+
context: 'Hinaan untuk menyebut orang yang dianggap gila atau tidak waras',
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
word: 'sarap',
|
|
383
|
+
category: 'insult',
|
|
384
|
+
region: 'general',
|
|
385
|
+
severity: 0.6,
|
|
386
|
+
aliases: ['saraf', 'srap'],
|
|
387
|
+
description: 'Kata yang mengacu pada kegilaan atau ketidakwarasan seseorang',
|
|
388
|
+
context: 'Hinaan untuk menyebut orang yang dianggap gila atau tidak waras',
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
word: 'geblek',
|
|
392
|
+
category: 'insult',
|
|
393
|
+
region: 'general',
|
|
394
|
+
severity: 0.5,
|
|
395
|
+
aliases: ['gblk', 'geblk'],
|
|
396
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
397
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak pintar',
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
word: 'kampungan',
|
|
401
|
+
category: 'insult',
|
|
402
|
+
region: 'general',
|
|
403
|
+
severity: 0.5,
|
|
404
|
+
aliases: ['kmpngn', 'kamphungan'],
|
|
405
|
+
description: 'Kata yang mengacu pada ketidaksopanan atau kenaifan seseorang',
|
|
406
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak modern atau primitif',
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
word: 'udik',
|
|
410
|
+
category: 'insult',
|
|
411
|
+
region: 'general',
|
|
412
|
+
severity: 0.5,
|
|
413
|
+
aliases: ['udhik', 'udek'],
|
|
414
|
+
description: 'Kata yang mengacu pada ketidaksopanan atau kenaifan seseorang',
|
|
415
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak modern atau primitif',
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
word: 'dongo',
|
|
419
|
+
category: 'insult',
|
|
420
|
+
region: 'general',
|
|
421
|
+
severity: 0.5,
|
|
422
|
+
aliases: ['donggo', 'dungu'],
|
|
423
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
424
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak pintar',
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
word: 'tolol',
|
|
428
|
+
category: 'insult',
|
|
429
|
+
region: 'general',
|
|
430
|
+
severity: 0.6,
|
|
431
|
+
aliases: ['tol0l', 'tollo', 'tlol'],
|
|
432
|
+
description: 'Kata yang mengacu pada kebodohan seseorang',
|
|
433
|
+
context: 'Hinaan untuk menyebut orang yang dianggap tidak pintar',
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
word: 'brengsek',
|
|
437
|
+
category: 'insult',
|
|
438
|
+
region: 'general',
|
|
439
|
+
severity: 0.7,
|
|
440
|
+
aliases: ['brengskek', 'brengsik', 'brengzek'],
|
|
441
|
+
description: 'Kata yang mengacu pada kelakuan buruk atau tidak bermoral',
|
|
442
|
+
context: 'Hinaan untuk menyebut orang yang dianggap memiliki kelakuan buruk',
|
|
443
|
+
},
|
|
444
|
+
];
|
|
445
|
+
insult.map((item) => item.word);
|
|
446
|
+
|
|
447
|
+
const batak = [
|
|
448
|
+
{
|
|
449
|
+
word: 'sundel',
|
|
450
|
+
category: 'sexual',
|
|
451
|
+
region: 'batak',
|
|
452
|
+
severity: 0.8,
|
|
453
|
+
aliases: ['sundal'],
|
|
454
|
+
description: 'Kata kasar untuk menyebut pekerja seks komersial',
|
|
455
|
+
context: 'Hinaan kasar untuk wanita',
|
|
456
|
+
},
|
|
457
|
+
];
|
|
458
|
+
batak.map((item) => item.word);
|
|
459
|
+
|
|
460
|
+
const wordObjects = [
|
|
461
|
+
...general,
|
|
462
|
+
...jawa,
|
|
463
|
+
...sunda,
|
|
464
|
+
...betawi,
|
|
465
|
+
...batak,
|
|
466
|
+
// ...minang,
|
|
467
|
+
// ...bali,
|
|
468
|
+
// ...madura,
|
|
469
|
+
// ...bugis,
|
|
470
|
+
// ...aceh,
|
|
471
|
+
// ...ambon,
|
|
472
|
+
// ...papua,
|
|
473
|
+
// ...manado,
|
|
474
|
+
// ...banjar,
|
|
475
|
+
// ...palembang,
|
|
476
|
+
// ...lampung,
|
|
477
|
+
// ...ntt,
|
|
478
|
+
// ...ntb,
|
|
479
|
+
];
|
|
480
|
+
wordObjects.map((item) => item.word);
|
|
481
|
+
/**
|
|
482
|
+
* Kata-kata dengan tingkat keparahan tinggi (subset dari semua kata)
|
|
483
|
+
*/
|
|
484
|
+
wordObjects
|
|
485
|
+
.filter((word) => word.severity >= 0.8)
|
|
486
|
+
.map((item) => item.word);
|
|
487
|
+
|
|
488
|
+
function findProfanity(text, options = {}) {
|
|
489
|
+
const { wordList = [], detectLeetSpeak = true, checkSubstring = false, whitelist = [], categories, regions, severityThreshold = 0, } = options;
|
|
490
|
+
const normalizedText = normalizeText(text);
|
|
491
|
+
let wordsToCheck = wordList;
|
|
492
|
+
if (wordsToCheck.length === 0) {
|
|
493
|
+
if (categories || regions || severityThreshold > 0) {
|
|
494
|
+
wordsToCheck = wordObjects
|
|
495
|
+
.filter((word) => {
|
|
496
|
+
const matchCategory = categories
|
|
497
|
+
? categories.includes(word.category)
|
|
498
|
+
: true;
|
|
499
|
+
const matchRegion = regions ? regions.includes(word.region) : true;
|
|
500
|
+
const matchSeverity = word.severity >= severityThreshold;
|
|
501
|
+
return matchCategory && matchRegion && matchSeverity;
|
|
502
|
+
})
|
|
503
|
+
.map((word) => word.word);
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
wordsToCheck = wordObjects.map((word) => word.word);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
wordsToCheck = wordsToCheck.filter((word) => !whitelist.includes(word.toLocaleLowerCase()));
|
|
510
|
+
if (wordsToCheck.length === 0) {
|
|
511
|
+
return [];
|
|
512
|
+
}
|
|
513
|
+
const matches = new Set();
|
|
514
|
+
wordsToCheck.forEach((word) => {
|
|
515
|
+
const pattern = checkSubstring ? word : `\\b${escapeRegExp$2(word)}\\b`;
|
|
516
|
+
const regex = new RegExp(pattern, 'gi');
|
|
517
|
+
let match;
|
|
518
|
+
while ((match = regex.exec(normalizedText)) !== null) {
|
|
519
|
+
matches.add(match[0].toLowerCase());
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
// jika detectLeetSpeak diaktifkan, cari variasi leet speak
|
|
523
|
+
if (detectLeetSpeak) {
|
|
524
|
+
wordsToCheck.forEach((word) => {
|
|
525
|
+
// Cek leet speak
|
|
526
|
+
const leetPattern = createLeetSpeakPattern(word);
|
|
527
|
+
const leetRegex = new RegExp(checkSubstring ? leetPattern : `\\b${leetPattern}\\b`, 'gi');
|
|
528
|
+
while ((leetRegex.exec(text)) !== null) {
|
|
529
|
+
matches.add(word.toLowerCase());
|
|
530
|
+
}
|
|
531
|
+
// cek karakter yang dipisah
|
|
532
|
+
const evasionPattern = createEvasionPattern(word);
|
|
533
|
+
const evasionRegex = new RegExp(evasionPattern, 'gi');
|
|
534
|
+
while ((evasionRegex.exec(text)) !== null) {
|
|
535
|
+
matches.add(word.toLowerCase());
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
return Array.from(matches);
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Menormalisasi teks untuk perbandingan
|
|
543
|
+
*
|
|
544
|
+
* @param text Teks untuk dinormalisasi
|
|
545
|
+
* @returns Teks yang dinormalisasi
|
|
546
|
+
*/
|
|
547
|
+
function normalizeText(text) {
|
|
548
|
+
return text
|
|
549
|
+
.toLowerCase()
|
|
550
|
+
.normalize('NFD') // Normalisasi Unicode
|
|
551
|
+
.replace(/[\u0300-\u036f]/g, '') // Hapus diacritic marks
|
|
552
|
+
.trim();
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Escape karakter khusus dalam regex
|
|
556
|
+
*
|
|
557
|
+
* @param string String untuk di-escape
|
|
558
|
+
* @returns String yang sudah di-escape
|
|
559
|
+
*/
|
|
560
|
+
function escapeRegExp$2(string) {
|
|
561
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Pattern untuk leet speak
|
|
565
|
+
*
|
|
566
|
+
* @param word Kata untuk dibuat pattern leet speak
|
|
567
|
+
* @return Pattern regex untuk leet speak
|
|
568
|
+
*/
|
|
569
|
+
function createLeetSpeakPattern(word) {
|
|
570
|
+
const leetMap = {
|
|
571
|
+
a: ['a', '4', '@'],
|
|
572
|
+
b: ['b', '8', '6'],
|
|
573
|
+
c: ['c', '<', '(', '{'],
|
|
574
|
+
e: ['e', '3'],
|
|
575
|
+
g: ['g', '9'],
|
|
576
|
+
i: ['i', '1', '!'],
|
|
577
|
+
l: ['l', '1', '|'],
|
|
578
|
+
o: ['o', '0'],
|
|
579
|
+
s: ['s', '5', '$'],
|
|
580
|
+
t: ['t', '7', '+'],
|
|
581
|
+
z: ['z', '2'],
|
|
582
|
+
};
|
|
583
|
+
return word
|
|
584
|
+
.split('')
|
|
585
|
+
.map((char) => {
|
|
586
|
+
const lowerChar = char.toLowerCase();
|
|
587
|
+
const replacements = leetMap[lowerChar];
|
|
588
|
+
if (replacements && replacements.length > 0) {
|
|
589
|
+
return `[${replacements.join('')}]`;
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
return escapeRegExp$2(char);
|
|
593
|
+
}
|
|
594
|
+
})
|
|
595
|
+
.join('');
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Pattern untuk deteksi upaya menghindari filter
|
|
599
|
+
*
|
|
600
|
+
* @param word Kata untuk dibuat pattern evasion
|
|
601
|
+
* @return Pattern regex untuk evasion
|
|
602
|
+
*/
|
|
603
|
+
function createEvasionPattern(word) {
|
|
604
|
+
return word
|
|
605
|
+
.split('')
|
|
606
|
+
.map((char) => escapeRegExp$2(char))
|
|
607
|
+
.join('[\\s\\-._*+]?');
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Mencari kata kotor lengkap dengan metadata
|
|
611
|
+
*
|
|
612
|
+
* @param text Teks yang akan diperika
|
|
613
|
+
* @param options Opsi utnuk pencarian kata kotor
|
|
614
|
+
* @return Array dari objek kata kotor yang ditemukan
|
|
615
|
+
*/
|
|
616
|
+
function findProfanityWithMetadata(text, options = {}) {
|
|
617
|
+
const matches = findProfanity(text, options);
|
|
618
|
+
if (matches.length === 0) {
|
|
619
|
+
return [];
|
|
620
|
+
}
|
|
621
|
+
return matches
|
|
622
|
+
.map((word) => {
|
|
623
|
+
const wordObject = wordObjects.find((obj) => obj.word.toLowerCase() === word.toLowerCase() ||
|
|
624
|
+
(obj.aliases &&
|
|
625
|
+
obj.aliases.some((alias) => alias.toLowerCase() === word.toLowerCase())));
|
|
626
|
+
return wordObject;
|
|
627
|
+
})
|
|
628
|
+
.filter((word) => word !== undefined);
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Mencari kategory kata kotor yang ada dalam teks
|
|
632
|
+
*
|
|
633
|
+
* @param text matchDetails Hasil pencarian dari fingProfanityWithMetadata()
|
|
634
|
+
* @param options Opsi untuk pencarian kategori
|
|
635
|
+
*/
|
|
636
|
+
function findCategories(matchDetails) {
|
|
637
|
+
const categories = new Set();
|
|
638
|
+
matchDetails.forEach((word) => {
|
|
639
|
+
categories.add(word.category);
|
|
640
|
+
});
|
|
641
|
+
return Array.from(categories);
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Mencari region kata kotor yang ada dalam teks
|
|
645
|
+
*
|
|
646
|
+
* @param text matchDetails Hasil pencarian dari fingProfanityWithMetadata()
|
|
647
|
+
* @param options Opsi untuk pencarian region
|
|
648
|
+
*/
|
|
649
|
+
function findRegions(matchDetails) {
|
|
650
|
+
const regions = new Set();
|
|
651
|
+
matchDetails.forEach((word) => {
|
|
652
|
+
regions.add(word.region);
|
|
653
|
+
});
|
|
654
|
+
return Array.from(regions);
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Menghitung tingkat keparahan kata kotor yang ditemukan
|
|
658
|
+
*
|
|
659
|
+
* @param matchDetails Hasil pencarian dari findProfanityWithMetadata()
|
|
660
|
+
* @return Skor keparahan dari 0-1
|
|
661
|
+
*/
|
|
662
|
+
function calculateSeverity(matchDetails) {
|
|
663
|
+
if (matchDetails.length === 0) {
|
|
664
|
+
return 0;
|
|
665
|
+
}
|
|
666
|
+
const countFactor = Math.min(matchDetails.length / 10, 1); // Maksimal 10 kata
|
|
667
|
+
const categoryWeights = {
|
|
668
|
+
sexual: 0.9,
|
|
669
|
+
blasphemy: 0.9,
|
|
670
|
+
slur: 0.8,
|
|
671
|
+
profanity: 0.7,
|
|
672
|
+
insult: 0.6,
|
|
673
|
+
drugs: 0.5,
|
|
674
|
+
disgusting: 0.5,
|
|
675
|
+
};
|
|
676
|
+
let severitySum = 0;
|
|
677
|
+
matchDetails.forEach((word) => {
|
|
678
|
+
const categoryWeight = categoryWeights[word.category] || 0.5;
|
|
679
|
+
const wordSeverity = word.severity * categoryWeight;
|
|
680
|
+
severitySum += wordSeverity;
|
|
681
|
+
});
|
|
682
|
+
const severityAvg = severitySum / matchDetails.length;
|
|
683
|
+
// Gabungkan jumlah kata dan keparahan rata-rata
|
|
684
|
+
// 70% keparahan kata + 30% faktor jumlah
|
|
685
|
+
return 0.7 * severityAvg + 0.3 * countFactor;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Menyensor kata kotor dalam teks
|
|
690
|
+
*
|
|
691
|
+
* @param text Teks yang akan disensor
|
|
692
|
+
* @param options Opsi untuk filter
|
|
693
|
+
* @returns FilterResult dengan hasil filter
|
|
694
|
+
*/
|
|
695
|
+
function filter(text, options = {}) {
|
|
696
|
+
const { replaceWith = '*', fullWordCensor = true, detectLeetSpeak = true, whitelist = [], checkSubstring = false, } = options;
|
|
697
|
+
const matches = findProfanity(text, {
|
|
698
|
+
...options,
|
|
699
|
+
detectLeetSpeak,
|
|
700
|
+
whitelist,
|
|
701
|
+
checkSubstring,
|
|
702
|
+
});
|
|
703
|
+
const matchDetails = findProfanityWithMetadata(text, options);
|
|
704
|
+
if (matches.length === 0) {
|
|
705
|
+
return {
|
|
706
|
+
filtered: text,
|
|
707
|
+
censored: 0,
|
|
708
|
+
replacements: [],
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
let filteredText = text;
|
|
712
|
+
const replacements = [];
|
|
713
|
+
matches.forEach((word) => {
|
|
714
|
+
const metadata = matchDetails.find((m) => m.word.toLowerCase() === word.toLowerCase() ||
|
|
715
|
+
(m.aliases &&
|
|
716
|
+
m.aliases.some((alias) => alias.toLowerCase() === word.toLowerCase())));
|
|
717
|
+
const regex = new RegExp(`\\b${escapeRegExp$1(word)}\\b`, 'gi');
|
|
718
|
+
let match;
|
|
719
|
+
while ((match = regex.exec(filteredText)) !== null) {
|
|
720
|
+
const originalWord = match[0];
|
|
721
|
+
if (whitelist.includes(originalWord.toLowerCase()))
|
|
722
|
+
continue;
|
|
723
|
+
const censoredWord = fullWordCensor
|
|
724
|
+
? replaceWith.repeat(originalWord.length)
|
|
725
|
+
: censorPartialWord(originalWord, replaceWith);
|
|
726
|
+
replacements.push({
|
|
727
|
+
original: originalWord,
|
|
728
|
+
censored: censoredWord,
|
|
729
|
+
metadata,
|
|
730
|
+
});
|
|
731
|
+
const replaceRegex = new RegExp(`\\b${escapeRegExp$1(originalWord)}\\b`, 'g');
|
|
732
|
+
filteredText = filteredText.replace(replaceRegex, censoredWord);
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
// if (detectLeetSpeak) {
|
|
736
|
+
// }
|
|
737
|
+
return {
|
|
738
|
+
filtered: filteredText,
|
|
739
|
+
censored: replacements.length,
|
|
740
|
+
replacements,
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Memeriksa apakah teks mengandung kata kotor
|
|
745
|
+
*
|
|
746
|
+
* @param text Teks yang akan diperiksa
|
|
747
|
+
* @param options Opsi untuk pemeriksaan
|
|
748
|
+
* @returns Boolean apakah teks mengandung kata kotor
|
|
749
|
+
*/
|
|
750
|
+
function isProfane(text, options = {}) {
|
|
751
|
+
const matches = findProfanity(text, options);
|
|
752
|
+
return matches.length > 0;
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Escape karakter khusus regex
|
|
756
|
+
*
|
|
757
|
+
* @param string String untuk di-escape
|
|
758
|
+
* @returns String yang telah di-escape
|
|
759
|
+
*/
|
|
760
|
+
function escapeRegExp$1(string) {
|
|
761
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Menyensor sebagian kata
|
|
765
|
+
* @param word Kata yang akan disensor
|
|
766
|
+
* @param replaceChar Karakter pengganti
|
|
767
|
+
* @returns Kata yang sudah disensor sebagian
|
|
768
|
+
*/
|
|
769
|
+
function censorPartialWord(word, replaceChar) {
|
|
770
|
+
if (word.length <= 2) {
|
|
771
|
+
return replaceChar.repeat(word.length);
|
|
772
|
+
}
|
|
773
|
+
// Simpan huruf pertama dan terakhir, sensor yang lain
|
|
774
|
+
return word[0] + replaceChar.repeat(word.length - 2) + word[word.length - 1];
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Menganalisis teks untuk kata kotor
|
|
779
|
+
*
|
|
780
|
+
* @param text Teks yang akan dianalisis
|
|
781
|
+
* @param options Opsi untuk analisis
|
|
782
|
+
* @return AnalysisResult dengan hasil analisis
|
|
783
|
+
*/
|
|
784
|
+
function analyze(text, options = {}) {
|
|
785
|
+
const matches = findProfanity(text, options);
|
|
786
|
+
if (matches.length === 0) {
|
|
787
|
+
return {
|
|
788
|
+
hasProfanity: false,
|
|
789
|
+
matches: [],
|
|
790
|
+
matchDetails: [],
|
|
791
|
+
categories: [],
|
|
792
|
+
regions: [],
|
|
793
|
+
severityScore: 0,
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
const matchDetails = findProfanityWithMetadata(text, options);
|
|
797
|
+
const categories = findCategories(matchDetails);
|
|
798
|
+
const regions = findRegions(matchDetails);
|
|
799
|
+
const severityScore = calculateSeverity(matchDetails);
|
|
800
|
+
return {
|
|
801
|
+
hasProfanity: true,
|
|
802
|
+
matches,
|
|
803
|
+
matchDetails,
|
|
804
|
+
categories,
|
|
805
|
+
regions,
|
|
806
|
+
severityScore,
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* menganalisis daftar teks dan ringkasan
|
|
811
|
+
*
|
|
812
|
+
* @param texts Daftar teks yagn dianalisis
|
|
813
|
+
* @param options Opsi untuk analisis
|
|
814
|
+
* @return Objek dengan ringkasan analisis
|
|
815
|
+
*/
|
|
816
|
+
function batchAnalyze(texts, options = {}) {
|
|
817
|
+
const results = texts.map((text) => analyze(text, options));
|
|
818
|
+
const profaneTexts = results.filter((result) => result.hasProfanity).length;
|
|
819
|
+
const totalSeverity = results.reduce((sum, result) => sum + result.severityScore, 0);
|
|
820
|
+
const averageSeverity = profaneTexts > 0 ? totalSeverity / profaneTexts : 0;
|
|
821
|
+
const allCategories = results.flatMap((result) => result.categories);
|
|
822
|
+
const categoryCount = {};
|
|
823
|
+
allCategories.forEach((category) => {
|
|
824
|
+
categoryCount[category] = (categoryCount[category] || 0) + 1;
|
|
825
|
+
});
|
|
826
|
+
const topCategories = Object.entries(categoryCount)
|
|
827
|
+
.sort((a, b) => b[1] - a[1])
|
|
828
|
+
.map(([category]) => category);
|
|
829
|
+
const allRegions = results.flatMap((result) => result.regions);
|
|
830
|
+
const regionCount = {};
|
|
831
|
+
allRegions.forEach((region) => {
|
|
832
|
+
regionCount[region] = (regionCount[region] || 0) + 1;
|
|
833
|
+
});
|
|
834
|
+
const topRegions = Object.entries(regionCount)
|
|
835
|
+
.sort((a, b) => b[1] - a[1])
|
|
836
|
+
.map(([region]) => region);
|
|
837
|
+
const allWords = results.flatMap((result) => result.matches);
|
|
838
|
+
const wordCount = {};
|
|
839
|
+
allWords.forEach((word) => {
|
|
840
|
+
wordCount[word] = (wordCount[word] || 0) + 1;
|
|
841
|
+
});
|
|
842
|
+
const mostFrequentWords = Object.entries(wordCount)
|
|
843
|
+
.sort((a, b) => b[1] - a[1])
|
|
844
|
+
.slice(0, 10)
|
|
845
|
+
.map(([word, count]) => ({ word, count }));
|
|
846
|
+
return {
|
|
847
|
+
totalTexts: texts.length,
|
|
848
|
+
profaneTexts,
|
|
849
|
+
cleanTexts: texts.length - profaneTexts,
|
|
850
|
+
averageSeverity,
|
|
851
|
+
topCategories,
|
|
852
|
+
topRegions,
|
|
853
|
+
mostFrequentWords,
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Menganalisis per-kalimat untuk melokalisasi kata kotor
|
|
858
|
+
*
|
|
859
|
+
* @param text Teks yang akan dianalisis per-kalimat
|
|
860
|
+
* @param options Opsi untuk analisis
|
|
861
|
+
* @returns Array hasil analisis per-kalimat
|
|
862
|
+
*/
|
|
863
|
+
function analyzeBySentence(text, options = {}) {
|
|
864
|
+
const sentences = text
|
|
865
|
+
.split(/(?<=[.!?])\s+/)
|
|
866
|
+
.filter((sentence) => sentence.trim().length > 0);
|
|
867
|
+
return sentences.map((sentence) => {
|
|
868
|
+
const result = analyze(sentence, options);
|
|
869
|
+
return {
|
|
870
|
+
...result,
|
|
871
|
+
sentence,
|
|
872
|
+
};
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Menganalisis teks untuk menemukan kata kotor pada konteks tertentu
|
|
877
|
+
*
|
|
878
|
+
* @param text Teks yang akan dianalisis
|
|
879
|
+
* @param context Kata konteks untuk dicari di dekat kata kotor
|
|
880
|
+
* @param options Opsi untuk analisis
|
|
881
|
+
* @returns Konteks di dekat kata kotor
|
|
882
|
+
*/
|
|
883
|
+
function analyzeWithContext(text, contextWindowSize = 5, options = {}) {
|
|
884
|
+
const matches = findProfanity(text, options);
|
|
885
|
+
if (matches.length === 0) {
|
|
886
|
+
return [];
|
|
887
|
+
}
|
|
888
|
+
const result = [];
|
|
889
|
+
for (const word of matches) {
|
|
890
|
+
const regex = new RegExp(`((?:\\S+\\s+){0,${contextWindowSize}})(\\b${escapeRegExp(word)}\\b)((?:\\s+\\S+){0,${contextWindowSize}})`, 'gi');
|
|
891
|
+
let match;
|
|
892
|
+
while ((match = regex.exec(text)) !== null) {
|
|
893
|
+
const beforeContext = match[1] || '';
|
|
894
|
+
const wordMatch = match[2];
|
|
895
|
+
const afterContext = match[3] || '';
|
|
896
|
+
result.push({
|
|
897
|
+
word: wordMatch,
|
|
898
|
+
context: beforeContext + wordMatch + afterContext,
|
|
899
|
+
position: {
|
|
900
|
+
start: match.index,
|
|
901
|
+
end: match.index + match[0].length,
|
|
902
|
+
},
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return result;
|
|
907
|
+
}
|
|
908
|
+
function escapeRegExp(string) {
|
|
909
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
class IDProfanityFilter {
|
|
913
|
+
/**
|
|
914
|
+
* Membuat instance filter baru
|
|
915
|
+
* @param options Opsi untuk filter
|
|
916
|
+
*/
|
|
917
|
+
constructor(options = {}) {
|
|
918
|
+
this.options = options;
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Menyensor teks yang diberikan
|
|
922
|
+
* @param text Teks yang akan disensor
|
|
923
|
+
* @returns Hasil filter
|
|
924
|
+
*/
|
|
925
|
+
filter(text) {
|
|
926
|
+
return filter(text, this.options);
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Memeriksa apakah teks mengandung kata kotor
|
|
930
|
+
* @param text Teks yang akan diperiksa
|
|
931
|
+
* @returns Boolean apakah teks mengandung kata kotor
|
|
932
|
+
*/
|
|
933
|
+
isProfane(text) {
|
|
934
|
+
return isProfane(text, this.options);
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Menganalisis teks untuk kata kotor
|
|
938
|
+
* @param text Teks yang akan dianalisis
|
|
939
|
+
* @returns Hasil analisis
|
|
940
|
+
*/
|
|
941
|
+
analyze(text) {
|
|
942
|
+
return analyze(text, this.options);
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Menganalisis batch teks untuk kata kotor
|
|
946
|
+
* @param texts Array dari teks yang akan dianalisis
|
|
947
|
+
* @returns Hasil analisis batch
|
|
948
|
+
*/
|
|
949
|
+
batchAnalyze(texts) {
|
|
950
|
+
return batchAnalyze(texts, this.options);
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Menganalisis teks per-kalimat
|
|
954
|
+
* @param text Teks yang akan dianalisis
|
|
955
|
+
* @returns Array hasil analisis per-kalimat
|
|
956
|
+
*/
|
|
957
|
+
analyzeBySentence(text) {
|
|
958
|
+
return analyzeBySentence(text, this.options);
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Menganalisis teks dengan konteks di sekitar kata kotor
|
|
962
|
+
* @param text Teks yang akan dianalisis
|
|
963
|
+
* @param contextWindowSize Jumlah kata konteks
|
|
964
|
+
* @returns Konteks di dekat kata kotor
|
|
965
|
+
*/
|
|
966
|
+
analyzeWithContext(text, contextWindowSize = 5) {
|
|
967
|
+
return analyzeWithContext(text, contextWindowSize, this.options);
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Mengubah opsi filter
|
|
971
|
+
* @param options Opsi baru untuk filter
|
|
972
|
+
*/
|
|
973
|
+
setOptions(options) {
|
|
974
|
+
this.options = {
|
|
975
|
+
...this.options,
|
|
976
|
+
...options,
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* Menetapkan daftar kata kustom
|
|
981
|
+
* @param wordList Daftar kata untuk digunakan
|
|
982
|
+
*/
|
|
983
|
+
setWordList(wordList) {
|
|
984
|
+
this.options.wordList = wordList;
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Menambahkan kata ke whitelist
|
|
988
|
+
* @param word Kata yang akan diabaikan
|
|
989
|
+
*/
|
|
990
|
+
addToWhitelist(word) {
|
|
991
|
+
this.options.whitelist = [
|
|
992
|
+
...(this.options.whitelist || []),
|
|
993
|
+
word.toLowerCase(),
|
|
994
|
+
];
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Menghapus kata dari whitelist
|
|
998
|
+
* @param word Kata yang akan dihapus dari whitelist
|
|
999
|
+
*/
|
|
1000
|
+
removeFromWhitelist(word) {
|
|
1001
|
+
if (!this.options.whitelist)
|
|
1002
|
+
return;
|
|
1003
|
+
this.options.whitelist = this.options.whitelist.filter((w) => w.toLowerCase() !== word.toLowerCase());
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
const idFilter = {
|
|
1007
|
+
filter: (text, options) => filter(text, options),
|
|
1008
|
+
isProfane: (text, options) => isProfane(text, options),
|
|
1009
|
+
analyze: (text, options) => analyze(text, options),
|
|
1010
|
+
batchAnalyze: (texts, options) => batchAnalyze(texts, options),
|
|
1011
|
+
};
|
|
1012
|
+
|
|
1013
|
+
export { IDProfanityFilter, analyze, analyzeBySentence, analyzeWithContext, batchAnalyze, calculateSeverity, IDProfanityFilter as default, filter, findCategories, findProfanity, findProfanityWithMetadata, findRegions, idFilter, isProfane };
|
|
1014
|
+
//# sourceMappingURL=index.esm.js.map
|