@koralabs/kora-labs-common 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -243,4 +243,32 @@ export interface OAuthToken {
243
243
  token: string;
244
244
  social: OAuthSocial;
245
245
  }
246
+ export interface ProtectedWord {
247
+ word: string;
248
+ algorithms: ('modifier' | 'badword' | 'suggestive' | 'hatespeech' | 'vulnerable')[];
249
+ modType?: ('modifier' | 'suggestive' | 'hatespeech')[];
250
+ canBePositive?: boolean;
251
+ position?: 'exact' | 'any' | 'beginswith';
252
+ exceptions?: string[];
253
+ }
254
+ export declare enum AvailabilityResponseCode {
255
+ AVAILABLE = 200,
256
+ NOT_AVAILABLE_FOR_LEGAL_REASONS = 451,
257
+ NOT_ACCEPTABLE = 406,
258
+ LOCKED = 423
259
+ }
260
+ export interface AvailabilityResponse {
261
+ available: boolean;
262
+ handle: string;
263
+ message?: string;
264
+ type?: 'notallowed' | 'invalid';
265
+ link?: string;
266
+ reason?: string;
267
+ duration?: number;
268
+ code: AvailabilityResponseCode;
269
+ }
270
+ export interface ReservedOrProtected {
271
+ reserved?: string[];
272
+ protected: ProtectedWord[];
273
+ }
246
274
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OAuthSocial = exports.AssetNameLabel = exports.Rarity = void 0;
3
+ exports.AvailabilityResponseCode = exports.OAuthSocial = exports.AssetNameLabel = exports.Rarity = void 0;
4
4
  var Rarity;
5
5
  (function (Rarity) {
6
6
  Rarity["basic"] = "basic";
@@ -44,3 +44,10 @@ var OAuthSocial;
44
44
  OAuthSocial[OAuthSocial["soundcloud"] = 17] = "soundcloud";
45
45
  OAuthSocial[OAuthSocial["paypal"] = 18] = "paypal";
46
46
  })(OAuthSocial = exports.OAuthSocial || (exports.OAuthSocial = {}));
47
+ var AvailabilityResponseCode;
48
+ (function (AvailabilityResponseCode) {
49
+ AvailabilityResponseCode[AvailabilityResponseCode["AVAILABLE"] = 200] = "AVAILABLE";
50
+ AvailabilityResponseCode[AvailabilityResponseCode["NOT_AVAILABLE_FOR_LEGAL_REASONS"] = 451] = "NOT_AVAILABLE_FOR_LEGAL_REASONS";
51
+ AvailabilityResponseCode[AvailabilityResponseCode["NOT_ACCEPTABLE"] = 406] = "NOT_ACCEPTABLE";
52
+ AvailabilityResponseCode[AvailabilityResponseCode["LOCKED"] = 423] = "LOCKED";
53
+ })(AvailabilityResponseCode = exports.AvailabilityResponseCode || (exports.AvailabilityResponseCode = {}));
package/lib/index.d.ts CHANGED
@@ -3,3 +3,5 @@ export { Environment, ComputeEnvironment } from "./environment";
3
3
  export * from "./handles/interfaces";
4
4
  export * from "./handles/constants";
5
5
  export { checkHandlePattern } from "./handles/validation";
6
+ export * from "./utils";
7
+ export { ProtectedWords } from "./protectedWords";
package/lib/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.checkHandlePattern = exports.ComputeEnvironment = exports.Environment = exports.LogCategory = exports.Logger = void 0;
17
+ exports.ProtectedWords = exports.checkHandlePattern = exports.ComputeEnvironment = exports.Environment = exports.LogCategory = exports.Logger = void 0;
18
18
  var logger_1 = require("./logger");
19
19
  Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return logger_1.Logger; } });
20
20
  Object.defineProperty(exports, "LogCategory", { enumerable: true, get: function () { return logger_1.LogCategory; } });
@@ -25,3 +25,6 @@ __exportStar(require("./handles/interfaces"), exports);
25
25
  __exportStar(require("./handles/constants"), exports);
26
26
  var validation_1 = require("./handles/validation");
27
27
  Object.defineProperty(exports, "checkHandlePattern", { enumerable: true, get: function () { return validation_1.checkHandlePattern; } });
28
+ __exportStar(require("./utils"), exports);
29
+ var protectedWords_1 = require("./protectedWords");
30
+ Object.defineProperty(exports, "ProtectedWords", { enumerable: true, get: function () { return protectedWords_1.ProtectedWords; } });
@@ -22,6 +22,7 @@ describe('Logger Tests', () => {
22
22
  dimensions: ['taco'],
23
23
  event: 'test.log',
24
24
  message: 'burritos',
25
+ network: "UNSET",
25
26
  milliseconds: now,
26
27
  timestamp: expect.stringMatching(/[0-9\-]+T[0-9\:\.]+Z/)
27
28
  });
@@ -0,0 +1,33 @@
1
+ import { AvailabilityResponse, ReservedOrProtected } from '../handles/interfaces';
2
+ declare global {
3
+ interface String {
4
+ includesSingularOrPlural(word: string): boolean;
5
+ replaceSingularOrPlural(word: string, replacement: string): string;
6
+ }
7
+ }
8
+ export declare class ProtectedWords {
9
+ static protectedHandles: ReservedOrProtected;
10
+ static readLock: boolean;
11
+ static cacheResetTime: number;
12
+ static checkAvailability(handle: string): Promise<AvailabilityResponse>;
13
+ static setSingular(handle: string): {
14
+ plural: string;
15
+ singular: string;
16
+ };
17
+ static isNumberReplacementsProtected(handle: string, checkIfMatches?: (h: string) => {
18
+ protected: boolean;
19
+ words?: string[];
20
+ }): {
21
+ protected: boolean;
22
+ words?: string[];
23
+ };
24
+ static isProtected(handle: string): {
25
+ protected: boolean;
26
+ words?: string[];
27
+ };
28
+ static isBadWord(handle: string): {
29
+ badword: boolean;
30
+ words?: string[];
31
+ };
32
+ static trimChars(handle: string, chars: string): string;
33
+ }
@@ -0,0 +1,363 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ProtectedWords = void 0;
16
+ const pluralize_1 = __importDefault(require("pluralize"));
17
+ const protectedWords_1 = require("./protectedWords");
18
+ const utils_1 = require("../utils");
19
+ const interfaces_1 = require("../handles/interfaces");
20
+ const constants_1 = require("../handles/constants");
21
+ String.prototype.includesSingularOrPlural = function (word) {
22
+ const singPlur = ProtectedWords.setSingular(word);
23
+ return this.includes(singPlur.singular) || this.includes(singPlur.plural);
24
+ };
25
+ String.prototype.replaceSingularOrPlural = function (word, replacement) {
26
+ const singPlur = ProtectedWords.setSingular(word);
27
+ return this.replace(singPlur.singular, replacement).replace(singPlur.plural, replacement);
28
+ };
29
+ class ProtectedWords {
30
+ static checkAvailability(handle) {
31
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
32
+ return __awaiter(this, void 0, void 0, function* () {
33
+ yield (0, utils_1.delay)(0); // This has to be here to allow early Promise return
34
+ const startTime = Date.now();
35
+ handle = handle.toLowerCase();
36
+ const notAllowedResponse = {
37
+ available: false,
38
+ handle,
39
+ type: 'notallowed',
40
+ code: interfaces_1.AvailabilityResponseCode.NOT_AVAILABLE_FOR_LEGAL_REASONS
41
+ };
42
+ const allowedResponse = {
43
+ available: true,
44
+ handle,
45
+ code: interfaces_1.AvailabilityResponseCode.AVAILABLE
46
+ };
47
+ // if it is all numbers or non-alphas, we don't care
48
+ if (handle.match(/^[0-9@_.-]{1,28}$/)) {
49
+ allowedResponse.duration = Date.now() - startTime;
50
+ return allowedResponse;
51
+ }
52
+ let handleMatches = handle.match(constants_1.REGEX_SPLIT_ON_CHARS);
53
+ if (handleMatches) {
54
+ for (let i = 0; i < (handleMatches === null || handleMatches === void 0 ? void 0 : handleMatches.length); i++) {
55
+ const match = handleMatches[i];
56
+ let listed = this.isProtected(match);
57
+ // This will get `my.shit.stinks`, `_my-shits_stink`, `my.shitz.stink`, and `-my_shit5_stink-`
58
+ if (listed.protected) {
59
+ notAllowedResponse.reason = `Protected word match on '${(_a = listed.words) === null || _a === void 0 ? void 0 : _a.join(',')}'`;
60
+ notAllowedResponse.duration = Date.now() - startTime;
61
+ return notAllowedResponse;
62
+ }
63
+ // This will get `my.5h1t.stinks`, `_my-shi7s_stink`, `my_sh1tz.stink`, and `-my_5hit5_stink`
64
+ listed = this.isNumberReplacementsProtected(match);
65
+ if (listed.protected) {
66
+ notAllowedResponse.reason = `Number replacement match on '${(_b = listed.words) === null || _b === void 0 ? void 0 : _b.join(',')}'`;
67
+ notAllowedResponse.duration = Date.now() - startTime;
68
+ return notAllowedResponse;
69
+ }
70
+ // This will get `my.123shit456`, `0shits0.stink`, `11shitz11.you`
71
+ let handleTrimmed = this.trimChars(match, '0123456789');
72
+ listed = this.isProtected(handleTrimmed);
73
+ if (listed.protected) {
74
+ notAllowedResponse.reason = `Number trim match on '${(_c = listed.words) === null || _c === void 0 ? void 0 : _c.join(',')}'`;
75
+ notAllowedResponse.duration = Date.now() - startTime;
76
+ return notAllowedResponse;
77
+ }
78
+ // This will get `1xshitx1`, `xxxshitsxxx`, `0x0shitz0x0`
79
+ handleTrimmed = this.trimChars(match, 'x0123456789');
80
+ listed = this.isProtected(handleTrimmed);
81
+ if (listed.protected) {
82
+ notAllowedResponse.reason = `Number and 'x' trim match on '${(_d = listed.words) === null || _d === void 0 ? void 0 : _d.join(',')}'`;
83
+ notAllowedResponse.duration = Date.now() - startTime;
84
+ return notAllowedResponse;
85
+ }
86
+ }
87
+ }
88
+ // This will get `.s.h.i.7.`, sh.1_7s`, `5.h-1-t__z`, and `sh1.t5`
89
+ handle = handle.replace(/[_.-]/g, '');
90
+ const listed = this.isNumberReplacementsProtected(handle);
91
+ if (listed.protected) {
92
+ notAllowedResponse.reason = `Protected word match (with stripped characters) on '${(_e = listed.words) === null || _e === void 0 ? void 0 : _e.join(',')}'`;
93
+ notAllowedResponse.duration = Date.now() - startTime;
94
+ return notAllowedResponse;
95
+ }
96
+ handleMatches = handle.match(constants_1.REGEX_SPLIT_ON_NUMS);
97
+ if (handleMatches) {
98
+ for (let i = 0; i < (handleMatches === null || handleMatches === void 0 ? void 0 : handleMatches.length); i++) {
99
+ const match = handleMatches[i];
100
+ // This will get `my1shit1stinks`, `0my1shits2stink`, `my3shitz4stink`, and `5my1shit5stink-`
101
+ const listed = this.isProtected(match);
102
+ if (listed.protected) {
103
+ notAllowedResponse.reason = `Split on numbers match for '${(_f = listed.words) === null || _f === void 0 ? void 0 : _f.join(',')}'`;
104
+ notAllowedResponse.duration = Date.now() - startTime;
105
+ return notAllowedResponse;
106
+ }
107
+ }
108
+ }
109
+ // anywhere in the string and beginswith lookups
110
+ // this will get `allmyshitsucks`, `eatsh17anddie`, `shithead`
111
+ let matchResult = this.isNumberReplacementsProtected(handle, (h) => {
112
+ let foundWord = '';
113
+ // First check the 'any' list - anywhere in the string is bad
114
+ if (ProtectedWords.protectedHandles.protected.some((entry) => {
115
+ var _a;
116
+ foundWord = entry.word;
117
+ return (entry.position == 'any' &&
118
+ !((_a = entry.exceptions) === null || _a === void 0 ? void 0 : _a.some((exc) => h.includes(exc))) &&
119
+ h.includesSingularOrPlural(entry.word));
120
+ })) {
121
+ return { protected: true, words: [foundWord] };
122
+ }
123
+ // Then check 'beginswith', a little note that "beginswith" works better when the next
124
+ // character is a consonant. This will let a few badwords through, but will greatly reduce
125
+ // false positives.
126
+ if (ProtectedWords.protectedHandles.protected.some((entry) => {
127
+ var _a, _b;
128
+ foundWord = entry.word;
129
+ return (entry.position == 'beginswith' &&
130
+ h.startsWith(entry.word) &&
131
+ !'aeiou'.includes((_a = h.replaceSingularOrPlural(entry.word, '')) === null || _a === void 0 ? void 0 : _a.charAt(0)) &&
132
+ !((_b = entry.exceptions) === null || _b === void 0 ? void 0 : _b.some((exc) => h.includes(exc))));
133
+ })) {
134
+ return { protected: true, words: [foundWord] };
135
+ }
136
+ return { protected: false };
137
+ });
138
+ if (matchResult.protected) {
139
+ notAllowedResponse.reason = `In string match found for '${(_g = matchResult.words) === null || _g === void 0 ? void 0 : _g.join(',')}'`;
140
+ notAllowedResponse.duration = Date.now() - startTime;
141
+ return notAllowedResponse;
142
+ }
143
+ // "vulnerable" targets are slightly different than "hatespeech" targets, but we can combine them here for speed.
144
+ const hatespeechEntries = ProtectedWords.protectedHandles.protected.filter((entry) => entry.algorithms.includes('hatespeech') || entry.algorithms.includes('vulnerable'));
145
+ const hatespeechWords = ProtectedWords.protectedHandles.protected.filter((entry) => { var _a; return (_a = entry.modType) === null || _a === void 0 ? void 0 : _a.includes('hatespeech'); });
146
+ // hatespeech lookups
147
+ matchResult = this.isNumberReplacementsProtected(handle, (h) => {
148
+ let foundWords = '';
149
+ if (hatespeechEntries.some((entry) => {
150
+ var _a;
151
+ return (h.includesSingularOrPlural(entry.word) &&
152
+ // It's a hatespeech target and includes a hatespeech modifier (check exceptions)
153
+ !((_a = entry.exceptions) === null || _a === void 0 ? void 0 : _a.some((exc) => h.includes(exc))) &&
154
+ hatespeechWords.some((hateWord) => {
155
+ var _a;
156
+ foundWords = `${entry.word},${hateWord.word}`;
157
+ return (h.replaceSingularOrPlural(entry.word, ' ').includes(hateWord.word) &&
158
+ !((_a = hateWord.exceptions) === null || _a === void 0 ? void 0 : _a.some((exc) => h.includes(exc))) &&
159
+ // If it's a vulnerable target, a positive word is fine
160
+ !(entry.algorithms.includes('vulnerable') && hateWord.canBePositive) &&
161
+ // If it's not a bad word and it is a hatespeech target then a positive word is fine
162
+ !(!entry.algorithms.includes('badword') &&
163
+ entry.algorithms.includes('hatespeech') &&
164
+ hateWord.canBePositive));
165
+ }));
166
+ })) {
167
+ return { protected: true, words: foundWords.split(',') };
168
+ }
169
+ return { protected: false };
170
+ });
171
+ if (matchResult.protected) {
172
+ notAllowedResponse.reason = `Hatespeech match found for ${(_h = matchResult.words) === null || _h === void 0 ? void 0 : _h.join(',')}`;
173
+ notAllowedResponse.duration = Date.now() - startTime;
174
+ return notAllowedResponse;
175
+ }
176
+ // 'pp' can make some pretty bad phrases, but can't be dealt with normally since it is in so many "good" words
177
+ // just combine with modifiers for now
178
+ const specialCaseVulnWords = ['pp'];
179
+ const modifiers = ProtectedWords.protectedHandles.protected.filter((entry) => { var _a; return (_a = entry.modType) === null || _a === void 0 ? void 0 : _a.includes('modifier'); });
180
+ // suggestive & vulnerable lookups - 'lickmyd1ck`, `s3xmyp3n1s`
181
+ const suggestiveWords = ProtectedWords.protectedHandles.protected.filter((entry) => { var _a; return (_a = entry.modType) === null || _a === void 0 ? void 0 : _a.includes('suggestive'); });
182
+ const vulnerableEntries = ProtectedWords.protectedHandles.protected.filter((entry) => entry.algorithms.includes('vulnerable'));
183
+ const suggestiveEntries = ProtectedWords.protectedHandles.protected.filter((entry) => entry.algorithms.includes('suggestive'));
184
+ matchResult = this.isNumberReplacementsProtected(handle, (h) => {
185
+ let foundWords = '';
186
+ if ([...suggestiveEntries, ...vulnerableEntries].some((entry) => {
187
+ var _a;
188
+ // is combined with a suggestive word, or another suggestive entry (from the same badwords list), or it's a modifier + `pp`
189
+ return (h.includesSingularOrPlural(entry.word) &&
190
+ !((_a = entry.exceptions) === null || _a === void 0 ? void 0 : _a.some((exc) => h.includes(exc))) &&
191
+ (suggestiveWords.some((s) => {
192
+ var _a;
193
+ // is combined with a suggestive word (check exceptions)
194
+ foundWords = `${entry.word},${s.word}`;
195
+ return (h.replaceSingularOrPlural(entry.word, ' ').includes(s.word) &&
196
+ !((_a = s.exceptions) === null || _a === void 0 ? void 0 : _a.some((exc) => h.includes(exc))) &&
197
+ !(entry.algorithms.includes('vulnerable') && s.canBePositive));
198
+ }) ||
199
+ suggestiveEntries.some((s) => {
200
+ var _a;
201
+ // is combined with another suggestive entry from the badwords list (check exceptions)
202
+ foundWords = `${entry.word},${s.word}`;
203
+ return (s != entry &&
204
+ h.replaceSingularOrPlural(entry.word, ' ').includesSingularOrPlural(s.word) &&
205
+ !((_a = s.exceptions) === null || _a === void 0 ? void 0 : _a.some((exc) => h.includes(exc))));
206
+ }) ||
207
+ modifiers.some((mod) => h.replaceSingularOrPlural(entry.word, ' ').includes(mod.word) &&
208
+ // If it can be a positive modifier, like "love", then vulnerable targets are OK
209
+ !(entry.algorithms.includes('vulnerable') &&
210
+ mod.canBePositive &&
211
+ !specialCaseVulnWords.some((spec) => {
212
+ // it's a modifier + `pp` - This is a hint that it's not a good phrase like "tinypreteenpp"
213
+ foundWords = `${entry.word},${mod.word},${spec}`;
214
+ return h
215
+ .replaceSingularOrPlural(entry.word, ' ')
216
+ .replaceSingularOrPlural(mod.word, ' ')
217
+ .includes(spec);
218
+ })) &&
219
+ specialCaseVulnWords.some((spec) => {
220
+ // it's a modifier + `pp` - This is a hint that it's not a good phrase like "tinypreteenpp"
221
+ foundWords = `${entry.word},${mod.word},${spec}`;
222
+ return h
223
+ .replaceSingularOrPlural(entry.word, ' ')
224
+ .replaceSingularOrPlural(mod.word, ' ')
225
+ .includes(spec);
226
+ }))));
227
+ })) {
228
+ return { protected: true, words: foundWords.split(',') };
229
+ }
230
+ return { protected: false };
231
+ });
232
+ if (matchResult.protected) {
233
+ notAllowedResponse.reason = `Suggestive language match found for ${(_j = matchResult.words) === null || _j === void 0 ? void 0 : _j.join(',')}`;
234
+ notAllowedResponse.duration = Date.now() - startTime;
235
+ return notAllowedResponse;
236
+ }
237
+ allowedResponse.duration = Date.now() - startTime;
238
+ return allowedResponse;
239
+ });
240
+ }
241
+ static setSingular(handle) {
242
+ let singular = handle;
243
+ let plural = handle;
244
+ if (pluralize_1.default.isPlural(handle)) {
245
+ singular = pluralize_1.default.singular(handle);
246
+ }
247
+ else {
248
+ plural = (0, pluralize_1.default)(handle);
249
+ }
250
+ return { plural, singular };
251
+ }
252
+ static isNumberReplacementsProtected(handle, checkIfMatches) {
253
+ // 8's can be problematic (because they are replaced with 'ate' or 'ait').
254
+ // When combined with multiple numbers they are probably not a bad word anyway
255
+ let handleReplacedTemp = handle;
256
+ // it's about 5x faster to check the includes first than it is to just call replace directly
257
+ if (handleReplacedTemp.includes('8'))
258
+ handleReplacedTemp = handleReplacedTemp.replace(/(8[0-9])|([0-9]8){2,}/g, '');
259
+ if (handleReplacedTemp.includes('0'))
260
+ handleReplacedTemp = handleReplacedTemp.replace(/0/g, 'o');
261
+ if (handleReplacedTemp.includes('2'))
262
+ handleReplacedTemp = handleReplacedTemp.replace(/2/g, 'z');
263
+ if (handleReplacedTemp.includes('3'))
264
+ handleReplacedTemp = handleReplacedTemp.replace(/3/g, 'e');
265
+ if (handleReplacedTemp.includes('4'))
266
+ handleReplacedTemp = handleReplacedTemp.replace(/4/g, 'a');
267
+ if (handleReplacedTemp.includes('5'))
268
+ handleReplacedTemp = handleReplacedTemp.replace(/5/g, 's');
269
+ if (handleReplacedTemp.includes('6'))
270
+ handleReplacedTemp = handleReplacedTemp.replace(/6/g, 'g');
271
+ if (handleReplacedTemp.includes('7'))
272
+ handleReplacedTemp = handleReplacedTemp.replace(/7/g, 't');
273
+ if (handleReplacedTemp.includes('9'))
274
+ handleReplacedTemp = handleReplacedTemp.replace(/9/g, 'g');
275
+ if (handleReplacedTemp.includes('@'))
276
+ handleReplacedTemp = handleReplacedTemp.replace(/@/g, 'a');
277
+ if (handleReplacedTemp.includes('1') || handleReplacedTemp.includes('8')) {
278
+ // ones and eights have two replaceable chars each
279
+ // This logic isn't quite right. It should check each individual instance with either replacement
280
+ // possible improvement needed here to catch more words
281
+ // letting it slide for now since number replacements are less obvious
282
+ // and this is the slowest part of the algorithm
283
+ for (const one of ['i', 'l']) {
284
+ for (const eight of ['ate', 'ait']) {
285
+ const handleReplaced = handleReplacedTemp.replace(/1/g, one).replace(/8/g, eight);
286
+ const listed = this.isProtected(handleReplaced);
287
+ if (listed.protected)
288
+ return { protected: true, words: listed.words };
289
+ if (checkIfMatches) {
290
+ const matches = checkIfMatches(handleReplaced);
291
+ if (matches.protected)
292
+ return { protected: true, words: matches.words };
293
+ }
294
+ }
295
+ }
296
+ }
297
+ const listed = this.isProtected(handleReplacedTemp);
298
+ if (listed.protected)
299
+ return { protected: true, words: listed.words };
300
+ if (checkIfMatches) {
301
+ const matches = checkIfMatches(handleReplacedTemp);
302
+ if (matches.protected)
303
+ return { protected: true, words: matches.words };
304
+ }
305
+ return { protected: false };
306
+ }
307
+ static isProtected(handle) {
308
+ let { singular } = this.setSingular(handle);
309
+ let bad = this.isBadWord(singular);
310
+ if (bad.badword) {
311
+ return { protected: true, words: bad.words };
312
+ }
313
+ const pluralz = handle.replace(/[z5]$/, 's');
314
+ if (pluralz != handle) {
315
+ ({ singular } = this.setSingular(handle));
316
+ bad = this.isBadWord(singular);
317
+ if (bad.badword) {
318
+ return { protected: true, words: bad.words };
319
+ }
320
+ }
321
+ return { protected: false };
322
+ }
323
+ static isBadWord(handle) {
324
+ const protectedWords = ProtectedWords.protectedHandles.protected;
325
+ const modifiers = ProtectedWords.protectedHandles.protected.filter((entry) => { var _a; return (_a = entry.modType) === null || _a === void 0 ? void 0 : _a.includes('modifier'); });
326
+ const found = protectedWords.find((x) => x.word == handle && x.algorithms.includes('badword'));
327
+ if (found)
328
+ return { badword: true, words: [found.word] };
329
+ let foundWords = '';
330
+ if (modifiers.some((m) => protectedWords.some((entry) => {
331
+ var _a, _b;
332
+ foundWords = `${entry.word},${m.word}`;
333
+ // If there is a badword modifier word, then it's a hint that the phrase is bad (check exceptions)
334
+ return (entry.algorithms.includes('badword') &&
335
+ !((_a = entry.exceptions) === null || _a === void 0 ? void 0 : _a.some((exc) => handle.includes(exc))) &&
336
+ !((_b = m.exceptions) === null || _b === void 0 ? void 0 : _b.some((exc) => handle.includes(exc))) &&
337
+ // small modifiers (<3 chars) can increase false positives, so just check to see if they are at the beginning or end of the word
338
+ ((m.word.length <= 3 &&
339
+ entry.word == handle.replace(new RegExp(`(^${m.word})|(${m.word}$)`), '')) ||
340
+ // if over 3 chars, check anywhere in the word
341
+ (m.word.length > 3 &&
342
+ handle.includes(entry.word) &&
343
+ handle.replaceSingularOrPlural(entry.word, ' ').includes(m.word))));
344
+ }))) {
345
+ return { badword: true, words: foundWords.split(',') };
346
+ }
347
+ return { badword: false };
348
+ }
349
+ static trimChars(handle, chars) {
350
+ let startIndex = 0;
351
+ let lastIndex = handle.length - 1;
352
+ while (chars.includes(handle[startIndex])) {
353
+ startIndex++;
354
+ }
355
+ while (chars.includes(handle[lastIndex])) {
356
+ lastIndex--;
357
+ }
358
+ return handle.substring(startIndex, lastIndex + 1);
359
+ }
360
+ }
361
+ exports.ProtectedWords = ProtectedWords;
362
+ ProtectedWords.protectedHandles = { protected: protectedWords_1.words };
363
+ ProtectedWords.readLock = false;
@@ -0,0 +1 @@
1
+ export {};